From 4d6f731f8075cc6ad9493c70a8d640a9e418caa7 Mon Sep 17 00:00:00 2001 From: giovanni Date: Wed, 28 Jan 2026 13:32:34 +0700 Subject: [PATCH] add migration add field stock to stock_logs; adjust logic stock for insert data stock_logs --- ...20260128034158_create_field_stock.down.sql | 2 + .../20260128034158_create_field_stock.up.sql | 18 +++ internal/entities/stock_log.go | 1 + .../services/adjustment.service.go | 15 +++ .../transfers/services/transfer.service.go | 23 ++++ .../services/deliveryorder.service.go | 36 ++++++ .../chickins/services/chickin.service.go | 24 ++++ .../recordings/services/recording.service.go | 103 +++++++++++++++++- .../services/transfer_laying.service.go | 24 ++++ .../purchases/services/purchase.service.go | 17 ++- 10 files changed, 259 insertions(+), 4 deletions(-) create mode 100644 internal/database/migrations/20260128034158_create_field_stock.down.sql create mode 100644 internal/database/migrations/20260128034158_create_field_stock.up.sql diff --git a/internal/database/migrations/20260128034158_create_field_stock.down.sql b/internal/database/migrations/20260128034158_create_field_stock.down.sql new file mode 100644 index 00000000..7a508600 --- /dev/null +++ b/internal/database/migrations/20260128034158_create_field_stock.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE stock_logs +DROP COLUMN stock; diff --git a/internal/database/migrations/20260128034158_create_field_stock.up.sql b/internal/database/migrations/20260128034158_create_field_stock.up.sql new file mode 100644 index 00000000..9b7847f1 --- /dev/null +++ b/internal/database/migrations/20260128034158_create_field_stock.up.sql @@ -0,0 +1,18 @@ +ALTER TABLE stock_logs +ADD COLUMN stock NUMERIC(15, 3) NOT NULL DEFAULT 0; + +WITH calc AS ( + SELECT + id, + SUM(COALESCE(increase, 0) - COALESCE(decrease, 0)) + OVER ( + PARTITION BY product_warehouse_id + ORDER BY id + ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW + ) AS running_stock + FROM stock_logs +) +UPDATE stock_logs t +SET stock = c.running_stock +FROM calc c +WHERE t.id = c.id; diff --git a/internal/entities/stock_log.go b/internal/entities/stock_log.go index d6acafb8..1bebdd73 100644 --- a/internal/entities/stock_log.go +++ b/internal/entities/stock_log.go @@ -9,6 +9,7 @@ type StockLog struct { Increase float64 `gorm:"column:increase;type:numeric(15,3);default:0"` Decrease float64 `gorm:"column:decrease;type:numeric(15,3);default:0"` + Stock float64 `gorm:"column:stock;type:numeric(15,3);not null;default:0"` LoggableType string `gorm:"column:loggable_type;type:varchar(50);not null"` LoggableId uint `gorm:"column:loggable_id;not null"` diff --git a/internal/modules/inventory/adjustments/services/adjustment.service.go b/internal/modules/inventory/adjustments/services/adjustment.service.go index 16bcf70a..b034fda7 100644 --- a/internal/modules/inventory/adjustments/services/adjustment.service.go +++ b/internal/modules/inventory/adjustments/services/adjustment.service.go @@ -162,15 +162,30 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e CreatedBy: actorID, } + stockLogs, err := s.StockLogsRepository.GetByProductWarehouse(ctx, productWarehouse.Id, 1) + if err != nil { + s.Log.Errorf("Failed to get stock logs: %+v", err) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + newLog.Stock = latestStockLog.Stock + } else { + newLog.Stock = 0 + } + if transactionType == string(utils.StockLogTransactionTypeIncrease) { afterQuantity += req.Quantity newLog.Increase = req.Quantity + newLog.Stock += newLog.Increase } else { if productWarehouse.Quantity < req.Quantity { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Stok tidak mencukupi untuk pengurangan. Stok saat ini: %.2f, Jumlah yang akan dikurangi: %.2f", productWarehouse.Quantity, req.Quantity)) } afterQuantity -= req.Quantity newLog.Decrease = req.Quantity + newLog.Stock -= newLog.Decrease } if err := s.StockLogsRepository.WithTx(tx).CreateOne(ctx, newLog, nil); err != nil { diff --git a/internal/modules/inventory/transfers/services/transfer.service.go b/internal/modules/inventory/transfers/services/transfer.service.go index 8278ce9f..462b9d2a 100644 --- a/internal/modules/inventory/transfers/services/transfer.service.go +++ b/internal/modules/inventory/transfers/services/transfer.service.go @@ -427,6 +427,18 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques LoggableId: uint(detail.Id), Notes: "", } + stockLogs, err := s.StockLogsRepository.GetByProductWarehouse(c.Context(), uint(*detail.SourceProductWarehouseID), 1) + if err != nil { + s.Log.Errorf("Failed to get stock logs: %+v", err) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + stockLogDecrease.Stock -= latestStockLog.Stock - stockLogDecrease.Decrease + } else { + stockLogDecrease.Stock -= stockLogDecrease.Decrease + } + if err := stocklogsRepoTx.CreateOne(c.Context(), stockLogDecrease, nil); err != nil { return fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat log stok keluar") } @@ -463,6 +475,17 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques LoggableId: uint(detail.Id), Notes: "", } + stockLogs, err = s.StockLogsRepository.GetByProductWarehouse(c.Context(), uint(*detail.DestProductWarehouseID), 1) + if err != nil { + s.Log.Errorf("Failed to get stock logs: %+v", err) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + stockLogIncrease.Stock = latestStockLog.Stock + stockLogIncrease.Increase + } else { + stockLogIncrease.Stock += stockLogIncrease.Increase + } if err := stocklogsRepoTx.CreateOne(c.Context(), stockLogIncrease, nil); err != nil { return fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat log stok masuk") } diff --git a/internal/modules/marketing/services/deliveryorder.service.go b/internal/modules/marketing/services/deliveryorder.service.go index 7e60662d..46ca1a0c 100644 --- a/internal/modules/marketing/services/deliveryorder.service.go +++ b/internal/modules/marketing/services/deliveryorder.service.go @@ -479,6 +479,18 @@ func (s deliveryOrdersService) consumeDeliveryStock(ctx context.Context, tx *gor CreatedBy: actorID, Notes: "", } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, marketingProduct.ProductWarehouseId, 1) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + decreaseLog.Stock = latestStockLog.Stock + decreaseLog.Stock -= decreaseLog.Decrease + } else { + decreaseLog.Stock -= decreaseLog.Decrease + } + s.StockLogRepo.WithTx(tx).CreateOne(ctx, decreaseLog, nil) } } @@ -513,6 +525,18 @@ func (s deliveryOrdersService) consumeDeliveryStock(ctx context.Context, tx *gor CreatedBy: actorID, Notes: "", } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, marketingProduct.ProductWarehouseId, 1) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + decreaseLog.Stock = latestStockLog.Stock + decreaseLog.Stock -= decreaseLog.Decrease + } else { + decreaseLog.Stock -= decreaseLog.Decrease + } + s.StockLogRepo.WithTx(tx).CreateOne(ctx, decreaseLog, nil) } @@ -562,6 +586,18 @@ func (s deliveryOrdersService) releaseDeliveryStock(ctx context.Context, tx *gor CreatedBy: actorID, Notes: "", } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, marketingProduct.ProductWarehouseId, 1) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + increaseLog.Stock = latestStockLog.Stock + increaseLog.Stock += increaseLog.Increase + } else { + increaseLog.Stock += increaseLog.Increase + } + s.StockLogRepo.WithTx(tx).CreateOne(ctx, increaseLog, nil) } diff --git a/internal/modules/production/chickins/services/chickin.service.go b/internal/modules/production/chickins/services/chickin.service.go index b39dca78..971ee072 100644 --- a/internal/modules/production/chickins/services/chickin.service.go +++ b/internal/modules/production/chickins/services/chickin.service.go @@ -645,6 +645,18 @@ func (s *chickinService) ConsumeChickinStocks(ctx context.Context, tx *gorm.DB, CreatedBy: actorID, Notes: fmt.Sprintf("Chickin #%d", chickin.Id), } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, chickin.ProductWarehouseId, 1) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + decreaseLog.Stock = latestStockLog.Stock + decreaseLog.Stock -= decreaseLog.Decrease + } else { + decreaseLog.Stock -= decreaseLog.Decrease + } + s.StockLogRepo.CreateOne(ctx, decreaseLog, nil) } @@ -701,6 +713,18 @@ func (s *chickinService) ReleaseChickinStocks(ctx context.Context, tx *gorm.DB, CreatedBy: actorID, Notes: fmt.Sprintf("Chickin #%d - Stock released", chickin.Id), } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, chickin.ProductWarehouseId, 1) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + increaseLog.Stock = latestStockLog.Stock + increaseLog.Stock += increaseLog.Increase + } else { + increaseLog.Stock += increaseLog.Increase + } + s.StockLogRepo.CreateOne(ctx, increaseLog, nil) } diff --git a/internal/modules/production/recordings/services/recording.service.go b/internal/modules/production/recordings/services/recording.service.go index 25103c2f..0b16bbd0 100644 --- a/internal/modules/production/recordings/services/recording.service.go +++ b/internal/modules/production/recordings/services/recording.service.go @@ -4,6 +4,10 @@ import ( "context" "errors" "fmt" + "math" + "strings" + "time" + commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository" commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" @@ -19,9 +23,6 @@ import ( approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals" "gitlab.com/mbugroup/lti-api.git/internal/utils/fifo" recordingutil "gitlab.com/mbugroup/lti-api.git/internal/utils/recording" - "math" - "strings" - "time" "github.com/go-playground/validator/v10" "github.com/gofiber/fiber/v2" @@ -508,6 +509,17 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin if egg.ProductWarehouseId == 0 || egg.Qty <= 0 { continue } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, egg.ProductWarehouseId, 1) + if err != nil { + s.Log.Errorf("Failed to get stock logs: %+v", err) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + latestStockLog := &entity.StockLog{} + if len(stockLogs) > 0 { + latestStockLog = stockLogs[0] + } else { + latestStockLog.Stock = 0 + } logs = append(logs, &entity.StockLog{ ProductWarehouseId: egg.ProductWarehouseId, CreatedBy: actorID, @@ -515,6 +527,7 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin LoggableType: string(utils.StockLogTypeRecording), LoggableId: recordingEntity.Id, Notes: note, + Stock: latestStockLog.Stock - float64(egg.Qty), }) } if len(logs) > 0 { @@ -859,6 +872,18 @@ func (s *recordingService) consumeRecordingStocks( LoggableId: stock.RecordingId, Notes: note, } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, stock.ProductWarehouseId, 1) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + log.Stock = latestStockLog.Stock + log.Stock -= log.Decrease + } else { + log.Stock -= log.Decrease + } + if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } @@ -926,6 +951,18 @@ func (s *recordingService) consumeRecordingDepletions( LoggableId: depletion.RecordingId, Notes: note, } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, sourceWarehouseID, 1) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + log.Stock = latestStockLog.Stock + log.Stock -= log.Decrease + } else { + log.Stock -= log.Decrease + } + if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } @@ -944,6 +981,18 @@ func (s *recordingService) consumeRecordingDepletions( LoggableId: depletion.RecordingId, Notes: note, } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, depletion.ProductWarehouseId, 1) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + log.Stock = latestStockLog.Stock + log.Stock += log.Increase + } else { + log.Stock += log.Increase + } + if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } @@ -1004,6 +1053,18 @@ func (s *recordingService) releaseRecordingStocks( LoggableId: stock.RecordingId, Notes: note, } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, stock.ProductWarehouseId, 1) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + log.Stock = latestStockLog.Stock + log.Stock += log.Increase + } else { + log.Stock += log.Increase + } + if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } @@ -1066,6 +1127,18 @@ func (s *recordingService) releaseRecordingDepletions( LoggableId: depletion.RecordingId, Notes: note, } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, sourceWarehouseID, 1) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + log.Stock = latestStockLog.Stock + log.Stock += log.Increase + } else { + log.Stock += log.Increase + } + if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } @@ -1084,6 +1157,18 @@ func (s *recordingService) releaseRecordingDepletions( LoggableId: depletion.RecordingId, Notes: note, } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, depletion.ProductWarehouseId, 1) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + log.Stock = latestStockLog.Stock + log.Stock -= log.Decrease + } else { + log.Stock -= log.Decrease + } + if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } @@ -1231,6 +1316,18 @@ func (s *recordingService) replenishRecordingEggs( LoggableId: egg.RecordingId, Notes: note, } + stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, egg.ProductWarehouseId, 1) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + log.Stock = latestStockLog.Stock + log.Stock += log.Increase + } else { + log.Stock += log.Increase + } + if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } diff --git a/internal/modules/production/transfer_layings/services/transfer_laying.service.go b/internal/modules/production/transfer_layings/services/transfer_laying.service.go index 3aa4788b..24498979 100644 --- a/internal/modules/production/transfer_layings/services/transfer_laying.service.go +++ b/internal/modules/production/transfer_layings/services/transfer_laying.service.go @@ -732,6 +732,18 @@ func (s transferLayingService) Approval(c *fiber.Ctx, req *validation.Approve) ( LoggableId: approvableID, Notes: fmt.Sprintf("TL #%s", transfer.TransferNumber), } + stockLogs, err := stockLogRepoTx.GetByProductWarehouse(c.Context(), *source.ProductWarehouseId, 1) + if err != nil { + s.Log.Errorf("Failed to get stock logs: %+v", err) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + stockLogDecrease.Stock = latestStockLog.Stock - stockLogDecrease.Decrease + } else { + stockLogDecrease.Stock -= stockLogDecrease.Decrease + } + if err := stockLogRepoTx.CreateOne(c.Context(), stockLogDecrease, nil); err != nil { return fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat log stok keluar") } @@ -770,6 +782,18 @@ func (s transferLayingService) Approval(c *fiber.Ctx, req *validation.Approve) ( LoggableId: approvableID, Notes: fmt.Sprintf("TL #%s", transfer.TransferNumber), } + stockLogs, err := stockLogRepoTx.GetByProductWarehouse(c.Context(), *target.ProductWarehouseId, 1) + if err != nil { + s.Log.Errorf("Failed to get stock logs: %+v", err) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + stockLogIncrease.Stock = latestStockLog.Stock + stockLogIncrease.Increase + } else { + stockLogIncrease.Stock += stockLogIncrease.Increase + } + if err := stockLogRepoTx.CreateOne(c.Context(), stockLogIncrease, nil); err != nil { return fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat log stok masuk") } diff --git a/internal/modules/purchases/services/purchase.service.go b/internal/modules/purchases/services/purchase.service.go index 6b423d33..3aa5bb17 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" @@ -1026,10 +1026,25 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation LoggableId: purchase.Id, Notes: receiveNote, } + stockLogs, err := stockLogRepoTx.GetByProductWarehouse(ctx, entry.pwID, 1) + if err != nil { + s.Log.Errorf("Failed to get stock logs: %+v", err) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs") + } + + if len(stockLogs) > 0 { + latestStockLog := stockLogs[0] + log.Stock = latestStockLog.Stock + } else { + log.Stock = 0 + } + if entry.delta > 0 { log.Increase = entry.delta + log.Stock += log.Increase } else { log.Decrease = -entry.delta + log.Stock -= log.Decrease } logs = append(logs, log) }