adjust response depretitation v2

This commit is contained in:
giovanni
2026-06-08 12:30:51 +07:00
parent 61d375a59a
commit 217f35b250
7 changed files with 210 additions and 69 deletions
@@ -50,7 +50,7 @@ type ExpenseDepreciationV2MetaDTO struct {
}
type ExpenseDepreciationV2RowDTO struct {
Date string `json:"date"`
Date string `json:"date"`
DepreciationPercentEffective float64 `json:"depreciation_percent_effective"`
DepreciationValue float64 `json:"depreciation_value"`
PulletCostDayNTotal float64 `json:"pullet_cost_day_n_total"`
@@ -60,7 +60,6 @@ type ExpenseDepreciationV2RowDTO struct {
TotalValuePulletAfterDepreciation float64 `json:"total_value_pullet_after_depreciation"`
StandardEffectiveDate string `json:"standard_effective_date,omitempty"`
TotalPopulation float64 `json:"total_population"`
Components any `json:"components"`
}
func NewExpenseDepreciationFiltersDTO(area, location, projectFlockID, period string) ExpenseDepreciationFiltersDTO {
@@ -0,0 +1,51 @@
package dto
import (
"encoding/json"
"testing"
)
func TestExpenseDepreciationRowDTOComponentsJSONContract(t *testing.T) {
v1 := ExpenseDepreciationRowDTO{
ProjectFlockID: 1,
FarmName: "Farm A",
Period: "2026-06-05",
Components: map[string]any{"kandang_count": 1},
}
rawV1, err := json.Marshal(v1)
if err != nil {
t.Fatalf("marshal v1 dto: %v", err)
}
var decodedV1 map[string]any
if err := json.Unmarshal(rawV1, &decodedV1); err != nil {
t.Fatalf("unmarshal v1 dto: %v", err)
}
if _, ok := decodedV1["components"]; !ok {
t.Fatalf("expected v1 components to be present, got %s", string(rawV1))
}
v2 := ExpenseDepreciationV2RowDTO{
Date: "2026-06-05",
DepreciationPercentEffective: 10,
DepreciationValue: 100,
PulletCostDayNTotal: 1000,
MultiplicationPercentage: 0.9,
DayN: 2,
ChickinDate: "2026-01-01",
TotalValuePulletAfterDepreciation: 900,
TotalPopulation: 100,
}
rawV2, err := json.Marshal(v2)
if err != nil {
t.Fatalf("marshal v2 dto: %v", err)
}
var decodedV2 map[string]any
if err := json.Unmarshal(rawV2, &decodedV2); err != nil {
t.Fatalf("unmarshal v2 dto: %v", err)
}
if _, ok := decodedV2["components"]; ok {
t.Fatalf("expected v2 components to be omitted, got %s", string(rawV2))
}
}
@@ -90,6 +90,12 @@ func (m *expenseDepreciationRepoMock) DeleteSnapshotsFromDate(_ context.Context,
return nil
}
func (m *expenseDepreciationRepoMock) DeleteSnapshotsByFarmIDs(_ context.Context, farmIDs []uint) error {
m.deleteCalled = true
m.deleteFarmIDs = append([]uint{}, farmIDs...)
return nil
}
func (m *expenseDepreciationRepoMock) GetLatestManualInputsByFarms(_ context.Context, _ []int64, _ []int64, _ []int64) ([]repportRepo.FarmDepreciationManualInputRow, error) {
return append([]repportRepo.FarmDepreciationManualInputRow{}, m.manualInputs...), nil
}
@@ -423,7 +423,10 @@ func (s *repportService) GetExpenseDepreciationV2(ctx *fiber.Ctx) ([]dto.Expense
var totalDepreciationValue float64
var totalPulletCostDayN float64
var totalPopulation float64
var allKandangComponents []depreciationKandangComponent
var multiplicationPercentage float64
var dayN int
var chickinDate string
var standardEffectiveDate string
for _, kandangID := range kandangIDs {
breakdown, err := s.HppV2Svc.CalculateHppBreakdown(kandangID, &dayDate)
@@ -444,72 +447,33 @@ func (s *repportService) GetExpenseDepreciationV2(ctx *fiber.Ctx) ([]dto.Expense
continue
}
houseType := approvalService.NormalizeDepreciationHouseType(breakdown.HouseType)
component := depreciationKandangComponent{
ProjectFlockKandangID: breakdown.ProjectFlockKandangID,
KandangID: breakdown.KandangID,
KandangName: breakdown.KandangName,
SourceProjectFlockID: hppV2DetailUint(part.Details, "source_project_flock_id"),
HouseType: houseType,
DayN: hppV2DetailInt(part.Details, "schedule_day"),
DepreciationPercent: hppV2DetailFloat(part.Details, "depreciation_percent"),
MultiplicationPercentage: hppV2DetailFloat(part.Details, "multiplication_percentage"),
PulletCostDayN: hppV2DetailFloat(part.Details, "pullet_cost_day_n"),
DepreciationValue: part.Total,
TotalValuePulletAfterDepreciation: hppV2DetailFloat(part.Details, "total_value_pullet_after_depreciation"),
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"),
partPulletCostDayN := hppV2DetailFloat(part.Details, "pullet_cost_day_n")
partPopulation := hppV2DetailFloat(part.Details, "kandang_population")
partDayN := hppV2DetailInt(part.Details, "schedule_day")
partMultiplicationPercentage := hppV2DetailFloat(part.Details, "multiplication_percentage")
partChickinDate := hppV2DetailString(part.Details, "chickin_date")
if partChickinDate == "" {
partChickinDate = hppV2DetailString(part.Details, "origin_date")
}
if component.HouseType == "" {
component.HouseType = approvalService.NormalizeDepreciationHouseType(hppV2DetailString(part.Details, "house_type"))
}
totalPulletCostDayN += partPulletCostDayN
totalDepreciationValue += part.Total
totalPopulation += partPopulation
if ref := hppV2FindReference(part.References, "laying_transfer"); ref != nil {
component.TransferID = ref.ID
component.TransferDate = ref.Date
component.TransferQty = ref.Qty
if dayN == 0 && multiplicationPercentage == 0 && chickinDate == "" &&
(partDayN > 0 || partMultiplicationPercentage > 0 || partChickinDate != "") {
dayN = partDayN
multiplicationPercentage = partMultiplicationPercentage
chickinDate = partChickinDate
standardEffectiveDate = hppV2DetailString(part.Details, "standard_effective_date")
}
if part.Code == "manual_cutover" {
if startDay := hppV2DetailInt(part.Details, "start_schedule_day"); startDay > 0 {
component.StartScheduleDay = &startDay
}
component.CutoverDate = hppV2DetailString(part.Details, "cutover_date")
if manualID := hppV2DetailUint(part.Details, "manual_input_id"); manualID > 0 {
component.ManualInputID = &manualID
}
if component.ManualInputID == nil {
if ref := hppV2FindReference(part.References, "farm_depreciation_manual_input"); ref != nil && ref.ID > 0 {
manualID := ref.ID
component.ManualInputID = &manualID
}
}
}
totalPulletCostDayN += component.PulletCostDayN
totalDepreciationValue += component.DepreciationValue
totalPopulation += component.Population
allKandangComponents = append(allKandangComponents, component)
}
}
effectivePercent := approvalService.CalculateEffectiveDepreciationPercent(totalDepreciationValue, totalPulletCostDayN)
components := depreciationFarmComponents{
KandangCount: len(allKandangComponents),
TotalPopulation: totalPopulation,
Kandang: allKandangComponents,
}
componentsJSON, _ := json.Marshal(components)
multiplicationPercentage, dayN, chickinDate, standardEffectiveDate := depreciationSnapshotInfo(parseSnapshotComponents(componentsJSON))
rows = append(rows, dto.ExpenseDepreciationV2RowDTO{
Date: dayStr,
Date: dayStr,
DepreciationPercentEffective: effectivePercent,
DepreciationValue: totalDepreciationValue,
PulletCostDayNTotal: totalPulletCostDayN,
@@ -519,7 +483,6 @@ func (s *repportService) GetExpenseDepreciationV2(ctx *fiber.Ctx) ([]dto.Expense
TotalValuePulletAfterDepreciation: totalPulletCostDayN - totalDepreciationValue,
StandardEffectiveDate: standardEffectiveDate,
TotalPopulation: totalPopulation,
Components: parseSnapshotComponents(componentsJSON),
})
actualDays++
}