mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-23 23:05:44 +00:00
feat[BE]: membetulkan perhitungan hpp di module penjualan harian
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
marketingRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/repositories"
|
||||
chickinRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories"
|
||||
projectflockRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||
purchaseRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
|
||||
|
||||
@@ -45,9 +46,10 @@ type closingService struct {
|
||||
ExpenseRealizationRepo expenseRealizationRepository.ExpenseRealizationRepository
|
||||
ProjectBudgetRepo projectflockRepository.ProjectBudgetRepository
|
||||
ChickinRepo chickinRepository.ProjectChickinRepository
|
||||
PurchaseRepo purchaseRepository.PurchaseRepository
|
||||
}
|
||||
|
||||
func NewClosingService(repo repository.ClosingRepository, projectFlockRepo projectflockRepository.ProjectflockRepository, marketingRepo marketingRepository.MarketingRepository, marketingDeliveryProductRepo marketingDeliveryProductRepository.MarketingDeliveryProductRepository, approvalSvc commonSvc.ApprovalService, expenseRealizationRepo expenseRealizationRepository.ExpenseRealizationRepository, projectBudgetRepo projectflockRepository.ProjectBudgetRepository, chickinRepo chickinRepository.ProjectChickinRepository, validate *validator.Validate) ClosingService {
|
||||
func NewClosingService(repo repository.ClosingRepository, projectFlockRepo projectflockRepository.ProjectflockRepository, marketingRepo marketingRepository.MarketingRepository, marketingDeliveryProductRepo marketingDeliveryProductRepository.MarketingDeliveryProductRepository, approvalSvc commonSvc.ApprovalService, expenseRealizationRepo expenseRealizationRepository.ExpenseRealizationRepository, projectBudgetRepo projectflockRepository.ProjectBudgetRepository, chickinRepo chickinRepository.ProjectChickinRepository, purchaseRepo purchaseRepository.PurchaseRepository, validate *validator.Validate) ClosingService {
|
||||
return &closingService{
|
||||
Log: utils.Log,
|
||||
Validate: validate,
|
||||
@@ -59,6 +61,7 @@ func NewClosingService(repo repository.ClosingRepository, projectFlockRepo proje
|
||||
ExpenseRealizationRepo: expenseRealizationRepo,
|
||||
ProjectBudgetRepo: projectBudgetRepo,
|
||||
ChickinRepo: chickinRepo,
|
||||
PurchaseRepo: purchaseRepo,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,24 +389,35 @@ func (s closingService) GetClosingKeuangan(c *fiber.Ctx, projectFlockID uint) (*
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid project flock id")
|
||||
}
|
||||
|
||||
_, err := s.Repository.GetByID(c.Context(), projectFlockID, nil)
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Project flock not found")
|
||||
if err := commonSvc.EnsureRelations(c.Context(),
|
||||
commonSvc.RelationCheck{Name: "Project Flock", ID: &projectFlockID, Exists: func(ctx context.Context, id uint) (bool, error) {
|
||||
_, err := s.ProjectFlockRepo.GetByID(ctx, id, nil)
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return false, nil
|
||||
}
|
||||
return err == nil, err
|
||||
}},
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectFlock, err := s.ProjectFlockRepo.GetByID(c.Context(), projectFlockID, nil)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get project flock %d for closing keuangan: %+v", projectFlockID, err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch project flock")
|
||||
}
|
||||
|
||||
budgets, err := s.ProjectBudgetRepo.GetByProjectFlockID(c.Context(), projectFlockID)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get budgets for project flock %d: %+v", projectFlockID, err)
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch budgets")
|
||||
}
|
||||
|
||||
purchaseItems, err := s.PurchaseRepo.GetItemsByProjectFlockID(c.Context(), projectFlockID)
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch purchase items")
|
||||
}
|
||||
|
||||
realizations, err := s.ExpenseRealizationRepo.GetByProjectFlockID(c.Context(), projectFlockID)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get realizations for project flock %d: %+v", projectFlockID, err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch realizations")
|
||||
}
|
||||
|
||||
@@ -413,204 +427,15 @@ func (s closingService) GetClosingKeuangan(c *fiber.Ctx, projectFlockID uint) (*
|
||||
Preload("MarketingProduct.ProductWarehouse.Product")
|
||||
})
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
s.Log.Errorf("Failed to get delivery products for project flock %d: %+v", projectFlockID, err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch delivery products")
|
||||
}
|
||||
|
||||
chickins, err := s.ChickinRepo.GetByProjectFlockID(c.Context(), projectFlockID)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get chickins for project flock %d: %+v", projectFlockID, err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch chickins")
|
||||
}
|
||||
|
||||
var totalPopulation float64
|
||||
for _, chickin := range chickins {
|
||||
totalPopulation += chickin.UsageQty
|
||||
}
|
||||
|
||||
var totalWeightSold float64
|
||||
for _, delivery := range deliveryProducts {
|
||||
totalWeightSold += delivery.TotalWeight
|
||||
}
|
||||
|
||||
hppItems := s.buildHppItems(budgets, realizations, totalWeightSold, totalPopulation)
|
||||
hppGroups := []dto.HppGroup{
|
||||
dto.ToHppGroup("Input Produksi", hppItems),
|
||||
}
|
||||
|
||||
summaryHpp := s.calculateHppSummary(budgets, realizations, totalWeightSold, totalPopulation)
|
||||
|
||||
penjualanItems := s.buildPenjualanItems(deliveryProducts, totalPopulation, totalWeightSold)
|
||||
pembelianItems := s.buildPembelianItems(budgets, realizations, totalPopulation, totalWeightSold)
|
||||
plSummary := s.calculatePLSummary(penjualanItems, pembelianItems)
|
||||
|
||||
hppSection := dto.ToHppPurchasesSection("HPP Pembelian", hppGroups, summaryHpp)
|
||||
plSection := dto.ToProfitLossSection("Laporan Laba Rugi", dto.ToProfitLossData(penjualanItems, pembelianItems, plSummary))
|
||||
|
||||
report := dto.ToReportResponse(hppSection, plSection)
|
||||
report := dto.ToClosingKeuanganReport(projectFlock.Category, purchaseItems, budgets, realizations, deliveryProducts, chickins)
|
||||
|
||||
return &report, nil
|
||||
}
|
||||
|
||||
func (s closingService) buildHppItems(budgets []entity.ProjectBudget, realizations []entity.ExpenseRealization, totalWeightSold, totalPopulation float64) []dto.HppItem {
|
||||
var totalBudgetAmount float64
|
||||
var totalRealizationAmount float64
|
||||
|
||||
for _, budget := range budgets {
|
||||
totalBudgetAmount += budget.Price * budget.Qty
|
||||
}
|
||||
|
||||
for _, realization := range realizations {
|
||||
totalRealizationAmount += realization.Price * realization.Qty
|
||||
}
|
||||
|
||||
budgetRpPerBird := 0.0
|
||||
budgetRpPerKg := 0.0
|
||||
if totalPopulation > 0 {
|
||||
budgetRpPerBird = totalBudgetAmount / totalPopulation
|
||||
}
|
||||
if totalWeightSold > 0 {
|
||||
budgetRpPerKg = totalBudgetAmount / totalWeightSold
|
||||
}
|
||||
|
||||
realizationRpPerBird := 0.0
|
||||
realizationRpPerKg := 0.0
|
||||
if totalPopulation > 0 {
|
||||
realizationRpPerBird = totalRealizationAmount / totalPopulation
|
||||
}
|
||||
if totalWeightSold > 0 {
|
||||
realizationRpPerKg = totalRealizationAmount / totalWeightSold
|
||||
}
|
||||
|
||||
items := []dto.HppItem{
|
||||
dto.ToHppItem("Total HPP Produksi", dto.ToComparison(
|
||||
dto.ToFinancialMetrics(budgetRpPerBird, budgetRpPerKg, totalBudgetAmount),
|
||||
dto.ToFinancialMetrics(realizationRpPerBird, realizationRpPerKg, totalRealizationAmount),
|
||||
)),
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
func (s closingService) calculateHppSummary(budgets []entity.ProjectBudget, realizations []entity.ExpenseRealization, totalWeightSold, totalPopulation float64) dto.SummaryHpp {
|
||||
var totalBudget float64
|
||||
var totalRealization float64
|
||||
|
||||
for _, budget := range budgets {
|
||||
totalBudget += budget.Price * budget.Qty
|
||||
}
|
||||
|
||||
for _, realization := range realizations {
|
||||
totalRealization += realization.Price * realization.Qty
|
||||
}
|
||||
|
||||
budgetRpPerBird := 0.0
|
||||
budgetRpPerKg := 0.0
|
||||
if totalPopulation > 0 {
|
||||
budgetRpPerBird = totalBudget / totalPopulation
|
||||
}
|
||||
if totalWeightSold > 0 {
|
||||
budgetRpPerKg = totalBudget / totalWeightSold
|
||||
}
|
||||
|
||||
realizationRpPerBird := 0.0
|
||||
realizationRpPerKg := 0.0
|
||||
if totalPopulation > 0 {
|
||||
realizationRpPerBird = totalRealization / totalPopulation
|
||||
}
|
||||
if totalWeightSold > 0 {
|
||||
realizationRpPerKg = totalRealization / totalWeightSold
|
||||
}
|
||||
|
||||
return dto.ToSummaryHpp("Total HPP", dto.ToComparison(
|
||||
dto.ToFinancialMetrics(budgetRpPerBird, budgetRpPerKg, totalBudget),
|
||||
dto.ToFinancialMetrics(realizationRpPerBird, realizationRpPerKg, totalRealization),
|
||||
))
|
||||
}
|
||||
|
||||
func (s closingService) buildPenjualanItems(deliveryProducts []entity.MarketingDeliveryProduct, totalPopulation, totalWeightSold float64) []dto.PLItem {
|
||||
var totalAmount float64
|
||||
|
||||
for _, delivery := range deliveryProducts {
|
||||
totalAmount += delivery.TotalPrice
|
||||
}
|
||||
|
||||
rpPerBird := 0.0
|
||||
rpPerKg := 0.0
|
||||
if totalPopulation > 0 {
|
||||
rpPerBird = totalAmount / totalPopulation
|
||||
}
|
||||
if totalWeightSold > 0 {
|
||||
rpPerKg = totalAmount / totalWeightSold
|
||||
}
|
||||
|
||||
items := []dto.PLItem{
|
||||
dto.ToPLItem("Penjualan", dto.ToFinancialMetrics(rpPerBird, rpPerKg, totalAmount)),
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
func (s closingService) buildPembelianItems(budgets []entity.ProjectBudget, realizations []entity.ExpenseRealization, totalPopulation, totalWeightSold float64) []dto.PLItem {
|
||||
var totalBudget float64
|
||||
var totalRealization float64
|
||||
|
||||
for _, budget := range budgets {
|
||||
totalBudget += budget.Price * budget.Qty
|
||||
}
|
||||
|
||||
for _, realization := range realizations {
|
||||
totalRealization += realization.Price * realization.Qty
|
||||
}
|
||||
|
||||
budgetRpPerBird := 0.0
|
||||
budgetRpPerKg := 0.0
|
||||
if totalPopulation > 0 {
|
||||
budgetRpPerBird = totalBudget / totalPopulation
|
||||
}
|
||||
if totalWeightSold > 0 {
|
||||
budgetRpPerKg = totalBudget / totalWeightSold
|
||||
}
|
||||
|
||||
realizationRpPerBird := 0.0
|
||||
realizationRpPerKg := 0.0
|
||||
if totalPopulation > 0 {
|
||||
realizationRpPerBird = totalRealization / totalPopulation
|
||||
}
|
||||
if totalWeightSold > 0 {
|
||||
realizationRpPerKg = totalRealization / totalWeightSold
|
||||
}
|
||||
|
||||
items := []dto.PLItem{
|
||||
dto.ToPLItem("Beban Pokok Produksi", dto.ToFinancialMetrics(budgetRpPerBird, budgetRpPerKg, totalBudget)),
|
||||
dto.ToPLItem("Realisasi Beban Pokok", dto.ToFinancialMetrics(realizationRpPerBird, realizationRpPerKg, totalRealization)),
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
func (s closingService) calculatePLSummary(penjualanItems, pembelianItems []dto.PLItem) dto.PLSummaryGroup {
|
||||
var totalPenjualan float64
|
||||
var totalPenjualanPerBird float64
|
||||
var totalPembelian float64
|
||||
var totalPembelianPerBird float64
|
||||
|
||||
for _, item := range penjualanItems {
|
||||
totalPenjualan += item.Amount
|
||||
totalPenjualanPerBird += item.RpPerBird
|
||||
}
|
||||
|
||||
for _, item := range pembelianItems {
|
||||
totalPembelian += item.Amount
|
||||
totalPembelianPerBird += item.RpPerBird
|
||||
}
|
||||
|
||||
grossProfit := totalPenjualan - totalPembelian
|
||||
grossProfitPerBird := totalPenjualanPerBird - totalPembelianPerBird
|
||||
|
||||
return dto.ToPLSummaryGroup(
|
||||
dto.ToPLSummaryItem("Laba Kotor", dto.ToFinancialMetrics(grossProfitPerBird, 0, grossProfit)),
|
||||
dto.ToPLSummaryItem("Sub Total", dto.ToFinancialMetrics(grossProfitPerBird, 0, grossProfit)),
|
||||
dto.ToPLSummaryItem("Laba Bersih", dto.ToFinancialMetrics(grossProfitPerBird, 0, grossProfit)),
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user