Feat[BE]: enhance chickin stock management with FIFO service integration and fix key naming inconsistencies

This commit is contained in:
aguhh18
2025-12-24 09:24:32 +07:00
committed by Hafizh A. Y
parent ebf0f8c5ab
commit 67ddd8e667
4 changed files with 26 additions and 30 deletions
@@ -39,19 +39,19 @@ func (ChickinModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *
projectFlockRepo := rProjectFlock.NewProjectflockRepository(db)
productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db)
stockAllocationRepo := commonRepo.NewStockAllocationRepository(db)
fifoService := commonSvc.NewFifoService(db, stockAllocationRepo, productWarehouseRepo, utils.Log)
userRepo := rUser.NewUserRepository(db)
fifoService := commonSvc.NewFifoService(db, stockAllocationRepo, productWarehouseRepo, utils.Log)
// Register PROJECT_CHICKIN as usable
if err := fifoService.RegisterUsable(fifo.UsableConfig{
Key: fifo.UsablekeyProjectChickin,
Key: fifo.UsableKeyProjectChickin,
Table: "project_chickins",
Columns: fifo.UsableColumns{
ID: "id",
ProductWarehouseID: "product_warehouse_id",
UsageQuantity: "usage_qty",
PendingQuantity: "pending_usage_qty",
CreatedAt: "id",
CreatedAt: "created_at",
},
}); err != nil {
if !strings.Contains(strings.ToLower(err.Error()), "already registered") {
@@ -25,7 +25,7 @@ import (
"gorm.io/gorm"
)
var chickinUsableKey = fifo.UsablekeyProjectChickin
var chickinUsableKey = fifo.UsableKeyProjectChickin
type ChickinService interface {
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectChickin, int64, error)
@@ -135,8 +135,9 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]enti
return nil, err
}
newChikins := make([]*entity.ProjectChickin, 0)
chickinQtyMap := make(map[uint]float64) // Store desired qty for each chickin index
for _, chickinReq := range req.ChickinRequests {
for idx, chickinReq := range req.ChickinRequests {
productWarehouse, err := s.ProductWarehouseRepo.GetByID(c.Context(), chickinReq.ProductWarehouseId, nil)
if err != nil {
@@ -164,7 +165,7 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]enti
newChickin := &entity.ProjectChickin{
ProjectFlockKandangId: req.ProjectFlockKandangId,
ChickInDate: chickinDate,
UsageQty: availableQty,
UsageQty: 0,
PendingUsageQty: 0,
ProductWarehouseId: chickinReq.ProductWarehouseId,
Notes: chickinReq.Note,
@@ -172,6 +173,7 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]enti
}
newChikins = append(newChikins, newChickin)
chickinQtyMap[uint(idx)] = availableQty
}
if len(newChikins) == 0 {
@@ -193,24 +195,14 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]enti
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create chickins")
}
for _, chickin := range newChikins {
if err := s.ConsumeChickinStocks(c.Context(), dbTransaction, chickin); err != nil {
for idx, chickin := range newChikins {
desiredQty := chickinQtyMap[uint(idx)]
if err := s.ConsumeChickinStocks(c.Context(), dbTransaction, chickin, desiredQty); err != nil {
return err
}
if chickin.PendingUsageQty > 0 {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Cannot create chickin %d - insufficient stock. Required: %.0f, Available: %.0f, Pending: %.0f", chickin.Id, chickin.UsageQty+chickin.PendingUsageQty, chickin.UsageQty, chickin.PendingUsageQty))
}
}
warehouseDeltas := make(map[uint]float64)
for _, chickin := range newChikins {
warehouseDeltas[chickin.ProductWarehouseId] -= chickin.UsageQty
}
if err := s.adjustProductWarehouseQuantities(c.Context(), dbTransaction, warehouseDeltas); err != nil {
s.Log.Errorf("Failed to adjust product warehouses: %+v", err)
return err
}
// Note: FIFO Consume already adjusts product warehouse quantities, no need to adjust again
latest, err := approvalSvcTx.LatestByTarget(c.Context(), utils.ApprovalWorkflowChickin, projectFlockKandang.Id, nil)
if err != nil {
@@ -599,19 +591,20 @@ func (s *chickinService) convertChickinsToTarget(ctx *fiber.Ctx, chickins []enti
return nil
}
func (s *chickinService) ConsumeChickinStocks(ctx context.Context, tx *gorm.DB, chickin *entity.ProjectChickin) error {
func (s *chickinService) ConsumeChickinStocks(ctx context.Context, tx *gorm.DB, chickin *entity.ProjectChickin, desiredQty float64) error {
if chickin == nil || s.FifoSvc == nil {
return nil
}
var desired float64 = chickin.UsageQty
s.Log.Infof("ConsumeChickinStocks: chickin_id=%d, product_warehouse_id=%d, desired_qty=%.3f",
chickin.Id, chickin.ProductWarehouseId, desiredQty)
result, err := s.FifoSvc.Consume(ctx, commonSvc.StockConsumeRequest{
UsableKey: chickinUsableKey,
UsableID: chickin.Id,
ProductWarehouseID: chickin.ProductWarehouseId,
Quantity: desired,
AllowPending: false,
Quantity: desiredQty,
AllowPending: true,
Tx: tx,
})
if err != nil {
@@ -619,6 +612,9 @@ func (s *chickinService) ConsumeChickinStocks(ctx context.Context, tx *gorm.DB,
return err
}
s.Log.Infof("ConsumeChickinStocks result: usage_qty=%.3f, pending_qty=%.3f, allocated_allocations=%d",
result.UsageQuantity, result.PendingQuantity, len(result.AddedAllocations))
if err := tx.Model(&entity.ProjectChickin{}).Where("id = ?", chickin.Id).Updates(map[string]interface{}{
"usage_qty": result.UsageQuantity,
"pending_usage_qty": result.PendingQuantity,