Merge branch 'FIX/BE/Marketing' into 'development'

FIX[BE]; fixing penjualan qty tidak berkurang jika qty tida ada dalam stockable

See merge request mbugroup/lti-api!283
This commit is contained in:
Adnan Zahir
2026-01-30 10:18:58 +07:00
@@ -410,6 +410,7 @@ func (s deliveryOrdersService) UpdateOne(c *fiber.Ctx, req *validation.DeliveryO
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch delivery product") return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch delivery product")
} }
oldRequestedQty := deliveryProduct.UsageQty + deliveryProduct.PendingQty
var itemDeliveryDate *time.Time var itemDeliveryDate *time.Time
if requestedProduct.DeliveryDate != "" { if requestedProduct.DeliveryDate != "" {
parsedDate, err := utils.ParseDateString(requestedProduct.DeliveryDate) parsedDate, err := utils.ParseDateString(requestedProduct.DeliveryDate)
@@ -421,11 +422,8 @@ func (s deliveryOrdersService) UpdateOne(c *fiber.Ctx, req *validation.DeliveryO
itemDeliveryDate = deliveryProduct.DeliveryDate itemDeliveryDate = deliveryProduct.DeliveryDate
} }
oldRequestedQty := deliveryProduct.UsageQty + deliveryProduct.PendingQty
// Cek apakah product punya flag PAKAN atau OVK
isPakanOrOVK := false isPakanOrOVK := false
if foundMarketingProduct.ProductWarehouse.Product.Id != 0 && len(foundMarketingProduct.ProductWarehouse.Product.Flags) > 0 { if foundMarketingProduct.ProductWarehouse.Id != 0 && foundMarketingProduct.ProductWarehouse.Product.Id != 0 && len(foundMarketingProduct.ProductWarehouse.Product.Flags) > 0 {
for _, flag := range foundMarketingProduct.ProductWarehouse.Product.Flags { for _, flag := range foundMarketingProduct.ProductWarehouse.Product.Flags {
if flag.Name == string(utils.FlagPakan) || flag.Name == string(utils.FlagOVK) { if flag.Name == string(utils.FlagPakan) || flag.Name == string(utils.FlagOVK) {
isPakanOrOVK = true isPakanOrOVK = true
@@ -506,60 +504,71 @@ func (s deliveryOrdersService) consumeDeliveryStock(ctx context.Context, tx *gor
deliveryProductRepo := marketingRepo.NewMarketingDeliveryProductRepository(tx) deliveryProductRepo := marketingRepo.NewMarketingDeliveryProductRepository(tx)
if err == nil && result.UsageQuantity > 0 { totalConsumed := 0.0
if actorID > 0 { var fifoConsumed float64
decreaseLog := &entity.StockLog{ var directConsumed float64
Decrease: result.UsageQuantity,
LoggableType: string(utils.StockLogTypeMarketing), if result != nil && result.UsageQuantity > 0 {
LoggableId: deliveryProduct.Id, fifoConsumed = result.UsageQuantity
ProductWarehouseId: marketingProduct.ProductWarehouseId, totalConsumed = result.UsageQuantity
CreatedBy: actorID,
Notes: "",
}
s.StockLogRepo.WithTx(tx).CreateOne(ctx, decreaseLog, nil)
}
} }
if err != nil { if err != nil || (totalConsumed < requestedQty) {
remainder := requestedQty - totalConsumed
pwRepo := productWarehouseRepo.NewProductWarehouseRepository(tx) pwRepo := productWarehouseRepo.NewProductWarehouseRepository(tx)
pw, err2 := pwRepo.GetByID(ctx, marketingProduct.ProductWarehouseId, nil) pw, err2 := pwRepo.GetByID(ctx, marketingProduct.ProductWarehouseId, nil)
if err2 != nil { if err2 != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to check product warehouse stock") return fiber.NewError(fiber.StatusInternalServerError, "Failed to check product warehouse stock")
} }
if pw == nil || pw.Quantity < requestedQty { if pw == nil || pw.Quantity < remainder {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Insufficient stock. Available: %.2f, Requested: %.2f", func() float64 { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Insufficient stock. FIFO: %.2f, Direct Available: %.2f, Total Needed: %.2f", func() float64 {
if pw != nil { if pw != nil {
return pw.Quantity return pw.Quantity
} else { } else {
return 0 return 0
} }
}(), requestedQty)) }(), remainder, requestedQty))
} }
if err := deliveryProductRepo.UpdateFifoFields(ctx, deliveryProduct.Id, requestedQty, 0); err != nil { if err := pwRepo.AdjustQuantities(ctx, map[uint]float64{
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update delivery product") marketingProduct.ProductWarehouseId: -remainder,
}, func(db *gorm.DB) *gorm.DB {
return tx
}); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to adjust product warehouse quantity")
} }
if actorID > 0 { directConsumed = remainder
decreaseLog := &entity.StockLog{ totalConsumed += remainder
Decrease: requestedQty,
LoggableType: string(utils.StockLogTypeMarketing),
LoggableId: deliveryProduct.Id,
ProductWarehouseId: marketingProduct.ProductWarehouseId,
CreatedBy: actorID,
Notes: "",
}
s.StockLogRepo.WithTx(tx).CreateOne(ctx, decreaseLog, nil)
}
return nil
} }
if err := deliveryProductRepo.UpdateFifoFields(ctx, deliveryProduct.Id, result.UsageQuantity, result.PendingQuantity); err != nil { if err := deliveryProductRepo.UpdateFifoFields(ctx, deliveryProduct.Id, totalConsumed, 0); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update delivery product") return fiber.NewError(fiber.StatusInternalServerError, "Failed to update delivery product")
} }
if actorID > 0 && totalConsumed > 0 {
notes := ""
if fifoConsumed > 0 && directConsumed > 0 {
notes = fmt.Sprintf("Partial FIFO (%.2f) + Direct (%.2f)", fifoConsumed, directConsumed)
} else if fifoConsumed > 0 {
notes = fmt.Sprintf("FIFO stock only (%.2f)", fifoConsumed)
} else if directConsumed > 0 {
notes = fmt.Sprintf("Direct stock only (%.2f)", directConsumed)
}
decreaseLog := &entity.StockLog{
Decrease: totalConsumed,
LoggableType: string(utils.StockLogTypeMarketing),
LoggableId: deliveryProduct.Id,
ProductWarehouseId: marketingProduct.ProductWarehouseId,
CreatedBy: actorID,
Notes: notes,
}
s.StockLogRepo.WithTx(tx).CreateOne(ctx, decreaseLog, nil)
}
return nil return nil
} }