feat[BE-384]: enhance reporting by adding chickin quantity and egg production weight calculations; refactor HPP calculations to consider product categories

This commit is contained in:
aguhh18
2025-12-18 17:56:18 +07:00
parent c95f90f0b9
commit e551995c66
6 changed files with 157 additions and 110 deletions
@@ -3,7 +3,6 @@ package service
import (
"context"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
"gitlab.com/mbugroup/lti-api.git/internal/modules/repports/dto"
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/repports/validations"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
@@ -12,6 +11,7 @@ import (
approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto"
expenseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories"
marketingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/repositories"
chickinRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories"
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
purchaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories"
@@ -32,17 +32,19 @@ type repportService struct {
ExpenseRealizationRepo expenseRepo.ExpenseRealizationRepository
MarketingDeliveryRepo marketingRepo.MarketingDeliveryProductRepository
PurchaseRepo purchaseRepo.PurchaseRepository
ChickinRepo chickinRepo.ProjectChickinRepository
RecordingRepo recordingRepo.RecordingRepository
ApprovalSvc approvalService.ApprovalService
}
func NewRepportService(validate *validator.Validate, expenseRealizationRepo expenseRepo.ExpenseRealizationRepository, marketingDeliveryRepo marketingRepo.MarketingDeliveryProductRepository, purchaseRepo purchaseRepo.PurchaseRepository, recordingRepo recordingRepo.RecordingRepository, approvalSvc approvalService.ApprovalService) RepportService {
func NewRepportService(validate *validator.Validate, expenseRealizationRepo expenseRepo.ExpenseRealizationRepository, marketingDeliveryRepo marketingRepo.MarketingDeliveryProductRepository, purchaseRepo purchaseRepo.PurchaseRepository, chickinRepo chickinRepo.ProjectChickinRepository, recordingRepo recordingRepo.RecordingRepository, approvalSvc approvalService.ApprovalService) RepportService {
return &repportService{
Log: utils.Log,
Validate: validate,
ExpenseRealizationRepo: expenseRealizationRepo,
MarketingDeliveryRepo: marketingDeliveryRepo,
PurchaseRepo: purchaseRepo,
ChickinRepo: chickinRepo,
RecordingRepo: recordingRepo,
ApprovalSvc: approvalSvc,
}
@@ -98,74 +100,63 @@ func (s *repportService) GetMarketing(c *fiber.Ctx, params *validation.Marketing
return nil, 0, err
}
projectFlockIDs := s.collectProjectFlockIDs(deliveryProducts)
hppMap := s.buildHppMap(c.Context(), projectFlockIDs, deliveryProducts)
items := dto.ToRepportMarketingItemDTOsWithHppMap(deliveryProducts, hppMap)
projectFlockIDMap := make(map[uint]bool)
hppMap := make(map[uint]float64)
for _, dp := range deliveryProducts {
if projectFlockKandang := dp.MarketingProduct.ProductWarehouse.ProjectFlockKandang; projectFlockKandang != nil {
projectFlockID := projectFlockKandang.ProjectFlockId
if projectFlockID > 0 && !projectFlockIDMap[projectFlockID] {
projectFlockIDMap[projectFlockID] = true
category := projectFlockKandang.ProjectFlock.Category
hppPerKg := s.calculateHppPricePerKg(c.Context(), projectFlockID, category)
hppMap[projectFlockID] = hppPerKg
}
}
}
items := dto.ToRepportMarketingItemDTOsWithHppMap(deliveryProducts, hppMap)
return items, total, nil
}
func (s *repportService) collectProjectFlockIDs(deliveryProducts []entity.MarketingDeliveryProduct) []uint {
projectFlockIDMap := make(map[uint]bool)
projectFlockIDs := make([]uint, 0)
for _, dp := range deliveryProducts {
if projectFlockKandang := dp.MarketingProduct.ProductWarehouse.ProjectFlockKandang; projectFlockKandang != nil {
if projectFlockKandang.ProjectFlockId > 0 && !projectFlockIDMap[projectFlockKandang.ProjectFlockId] {
projectFlockIDs = append(projectFlockIDs, projectFlockKandang.ProjectFlockId)
projectFlockIDMap[projectFlockKandang.ProjectFlockId] = true
}
}
}
return projectFlockIDs
}
func (s *repportService) buildHppMap(ctx context.Context, projectFlockIDs []uint, deliveryProducts []entity.MarketingDeliveryProduct) map[uint]float64 {
hppMap := make(map[uint]float64)
for _, projectFlockID := range projectFlockIDs {
category := s.getProjectFlockCategory(deliveryProducts, projectFlockID)
hppPerKg := s.calculateHppByCategory(ctx, category, projectFlockID, deliveryProducts)
hppMap[projectFlockID] = hppPerKg
}
return hppMap
}
func (s *repportService) calculateHppByCategory(ctx context.Context, category string, projectFlockID uint, deliveryProducts []entity.MarketingDeliveryProduct) float64 {
switch utils.ProjectFlockCategory(category) {
case utils.ProjectFlockCategoryGrowing:
return s.calculateHppPricePerKg(ctx, projectFlockID, deliveryProducts)
case utils.ProjectFlockCategoryLaying:
return 0
default:
func (s *repportService) calculateHppPricePerKg(ctx context.Context, projectFlockID uint, category string) float64 {
totalCost := s.getTotalProjectCost(ctx, projectFlockID)
if totalCost == 0 {
return 0
}
}
func (s *repportService) getProjectFlockCategory(deliveryProducts []entity.MarketingDeliveryProduct, projectFlockID uint) string {
for _, dp := range deliveryProducts {
if projectFlockKandang := dp.MarketingProduct.ProductWarehouse.ProjectFlockKandang; projectFlockKandang != nil {
if projectFlockKandang.ProjectFlockId == projectFlockID {
return projectFlockKandang.ProjectFlock.Category
}
}
chickinQty, _ := s.ChickinRepo.GetTotalChickinQtyByProjectFlockID(ctx, projectFlockID)
depletion, _ := s.RecordingRepo.GetTotalDepletionByProjectFlockID(ctx, projectFlockID)
avgWeight, _ := s.RecordingRepo.GetLatestAvgWeightByProjectFlockID(ctx, projectFlockID)
var totalWeight float64
if utils.ProjectFlockCategory(category) == utils.ProjectFlockCategoryGrowing {
totalWeight = (chickinQty - depletion) * avgWeight
} else {
eggWeight, _ := s.RecordingRepo.GetTotalEggProductionWeightByProjectFlockID(ctx, projectFlockID)
totalWeight = (chickinQty-depletion)*avgWeight + eggWeight
}
return ""
if totalWeight == 0 {
return 0
}
return totalCost / totalWeight
}
func (s *repportService) calculateHppPricePerKg(ctx context.Context, projectFlockID uint, deliveryProducts []entity.MarketingDeliveryProduct) float64 {
func (s *repportService) getTotalProjectCost(ctx context.Context, projectFlockID uint) float64 {
if projectFlockID == 0 {
return 0
}
purchaseItems, err := s.PurchaseRepo.GetItemsByProjectFlockID(ctx, projectFlockID)
purchases, err := s.PurchaseRepo.GetItemsByProjectFlockID(ctx, projectFlockID)
if err != nil {
s.Log.Warnf("GetItemsByProjectFlockID error: %v", err)
}
costPurchase := float64(0)
for _, item := range purchaseItems {
costPurchase += item.TotalPrice
cost := float64(0)
for _, p := range purchases {
cost += p.TotalPrice
}
realizations, err := s.ExpenseRealizationRepo.GetByProjectFlockID(ctx, projectFlockID)
@@ -173,34 +164,11 @@ func (s *repportService) calculateHppPricePerKg(ctx context.Context, projectFloc
s.Log.Warnf("GetByProjectFlockID error: %v", err)
}
costBop := float64(0)
for _, realization := range realizations {
cost := realization.Price * realization.Qty
category := ""
if realization.ExpenseNonstock != nil && realization.ExpenseNonstock.Expense != nil {
category = realization.ExpenseNonstock.Expense.Category
}
if category == "BOP" {
costBop += cost
for _, r := range realizations {
if r.ExpenseNonstock != nil && r.ExpenseNonstock.Expense != nil &&
r.ExpenseNonstock.Expense.Category == string(utils.ExpenseCategoryBOP) {
cost += r.Price * r.Qty
}
}
totalActualCost := costPurchase + costBop
if totalActualCost == 0 {
return 0
}
totalWeightProduced, _, err := s.RecordingRepo.GetProductionWeightAndQtyByProjectFlockID(ctx, projectFlockID)
if err != nil {
s.Log.Warnf("GetProductionWeightAndQtyByProjectFlockID error: %v", err)
}
if totalWeightProduced == 0 {
return 0
}
hppPerKg := totalActualCost / totalWeightProduced
return hppPerKg
return cost
}