mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 21:41:55 +00:00
feat[BE]: add overhead and ekspedisi items to profit loss report; include total depletion in closing report calculation
This commit is contained in:
@@ -60,6 +60,8 @@ type PLSummaryGroup struct {
|
|||||||
type ProfitLossData struct {
|
type ProfitLossData struct {
|
||||||
Penjualan []PLItem `json:"penjualan"`
|
Penjualan []PLItem `json:"penjualan"`
|
||||||
Pembelian []PLItem `json:"pembelian"`
|
Pembelian []PLItem `json:"pembelian"`
|
||||||
|
Overhead PLItem `json:"overhead"`
|
||||||
|
Ekspedisi PLItem `json:"ekspedisi"`
|
||||||
Summary PLSummaryGroup `json:"summary"`
|
Summary PLSummaryGroup `json:"summary"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,15 +169,13 @@ func ToHppBahanBakuGroup(budgets []entities.ProjectBudget, realizations []entiti
|
|||||||
ekspedisiAmount := sumRealizationsByFilter(realizations, filterRealizationByNonstockFlag(utils.FlagEkspedisi))
|
ekspedisiAmount := sumRealizationsByFilter(realizations, filterRealizationByNonstockFlag(utils.FlagEkspedisi))
|
||||||
ekspedisiRpPerBird, ekspedisiRpPerKg := calculatePerUnitMetrics(ekspedisiAmount, totalPopulation, totalWeightProduced)
|
ekspedisiRpPerBird, ekspedisiRpPerKg := calculatePerUnitMetrics(ekspedisiAmount, totalPopulation, totalWeightProduced)
|
||||||
|
|
||||||
if ekspedisiAmount > 0 {
|
items = append(items, HppItem{
|
||||||
items = append(items, HppItem{
|
Type: "Beban Ekspedisi",
|
||||||
Type: "Beban Ekspedisi",
|
Comparison: ToComparison(
|
||||||
Comparison: ToComparison(
|
ToFinancialMetrics(ekspedisiRpPerBird, ekspedisiRpPerKg, ekspedisiAmount),
|
||||||
ToFinancialMetrics(ekspedisiRpPerBird, ekspedisiRpPerKg, ekspedisiAmount),
|
ToFinancialMetrics(ekspedisiRpPerBird, ekspedisiRpPerKg, ekspedisiAmount), // Same as realization
|
||||||
ToFinancialMetrics(ekspedisiRpPerBird, ekspedisiRpPerKg, ekspedisiAmount), // Same as realization
|
),
|
||||||
),
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return HppGroup{
|
return HppGroup{
|
||||||
GroupName: "HPP dan Bahan Baku",
|
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 {
|
func ToPenjualanItems(projectFlockCategory string, deliveryProducts []entities.MarketingDeliveryProduct, totalPopulation, totalWeightSold float64) []PLItem {
|
||||||
|
items := []PLItem{}
|
||||||
|
|
||||||
// Categorize deliveries by sales type based on Product flags
|
// Categorize deliveries by sales type based on Product flags
|
||||||
categorized := categorizeDeliveriesBySalesType(deliveryProducts)
|
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
|
// Penjualan Ayam Besar
|
||||||
for salesType, deliveries := range categorized {
|
rpPerBird, rpPerKg := calculatePerUnitMetrics(ayamAmount, totalPopulation, totalWeightSold)
|
||||||
amount := sumDeliveriesByCategory(deliveries)
|
items = append(items, ToPLItem("Penjualan Ayam Besar", ToFinancialMetrics(rpPerBird, rpPerKg, ayamAmount)))
|
||||||
|
|
||||||
// Use totalPopulation and totalWeightSold for per-unit calculations
|
// Penjualan Telur
|
||||||
rpPerBird, rpPerKg := calculatePerUnitMetrics(amount, totalPopulation, totalWeightSold)
|
rpPerBird, rpPerKg = calculatePerUnitMetrics(telurAmount, totalPopulation, totalWeightSold)
|
||||||
|
items = append(items, ToPLItem("Penjualan Telur", ToFinancialMetrics(rpPerBird, rpPerKg, telurAmount)))
|
||||||
items = append(items, ToPLItem(salesType, ToFinancialMetrics(rpPerBird, rpPerKg, amount)))
|
} 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
|
return items
|
||||||
@@ -278,7 +287,7 @@ func ToPembelianItems(purchases []entities.PurchaseItem, budgets []entities.Proj
|
|||||||
|
|
||||||
rpPerBird, rpPerKg := calculatePerUnitMetrics(totalCost, totalPopulation, totalWeightProduced)
|
rpPerBird, rpPerKg := calculatePerUnitMetrics(totalCost, totalPopulation, totalWeightProduced)
|
||||||
return []PLItem{
|
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 {
|
func ToPLSummaryGroup(penjualanItems, pembelianItems, overheadItems, ekspedisiItems []PLItem) PLSummaryGroup {
|
||||||
totalPenjualan, totalPenjualanPerBird := sumPLItems(penjualanItems)
|
totalPenjualan, totalPenjualanPerBird := sumPLItems(penjualanItems)
|
||||||
totalPembelian, totalPembelianPerBird := sumPLItems(pembelianItems)
|
totalPembelian, totalPembelianPerBird := sumPLItems(pembelianItems)
|
||||||
totalOverhead, _ := sumPLItems(overheadItems)
|
totalOverhead, totalOverheadPerBird := sumPLItems(overheadItems)
|
||||||
totalEkspedisi, _ := sumPLItems(ekspedisiItems)
|
totalEkspedisi, totalEkspedisiPerBird := sumPLItems(ekspedisiItems)
|
||||||
|
|
||||||
grossProfit := totalPenjualan - totalPembelian
|
grossProfit := totalPenjualan - totalPembelian
|
||||||
grossProfitPerBird := totalPenjualanPerBird - totalPembelianPerBird
|
grossProfitPerBird := totalPenjualanPerBird - totalPembelianPerBird
|
||||||
|
|
||||||
totalOtherExpenses := totalOverhead + totalEkspedisi
|
totalOtherExpenses := totalOverhead + totalEkspedisi
|
||||||
|
totalOtherExpensesPerBird := totalOverheadPerBird + totalEkspedisiPerBird
|
||||||
|
|
||||||
netProfit := grossProfit - totalOtherExpenses
|
netProfit := grossProfit - totalOtherExpenses
|
||||||
netProfitPerBird := grossProfitPerBird - 0.0
|
netProfitPerBird := grossProfitPerBird - totalOtherExpensesPerBird
|
||||||
|
|
||||||
return PLSummaryGroup{
|
return PLSummaryGroup{
|
||||||
GrossProfit: ToPLSummaryItem("LABA RUGI BRUTTO", ToFinancialMetrics(grossProfitPerBird, 0, grossProfit)),
|
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)),
|
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 {
|
func ToProfitLossData(penjualanItems, pembelianItems, overheadItems, ekspedisiItems []PLItem) ProfitLossData {
|
||||||
summary := ToPLSummaryGroup(penjualanItems, pembelianItems, overheadItems, ekspedisiItems)
|
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{
|
return ProfitLossData{
|
||||||
Penjualan: penjualanItems,
|
Penjualan: penjualanItems,
|
||||||
Pembelian: pembelianItems,
|
Pembelian: pembelianItems,
|
||||||
|
Overhead: totalOverhead,
|
||||||
|
Ekspedisi: totalEkspedisi,
|
||||||
Summary: summary,
|
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 {
|
func ToReportResponse(hppPurchases HppPurchasesSection, profitLoss ProfitLossSection) ReportResponse {
|
||||||
return ReportResponse{
|
return ReportResponse{
|
||||||
HppPurchases: hppPurchases,
|
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, totalDepletion float64) ReportResponse {
|
||||||
|
|
||||||
func ToClosingKeuanganReport(projectFlockCategory string, purchaseItems []entities.PurchaseItem, budgets []entities.ProjectBudget, realizations []entities.ExpenseRealization, deliveryProducts []entities.MarketingDeliveryProduct, chickins []entities.ProjectChickin, totalWeightProduced float64) ReportResponse {
|
|
||||||
var totalPopulation float64
|
var totalPopulation float64
|
||||||
var totalWeightSold float64
|
var totalWeightSold float64
|
||||||
|
|
||||||
@@ -356,13 +375,16 @@ func ToClosingKeuanganReport(projectFlockCategory string, purchaseItems []entiti
|
|||||||
totalWeightSold += delivery.TotalWeight
|
totalWeightSold += delivery.TotalWeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate actual population (chickin - depletion) for cost allocation
|
||||||
|
actualPopulation := totalPopulation - totalDepletion
|
||||||
|
|
||||||
// Use totalWeightProduced for HPP calculation (not totalWeightSold)
|
// Use totalWeightProduced for HPP calculation (not totalWeightSold)
|
||||||
hppSection := ToHppPurchasesSection(purchaseItems, budgets, realizations, totalWeightProduced, totalPopulation)
|
hppSection := ToHppPurchasesSection(purchaseItems, budgets, realizations, totalWeightProduced, totalPopulation)
|
||||||
|
|
||||||
penjualanItems := ToPenjualanItems(projectFlockCategory, deliveryProducts, totalPopulation, totalWeightSold)
|
penjualanItems := ToPenjualanItems(projectFlockCategory, deliveryProducts, totalPopulation, totalWeightSold)
|
||||||
pembelianItems := ToPembelianItems(purchaseItems, budgets, realizations, totalPopulation, totalWeightProduced)
|
pembelianItems := ToPembelianItems(purchaseItems, budgets, realizations, actualPopulation, totalWeightProduced)
|
||||||
overheadItems := ToOverheadItems(budgets, realizations, totalPopulation, totalWeightProduced)
|
overheadItems := ToOverheadItems(budgets, realizations, actualPopulation, totalWeightProduced)
|
||||||
ekspedisiItems := ToEkspedisiItems(realizations, totalPopulation, totalWeightProduced)
|
ekspedisiItems := ToEkspedisiItems(realizations, actualPopulation, totalWeightProduced)
|
||||||
plSection := ToProfitLossSection(penjualanItems, pembelianItems, overheadItems, ekspedisiItems)
|
plSection := ToProfitLossSection(penjualanItems, pembelianItems, overheadItems, ekspedisiItems)
|
||||||
|
|
||||||
return ToReportResponse(hppSection, plSection)
|
return ToReportResponse(hppSection, plSection)
|
||||||
|
|||||||
@@ -450,7 +450,13 @@ func (s closingService) GetClosingKeuangan(c *fiber.Ctx, projectFlockID uint) (*
|
|||||||
s.Log.Warnf("GetProductionWeightAndQtyByProjectFlockID error: %v", err)
|
s.Log.Warnf("GetProductionWeightAndQtyByProjectFlockID error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
report := dto.ToClosingKeuanganReport(projectFlock.Category, purchaseItems, budgets, realizations, deliveryProducts, chickins, totalWeightProduced)
|
// Fetch depletion data to calculate actual population for cost allocation
|
||||||
|
totalDepletion, err := s.RecordingRepo.GetTotalDepletionByProjectFlockID(c.Context(), projectFlockID)
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Warnf("GetTotalDepletionByProjectFlockID error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
report := dto.ToClosingKeuanganReport(projectFlock.Category, purchaseItems, budgets, realizations, deliveryProducts, chickins, totalWeightProduced, totalDepletion)
|
||||||
|
|
||||||
return &report, nil
|
return &report, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user