From 1a0261ed367b68b9771e528b40c0137199cb9221 Mon Sep 17 00:00:00 2001 From: ragilap Date: Wed, 28 Jan 2026 10:08:41 +0700 Subject: [PATCH] [FIX/BE-US] fixing stock log delete recording and purchase --- .../recordings/services/recording.service.go | 47 +++++++- .../purchases/services/purchase.service.go | 100 +++++++++++++++++- 2 files changed, 144 insertions(+), 3 deletions(-) diff --git a/internal/modules/production/recordings/services/recording.service.go b/internal/modules/production/recordings/services/recording.service.go index 25103c2f..0499bb17 100644 --- a/internal/modules/production/recordings/services/recording.service.go +++ b/internal/modules/production/recordings/services/recording.service.go @@ -711,6 +711,11 @@ func (s recordingService) Approval(c *fiber.Ctx, req *validation.Approve) ([]ent func (s recordingService) DeleteOne(c *fiber.Ctx, id uint) error { ctx := c.Context() + actorID, err := m.ActorIDFromContext(c) + if err != nil { + return err + } + note := fmt.Sprintf("Recording-Delete#%d", id) return s.Repository.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error { oldDepletions, err := s.Repository.ListDepletions(tx, id) @@ -719,7 +724,7 @@ func (s recordingService) DeleteOne(c *fiber.Ctx, id uint) error { return err } if s.FifoSvc != nil { - if err := s.releaseRecordingDepletions(ctx, tx, oldDepletions, "", 0); err != nil { + if err := s.releaseRecordingDepletions(ctx, tx, oldDepletions, note, actorID); err != nil { return err } } @@ -741,7 +746,7 @@ func (s recordingService) DeleteOne(c *fiber.Ctx, id uint) error { return err } - if err := s.releaseRecordingStocks(ctx, tx, oldStocks, "", 0); err != nil { + if err := s.releaseRecordingStocks(ctx, tx, oldStocks, note, actorID); err != nil { return err } @@ -749,6 +754,10 @@ func (s recordingService) DeleteOne(c *fiber.Ctx, id uint) error { return err } + if err := s.logRecordingEggRollback(ctx, tx, oldEggs, note, actorID); err != nil { + return err + } + if err := s.Repository.WithTx(tx).DeleteOne(ctx, id); err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fiber.NewError(fiber.StatusNotFound, "Recording not found") @@ -761,6 +770,40 @@ func (s recordingService) DeleteOne(c *fiber.Ctx, id uint) error { }) } +func (s *recordingService) logRecordingEggRollback( + ctx context.Context, + tx *gorm.DB, + eggs []entity.RecordingEgg, + note string, + actorID uint, +) error { + if len(eggs) == 0 || s.StockLogRepo == nil { + return nil + } + if strings.TrimSpace(note) == "" || actorID == 0 { + return nil + } + + for _, egg := range eggs { + if egg.ProductWarehouseId == 0 || egg.Qty <= 0 { + continue + } + log := &entity.StockLog{ + ProductWarehouseId: egg.ProductWarehouseId, + CreatedBy: actorID, + Decrease: float64(egg.Qty), + LoggableType: string(utils.StockLogTypeRecording), + LoggableId: egg.RecordingId, + Notes: note, + } + if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { + return err + } + } + + return nil +} + // === Persistence Helpers === func (s *recordingService) ensureProductWarehousesExist(c *fiber.Ctx, stocks []validation.Stock, depletions []validation.Depletion, eggs []validation.Egg) error { diff --git a/internal/modules/purchases/services/purchase.service.go b/internal/modules/purchases/services/purchase.service.go index 6b423d33..572069ed 100644 --- a/internal/modules/purchases/services/purchase.service.go +++ b/internal/modules/purchases/services/purchase.service.go @@ -18,9 +18,9 @@ import ( rSupplier "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/repositories" rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories" projectFlockKandangRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories" - rStockLogs "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/repositories" rPurchase "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/validations" + rStockLogs "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/repositories" "gitlab.com/mbugroup/lti-api.git/internal/utils" approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals" "gitlab.com/mbugroup/lti-api.git/internal/utils/fifo" @@ -1256,6 +1256,10 @@ func (s *purchaseService) DeletePurchase(c *fiber.Ctx, id uint) error { } ctx := c.Context() + actorID, err := m.ActorIDFromContext(c) + if err != nil { + return err + } purchase, err := s.loadPurchase(ctx, id) if err != nil { return err @@ -1269,7 +1273,16 @@ func (s *purchaseService) DeletePurchase(c *fiber.Ctx, id uint) error { itemsToDelete[i] = item } + note := fmt.Sprintf("Purchase-Delete#%d", purchase.Id) + if purchase.PoNumber != nil && strings.TrimSpace(*purchase.PoNumber) != "" { + note = fmt.Sprintf("%s#delete", strings.TrimSpace(*purchase.PoNumber)) + } + transactionErr := s.PurchaseRepo.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error { + if err := s.rollbackPurchaseStock(ctx, tx, itemsToDelete, note, actorID); err != nil { + return err + } + approvalRepoTx := commonRepo.NewApprovalRepository(tx) if err := approvalRepoTx.DeleteByTarget(ctx, utils.ApprovalWorkflowPurchase.String(), uint(id)); err != nil { return err @@ -1305,6 +1318,91 @@ func (s *purchaseService) DeletePurchase(c *fiber.Ctx, id uint) error { return nil } +func (s *purchaseService) rollbackPurchaseStock(ctx context.Context, tx *gorm.DB, items []entity.PurchaseItem, note string, actorID uint) error { + if len(items) == 0 { + return nil + } + + pwRepoTx := rProductWarehouse.NewProductWarehouseRepository(tx) + stockLogRepoTx := rStockLogs.NewStockLogRepository(tx) + deltas := make(map[uint]float64) + affected := make(map[uint]struct{}) + logEntries := make([]struct { + pwID uint + qty float64 + }, 0, len(items)) + + for _, item := range items { + if item.ProductWarehouseId == nil || *item.ProductWarehouseId == 0 { + continue + } + if item.TotalQty == 0 { + continue + } + pwID := *item.ProductWarehouseId + qty := item.TotalQty + + if s.FifoSvc != nil { + if err := s.FifoSvc.AdjustStockableQuantity(ctx, commonSvc.StockAdjustRequest{ + StockableKey: fifo.StockableKeyPurchaseItems, + StockableID: item.Id, + ProductWarehouseID: pwID, + Quantity: -qty, + Tx: tx, + }); err != nil { + return err + } + logEntries = append(logEntries, struct { + pwID uint + qty float64 + }{pwID: pwID, qty: qty}) + continue + } + + deltas[pwID] -= qty + affected[pwID] = struct{}{} + logEntries = append(logEntries, struct { + pwID uint + qty float64 + }{pwID: pwID, qty: qty}) + } + + if s.FifoSvc == nil && len(deltas) > 0 { + if err := pwRepoTx.AdjustQuantities(ctx, deltas, nil); err != nil { + return err + } + if len(affected) > 0 { + if err := pwRepoTx.CleanupEmpty(ctx, affected); err != nil { + return err + } + } + } + + if strings.TrimSpace(note) != "" && actorID != 0 && len(logEntries) > 0 { + logs := make([]*entity.StockLog, 0, len(logEntries)) + for _, entry := range logEntries { + if entry.pwID == 0 || entry.qty <= 0 { + continue + } + logs = append(logs, &entity.StockLog{ + ProductWarehouseId: entry.pwID, + CreatedBy: actorID, + Decrease: entry.qty, + LoggableType: string(utils.StockLogTypePurchase), + LoggableId: items[0].PurchaseId, + Notes: note, + }) + } + if len(logs) > 0 { + if err := stockLogRepoTx.CreateMany(ctx, logs, nil); err != nil { + return err + } + } + } + + return nil +} + func (s *purchaseService) createPurchaseApproval( ctx context.Context, db *gorm.DB,