fix: chickin include stock allocation, fix calculation hpp

This commit is contained in:
Hafizh A. Y
2026-03-03 10:36:48 +07:00
parent d5a1751868
commit f6e25be76b
19 changed files with 665 additions and 59 deletions
+185 -1
View File
@@ -5,6 +5,7 @@ import (
"flag"
"fmt"
"log"
"math"
"os"
"sort"
"strings"
@@ -14,6 +15,7 @@ import (
"gitlab.com/mbugroup/lti-api.git/internal/config"
"gitlab.com/mbugroup/lti-api.git/internal/database"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
"gitlab.com/mbugroup/lti-api.git/internal/utils/fifo"
"gorm.io/gorm"
)
@@ -181,6 +183,8 @@ func main() {
orphanPopulationRows := int64(0)
syncedPopulationQtyRows := int64(0)
syncedPopulationUsedRows := int64(0)
traceReleasedRows := int64(0)
traceInsertedRows := int64(0)
if rowsOrphan, rowsQty, rowsUsed, err := resyncProjectFlockPopulation(ctx, db, projectFlockKandangID); err != nil {
fmt.Printf("FAIL population_resync project_flock_kandang_id=%d error=%v\n", projectFlockKandangID, err)
failedApply++
@@ -196,9 +200,22 @@ func main() {
)
}
if released, inserted, err := resyncChickinTraceByProjectFlockKandang(ctx, db, fifoStockV2Svc, projectFlockKandangID); err != nil {
fmt.Printf("FAIL chickin_trace_resync project_flock_kandang_id=%d error=%v\n", projectFlockKandangID, err)
failedApply++
} else {
traceReleasedRows = released
traceInsertedRows = inserted
fmt.Printf(
"SYNC chickin_trace released=%d inserted=%d\n",
traceReleasedRows,
traceInsertedRows,
)
}
fmt.Println()
fmt.Printf(
"Summary: planned=%d skipped_pw=%d failed_resolve=%d applied=%d failed_apply=%d population_orphan=%d population_qty_synced=%d population_used_synced=%d\n",
"Summary: planned=%d skipped_pw=%d failed_resolve=%d applied=%d failed_apply=%d population_orphan=%d population_qty_synced=%d population_used_synced=%d trace_released=%d trace_inserted=%d\n",
len(targets),
skippedPW,
failedResolve,
@@ -207,6 +224,8 @@ func main() {
orphanPopulationRows,
syncedPopulationQtyRows,
syncedPopulationUsedRows,
traceReleasedRows,
traceInsertedRows,
)
if failedResolve > 0 || failedApply > 0 {
os.Exit(1)
@@ -448,6 +467,7 @@ func resyncProjectFlockPopulation(ctx context.Context, db *gorm.DB, projectFlock
FROM stock_allocations sa
WHERE sa.stockable_type = 'PROJECT_FLOCK_POPULATION'
AND sa.status = 'ACTIVE'
AND sa.allocation_purpose = 'CONSUME'
GROUP BY sa.stockable_id
)
UPDATE project_flock_populations p
@@ -463,3 +483,167 @@ func resyncProjectFlockPopulation(ctx context.Context, db *gorm.DB, projectFlock
return orphanResult.RowsAffected, qtyResult.RowsAffected, usedResult.RowsAffected, nil
}
func resyncChickinTraceByProjectFlockKandang(
ctx context.Context,
db *gorm.DB,
fifoStockV2Svc commonSvc.FifoStockV2Service,
projectFlockKandangID uint,
) (int64, int64, error) {
if projectFlockKandangID == 0 {
return 0, 0, nil
}
var productWarehouseIDs []uint
if err := db.WithContext(ctx).
Table("project_chickins").
Distinct("product_warehouse_id").
Where("project_flock_kandang_id = ?", projectFlockKandangID).
Where("deleted_at IS NULL").
Order("product_warehouse_id ASC").
Pluck("product_warehouse_id", &productWarehouseIDs).Error; err != nil {
return 0, 0, err
}
if len(productWarehouseIDs) == 0 {
return 0, 0, nil
}
totalReleased := int64(0)
totalInserted := int64(0)
for _, productWarehouseID := range productWarehouseIDs {
var releasedRows int64
var insertedRows int64
err := db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
flagGroups, err := resolveFlagGroupsByProductWarehouse(ctx, tx, productWarehouseID)
if err != nil {
return err
}
if len(flagGroups) == 0 {
return nil
}
flagGroupCode := strings.TrimSpace(flagGroups[0])
if flagGroupCode == "" {
return nil
}
released := tx.WithContext(ctx).
Table("stock_allocations").
Where("product_warehouse_id = ?", productWarehouseID).
Where("usable_type = ?", fifo.UsableKeyProjectChickin.String()).
Where("allocation_purpose = ?", entity.StockAllocationPurposeTraceChickin).
Where("status = ?", entity.StockAllocationStatusActive).
Updates(map[string]any{
"status": entity.StockAllocationStatusReleased,
"released_at": time.Now(),
"updated_at": time.Now(),
"note": "chickin_trace_reflow_reset",
})
if released.Error != nil {
return released.Error
}
releasedRows = released.RowsAffected
type chickinRow struct {
ID uint `gorm:"column:id"`
UsageQty float64 `gorm:"column:usage_qty"`
ChickIn time.Time `gorm:"column:chick_in_date"`
}
chickins := make([]chickinRow, 0)
if err := tx.WithContext(ctx).
Table("project_chickins").
Select("id, usage_qty, chick_in_date").
Where("product_warehouse_id = ?", productWarehouseID).
Where("deleted_at IS NULL").
Where("usage_qty > 0").
Order("chick_in_date ASC, id ASC").
Scan(&chickins).Error; err != nil {
return err
}
if len(chickins) == 0 {
return nil
}
gatherRows, err := fifoStockV2Svc.Gather(ctx, commonSvc.FifoStockV2GatherRequest{
FlagGroupCode: flagGroupCode,
Lane: "STOCKABLE",
AllocationPurpose: entity.StockAllocationPurposeTraceChickin,
IgnoreSourceUsed: true,
ProductWarehouseID: productWarehouseID,
Limit: 50000,
Tx: tx,
})
if err != nil {
return err
}
if len(gatherRows) == 0 {
return nil
}
type lotKey struct {
StockableType string
StockableID uint
}
remainingByLot := make(map[lotKey]float64, len(gatherRows))
for _, row := range gatherRows {
key := lotKey{StockableType: row.Ref.LegacyTypeKey, StockableID: row.Ref.ID}
remainingByLot[key] = row.AvailableQuantity
}
now := time.Now()
lotIndex := 0
for _, chickinRow := range chickins {
remaining := chickinRow.UsageQty
for remaining > 1e-6 && lotIndex < len(gatherRows) {
lot := gatherRows[lotIndex]
key := lotKey{StockableType: lot.Ref.LegacyTypeKey, StockableID: lot.Ref.ID}
available := remainingByLot[key]
if available <= 1e-6 {
lotIndex++
continue
}
portion := math.Min(remaining, available)
if portion <= 1e-6 {
lotIndex++
continue
}
insert := map[string]any{
"product_warehouse_id": productWarehouseID,
"stockable_type": lot.Ref.LegacyTypeKey,
"stockable_id": lot.Ref.ID,
"usable_type": fifo.UsableKeyProjectChickin.String(),
"usable_id": chickinRow.ID,
"qty": portion,
"status": entity.StockAllocationStatusActive,
"allocation_purpose": entity.StockAllocationPurposeTraceChickin,
"engine_version": "v2",
"flag_group_code": flagGroupCode,
"function_code": "CHICKIN_TRACE",
"created_at": now,
"updated_at": now,
}
if err := tx.WithContext(ctx).Table("stock_allocations").Create(insert).Error; err != nil {
return err
}
insertedRows++
remaining -= portion
remainingByLot[key] = available - portion
}
}
return nil
})
if err != nil {
return totalReleased, totalInserted, err
}
totalReleased += releasedRows
totalInserted += insertedRows
}
return totalReleased, totalInserted, nil
}