feat[BE]: add overhead and ekspedisi items to profit loss report; include total depletion in closing report calculation

This commit is contained in:
aguhh18
2025-12-18 14:49:48 +07:00
parent 096a446450
commit f2df7f4847
2 changed files with 57 additions and 29 deletions
@@ -60,6 +60,8 @@ type PLSummaryGroup struct {
type ProfitLossData struct {
Penjualan []PLItem `json:"penjualan"`
Pembelian []PLItem `json:"pembelian"`
Overhead PLItem `json:"overhead"`
Ekspedisi PLItem `json:"ekspedisi"`
Summary PLSummaryGroup `json:"summary"`
}
@@ -167,15 +169,13 @@ func ToHppBahanBakuGroup(budgets []entities.ProjectBudget, realizations []entiti
ekspedisiAmount := sumRealizationsByFilter(realizations, filterRealizationByNonstockFlag(utils.FlagEkspedisi))
ekspedisiRpPerBird, ekspedisiRpPerKg := calculatePerUnitMetrics(ekspedisiAmount, totalPopulation, totalWeightProduced)
if ekspedisiAmount > 0 {
items = append(items, HppItem{
Type: "Beban Ekspedisi",
Comparison: ToComparison(
ToFinancialMetrics(ekspedisiRpPerBird, ekspedisiRpPerKg, ekspedisiAmount),
ToFinancialMetrics(ekspedisiRpPerBird, ekspedisiRpPerKg, ekspedisiAmount), // Same as realization
),
})
}
items = append(items, HppItem{
Type: "Beban Ekspedisi",
Comparison: ToComparison(
ToFinancialMetrics(ekspedisiRpPerBird, ekspedisiRpPerKg, ekspedisiAmount),
ToFinancialMetrics(ekspedisiRpPerBird, ekspedisiRpPerKg, ekspedisiAmount), // Same as realization
),
})
return HppGroup{
GroupName: "HPP dan Bahan Baku",
@@ -248,19 +248,28 @@ func sumPLItems(items []PLItem) (totalAmount, totalPerBird float64) {
}
func ToPenjualanItems(projectFlockCategory string, deliveryProducts []entities.MarketingDeliveryProduct, totalPopulation, totalWeightSold float64) []PLItem {
items := []PLItem{}
// Categorize deliveries by sales type based on Product flags
categorized := categorizeDeliveriesBySalesType(deliveryProducts)
items := []PLItem{}
if projectFlockCategory == string(utils.ProjectFlockCategoryLaying) {
// For LAYING: show both Penjualan Ayam Besar and Penjualan Telur (even if 0)
ayamAmount := sumDeliveriesByCategory(categorized["Penjualan Ayam Besar"])
telurAmount := sumDeliveriesByCategory(categorized["Penjualan Telur"])
// Process each sales category
for salesType, deliveries := range categorized {
amount := sumDeliveriesByCategory(deliveries)
// Penjualan Ayam Besar
rpPerBird, rpPerKg := calculatePerUnitMetrics(ayamAmount, totalPopulation, totalWeightSold)
items = append(items, ToPLItem("Penjualan Ayam Besar", ToFinancialMetrics(rpPerBird, rpPerKg, ayamAmount)))
// Use totalPopulation and totalWeightSold for per-unit calculations
rpPerBird, rpPerKg := calculatePerUnitMetrics(amount, totalPopulation, totalWeightSold)
items = append(items, ToPLItem(salesType, ToFinancialMetrics(rpPerBird, rpPerKg, amount)))
// Penjualan Telur
rpPerBird, rpPerKg = calculatePerUnitMetrics(telurAmount, totalPopulation, totalWeightSold)
items = append(items, ToPLItem("Penjualan Telur", ToFinancialMetrics(rpPerBird, rpPerKg, telurAmount)))
} else {
// For GROWING: show only Penjualan Ayam Besar
ayamAmount := sumDeliveriesByCategory(categorized["Penjualan Ayam Besar"])
rpPerBird, rpPerKg := calculatePerUnitMetrics(ayamAmount, totalPopulation, totalWeightSold)
items = append(items, ToPLItem("Penjualan Ayam Besar", ToFinancialMetrics(rpPerBird, rpPerKg, ayamAmount)))
}
return items
@@ -278,7 +287,7 @@ func ToPembelianItems(purchases []entities.PurchaseItem, budgets []entities.Proj
rpPerBird, rpPerKg := calculatePerUnitMetrics(totalCost, totalPopulation, totalWeightProduced)
return []PLItem{
ToPLItem("Harga Pokok Penjualan (HPP)", ToFinancialMetrics(rpPerBird, rpPerKg, totalCost)),
ToPLItem("Pembelian Sapronak", ToFinancialMetrics(rpPerBird, rpPerKg, totalCost)),
}
}
@@ -301,20 +310,21 @@ func ToEkspedisiItems(realizations []entities.ExpenseRealization, totalPopulatio
func ToPLSummaryGroup(penjualanItems, pembelianItems, overheadItems, ekspedisiItems []PLItem) PLSummaryGroup {
totalPenjualan, totalPenjualanPerBird := sumPLItems(penjualanItems)
totalPembelian, totalPembelianPerBird := sumPLItems(pembelianItems)
totalOverhead, _ := sumPLItems(overheadItems)
totalEkspedisi, _ := sumPLItems(ekspedisiItems)
totalOverhead, totalOverheadPerBird := sumPLItems(overheadItems)
totalEkspedisi, totalEkspedisiPerBird := sumPLItems(ekspedisiItems)
grossProfit := totalPenjualan - totalPembelian
grossProfitPerBird := totalPenjualanPerBird - totalPembelianPerBird
totalOtherExpenses := totalOverhead + totalEkspedisi
totalOtherExpensesPerBird := totalOverheadPerBird + totalEkspedisiPerBird
netProfit := grossProfit - totalOtherExpenses
netProfitPerBird := grossProfitPerBird - 0.0
netProfitPerBird := grossProfitPerBird - totalOtherExpensesPerBird
return PLSummaryGroup{
GrossProfit: ToPLSummaryItem("LABA RUGI BRUTTO", ToFinancialMetrics(grossProfitPerBird, 0, grossProfit)),
SubTotal: ToPLSummaryItem("SUB TOTAL", ToFinancialMetrics(0, 0, totalOtherExpenses)),
SubTotal: ToPLSummaryItem("SUB TOTAL", ToFinancialMetrics(totalOtherExpensesPerBird, 0, totalOtherExpenses)),
NetProfit: ToPLSummaryItem("LABA RUGI NETTO", ToFinancialMetrics(netProfitPerBird, 0, netProfit)),
}
}
@@ -322,9 +332,15 @@ func ToPLSummaryGroup(penjualanItems, pembelianItems, overheadItems, ekspedisiIt
func ToProfitLossData(penjualanItems, pembelianItems, overheadItems, ekspedisiItems []PLItem) ProfitLossData {
summary := ToPLSummaryGroup(penjualanItems, pembelianItems, overheadItems, ekspedisiItems)
// Get total overhead and ekspedisi as single items
totalOverhead := aggregatePLItems(overheadItems, "Pengeluaran Overhead")
totalEkspedisi := aggregatePLItems(ekspedisiItems, "Beban Ekspedisi")
return ProfitLossData{
Penjualan: penjualanItems,
Pembelian: pembelianItems,
Overhead: totalOverhead,
Ekspedisi: totalEkspedisi,
Summary: summary,
}
}
@@ -335,6 +351,11 @@ func ToProfitLossSection(penjualanItems, pembelianItems, overheadItems, ekspedis
}
}
func aggregatePLItems(items []PLItem, label string) PLItem {
totalAmount, totalPerBird := sumPLItems(items)
return ToPLItem(label, ToFinancialMetrics(totalPerBird, 0, totalAmount))
}
func ToReportResponse(hppPurchases HppPurchasesSection, profitLoss ProfitLossSection) ReportResponse {
return ReportResponse{
HppPurchases: hppPurchases,
@@ -342,9 +363,7 @@ func ToReportResponse(hppPurchases HppPurchasesSection, profitLoss ProfitLossSec
}
}
// === MAIN BUILDER ===
func ToClosingKeuanganReport(projectFlockCategory string, purchaseItems []entities.PurchaseItem, budgets []entities.ProjectBudget, realizations []entities.ExpenseRealization, deliveryProducts []entities.MarketingDeliveryProduct, chickins []entities.ProjectChickin, totalWeightProduced float64) ReportResponse {
func ToClosingKeuanganReport(projectFlockCategory string, purchaseItems []entities.PurchaseItem, budgets []entities.ProjectBudget, realizations []entities.ExpenseRealization, deliveryProducts []entities.MarketingDeliveryProduct, chickins []entities.ProjectChickin, totalWeightProduced, totalDepletion float64) ReportResponse {
var totalPopulation float64
var totalWeightSold float64
@@ -356,13 +375,16 @@ func ToClosingKeuanganReport(projectFlockCategory string, purchaseItems []entiti
totalWeightSold += delivery.TotalWeight
}
// Calculate actual population (chickin - depletion) for cost allocation
actualPopulation := totalPopulation - totalDepletion
// Use totalWeightProduced for HPP calculation (not totalWeightSold)
hppSection := ToHppPurchasesSection(purchaseItems, budgets, realizations, totalWeightProduced, totalPopulation)
penjualanItems := ToPenjualanItems(projectFlockCategory, deliveryProducts, totalPopulation, totalWeightSold)
pembelianItems := ToPembelianItems(purchaseItems, budgets, realizations, totalPopulation, totalWeightProduced)
overheadItems := ToOverheadItems(budgets, realizations, totalPopulation, totalWeightProduced)
ekspedisiItems := ToEkspedisiItems(realizations, totalPopulation, totalWeightProduced)
pembelianItems := ToPembelianItems(purchaseItems, budgets, realizations, actualPopulation, totalWeightProduced)
overheadItems := ToOverheadItems(budgets, realizations, actualPopulation, totalWeightProduced)
ekspedisiItems := ToEkspedisiItems(realizations, actualPopulation, totalWeightProduced)
plSection := ToProfitLossSection(penjualanItems, pembelianItems, overheadItems, ekspedisiItems)
return ToReportResponse(hppSection, plSection)