mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 21:41:55 +00:00
132 lines
3.4 KiB
Go
132 lines
3.4 KiB
Go
package fifo_stock_v2
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"math"
|
|
"sort"
|
|
|
|
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
|
"gitlab.com/mbugroup/lti-api.git/internal/utils/fifo"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func ReleasePopulationConsumptionByUsable(
|
|
ctx context.Context,
|
|
tx *gorm.DB,
|
|
usableType string,
|
|
usableID uint,
|
|
) error {
|
|
if tx == nil {
|
|
return errors.New("transaction is required")
|
|
}
|
|
if usableType == "" || usableID == 0 {
|
|
return errors.New("usable type and id are required")
|
|
}
|
|
|
|
stockAllocationRepo := commonRepo.NewStockAllocationRepository(tx)
|
|
allocations, err := stockAllocationRepo.FindActiveByUsable(ctx, usableType, usableID, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, allocation := range allocations {
|
|
if allocation.StockableType != fifo.StockableKeyProjectFlockPopulation.String() || allocation.StockableId == 0 || allocation.Qty <= 0 {
|
|
continue
|
|
}
|
|
if err := tx.WithContext(ctx).
|
|
Model(&entity.ProjectFlockPopulation{}).
|
|
Where("id = ?", allocation.StockableId).
|
|
Update("total_used_qty", gorm.Expr("GREATEST(total_used_qty - ?, 0)", allocation.Qty)).Error; err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return stockAllocationRepo.ReleaseByUsable(ctx, usableType, usableID, nil, nil)
|
|
}
|
|
|
|
func AllocatePopulationConsumption(
|
|
ctx context.Context,
|
|
tx *gorm.DB,
|
|
populations []entity.ProjectFlockPopulation,
|
|
productWarehouseID uint,
|
|
usableType string,
|
|
usableID uint,
|
|
consumeQty float64,
|
|
) error {
|
|
if consumeQty <= 0 {
|
|
return nil
|
|
}
|
|
if tx == nil {
|
|
return errors.New("transaction is required")
|
|
}
|
|
if productWarehouseID == 0 {
|
|
return fiber.NewError(fiber.StatusBadRequest, "Product warehouse tidak valid")
|
|
}
|
|
if usableType == "" || usableID == 0 {
|
|
return errors.New("usable type and id are required")
|
|
}
|
|
if len(populations) == 0 {
|
|
return fiber.NewError(fiber.StatusBadRequest, "Populasi tidak ditemukan")
|
|
}
|
|
|
|
if err := ReleasePopulationConsumptionByUsable(ctx, tx, usableType, usableID); err != nil {
|
|
return err
|
|
}
|
|
|
|
sort.Slice(populations, func(i, j int) bool {
|
|
if populations[i].CreatedAt.Equal(populations[j].CreatedAt) {
|
|
return populations[i].Id < populations[j].Id
|
|
}
|
|
return populations[i].CreatedAt.Before(populations[j].CreatedAt)
|
|
})
|
|
|
|
stockAllocationRepo := commonRepo.NewStockAllocationRepository(tx)
|
|
remaining := consumeQty
|
|
for _, pop := range populations {
|
|
available := pop.TotalQty - pop.TotalUsedQty
|
|
if available <= 0 {
|
|
continue
|
|
}
|
|
portion := math.Min(available, remaining)
|
|
if portion <= 0 {
|
|
continue
|
|
}
|
|
|
|
allocation := &entity.StockAllocation{
|
|
ProductWarehouseId: productWarehouseID,
|
|
StockableType: fifo.StockableKeyProjectFlockPopulation.String(),
|
|
StockableId: pop.Id,
|
|
UsableType: usableType,
|
|
UsableId: usableID,
|
|
Qty: portion,
|
|
Status: entity.StockAllocationStatusActive,
|
|
AllocationPurpose: entity.StockAllocationPurposeConsume,
|
|
}
|
|
if err := stockAllocationRepo.CreateOne(ctx, allocation, nil); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := tx.WithContext(ctx).
|
|
Model(&entity.ProjectFlockPopulation{}).
|
|
Where("id = ?", pop.Id).
|
|
Update("total_used_qty", gorm.Expr("total_used_qty + ?", portion)).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
remaining -= portion
|
|
if remaining <= 1e-6 {
|
|
break
|
|
}
|
|
}
|
|
|
|
if remaining > 1e-6 {
|
|
return fiber.NewError(fiber.StatusBadRequest, "Populasi tidak mencukupi")
|
|
}
|
|
|
|
return nil
|
|
}
|