feat: doc direct purchase cost

This commit is contained in:
Adnan Zahir
2026-04-19 14:52:01 +07:00
parent 58fbceea24
commit a2ae139fae
7 changed files with 718 additions and 108 deletions
@@ -17,6 +17,7 @@ type hppV2RepoStub struct {
pfkIDsByProject map[uint][]uint
usageRowsByKey map[string][]commonRepo.HppV2UsageCostRow
adjustRowsByKey map[string][]commonRepo.HppV2AdjustmentCostRow
chickinRowsByKey map[string][]commonRepo.HppV2ChickinCostRow
expenseRowsByPFKKey map[string][]commonRepo.HppV2ExpenseCostRow
expenseRowsByFarmKey map[string][]commonRepo.HppV2ExpenseCostRow
totalPopulationByKey map[string]float64
@@ -62,6 +63,10 @@ func (s *hppV2RepoStub) ListExpenseRealizationRowsByProjectFlockID(_ context.Con
return append([]commonRepo.HppV2ExpenseCostRow{}, s.expenseRowsByFarmKey[expenseFarmKey(projectFlockID, ekspedisi)]...), nil
}
func (s *hppV2RepoStub) ListChickinCostRowsByProductFlags(_ context.Context, projectFlockKandangIDs []uint, flagNames []string, _ *time.Time, excludeTransferToLaying bool) ([]commonRepo.HppV2ChickinCostRow, error) {
return append([]commonRepo.HppV2ChickinCostRow{}, s.chickinRowsByKey[chickinStubKey(projectFlockKandangIDs, flagNames, excludeTransferToLaying)]...), nil
}
func (s *hppV2RepoStub) GetFeedUsageCost(_ context.Context, _ []uint, _ *time.Time) (float64, error) {
return 0, nil
}
@@ -339,6 +344,80 @@ func TestHppV2CalculateHppBreakdown_IncludesOvkComponent(t *testing.T) {
}
}
func TestHppV2CalculateHppBreakdown_IncludesDocAndDirectPulletChickin(t *testing.T) {
repo := &hppV2RepoStub{
contextByPFK: map[uint]*commonRepo.HppV2ProjectFlockKandangContext{
35: {
ProjectFlockKandangID: 35,
ProjectFlockID: 8,
ProjectFlockCategory: "LAYING",
KandangID: 350,
KandangName: "Kandang E",
LocationID: 20,
},
},
pfkIDsByProject: map[uint][]uint{
9: {901, 902},
},
totalPopulationByKey: map[string]float64{
stubKey([]uint{901, 902}, nil): 1000,
},
transferSummaryByPFK: map[uint]struct {
projectFlockID uint
totalQty float64
}{
35: {projectFlockID: 9, totalQty: 250},
},
chickinRowsByKey: map[string][]commonRepo.HppV2ChickinCostRow{
chickinStubKey([]uint{901, 902}, []string{string(utils.FlagDOC)}, false): {
{ProjectChickinID: 1, ProjectFlockKandangID: 901, ChickInDate: mustTime(t, "2026-04-01"), StockableType: "purchase_items", StockableID: 1001, SourceProductID: 77, SourceProductName: "DOC", Qty: 1000, UnitPrice: 2, TotalCost: 2000},
},
chickinStubKey([]uint{35}, []string{string(utils.FlagPullet), string(utils.FlagLayer)}, true): {
{ProjectChickinID: 2, ProjectFlockKandangID: 35, ChickInDate: mustTime(t, "2026-04-15"), StockableType: "purchase_items", StockableID: 1002, SourceProductID: 78, SourceProductName: "Pullet", Qty: 50, UnitPrice: 20, TotalCost: 1000},
},
},
eggProductionByPFK: map[uint]struct {
pieces float64
kg float64
}{
35: {pieces: 100, kg: 10},
},
eggSalesByPFK: map[uint]struct {
pieces float64
kg float64
}{
35: {pieces: 80, kg: 8},
},
}
svc := NewHppV2Service(repo)
result, err := svc.CalculateHppBreakdown(35, mustDate(t, "2026-04-19"))
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
componentTotals := map[string]float64{}
for _, component := range result.Components {
componentTotals[component.Code] = component.Total
}
if componentTotals[hppV2ComponentDocChickin] != 500 {
t.Fatalf("expected doc chickin total 500, got %v", componentTotals[hppV2ComponentDocChickin])
}
if componentTotals[hppV2ComponentDirectPulletPurchase] != 1000 {
t.Fatalf("expected direct pullet purchase total 1000, got %v", componentTotals[hppV2ComponentDirectPulletPurchase])
}
if result.TotalPulletCost != 500 {
t.Fatalf("expected total pullet cost 500, got %v", result.TotalPulletCost)
}
if result.TotalProductionCost != 1000 {
t.Fatalf("expected total production cost 1000, got %v", result.TotalProductionCost)
}
if result.Hpp.Estimation.HargaKg != 100 {
t.Fatalf("expected estimation harga/kg 100, got %v", result.Hpp.Estimation.HargaKg)
}
}
func TestHppV2CalculateHppBreakdown_IncludesBopRegularAndEkspedisi(t *testing.T) {
repo := &hppV2RepoStub{
contextByPFK: map[uint]*commonRepo.HppV2ProjectFlockKandangContext{
@@ -471,3 +550,7 @@ func expenseStubKey(ids []uint, ekspedisi bool) string {
func expenseFarmKey(projectFlockID uint, ekspedisi bool) string {
return fmt.Sprintf("farm=%d|ekspedisi=%t", projectFlockID, ekspedisi)
}
func chickinStubKey(ids []uint, flags []string, excludeTransferToLaying bool) string {
return stubKey(ids, append(append([]string{}, flags...), fmt.Sprintf("exclude_transfer_to_laying=%t", excludeTransferToLaying)))
}