init depresiasi

This commit is contained in:
giovanni
2026-04-17 21:26:56 +07:00
parent a54c6184a2
commit fcde3b0a36
34 changed files with 3588 additions and 46 deletions
@@ -675,6 +675,12 @@ func (s *purchaseService) CreateOne(c *fiber.Ctx, req *validation.CreatePurchase
if err := s.attachLatestApproval(c.Context(), created); err != nil {
s.Log.Warnf("Unable to attach latest approval for purchase %d: %+v", created.Id, err)
}
s.invalidateDepreciationSnapshots(
c.Context(),
nil,
collectPFKIDsFromPurchase(created),
resolvePurchaseDepreciationInvalidateDate(created, created.Items, now),
)
return created, nil
}
@@ -826,6 +832,12 @@ func (s *purchaseService) ApproveStaffPurchase(c *fiber.Ctx, id uint, req *valid
if err := s.attachLatestApproval(c.Context(), updated); err != nil {
s.Log.Warnf("Unable to attach latest approval for purchase %d: %+v", updated.Id, err)
}
s.invalidateDepreciationSnapshots(
c.Context(),
nil,
collectPFKIDsFromPurchase(updated),
resolvePurchaseDepreciationInvalidateDate(updated, updated.Items, time.Now().UTC()),
)
return updated, nil
}
@@ -934,6 +946,12 @@ func (s *purchaseService) ApproveManagerPurchase(c *fiber.Ctx, id uint, req *val
if err := s.attachLatestApproval(c.Context(), updated); err != nil {
s.Log.Warnf("Unable to attach latest approval for purchase %d: %+v", updated.Id, err)
}
s.invalidateDepreciationSnapshots(
c.Context(),
nil,
collectPFKIDsFromPurchase(updated),
resolvePurchaseDepreciationInvalidateDate(updated, updated.Items, now),
)
return updated, nil
}
@@ -1421,6 +1439,16 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation
if err := s.attachLatestApproval(c.Context(), updated); err != nil {
s.Log.Warnf("Unable to attach latest approval for purchase %d: %+v", updated.Id, err)
}
invalidateFromDate := resolvePurchaseDepreciationInvalidateDate(updated, updated.Items, time.Now().UTC())
if earliestReceived != nil {
invalidateFromDate = commonSvc.MinNonZeroDateOnlyUTC(invalidateFromDate, *earliestReceived)
}
s.invalidateDepreciationSnapshots(
c.Context(),
nil,
collectPFKIDsFromPurchase(updated),
invalidateFromDate,
)
receivingPayloads := make([]ExpenseReceivingPayload, 0, len(prepared))
for _, prep := range prepared {
@@ -1628,6 +1656,12 @@ func (s *purchaseService) DeleteItems(c *fiber.Ctx, id uint, req *validation.Del
if err := s.attachLatestApproval(ctx, updated); err != nil {
s.Log.Warnf("Unable to attach latest approval for purchase %d: %+v", updated.Id, err)
}
s.invalidateDepreciationSnapshots(
ctx,
nil,
collectPFKIDsFromPurchaseItems(itemsToDelete),
resolvePurchaseDepreciationInvalidateDate(purchase, itemsToDelete, time.Now().UTC()),
)
return updated, nil
}
@@ -1721,6 +1755,12 @@ func (s *purchaseService) DeletePurchase(c *fiber.Ctx, id uint) error {
return utils.Internal("Failed to sync expense")
}
}
s.invalidateDepreciationSnapshots(
ctx,
nil,
collectPFKIDsFromPurchaseItems(itemsToDelete),
resolvePurchaseDepreciationInvalidateDate(purchase, itemsToDelete, time.Now().UTC()),
)
return nil
}
@@ -2391,7 +2431,17 @@ func (s *purchaseService) rejectAndReload(
if err := s.createPurchaseApproval(c.Context(), nil, purchaseID, step, entity.ApprovalActionRejected, actorID, notes, false); err != nil {
return nil, err
}
return s.loadPurchase(c.Context(), purchaseID)
updated, err := s.loadPurchase(c.Context(), purchaseID)
if err != nil {
return nil, err
}
s.invalidateDepreciationSnapshots(
c.Context(),
nil,
collectPFKIDsFromPurchase(updated),
resolvePurchaseDepreciationInvalidateDate(updated, updated.Items, time.Now().UTC()),
)
return updated, nil
}
func (s *purchaseService) loadPurchase(
ctx context.Context,
@@ -2522,10 +2572,17 @@ func (s *purchaseService) resolveChickinLockedItemIDsByItemID(ctx context.Contex
}
func collectPFKIDsFromPurchase(p *entity.Purchase) []uint {
if p == nil {
return nil
}
return collectPFKIDsFromPurchaseItems(p.Items)
}
func collectPFKIDsFromPurchaseItems(items []entity.PurchaseItem) []uint {
seen := make(map[uint]struct{})
ids := make([]uint, 0)
for _, item := range p.Items {
for _, item := range items {
if item.ProjectFlockKandangId == nil || *item.ProjectFlockKandangId == 0 {
continue
}
@@ -2538,6 +2595,82 @@ func collectPFKIDsFromPurchase(p *entity.Purchase) []uint {
}
return ids
}
func resolvePurchaseDepreciationInvalidateDate(
purchase *entity.Purchase,
items []entity.PurchaseItem,
fallback time.Time,
) time.Time {
fromDate := time.Time{}
if purchase != nil {
fromDate = commonSvc.MinNonZeroDateOnlyUTC(fromDate, purchase.CreatedAt)
if purchase.PoDate != nil {
fromDate = commonSvc.MinNonZeroDateOnlyUTC(fromDate, *purchase.PoDate)
}
}
for _, item := range items {
if item.ReceivedDate == nil {
continue
}
fromDate = commonSvc.MinNonZeroDateOnlyUTC(fromDate, *item.ReceivedDate)
}
if fromDate.IsZero() {
fromDate = fallback
}
return fromDate
}
func (s *purchaseService) invalidateDepreciationSnapshots(
ctx context.Context,
tx *gorm.DB,
projectFlockKandangIDs []uint,
fromDate time.Time,
) {
if fromDate.IsZero() {
return
}
projectFlockKandangIDs = utils.UniqueUintSlice(projectFlockKandangIDs)
targetDB := s.PurchaseRepo.DB()
if tx != nil {
targetDB = tx
}
var farmIDs []uint
if len(projectFlockKandangIDs) > 0 {
resolvedFarmIDs, err := commonSvc.ResolveProjectFlockIDsByProjectFlockKandangIDs(ctx, targetDB, projectFlockKandangIDs)
if err != nil {
s.Log.Warnf(
"Failed to resolve farm ids for purchase depreciation invalidation (pfk_ids=%v): %+v",
projectFlockKandangIDs,
err,
)
} else {
farmIDs = resolvedFarmIDs
}
}
if len(farmIDs) == 0 {
if err := commonSvc.InvalidateFarmDepreciationSnapshotsFromDate(ctx, targetDB, nil, fromDate); err != nil {
s.Log.Warnf(
"Failed to invalidate depreciation snapshots globally (from=%s): %+v",
fromDate.Format("2006-01-02"),
err,
)
}
return
}
if err := commonSvc.InvalidateFarmDepreciationSnapshotsFromDate(ctx, targetDB, farmIDs, fromDate); err != nil {
s.Log.Warnf(
"Failed to invalidate depreciation snapshots (farm_ids=%v, from=%s): %+v",
farmIDs,
fromDate.Format("2006-01-02"),
err,
)
}
}
func (s *purchaseService) ensureProjectFlockNotClosedForPurchase(
ctx context.Context,
purchase *entity.Purchase,