add adjustment depresiasi calculation and percentage depresiasi

This commit is contained in:
giovanni
2026-05-29 21:48:20 +07:00
parent b4fbef702a
commit a46edc4498
14 changed files with 128 additions and 178 deletions
@@ -26,6 +26,8 @@ type ExpenseDepreciationRowDTO struct {
DayN int `json:"day_n"`
ChickinDate string `json:"chickin_date"`
TotalValuePulletAfterDepreciation float64 `json:"total_value_pullet_after_depreciation"`
StandardEffectiveDate string `json:"standard_effective_date,omitempty"`
TotalPopulation float64 `json:"total_population"`
Components any `json:"components"`
}
@@ -41,6 +41,7 @@ type houseMultiplicationPercentageRow struct {
HouseType string
Day int
MultiplicationPercentage float64
EffectiveDate *time.Time
}
type ExpenseDepreciationRepository interface {
@@ -50,7 +51,7 @@ type ExpenseDepreciationRepository interface {
DeleteSnapshotsFromDate(ctx context.Context, fromDate time.Time, farmIDs []uint) error
DeleteSnapshotsByFarmIDs(ctx context.Context, farmIDs []uint) error
GetLatestTransferInputsByFarms(ctx context.Context, period time.Time, farmIDs []uint) ([]FarmDepreciationLatestTransferRow, error)
GetMultiplicationPercentages(ctx context.Context, houseTypes []string, maxDay int) (map[string]map[int]float64, error)
GetMultiplicationPercentages(ctx context.Context, houseTypes []string, maxDay int) (map[string]map[int]float64, map[string]*time.Time, error)
GetLatestManualInputsByFarms(ctx context.Context, areaIDs, locationIDs, projectFlockIDs []int64) ([]FarmDepreciationManualInputRow, error)
UpsertManualInput(ctx context.Context, row *entity.FarmDepreciationManualInput) error
DB() *gorm.DB
@@ -244,21 +245,22 @@ func (r *expenseDepreciationRepository) GetMultiplicationPercentages(
ctx context.Context,
houseTypes []string,
maxDay int,
) (map[string]map[int]float64, error) {
) (map[string]map[int]float64, map[string]*time.Time, error) {
result := make(map[string]map[int]float64)
effectiveDates := make(map[string]*time.Time)
if len(houseTypes) == 0 || maxDay <= 0 {
return result, nil
return result, effectiveDates, nil
}
rows := make([]houseMultiplicationPercentageRow, 0)
if err := r.db.WithContext(ctx).Raw(`
SELECT DISTINCT ON (house_type::text, day)
house_type::text AS house_type, day, multiplication_percentage
house_type::text AS house_type, day, multiplication_percentage, effective_date
FROM house_depreciation_standards
WHERE house_type::text IN ? AND day <= ?
ORDER BY house_type, day, effective_date DESC NULLS LAST
`, houseTypes, maxDay).Scan(&rows).Error; err != nil {
return nil, err
return nil, nil, err
}
for _, row := range rows {
@@ -266,9 +268,12 @@ func (r *expenseDepreciationRepository) GetMultiplicationPercentages(
result[row.HouseType] = make(map[int]float64)
}
result[row.HouseType][row.Day] = row.MultiplicationPercentage
if _, tracked := effectiveDates[row.HouseType]; !tracked {
effectiveDates[row.HouseType] = row.EffectiveDate
}
}
return result, nil
return result, effectiveDates, nil
}
func (r *expenseDepreciationRepository) GetLatestManualInputsByFarms(
@@ -304,7 +304,8 @@ func (s *repportService) GetExpenseDepreciation(ctx *fiber.Ctx) ([]dto.ExpenseDe
continue
}
components := parseSnapshotComponents(snapshot.Components)
multiplicationPercentage, dayN, chickinDate := depreciationSnapshotInfo(components)
multiplicationPercentage, dayN, chickinDate, standardEffectiveDate := depreciationSnapshotInfo(components)
totalPopulation := depreciationTotalPopulation(components)
rows = append(rows, dto.ExpenseDepreciationRowDTO{
ProjectFlockID: int64(snapshot.ProjectFlockId),
FarmName: candidate.FarmName,
@@ -316,6 +317,8 @@ func (s *repportService) GetExpenseDepreciation(ctx *fiber.Ctx) ([]dto.ExpenseDe
DayN: dayN,
ChickinDate: chickinDate,
TotalValuePulletAfterDepreciation: snapshot.PulletCostDayNTotal - snapshot.DepreciationValue,
StandardEffectiveDate: standardEffectiveDate,
TotalPopulation: totalPopulation,
Components: components,
})
}
@@ -502,11 +505,14 @@ type depreciationKandangComponent struct {
OriginDate string `json:"origin_date,omitempty"`
ChickinDate string `json:"chickin_date,omitempty"`
StartScheduleDay *int `json:"start_schedule_day,omitempty"`
StandardEffectiveDate string `json:"standard_effective_date,omitempty"`
Population float64 `json:"population"`
}
type depreciationFarmComponents struct {
KandangCount int `json:"kandang_count"`
Kandang []depreciationKandangComponent `json:"kandang"`
KandangCount int `json:"kandang_count"`
TotalPopulation float64 `json:"total_population"`
Kandang []depreciationKandangComponent `json:"kandang"`
}
func (s *repportService) computeExpenseDepreciationSnapshots(
@@ -540,6 +546,7 @@ func (s *repportService) computeExpenseDepreciationSnapshots(
totalDepreciationValue := 0.0
totalPulletCostDayN := 0.0
totalPopulation := 0.0
for _, kandangID := range kandangIDs {
breakdown, err := s.HppV2Svc.CalculateHppBreakdown(kandangID, &periodDate)
if err != nil {
@@ -575,6 +582,8 @@ func (s *repportService) computeExpenseDepreciationSnapshots(
DepreciationSource: part.Code,
OriginDate: hppV2DetailString(part.Details, "origin_date"),
ChickinDate: hppV2DetailString(part.Details, "origin_date"),
StandardEffectiveDate: hppV2DetailString(part.Details, "standard_effective_date"),
Population: hppV2DetailFloat(part.Details, "kandang_population"),
}
if component.HouseType == "" {
@@ -605,11 +614,13 @@ func (s *repportService) computeExpenseDepreciationSnapshots(
totalPulletCostDayN += component.PulletCostDayN
totalDepreciationValue += component.DepreciationValue
totalPopulation += component.Population
components.Kandang = append(components.Kandang, component)
}
}
components.KandangCount = len(components.Kandang)
components.TotalPopulation = totalPopulation
effectivePercent := approvalService.CalculateEffectiveDepreciationPercent(totalDepreciationValue, totalPulletCostDayN)
componentsJSON, marshalErr := json.Marshal(components)
@@ -744,14 +755,14 @@ func parseSnapshotComponents(raw []byte) any {
return out
}
func depreciationSnapshotInfo(components any) (float64, int, string) {
func depreciationSnapshotInfo(components any) (float64, int, string, string) {
root, ok := components.(map[string]any)
if !ok {
return 0, 0, ""
return 0, 0, "", ""
}
kandang, ok := root["kandang"].([]any)
if !ok {
return 0, 0, ""
return 0, 0, "", ""
}
for _, raw := range kandang {
component, ok := raw.(map[string]any)
@@ -765,10 +776,19 @@ func depreciationSnapshotInfo(components any) (float64, int, string) {
chickinDate = anyString(component["origin_date"])
}
if dayN > 0 || multiplicationPercentage > 0 || chickinDate != "" {
return multiplicationPercentage, dayN, chickinDate
standardEffectiveDate := anyString(component["standard_effective_date"])
return multiplicationPercentage, dayN, chickinDate, standardEffectiveDate
}
}
return 0, 0, ""
return 0, 0, "", ""
}
func depreciationTotalPopulation(components any) float64 {
root, ok := components.(map[string]any)
if !ok {
return 0
}
return anyFloat(root["total_population"])
}
func anyFloat(raw any) float64 {
@@ -1823,15 +1843,6 @@ func (s *repportService) GetDebtSupplier(c *fiber.Ctx, params *validation.DebtSu
return nil, 0, err
}
expenseIDs := make([]uint64, 0, len(expenses))
for _, exp := range expenses {
expenseIDs = append(expenseIDs, exp.Id)
}
expenseWarehousesMap, err := s.DebtSupplierRepo.GetWarehousesByExpenseIDs(c.Context(), expenseIDs)
if err != nil {
return nil, 0, err
}
purchasesBySupplier := make(map[uint][]entity.Purchase, len(supplierIDs))
for _, purchase := range purchases {
purchasesBySupplier[purchase.SupplierId] = append(purchasesBySupplier[purchase.SupplierId], purchase)
@@ -1939,7 +1950,7 @@ func (s *repportService) GetDebtSupplier(c *fiber.Ctx, params *validation.DebtSu
}
for _, exp := range expensesBySupplier[supplierID] {
row := buildDebtSupplierExpenseRow(exp, expenseWarehousesMap[exp.Id], now, location)
row := buildDebtSupplierExpenseRow(exp, now, location)
sortTime := exp.TransactionDate.In(location)
rowIndex := len(combinedRows)
combinedRows = append(combinedRows, debtSupplierRowItem{
@@ -2111,6 +2122,12 @@ func buildDebtSupplierRow(purchase entity.Purchase, now time.Time, loc *time.Loc
poDate = purchase.PoDate.In(loc).Format("2006-01-02")
}
var firstWarehouse *warehouseDTO.WarehouseRelationDTO
if len(warehouses) > 0 {
w := warehouses[0]
firstWarehouse = &w
}
return dto.DebtSupplierRowDTO{
PrNumber: prNumber,
PoNumber: poNumber,
@@ -2118,7 +2135,7 @@ func buildDebtSupplierRow(purchase entity.Purchase, now time.Time, loc *time.Loc
ReceivedDate: receivedDate,
Aging: aging,
Area: area,
Warehouses: warehouses,
Warehouse: firstWarehouse,
DueDate: dueDate,
DueStatus: dueStatus,
TotalPrice: totalPrice,
@@ -2148,7 +2165,7 @@ func buildDebtSupplierPaymentRow(payment entity.Payment, loc *time.Location) dto
ReceivedDate: payment.PaymentDate.In(loc).Format("2006-01-02"),
Aging: 0,
Area: nil,
Warehouses: []warehouseDTO.WarehouseRelationDTO{},
Warehouse: nil,
DueDate: "-",
DueStatus: "-",
TotalPrice: 0,
@@ -2361,7 +2378,7 @@ func resolveDebtSupplierReceivedDate(purchase entity.Purchase, loc *time.Locatio
return time.Date(earliest.Year(), earliest.Month(), earliest.Day(), 0, 0, 0, 0, loc)
}
func buildDebtSupplierExpenseRow(exp entity.Expense, warehouses []entity.Warehouse, now time.Time, loc *time.Location) dto.DebtSupplierRowDTO {
func buildDebtSupplierExpenseRow(exp entity.Expense, now time.Time, loc *time.Location) dto.DebtSupplierRowDTO {
txDate := exp.TransactionDate.In(loc)
dateStr := txDate.Format("2006-01-02")
@@ -2383,15 +2400,6 @@ func buildDebtSupplierExpenseRow(exp entity.Expense, warehouses []entity.Warehou
area = &mapped
}
warehouseDTOs := make([]warehouseDTO.WarehouseRelationDTO, 0, len(warehouses))
seenWarehouseIDs := map[uint]bool{}
for _, w := range warehouses {
if w.Id != 0 && !seenWarehouseIDs[w.Id] {
seenWarehouseIDs[w.Id] = true
warehouseDTOs = append(warehouseDTOs, warehouseDTO.ToWarehouseRelationDTO(w))
}
}
poNumber := ""
if strings.TrimSpace(exp.PoNumber) != "" {
poNumber = exp.PoNumber
@@ -2404,7 +2412,7 @@ func buildDebtSupplierExpenseRow(exp entity.Expense, warehouses []entity.Warehou
ReceivedDate: dateStr,
Aging: aging,
Area: area,
Warehouses: warehouseDTOs,
Warehouse: nil,
DueDate: "-",
DueStatus: "-",
TotalPrice: totalPrice,