add paired adjustment triger depletion adjustment

This commit is contained in:
ragilap
2026-03-17 11:02:37 +07:00
parent 131949874a
commit c9dee7d1c4
9 changed files with 839 additions and 381 deletions
@@ -725,8 +725,21 @@ FROM (
transferIDs := make(map[uint]struct{})
adjustmentIDs := make(map[uint]struct{})
transferLayingIDs := make(map[uint]struct{})
orphanIDs := make(map[string]map[uint]struct{})
for _, row := range rows {
exists, existsErr := s.usableReferenceExistsForChickinDelete(ctx, db, row.UsableType, row.UsableID)
if existsErr != nil {
s.Log.Errorf("Failed to validate downstream usable reference %s:%d for chickin %d: %+v", row.UsableType, row.UsableID, chickinID, existsErr)
return fiber.NewError(fiber.StatusInternalServerError, "Gagal memvalidasi referensi transaksi turunan chickin")
}
if !exists {
if _, ok := orphanIDs[row.UsableType]; !ok {
orphanIDs[row.UsableType] = make(map[uint]struct{})
}
orphanIDs[row.UsableType][row.UsableID] = struct{}{}
continue
}
switch row.UsableType {
case fifo.UsableKeyMarketingDelivery.String():
marketingIDs[row.UsableID] = struct{}{}
@@ -740,6 +753,24 @@ FROM (
transferLayingIDs[row.UsableID] = struct{}{}
}
}
if len(orphanIDs) > 0 {
orphanDetails := make([]string, 0, len(orphanIDs))
for usableType, idsMap := range orphanIDs {
ids := sortedIDs(idsMap)
if len(ids) == 0 {
continue
}
orphanDetails = append(orphanDetails, fmt.Sprintf("%s=%s", usableType, joinUint(ids)))
}
sort.Strings(orphanDetails)
return fiber.NewError(
fiber.StatusBadRequest,
fmt.Sprintf(
"Delete chickin diblok karena ditemukan orphan stock allocation pada transaksi turunan: %s. Bersihkan orphan terlebih dahulu.",
strings.Join(orphanDetails, ", "),
),
)
}
details := make([]string, 0, 5)
if ids := sortedIDs(marketingIDs); len(ids) > 0 {
@@ -766,6 +797,72 @@ FROM (
return fiber.NewError(fiber.StatusBadRequest, message)
}
func (s *chickinService) usableReferenceExistsForChickinDelete(ctx context.Context, db *gorm.DB, usableType string, usableID uint) (bool, error) {
if usableID == 0 {
return false, nil
}
if db == nil {
return false, fmt.Errorf("db is required")
}
var count int64
switch usableType {
case fifo.UsableKeyAdjustmentOut.String():
if err := db.WithContext(ctx).
Table("adjustment_stocks").
Where("id = ?", usableID).
Count(&count).Error; err != nil {
return false, err
}
case fifo.UsableKeyMarketingDelivery.String():
if err := db.WithContext(ctx).
Table("marketing_delivery_products").
Where("id = ?", usableID).
Count(&count).Error; err != nil {
return false, err
}
case fifo.UsableKeyRecordingStock.String():
if err := db.WithContext(ctx).
Table("recording_stocks rs").
Joins("JOIN recordings r ON r.id = rs.recording_id").
Where("rs.id = ?", usableID).
Where("r.deleted_at IS NULL").
Count(&count).Error; err != nil {
return false, err
}
case fifo.UsableKeyRecordingDepletion.String():
if err := db.WithContext(ctx).
Table("recording_depletions rd").
Joins("JOIN recordings r ON r.id = rd.recording_id").
Where("rd.id = ?", usableID).
Where("r.deleted_at IS NULL").
Count(&count).Error; err != nil {
return false, err
}
case fifo.UsableKeyStockTransferOut.String():
if err := db.WithContext(ctx).
Table("stock_transfer_details std").
Joins("JOIN stock_transfers st ON st.id = std.stock_transfer_id").
Where("std.id = ?", usableID).
Where("std.deleted_at IS NULL").
Where("st.deleted_at IS NULL").
Count(&count).Error; err != nil {
return false, err
}
case fifo.UsableKeyTransferToLayingOut.String():
if err := db.WithContext(ctx).
Table("laying_transfers").
Where("id = ?", usableID).
Where("deleted_at IS NULL").
Count(&count).Error; err != nil {
return false, err
}
default:
return true, nil
}
return count > 0, nil
}
func sortedIDs(input map[uint]struct{}) []uint {
if len(input) == 0 {
return nil