mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-24 07:15:43 +00:00
add restrict create/edit/delete depletion
This commit is contained in:
@@ -56,6 +56,13 @@ type transferService struct {
|
||||
|
||||
const transferDeleteDownstreamGuardMessage = "Transfer stock tidak dapat dihapus karena stok transfer sudah dipakai transaksi turunan. Hapus dependensi terkait secara manual terlebih dahulu."
|
||||
|
||||
type downstreamDependency struct {
|
||||
UsableType string `gorm:"column:usable_type"`
|
||||
UsableID uint64 `gorm:"column:usable_id"`
|
||||
FunctionCode string `gorm:"column:function_code"`
|
||||
FlagGroupCode string `gorm:"column:flag_group_code"`
|
||||
}
|
||||
|
||||
func NewTransferService(validate *validator.Validate, stockTransferRepo rStockTransfer.StockTransferRepository, stockTransferDetailRepo rStockTransfer.StockTransferDetailRepository, stockTransferDeliveryRepo rStockTransfer.StockTransferDeliveryRepository, stockTransferDeliveryItemRepo rStockTransfer.StockTransferDeliveryItemRepository, stockLogsRepo rStockLogs.StockLogRepository, productWarehouseRepo rProductWarehouse.ProductWarehouseRepository, supplierRepo rSupplier.SupplierRepository, warehouseRepo warehouseRepo.WarehouseRepository, projectFlockKandangRepo projectFlockKandangRepo.ProjectFlockKandangRepository, projectFlockPopulationRepo projectFlockKandangRepo.ProjectFlockPopulationRepository, documentSvc commonSvc.DocumentService, fifoStockV2Svc commonSvc.FifoStockV2Service, expenseBridge TransferExpenseBridge) TransferService {
|
||||
return &transferService{
|
||||
Log: utils.Log,
|
||||
@@ -674,7 +681,7 @@ func (s *transferService) DeleteOne(c *fiber.Ctx, id uint) error {
|
||||
for _, detail := range details {
|
||||
detailIDs = append(detailIDs, detail.Id)
|
||||
}
|
||||
if err := s.ensureNoDownstreamConsumptionForDelete(c.Context(), tx, detailIDs); err != nil {
|
||||
if err := s.ensureDeletePolicyForDownstreamConsumption(c.Context(), tx, detailIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -936,37 +943,97 @@ func (s *transferService) ensureTransferAccess(ctx context.Context, id uint, c *
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *transferService) ensureNoDownstreamConsumptionForDelete(ctx context.Context, tx *gorm.DB, detailIDs []uint64) error {
|
||||
if len(detailIDs) == 0 {
|
||||
func (s *transferService) ensureDeletePolicyForDownstreamConsumption(ctx context.Context, tx *gorm.DB, detailIDs []uint64) error {
|
||||
dependencies, err := s.loadActiveTransferDownstreamDependencies(ctx, tx, detailIDs)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to load downstream stock transfer consumption: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal memvalidasi transaksi turunan transfer stock")
|
||||
}
|
||||
if len(dependencies) == 0 {
|
||||
return nil
|
||||
}
|
||||
ayamDependency, err := s.hasAyamDownstreamConsumption(ctx, tx, detailIDs)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to validate AYAM downstream dependency for transfer delete: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal memvalidasi dependensi AYAM pada transfer stock")
|
||||
}
|
||||
if ayamDependency {
|
||||
return fiber.NewError(
|
||||
fiber.StatusBadRequest,
|
||||
fmt.Sprintf(
|
||||
"%s Dependensi aktif: %s. Alasan block: produk AYAM yang sudah terpakai tidak dapat dihapus.",
|
||||
transferDeleteDownstreamGuardMessage,
|
||||
formatDownstreamDependencySummary(dependencies),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
denyReason := ""
|
||||
for _, dep := range dependencies {
|
||||
policy, policyErr := commonSvc.ResolveFifoPendingPolicy(ctx, tx, commonSvc.FifoPendingPolicyInput{
|
||||
Lane: "USABLE",
|
||||
FlagGroupCode: dep.FlagGroupCode,
|
||||
FunctionCode: dep.FunctionCode,
|
||||
LegacyTypeKey: dep.UsableType,
|
||||
})
|
||||
if policyErr != nil {
|
||||
s.Log.Errorf("Failed to resolve FIFO pending policy for transfer dependency: %+v", policyErr)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal membaca konfigurasi FIFO v2")
|
||||
}
|
||||
if !policy.Found || !policy.AllowPending {
|
||||
denyReason = "pending disabled by config"
|
||||
break
|
||||
}
|
||||
}
|
||||
if denyReason == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fiber.NewError(
|
||||
fiber.StatusBadRequest,
|
||||
fmt.Sprintf(
|
||||
"%s Dependensi aktif: %s. Alasan block: %s.",
|
||||
transferDeleteDownstreamGuardMessage,
|
||||
formatDownstreamDependencySummary(dependencies),
|
||||
denyReason,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func (s *transferService) loadActiveTransferDownstreamDependencies(
|
||||
ctx context.Context,
|
||||
tx *gorm.DB,
|
||||
detailIDs []uint64,
|
||||
) ([]downstreamDependency, error) {
|
||||
if len(detailIDs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
db := s.StockTransferRepo.DB().WithContext(ctx)
|
||||
if tx != nil {
|
||||
db = tx.WithContext(ctx)
|
||||
}
|
||||
|
||||
type downstreamRow struct {
|
||||
UsableType string `gorm:"column:usable_type"`
|
||||
UsableID uint64 `gorm:"column:usable_id"`
|
||||
}
|
||||
|
||||
var rows []downstreamRow
|
||||
if err := db.Table("stock_allocations").
|
||||
Select("usable_type, usable_id").
|
||||
var rows []downstreamDependency
|
||||
err := db.Table("stock_allocations").
|
||||
Select("usable_type, usable_id, COALESCE(function_code,'') AS function_code, COALESCE(flag_group_code,'') AS flag_group_code").
|
||||
Where("stockable_type = ?", fifo.StockableKeyStockTransferIn.String()).
|
||||
Where("stockable_id IN ?", detailIDs).
|
||||
Where("status = ?", entity.StockAllocationStatusActive).
|
||||
Where("allocation_purpose = ?", entity.StockAllocationPurposeConsume).
|
||||
Where("deleted_at IS NULL").
|
||||
Group("usable_type, usable_id").
|
||||
Scan(&rows).Error; err != nil {
|
||||
s.Log.Errorf("Failed to validate downstream stock transfer consumption: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal memvalidasi transaksi turunan transfer stock")
|
||||
Group("usable_type, usable_id, function_code, flag_group_code").
|
||||
Scan(&rows).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func formatDownstreamDependencySummary(rows []downstreamDependency) string {
|
||||
if len(rows) == 0 {
|
||||
return nil
|
||||
return "-"
|
||||
}
|
||||
|
||||
dependencyMap := make(map[string]map[uint64]struct{})
|
||||
@@ -990,10 +1057,35 @@ func (s *transferService) ensureNoDownstreamConsumptionForDelete(ctx context.Con
|
||||
details = append(details, fmt.Sprintf("%s=%s", label, joinUint64(ids)))
|
||||
}
|
||||
|
||||
return fiber.NewError(
|
||||
fiber.StatusBadRequest,
|
||||
fmt.Sprintf("%s Dependensi aktif: %s.", transferDeleteDownstreamGuardMessage, strings.Join(details, ", ")),
|
||||
)
|
||||
return strings.Join(details, ", ")
|
||||
}
|
||||
|
||||
func (s *transferService) hasAyamDownstreamConsumption(ctx context.Context, tx *gorm.DB, detailIDs []uint64) (bool, error) {
|
||||
if len(detailIDs) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
db := s.StockTransferRepo.DB().WithContext(ctx)
|
||||
if tx != nil {
|
||||
db = tx.WithContext(ctx)
|
||||
}
|
||||
|
||||
var found int64
|
||||
err := db.Table("stock_allocations sa").
|
||||
Joins("JOIN stock_transfer_details std ON std.id = sa.stockable_id AND std.deleted_at IS NULL").
|
||||
Joins("JOIN flags f ON f.flagable_type = ? AND f.flagable_id = std.product_id", entity.FlagableTypeProduct).
|
||||
Joins("JOIN fifo_stock_v2_flag_members fm ON fm.flag_name = f.name AND fm.flag_group_code = ? AND fm.is_active = TRUE", "AYAM").
|
||||
Where("sa.stockable_type = ?", fifo.StockableKeyStockTransferIn.String()).
|
||||
Where("sa.stockable_id IN ?", detailIDs).
|
||||
Where("sa.status = ?", entity.StockAllocationStatusActive).
|
||||
Where("sa.allocation_purpose = ?", entity.StockAllocationPurposeConsume).
|
||||
Where("sa.deleted_at IS NULL").
|
||||
Count(&found).Error
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return found > 0, nil
|
||||
}
|
||||
|
||||
func mapTransferDownstreamUsableLabel(usableType string) string {
|
||||
|
||||
Reference in New Issue
Block a user