diff --git a/internal/database/migrations/20260126093054_create_field_stock.down.sql b/internal/database/migrations/20260126093054_create_field_stock.down.sql new file mode 100644 index 00000000..7a508600 --- /dev/null +++ b/internal/database/migrations/20260126093054_create_field_stock.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE stock_logs +DROP COLUMN stock; diff --git a/internal/database/migrations/20260126093054_create_field_stock.up.sql b/internal/database/migrations/20260126093054_create_field_stock.up.sql new file mode 100644 index 00000000..c31ede66 --- /dev/null +++ b/internal/database/migrations/20260126093054_create_field_stock.up.sql @@ -0,0 +1,19 @@ +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..f6041cbd 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..920fb0cf 100644 --- a/internal/modules/inventory/adjustments/services/adjustment.service.go +++ b/internal/modules/inventory/adjustments/services/adjustment.service.go @@ -162,19 +162,33 @@ 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 { - return err } diff --git a/internal/modules/marketing/services/deliveryorder.service.go b/internal/modules/marketing/services/deliveryorder.service.go index 7e60662d..953a1ec0 100644 --- a/internal/modules/marketing/services/deliveryorder.service.go +++ b/internal/modules/marketing/services/deliveryorder.service.go @@ -479,6 +479,17 @@ 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 = 0 + } s.StockLogRepo.WithTx(tx).CreateOne(ctx, decreaseLog, nil) } } @@ -513,6 +524,17 @@ 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 = 0 + } s.StockLogRepo.WithTx(tx).CreateOne(ctx, decreaseLog, nil) } @@ -562,6 +584,17 @@ 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 = 0 + } s.StockLogRepo.WithTx(tx).CreateOne(ctx, increaseLog, nil) } diff --git a/internal/modules/master/phase-activities/validations/phase-activity.validation.go b/internal/modules/master/phase-activities/validations/phase-activity.validation.go index 54186315..d153f530 100644 --- a/internal/modules/master/phase-activities/validations/phase-activity.validation.go +++ b/internal/modules/master/phase-activities/validations/phase-activity.validation.go @@ -15,7 +15,7 @@ type Update struct { type Query struct { Page int `query:"page" validate:"omitempty,number,min=1,gt=0"` - Limit int `query:"limit" validate:"omitempty,number,min=1,max=100,gt=0"` + Limit int `query:"limit" validate:"omitempty,number,min=1,gt=0"` Search string `query:"search" validate:"omitempty,max=50"` PhaseIDs string `query:"phase_ids" validate:"omitempty"` } diff --git a/internal/modules/production/chickins/services/chickin.service.go b/internal/modules/production/chickins/services/chickin.service.go index b39dca78..3352abac 100644 --- a/internal/modules/production/chickins/services/chickin.service.go +++ b/internal/modules/production/chickins/services/chickin.service.go @@ -645,6 +645,17 @@ 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 = 0 + } s.StockLogRepo.CreateOne(ctx, decreaseLog, nil) } @@ -701,6 +712,17 @@ 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 = 0 + } 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..8a2218d8 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" @@ -859,6 +860,17 @@ 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 = 0 + } if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } @@ -926,6 +938,17 @@ 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 = 0 + } if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } @@ -944,6 +967,17 @@ 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 = 0 + } if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } @@ -1004,6 +1038,17 @@ 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 = 0 + } if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } @@ -1066,6 +1111,17 @@ 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 = 0 + } if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } @@ -1084,6 +1140,17 @@ 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 = 0 + } if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } @@ -1231,6 +1298,17 @@ 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 = 0 + } if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil { return err } diff --git a/internal/modules/purchases/services/purchase.service.go b/internal/modules/purchases/services/purchase.service.go index 6b423d33..644417f3 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,11 +1026,6 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation LoggableId: purchase.Id, Notes: receiveNote, } - if entry.delta > 0 { - log.Increase = entry.delta - } else { - log.Decrease = -entry.delta - } logs = append(logs, log) } if len(logs) > 0 {