mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
feat(BE): integrate FIFO service for stock adjustments and transfers
- Added FIFO service integration in the adjustments module to manage stockable and usable items for adjustments. - Created a new repository for adjustment stocks to handle database operations. - Enhanced the adjustment service to track stock adjustments using FIFO logic for both increase and decrease operations. - Updated product warehouse DTOs and repositories to include project flock information. - Implemented FIFO logic in the transfer module to manage stock transfers between warehouses. - Added integration tests for FIFO operations in stock transfers, ensuring correct stock consumption and replenishment.
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
common "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
m "gitlab.com/mbugroup/lti-api.git/internal/middleware"
|
||||
adjustmentStockRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/adjustments/repositories"
|
||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/adjustments/validations"
|
||||
ProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
|
||||
productRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/repositories"
|
||||
@@ -29,24 +30,37 @@ type AdjustmentService interface {
|
||||
}
|
||||
|
||||
type adjustmentService struct {
|
||||
Log *logrus.Logger
|
||||
Validate *validator.Validate
|
||||
StockLogsRepository stockLogsRepo.StockLogRepository
|
||||
WarehouseRepo warehouseRepo.WarehouseRepository
|
||||
ProductWarehouseRepo ProductWarehouse.ProductWarehouseRepository
|
||||
ProductRepo productRepo.ProductRepository
|
||||
ProjectFlockKandangRepo projectFlockKandangRepo.ProjectFlockKandangRepository
|
||||
Log *logrus.Logger
|
||||
Validate *validator.Validate
|
||||
StockLogsRepository stockLogsRepo.StockLogRepository
|
||||
WarehouseRepo warehouseRepo.WarehouseRepository
|
||||
ProductWarehouseRepo ProductWarehouse.ProductWarehouseRepository
|
||||
ProductRepo productRepo.ProductRepository
|
||||
ProjectFlockKandangRepo projectFlockKandangRepo.ProjectFlockKandangRepository
|
||||
AdjustmentStockRepository adjustmentStockRepo.AdjustmentStockRepository
|
||||
FifoSvc common.FifoService
|
||||
}
|
||||
|
||||
func NewAdjustmentService(productRepo productRepo.ProductRepository, stockLogsRepo stockLogsRepo.StockLogRepository, warehouseRepo warehouseRepo.WarehouseRepository, productWarehouseRepo ProductWarehouse.ProductWarehouseRepository, validate *validator.Validate, projectFlockKandangRepo projectFlockKandangRepo.ProjectFlockKandangRepository) AdjustmentService {
|
||||
func NewAdjustmentService(
|
||||
productRepo productRepo.ProductRepository,
|
||||
stockLogsRepo stockLogsRepo.StockLogRepository,
|
||||
warehouseRepo warehouseRepo.WarehouseRepository,
|
||||
productWarehouseRepo ProductWarehouse.ProductWarehouseRepository,
|
||||
adjustmentStockRepo adjustmentStockRepo.AdjustmentStockRepository,
|
||||
fifoSvc common.FifoService,
|
||||
validate *validator.Validate,
|
||||
projectFlockKandangRepo projectFlockKandangRepo.ProjectFlockKandangRepository,
|
||||
) AdjustmentService {
|
||||
return &adjustmentService{
|
||||
Log: utils.Log,
|
||||
Validate: validate,
|
||||
StockLogsRepository: stockLogsRepo,
|
||||
WarehouseRepo: warehouseRepo,
|
||||
ProductWarehouseRepo: productWarehouseRepo,
|
||||
ProductRepo: productRepo,
|
||||
ProjectFlockKandangRepo: projectFlockKandangRepo,
|
||||
Log: utils.Log,
|
||||
Validate: validate,
|
||||
StockLogsRepository: stockLogsRepo,
|
||||
WarehouseRepo: warehouseRepo,
|
||||
ProductWarehouseRepo: productWarehouseRepo,
|
||||
ProductRepo: productRepo,
|
||||
ProjectFlockKandangRepo: projectFlockKandangRepo,
|
||||
AdjustmentStockRepository: adjustmentStockRepo,
|
||||
FifoSvc: fifoSvc,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,15 +166,16 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get product warehouse")
|
||||
}
|
||||
|
||||
// Create StockLog for history tracking
|
||||
afterQuantity := productWarehouse.Quantity
|
||||
newLog := &entity.StockLog{
|
||||
|
||||
LoggableType: string(utils.StockLogTypeAdjustment),
|
||||
LoggableId: 0,
|
||||
Notes: req.Note,
|
||||
ProductWarehouseId: productWarehouse.Id,
|
||||
CreatedBy: actorID, // TODO: should Get from auth middleware
|
||||
CreatedBy: actorID,
|
||||
}
|
||||
|
||||
if transactionType == string(utils.StockLogTransactionTypeIncrease) {
|
||||
afterQuantity += req.Quantity
|
||||
newLog.Increase = afterQuantity
|
||||
@@ -177,6 +192,57 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
|
||||
return err
|
||||
}
|
||||
|
||||
// Create AdjustmentStock record for FIFO tracking
|
||||
adjustmentStock := &entity.AdjustmentStock{
|
||||
StockLogId: newLog.Id,
|
||||
ProductWarehouseId: productWarehouse.Id,
|
||||
}
|
||||
|
||||
if transactionType == string(utils.StockLogTransactionTypeIncrease) {
|
||||
// Adjustment INCREASE → Replenish stock (Stockable)
|
||||
note := fmt.Sprintf("Stock Adjustment IN #%d", newLog.Id)
|
||||
replenishResult, err := s.FifoSvc.Replenish(ctx, common.StockReplenishRequest{
|
||||
StockableKey: "ADJUSTMENT_IN",
|
||||
StockableID: newLog.Id,
|
||||
ProductWarehouseID: uint(productWarehouse.Id),
|
||||
Quantity: req.Quantity,
|
||||
Note: ¬e,
|
||||
Tx: tx,
|
||||
})
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Failed to replenish stock via FIFO: %v", err))
|
||||
}
|
||||
|
||||
// Update stockable tracking fields
|
||||
adjustmentStock.TotalQty = replenishResult.AddedQuantity
|
||||
adjustmentStock.TotalUsed = 0
|
||||
|
||||
} else {
|
||||
// Adjustment DECREASE → Consume stock (Usable)
|
||||
consumeResult, err := s.FifoSvc.Consume(ctx, common.StockConsumeRequest{
|
||||
UsableKey: "ADJUSTMENT_OUT",
|
||||
UsableID: newLog.Id,
|
||||
ProductWarehouseID: uint(productWarehouse.Id),
|
||||
Quantity: req.Quantity,
|
||||
AllowPending: false, // Don't allow pending for adjustment
|
||||
Tx: tx,
|
||||
})
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Failed to consume stock via FIFO: %v", err))
|
||||
}
|
||||
|
||||
// Update usable tracking fields
|
||||
adjustmentStock.UsageQty = consumeResult.UsageQuantity
|
||||
adjustmentStock.PendingQty = consumeResult.PendingQuantity
|
||||
}
|
||||
|
||||
// Save AdjustmentStock record
|
||||
if err := s.AdjustmentStockRepository.WithTx(tx).CreateOne(ctx, adjustmentStock, nil); err != nil {
|
||||
s.Log.Errorf("Failed to create adjustment stock: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create adjustment stock record")
|
||||
}
|
||||
|
||||
// Update ProductWarehouse quantity (for backward compatibility/reporting)
|
||||
productWarehouse.Quantity = afterQuantity
|
||||
if err := s.ProductWarehouseRepo.WithTx(tx).UpdateOne(ctx, productWarehouse.Id, productWarehouse, nil); err != nil {
|
||||
s.Log.Errorf("Failed to update product warehouse quantity: %+v", err)
|
||||
|
||||
Reference in New Issue
Block a user