codex: initiated changes

This commit is contained in:
Adnan Zahir
2026-03-30 13:40:29 +07:00
parent d76f72050e
commit be00837148
22 changed files with 1762 additions and 328 deletions
@@ -18,6 +18,7 @@ type ProjectFlockPopulationRepository interface {
GetTotalQtyByProductWarehouseID(ctx context.Context, productWarehouseID uint) (float64, error)
GetAvailableQtyByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (float64, error)
GetTotalChickInByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (int64, error)
ResyncUsageByProjectFlockKandangID(ctx context.Context, tx *gorm.DB, projectFlockKandangID uint) error
CreateOne(ctx context.Context, entity *entity.ProjectFlockPopulation, modifier func(*gorm.DB) *gorm.DB) error
PatchOne(ctx context.Context, id uint, updates map[string]any, modifier func(*gorm.DB) *gorm.DB) error
@@ -167,3 +168,58 @@ func (r *projectFlockPopulationRepositoryImpl) GetTotalChickInByProjectFlockKand
return int64(math.Round(total)), nil
}
func (r *projectFlockPopulationRepositoryImpl) ResyncUsageByProjectFlockKandangID(ctx context.Context, tx *gorm.DB, projectFlockKandangID uint) error {
if projectFlockKandangID == 0 {
return nil
}
idsSubquery := `
SELECT pfp.id
FROM project_flock_populations pfp
JOIN project_chickins pc ON pc.id = pfp.project_chickin_id
WHERE pc.project_flock_kandang_id = ?
`
updateWithAlloc := `
UPDATE project_flock_populations p
SET total_used_qty = COALESCE(a.used, 0)
FROM (
SELECT stockable_id, SUM(qty) AS used
FROM stock_allocations
WHERE stockable_type = 'PROJECT_FLOCK_POPULATION'
AND status = 'ACTIVE'
AND allocation_purpose = 'CONSUME'
GROUP BY stockable_id
) a
WHERE p.id = a.stockable_id
AND p.id IN (` + idsSubquery + `)
`
resetMissing := `
UPDATE project_flock_populations p
SET total_used_qty = 0
WHERE p.id IN (` + idsSubquery + `)
AND NOT EXISTS (
SELECT 1
FROM stock_allocations sa
WHERE sa.stockable_type = 'PROJECT_FLOCK_POPULATION'
AND sa.status = 'ACTIVE'
AND sa.allocation_purpose = 'CONSUME'
AND sa.stockable_id = p.id
)
`
db := r.DB().WithContext(ctx)
if tx != nil {
db = tx.WithContext(ctx)
}
if err := db.Exec(updateWithAlloc, projectFlockKandangID).Error; err != nil {
return err
}
if err := db.Exec(resetMissing, projectFlockKandangID).Error; err != nil {
return err
}
return nil
}
@@ -366,6 +366,15 @@ func (s *recordingService) CreateOne(c *fiber.Ctx, req *validation.Create) (*ent
if err := s.ensureProductWarehousesByFlags(ctx, depletionIDs, []string{"AYAM-AFKIR", "AYAM-CULLING", "AYAM-MATI"}, "depletion"); err != nil {
return nil, err
}
depletionSourceIDs := recordingutil.CollectWarehouseIDs(req.Depletions, func(d validation.Depletion) uint {
if d.SourceProductWarehouseId == nil {
return 0
}
return *d.SourceProductWarehouseId
})
if err := s.ensureProductWarehousesByFlags(ctx, depletionSourceIDs, []string{"DOC", "PULLET", "LAYER"}, "depletion source"); err != nil {
return nil, err
}
eggIDs := recordingutil.CollectWarehouseIDs(req.Eggs, func(e validation.Egg) uint { return e.ProductWarehouseId })
if err := s.ensureProductWarehousesByFlags(ctx, eggIDs, []string{"TELUR-UTUH", "TELUR-PECAH", "TELUR-PUTIH", "TELUR-RETAK", "TELUR"}, "egg"); err != nil {
return nil, err
@@ -435,11 +444,16 @@ func (s *recordingService) CreateOne(c *fiber.Ctx, req *validation.Create) (*ent
if err := s.ensureDepletionWithinPopulation(ctx, tx, req.ProjectFlockKandangId, sumDepletionQty(mappedDepletions), 0); err != nil {
return err
}
sourceWarehouseID, err := s.resolvePopulationWarehouseID(ctx, req.ProjectFlockKandangId)
if err != nil {
return err
}
sourceProjectFlockKandangID := req.ProjectFlockKandangId
for i := range mappedDepletions {
mappedDepletions[i].SourceProjectFlockKandangId = &sourceProjectFlockKandangID
if mappedDepletions[i].SourceProductWarehouseId != nil && *mappedDepletions[i].SourceProductWarehouseId != 0 {
continue
}
sourceWarehouseID, err := s.resolvePopulationWarehouseID(ctx, req.ProjectFlockKandangId)
if err != nil {
return err
}
mappedDepletions[i].SourceProductWarehouseId = &sourceWarehouseID
}
}
@@ -460,7 +474,7 @@ func (s *recordingService) CreateOne(c *fiber.Ctx, req *validation.Create) (*ent
return err
}
mappedEggs := recordingutil.MapEggs(createdRecording.Id, createdRecording.CreatedBy, req.Eggs)
mappedEggs := recordingutil.MapEggs(createdRecording.Id, createdRecording.ProjectFlockKandangId, createdRecording.CreatedBy, req.Eggs)
if err := s.Repository.CreateEggs(tx, mappedEggs); err != nil {
s.Log.Errorf("Failed to persist eggs: %+v", err)
return err
@@ -590,13 +604,13 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
s.Log.Errorf("Failed to list existing depletions: %+v", err)
return err
}
existingTotals := recordingutil.TotalsByWarehouse(existingDepletions, func(dep entity.RecordingDepletion) (uint, float64) {
return dep.ProductWarehouseId, dep.Qty
existingTotals := recordingutil.DepletionTotalsByRoute(existingDepletions, func(dep entity.RecordingDepletion) (uint, *uint, float64) {
return dep.ProductWarehouseId, dep.SourceProductWarehouseId, dep.Qty
})
incomingTotals := recordingutil.TotalsByWarehouse(req.Depletions, func(dep validation.Depletion) (uint, float64) {
return dep.ProductWarehouseId, dep.Qty
incomingTotals := recordingutil.DepletionTotalsByRoute(req.Depletions, func(dep validation.Depletion) (uint, *uint, float64) {
return dep.ProductWarehouseId, dep.SourceProductWarehouseId, dep.Qty
})
match := recordingutil.FloatMapsEqual(existingTotals, incomingTotals)
match := recordingutil.DepletionRouteMapsEqual(existingTotals, incomingTotals)
if match {
hasDepletionChanges = false
} else {
@@ -613,6 +627,15 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
if err := s.ensureProductWarehousesByFlags(ctx, depletionIDs, []string{"AYAM-AFKIR", "AYAM-CULLING", "AYAM-MATI"}, "depletion"); err != nil {
return err
}
depletionSourceIDs := recordingutil.CollectWarehouseIDs(req.Depletions, func(d validation.Depletion) uint {
if d.SourceProductWarehouseId == nil {
return 0
}
return *d.SourceProductWarehouseId
})
if err := s.ensureProductWarehousesByFlags(ctx, depletionSourceIDs, []string{"DOC", "PULLET", "LAYER"}, "depletion source"); err != nil {
return err
}
if err := s.reflowResetRecordingDepletionsOut(ctx, tx, existingDepletions, note, actorID); err != nil {
return err
}
@@ -630,11 +653,16 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
if err := s.ensureDepletionWithinPopulation(ctx, tx, recordingEntity.ProjectFlockKandangId, sumDepletionQty(mappedDepletions), sumDepletionQty(existingDepletions)); err != nil {
return err
}
sourceWarehouseID, err := s.resolvePopulationWarehouseID(ctx, recordingEntity.ProjectFlockKandangId)
if err != nil {
return err
}
sourceProjectFlockKandangID := recordingEntity.ProjectFlockKandangId
for i := range mappedDepletions {
mappedDepletions[i].SourceProjectFlockKandangId = &sourceProjectFlockKandangID
if mappedDepletions[i].SourceProductWarehouseId != nil && *mappedDepletions[i].SourceProductWarehouseId != 0 {
continue
}
sourceWarehouseID, err := s.resolvePopulationWarehouseID(ctx, recordingEntity.ProjectFlockKandangId)
if err != nil {
return err
}
mappedDepletions[i].SourceProductWarehouseId = &sourceWarehouseID
}
}
@@ -700,7 +728,7 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
return err
}
mappedEggs := recordingutil.MapEggs(recordingEntity.Id, recordingEntity.CreatedBy, req.Eggs)
mappedEggs := recordingutil.MapEggs(recordingEntity.Id, recordingEntity.ProjectFlockKandangId, recordingEntity.CreatedBy, req.Eggs)
if err := s.Repository.CreateEggs(tx, mappedEggs); err != nil {
s.Log.Errorf("Failed to update eggs: %+v", err)
return err
@@ -1476,6 +1504,9 @@ func (s *recordingService) ensureProductWarehousesExist(c *fiber.Ctx, stocks []v
if dep.ProductWarehouseId != 0 {
idSet[dep.ProductWarehouseId] = struct{}{}
}
if dep.SourceProductWarehouseId != nil && *dep.SourceProductWarehouseId != 0 {
idSet[*dep.SourceProductWarehouseId] = struct{}{}
}
}
for _, egg := range eggs {
if egg.ProductWarehouseId != 0 {
@@ -2500,12 +2531,17 @@ func (s *recordingService) allocatePopulationForDepletion(
}
var projectFlockKandangID uint
if err := tx.WithContext(ctx).
Table("recordings").
Select("project_flock_kandangs_id").
Where("id = ?", depletion.RecordingId).
Scan(&projectFlockKandangID).Error; err != nil {
return err
if depletion.SourceProjectFlockKandangId != nil {
projectFlockKandangID = *depletion.SourceProjectFlockKandangId
}
if projectFlockKandangID == 0 {
if err := tx.WithContext(ctx).
Table("recordings").
Select("project_flock_kandangs_id").
Where("id = ?", depletion.RecordingId).
Scan(&projectFlockKandangID).Error; err != nil {
return err
}
}
if projectFlockKandangID == 0 {
return fiber.NewError(fiber.StatusBadRequest, "Project flock kandang tidak ditemukan untuk depletion")
@@ -9,8 +9,9 @@ type (
}
Depletion struct {
ProductWarehouseId uint `json:"product_warehouse_id" validate:"required,number,min=1"`
Qty float64 `json:"qty" validate:"required,gte=0"`
ProductWarehouseId uint `json:"product_warehouse_id" validate:"required,number,min=1"`
SourceProductWarehouseId *uint `json:"source_product_warehouse_id,omitempty" validate:"omitempty,number,min=1"`
Qty float64 `json:"qty" validate:"required,gte=0"`
}
Egg struct {