mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
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:
@@ -90,6 +90,7 @@ func (r *MarketingDeliveryProductRepositoryImpl) GetAllWithFilters(ctx context.C
|
|||||||
Preload("Marketing.SalesPerson").
|
Preload("Marketing.SalesPerson").
|
||||||
Preload("ProductWarehouse").
|
Preload("ProductWarehouse").
|
||||||
Preload("ProductWarehouse.Product").
|
Preload("ProductWarehouse.Product").
|
||||||
|
Preload("ProductWarehouse.Product.Flags").
|
||||||
Preload("ProductWarehouse.Warehouse").
|
Preload("ProductWarehouse.Warehouse").
|
||||||
Preload("ProductWarehouse.ProjectFlockKandang").
|
Preload("ProductWarehouse.ProjectFlockKandang").
|
||||||
Preload("ProductWarehouse.ProjectFlockKandang.ProjectFlock")
|
Preload("ProductWarehouse.ProjectFlockKandang.ProjectFlock")
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type ProjectChickinRepository interface {
|
|||||||
GetByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) ([]entity.ProjectChickin, error)
|
GetByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) ([]entity.ProjectChickin, error)
|
||||||
GetPendingByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) ([]entity.ProjectChickin, error)
|
GetPendingByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) ([]entity.ProjectChickin, error)
|
||||||
GetTotalPendingUsageQtyByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (float64, error)
|
GetTotalPendingUsageQtyByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (float64, error)
|
||||||
|
GetTotalChickinQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (float64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChickinRepositoryImpl struct {
|
type ChickinRepositoryImpl struct {
|
||||||
@@ -90,3 +91,14 @@ func (r *ChickinRepositoryImpl) GetTotalPendingUsageQtyByProjectFlockKandangID(c
|
|||||||
}
|
}
|
||||||
return total, nil
|
return total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ChickinRepositoryImpl) GetTotalChickinQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (float64, error) {
|
||||||
|
var result float64
|
||||||
|
err := r.db.WithContext(ctx).
|
||||||
|
Table("project_chickins").
|
||||||
|
Select("COALESCE(SUM(project_chickins.usage_qty), 0)").
|
||||||
|
Joins("JOIN project_flock_kandangs ON project_flock_kandangs.id = project_chickins.project_flock_kandang_id").
|
||||||
|
Where("project_flock_kandangs.project_flock_id = ?", projectFlockID).
|
||||||
|
Scan(&result).Error
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ type RecordingRepository interface {
|
|||||||
GetProductionWeightAndQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (totalWeight float64, totalQty float64, err error)
|
GetProductionWeightAndQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (totalWeight float64, totalQty float64, err error)
|
||||||
GetTotalDepletionByProjectFlockID(ctx context.Context, projectFlockID uint) (totalDepletion float64, err error)
|
GetTotalDepletionByProjectFlockID(ctx context.Context, projectFlockID uint) (totalDepletion float64, err error)
|
||||||
GetLatestAvgWeightByProjectFlockID(ctx context.Context, projectFlockID uint) (avgWeight float64, err error)
|
GetLatestAvgWeightByProjectFlockID(ctx context.Context, projectFlockID uint) (avgWeight float64, err error)
|
||||||
|
GetTotalEggProductionWeightByProjectFlockID(ctx context.Context, projectFlockID uint) (totalWeightKg float64, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RecordingRepositoryImpl struct {
|
type RecordingRepositoryImpl struct {
|
||||||
@@ -371,28 +372,23 @@ func (r *RecordingRepositoryImpl) GetProductionWeightAndQtyByProjectFlockID(ctx
|
|||||||
return 0, 0, nil
|
return 0, 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get total chickin quantity for this ProjectFlock
|
|
||||||
totalChickinQty, err := r.getTotalChickinQtyByProjectFlockID(ctx, projectFlockID)
|
totalChickinQty, err := r.getTotalChickinQtyByProjectFlockID(ctx, projectFlockID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get total depletion for this ProjectFlock
|
|
||||||
totalDepletion, err := r.GetTotalDepletionByProjectFlockID(ctx, projectFlockID)
|
totalDepletion, err := r.GetTotalDepletionByProjectFlockID(ctx, projectFlockID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate actual quantity produced
|
|
||||||
actualQty := totalChickinQty - totalDepletion
|
actualQty := totalChickinQty - totalDepletion
|
||||||
|
|
||||||
// Get latest average weight from RecordingBW
|
|
||||||
avgWeight, err := r.GetLatestAvgWeightByProjectFlockID(ctx, projectFlockID)
|
avgWeight, err := r.GetLatestAvgWeightByProjectFlockID(ctx, projectFlockID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate total weight
|
|
||||||
totalWeight = actualQty * avgWeight
|
totalWeight = actualQty * avgWeight
|
||||||
|
|
||||||
return totalWeight, actualQty, nil
|
return totalWeight, actualQty, nil
|
||||||
@@ -434,6 +430,22 @@ func (r *RecordingRepositoryImpl) GetLatestAvgWeightByProjectFlockID(ctx context
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *RecordingRepositoryImpl) GetTotalEggProductionWeightByProjectFlockID(ctx context.Context, projectFlockID uint) (float64, error) {
|
||||||
|
if projectFlockID == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var result float64
|
||||||
|
err := r.DB().WithContext(ctx).
|
||||||
|
Table("recording_eggs").
|
||||||
|
Select("COALESCE(SUM(recording_eggs.qty * recording_eggs.weight), 0) / 1000").
|
||||||
|
Joins("JOIN recordings ON recordings.id = recording_eggs.recording_id").
|
||||||
|
Joins("JOIN project_flock_kandangs ON project_flock_kandangs.id = recordings.project_flock_kandangs_id").
|
||||||
|
Where("project_flock_kandangs.project_flock_id = ?", projectFlockID).
|
||||||
|
Scan(&result).Error
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func nextRecordingDay(days []int) int {
|
func nextRecordingDay(days []int) int {
|
||||||
if len(days) == 0 {
|
if len(days) == 0 {
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
marketingDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/dto"
|
||||||
customerDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/customers/dto"
|
customerDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/customers/dto"
|
||||||
productDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/dto"
|
productDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/dto"
|
||||||
warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
|
warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
|
||||||
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
||||||
|
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RepportMarketingItemDTO struct {
|
type RepportMarketingItemDTO struct {
|
||||||
@@ -45,7 +46,7 @@ type RepportMarketingResponseDTO struct {
|
|||||||
Total *Summary `json:"total,omitempty"`
|
Total *Summary `json:"total,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToRepportMarketingItemDTO(mdp entity.MarketingDeliveryProduct, hppPricePerKg float64) RepportMarketingItemDTO {
|
func ToRepportMarketingItemDTO(mdp entity.MarketingDeliveryProduct, hppPricePerKg float64, category string) RepportMarketingItemDTO {
|
||||||
soDate := time.Time{}
|
soDate := time.Time{}
|
||||||
agingDays := 0
|
agingDays := 0
|
||||||
if mdp.MarketingProduct.Marketing.SoDate.Year() > 1 {
|
if mdp.MarketingProduct.Marketing.SoDate.Year() > 1 {
|
||||||
@@ -58,11 +59,17 @@ func ToRepportMarketingItemDTO(mdp entity.MarketingDeliveryProduct, hppPricePerK
|
|||||||
realizationDate = *mdp.DeliveryDate
|
realizationDate = *mdp.DeliveryDate
|
||||||
}
|
}
|
||||||
|
|
||||||
doNumber := generateDoNumber(mdp.MarketingProduct.Marketing.SoNumber, mdp.DeliveryDate, mdp.MarketingProduct.ProductWarehouse.WarehouseId)
|
doNumber := marketingDTO.GenerateDeliveryOrderNumber(mdp.MarketingProduct.Marketing.SoNumber, mdp.DeliveryDate, mdp.MarketingProduct.ProductWarehouse.WarehouseId)
|
||||||
|
|
||||||
totalWeightKg := mdp.Qty * mdp.AvgWeight
|
totalWeightKg := mdp.Qty * mdp.AvgWeight
|
||||||
salesAmount := totalWeightKg * mdp.UnitPrice
|
salesAmount := totalWeightKg * mdp.UnitPrice
|
||||||
hppAmount := totalWeightKg * hppPricePerKg
|
|
||||||
|
var hpp float64
|
||||||
|
var hppAmount float64
|
||||||
|
if isProductEligibleForHpp(mdp, category) {
|
||||||
|
hpp = hppPricePerKg
|
||||||
|
hppAmount = totalWeightKg * hppPricePerKg
|
||||||
|
}
|
||||||
|
|
||||||
item := RepportMarketingItemDTO{
|
item := RepportMarketingItemDTO{
|
||||||
ID: int(mdp.Id),
|
ID: int(mdp.Id),
|
||||||
@@ -70,12 +77,12 @@ func ToRepportMarketingItemDTO(mdp entity.MarketingDeliveryProduct, hppPricePerK
|
|||||||
RealizationDate: realizationDate,
|
RealizationDate: realizationDate,
|
||||||
AgingDays: agingDays,
|
AgingDays: agingDays,
|
||||||
DoNumber: doNumber,
|
DoNumber: doNumber,
|
||||||
MarketingType: "ayam",
|
MarketingType: getMarketingType(mdp),
|
||||||
Qty: mdp.Qty,
|
Qty: mdp.Qty,
|
||||||
AverageWeightKg: mdp.AvgWeight,
|
AverageWeightKg: mdp.AvgWeight,
|
||||||
TotalWeightKg: totalWeightKg,
|
TotalWeightKg: totalWeightKg,
|
||||||
SalesPricePerKg: mdp.UnitPrice,
|
SalesPricePerKg: mdp.UnitPrice,
|
||||||
HppPricePerKg: hppPricePerKg,
|
HppPricePerKg: hpp,
|
||||||
SalesAmount: salesAmount,
|
SalesAmount: salesAmount,
|
||||||
HppAmount: hppAmount,
|
HppAmount: hppAmount,
|
||||||
}
|
}
|
||||||
@@ -105,10 +112,10 @@ func ToRepportMarketingItemDTO(mdp entity.MarketingDeliveryProduct, hppPricePerK
|
|||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToRepportMarketingItemDTOs(mdps []entity.MarketingDeliveryProduct, hppPricePerKg float64) []RepportMarketingItemDTO {
|
func ToRepportMarketingItemDTOs(mdps []entity.MarketingDeliveryProduct, hppPricePerKg float64, category string) []RepportMarketingItemDTO {
|
||||||
items := make([]RepportMarketingItemDTO, 0, len(mdps))
|
items := make([]RepportMarketingItemDTO, 0, len(mdps))
|
||||||
for _, mdp := range mdps {
|
for _, mdp := range mdps {
|
||||||
items = append(items, ToRepportMarketingItemDTO(mdp, hppPricePerKg))
|
items = append(items, ToRepportMarketingItemDTO(mdp, hppPricePerKg, category))
|
||||||
}
|
}
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
@@ -117,23 +124,72 @@ func ToRepportMarketingItemDTOsWithHppMap(mdps []entity.MarketingDeliveryProduct
|
|||||||
items := make([]RepportMarketingItemDTO, 0, len(mdps))
|
items := make([]RepportMarketingItemDTO, 0, len(mdps))
|
||||||
for _, mdp := range mdps {
|
for _, mdp := range mdps {
|
||||||
hppPerKg := float64(0)
|
hppPerKg := float64(0)
|
||||||
|
category := ""
|
||||||
if projectFlockKandang := mdp.MarketingProduct.ProductWarehouse.ProjectFlockKandang; projectFlockKandang != nil {
|
if projectFlockKandang := mdp.MarketingProduct.ProductWarehouse.ProjectFlockKandang; projectFlockKandang != nil {
|
||||||
if hpp, exists := hppMap[projectFlockKandang.ProjectFlockId]; exists {
|
if hpp, exists := hppMap[projectFlockKandang.ProjectFlockId]; exists {
|
||||||
hppPerKg = hpp
|
hppPerKg = hpp
|
||||||
}
|
}
|
||||||
|
category = projectFlockKandang.ProjectFlock.Category
|
||||||
}
|
}
|
||||||
items = append(items, ToRepportMarketingItemDTO(mdp, hppPerKg))
|
|
||||||
|
item := ToRepportMarketingItemDTO(mdp, hppPerKg, category)
|
||||||
|
items = append(items, item)
|
||||||
}
|
}
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToSummary(mdps []entity.MarketingDeliveryProduct, hppPricePerKg float64) *Summary {
|
func getMarketingType(mdp entity.MarketingDeliveryProduct) string {
|
||||||
|
hasAyam, hasTelur := checkProductFlags(mdp.MarketingProduct.ProductWarehouse.Product.Flags)
|
||||||
|
|
||||||
|
if hasAyam {
|
||||||
|
return "ayam"
|
||||||
|
}
|
||||||
|
if hasTelur {
|
||||||
|
return "telur"
|
||||||
|
}
|
||||||
|
return "trading"
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkProductFlags(flags []entity.Flag) (hasAyam, hasTelur bool) {
|
||||||
|
if len(flags) == 0 {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, flag := range flags {
|
||||||
|
ft := utils.FlagType(flag.Name)
|
||||||
|
|
||||||
|
if ft == utils.FlagAyamAfkir || ft == utils.FlagAyamCulling || ft == utils.FlagAyamMati ||
|
||||||
|
ft == utils.FlagDOC || ft == utils.FlagPullet || ft == utils.FlagLayer {
|
||||||
|
hasAyam = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if ft == utils.FlagTelur || ft == utils.FlagTelurUtuh || ft == utils.FlagTelurPecah ||
|
||||||
|
ft == utils.FlagTelurPutih || ft == utils.FlagTelurRetak {
|
||||||
|
hasTelur = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasAyam, hasTelur
|
||||||
|
}
|
||||||
|
|
||||||
|
func isProductEligibleForHpp(mdp entity.MarketingDeliveryProduct, category string) bool {
|
||||||
|
hasAyam, hasTelur := checkProductFlags(mdp.MarketingProduct.ProductWarehouse.Product.Flags)
|
||||||
|
|
||||||
|
if utils.ProjectFlockCategory(category) == utils.ProjectFlockCategoryGrowing {
|
||||||
|
return hasAyam
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasAyam || hasTelur
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToSummary(mdps []entity.MarketingDeliveryProduct, hppPricePerKg float64, category string) *Summary {
|
||||||
if len(mdps) == 0 {
|
if len(mdps) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
totalQty := 0
|
totalQty := 0
|
||||||
totalWeightKg := 0.0
|
totalWeightKg := 0.0
|
||||||
|
totalEligibleWeightKg := 0.0
|
||||||
totalSalesAmount := int64(0)
|
totalSalesAmount := int64(0)
|
||||||
totalHppAmount := int64(0)
|
totalHppAmount := int64(0)
|
||||||
|
|
||||||
@@ -142,12 +198,16 @@ func ToSummary(mdps []entity.MarketingDeliveryProduct, hppPricePerKg float64) *S
|
|||||||
totalQty += int(mdp.Qty)
|
totalQty += int(mdp.Qty)
|
||||||
totalWeightKg += calculatedTotalWeight
|
totalWeightKg += calculatedTotalWeight
|
||||||
totalSalesAmount += int64(calculatedTotalWeight * mdp.UnitPrice)
|
totalSalesAmount += int64(calculatedTotalWeight * mdp.UnitPrice)
|
||||||
totalHppAmount += int64(calculatedTotalWeight * hppPricePerKg)
|
|
||||||
|
if isProductEligibleForHpp(mdp, category) {
|
||||||
|
totalEligibleWeightKg += calculatedTotalWeight
|
||||||
|
totalHppAmount += int64(calculatedTotalWeight * hppPricePerKg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
totalHppPricePerKg := float64(0)
|
totalHppPricePerKg := float64(0)
|
||||||
if totalWeightKg > 0 {
|
if totalEligibleWeightKg > 0 {
|
||||||
totalHppPricePerKg = float64(totalHppAmount) / totalWeightKg
|
totalHppPricePerKg = float64(totalHppAmount) / totalEligibleWeightKg
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Summary{
|
return &Summary{
|
||||||
@@ -159,14 +219,6 @@ func ToSummary(mdps []entity.MarketingDeliveryProduct, hppPricePerKg float64) *S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateDoNumber(soNumber string, deliveryDate *time.Time, warehouseId uint) string {
|
|
||||||
dateStr := ""
|
|
||||||
if deliveryDate != nil {
|
|
||||||
dateStr = deliveryDate.Format("20060102")
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s-%s-%d", soNumber, dateStr, warehouseId)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToSummaryFromDTOItems(items []RepportMarketingItemDTO) *Summary {
|
func ToSummaryFromDTOItems(items []RepportMarketingItemDTO) *Summary {
|
||||||
if len(items) == 0 {
|
if len(items) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@@ -198,9 +250,9 @@ func ToSummaryFromDTOItems(items []RepportMarketingItemDTO) *Summary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToRepportMarketingResponseDTO(mdps []entity.MarketingDeliveryProduct, hppPricePerKg float64) RepportMarketingResponseDTO {
|
func ToRepportMarketingResponseDTO(mdps []entity.MarketingDeliveryProduct, hppPricePerKg float64, category string) RepportMarketingResponseDTO {
|
||||||
items := ToRepportMarketingItemDTOs(mdps, hppPricePerKg)
|
items := ToRepportMarketingItemDTOs(mdps, hppPricePerKg, category)
|
||||||
total := ToSummary(mdps, hppPricePerKg)
|
total := ToSummary(mdps, hppPricePerKg, category)
|
||||||
|
|
||||||
return RepportMarketingResponseDTO{
|
return RepportMarketingResponseDTO{
|
||||||
Items: items,
|
Items: items,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
expenseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories"
|
expenseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories"
|
||||||
marketingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/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"
|
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
||||||
purchaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories"
|
purchaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories"
|
||||||
)
|
)
|
||||||
@@ -22,11 +23,12 @@ func (RepportModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *
|
|||||||
expenseRealizationRepository := expenseRepo.NewExpenseRealizationRepository(db)
|
expenseRealizationRepository := expenseRepo.NewExpenseRealizationRepository(db)
|
||||||
marketingDeliveryProductRepository := marketingRepo.NewMarketingDeliveryProductRepository(db)
|
marketingDeliveryProductRepository := marketingRepo.NewMarketingDeliveryProductRepository(db)
|
||||||
purchaseRepository := purchaseRepo.NewPurchaseRepository(db)
|
purchaseRepository := purchaseRepo.NewPurchaseRepository(db)
|
||||||
|
chickinRepository := chickinRepo.NewChickinRepository(db)
|
||||||
recordingRepository := recordingRepo.NewRecordingRepository(db)
|
recordingRepository := recordingRepo.NewRecordingRepository(db)
|
||||||
approvalRepository := commonRepo.NewApprovalRepository(db)
|
approvalRepository := commonRepo.NewApprovalRepository(db)
|
||||||
|
|
||||||
approvalSvc := approvalService.NewApprovalService(approvalRepository)
|
approvalSvc := approvalService.NewApprovalService(approvalRepository)
|
||||||
repportService := sRepport.NewRepportService(validate, expenseRealizationRepository, marketingDeliveryProductRepository, purchaseRepository, recordingRepository, approvalSvc)
|
repportService := sRepport.NewRepportService(validate, expenseRealizationRepository, marketingDeliveryProductRepository, purchaseRepository, chickinRepository, recordingRepository, approvalSvc)
|
||||||
|
|
||||||
RepportRoutes(router, repportService)
|
RepportRoutes(router, repportService)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
|
||||||
"gitlab.com/mbugroup/lti-api.git/internal/modules/repports/dto"
|
"gitlab.com/mbugroup/lti-api.git/internal/modules/repports/dto"
|
||||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/repports/validations"
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/repports/validations"
|
||||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||||
@@ -12,6 +11,7 @@ import (
|
|||||||
approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto"
|
approvalDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto"
|
||||||
expenseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories"
|
expenseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories"
|
||||||
marketingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/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"
|
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
||||||
purchaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories"
|
purchaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories"
|
||||||
|
|
||||||
@@ -32,17 +32,19 @@ type repportService struct {
|
|||||||
ExpenseRealizationRepo expenseRepo.ExpenseRealizationRepository
|
ExpenseRealizationRepo expenseRepo.ExpenseRealizationRepository
|
||||||
MarketingDeliveryRepo marketingRepo.MarketingDeliveryProductRepository
|
MarketingDeliveryRepo marketingRepo.MarketingDeliveryProductRepository
|
||||||
PurchaseRepo purchaseRepo.PurchaseRepository
|
PurchaseRepo purchaseRepo.PurchaseRepository
|
||||||
|
ChickinRepo chickinRepo.ProjectChickinRepository
|
||||||
RecordingRepo recordingRepo.RecordingRepository
|
RecordingRepo recordingRepo.RecordingRepository
|
||||||
ApprovalSvc approvalService.ApprovalService
|
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{
|
return &repportService{
|
||||||
Log: utils.Log,
|
Log: utils.Log,
|
||||||
Validate: validate,
|
Validate: validate,
|
||||||
ExpenseRealizationRepo: expenseRealizationRepo,
|
ExpenseRealizationRepo: expenseRealizationRepo,
|
||||||
MarketingDeliveryRepo: marketingDeliveryRepo,
|
MarketingDeliveryRepo: marketingDeliveryRepo,
|
||||||
PurchaseRepo: purchaseRepo,
|
PurchaseRepo: purchaseRepo,
|
||||||
|
ChickinRepo: chickinRepo,
|
||||||
RecordingRepo: recordingRepo,
|
RecordingRepo: recordingRepo,
|
||||||
ApprovalSvc: approvalSvc,
|
ApprovalSvc: approvalSvc,
|
||||||
}
|
}
|
||||||
@@ -98,74 +100,63 @@ func (s *repportService) GetMarketing(c *fiber.Ctx, params *validation.Marketing
|
|||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
projectFlockIDs := s.collectProjectFlockIDs(deliveryProducts)
|
projectFlockIDMap := make(map[uint]bool)
|
||||||
hppMap := s.buildHppMap(c.Context(), projectFlockIDs, deliveryProducts)
|
hppMap := make(map[uint]float64)
|
||||||
items := dto.ToRepportMarketingItemDTOsWithHppMap(deliveryProducts, hppMap)
|
|
||||||
|
|
||||||
|
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
|
return items, total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *repportService) collectProjectFlockIDs(deliveryProducts []entity.MarketingDeliveryProduct) []uint {
|
func (s *repportService) calculateHppPricePerKg(ctx context.Context, projectFlockID uint, category string) float64 {
|
||||||
projectFlockIDMap := make(map[uint]bool)
|
totalCost := s.getTotalProjectCost(ctx, projectFlockID)
|
||||||
projectFlockIDs := make([]uint, 0)
|
if totalCost == 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:
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (s *repportService) getProjectFlockCategory(deliveryProducts []entity.MarketingDeliveryProduct, projectFlockID uint) string {
|
chickinQty, _ := s.ChickinRepo.GetTotalChickinQtyByProjectFlockID(ctx, projectFlockID)
|
||||||
for _, dp := range deliveryProducts {
|
depletion, _ := s.RecordingRepo.GetTotalDepletionByProjectFlockID(ctx, projectFlockID)
|
||||||
if projectFlockKandang := dp.MarketingProduct.ProductWarehouse.ProjectFlockKandang; projectFlockKandang != nil {
|
avgWeight, _ := s.RecordingRepo.GetLatestAvgWeightByProjectFlockID(ctx, projectFlockID)
|
||||||
if projectFlockKandang.ProjectFlockId == projectFlockID {
|
|
||||||
return projectFlockKandang.ProjectFlock.Category
|
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 {
|
if projectFlockID == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
purchaseItems, err := s.PurchaseRepo.GetItemsByProjectFlockID(ctx, projectFlockID)
|
purchases, err := s.PurchaseRepo.GetItemsByProjectFlockID(ctx, projectFlockID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.Log.Warnf("GetItemsByProjectFlockID error: %v", err)
|
s.Log.Warnf("GetItemsByProjectFlockID error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
costPurchase := float64(0)
|
cost := float64(0)
|
||||||
for _, item := range purchaseItems {
|
for _, p := range purchases {
|
||||||
costPurchase += item.TotalPrice
|
cost += p.TotalPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
realizations, err := s.ExpenseRealizationRepo.GetByProjectFlockID(ctx, projectFlockID)
|
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)
|
s.Log.Warnf("GetByProjectFlockID error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
costBop := float64(0)
|
for _, r := range realizations {
|
||||||
for _, realization := range realizations {
|
if r.ExpenseNonstock != nil && r.ExpenseNonstock.Expense != nil &&
|
||||||
cost := realization.Price * realization.Qty
|
r.ExpenseNonstock.Expense.Category == string(utils.ExpenseCategoryBOP) {
|
||||||
category := ""
|
cost += r.Price * r.Qty
|
||||||
if realization.ExpenseNonstock != nil && realization.ExpenseNonstock.Expense != nil {
|
|
||||||
category = realization.ExpenseNonstock.Expense.Category
|
|
||||||
}
|
|
||||||
|
|
||||||
if category == "BOP" {
|
|
||||||
costBop += cost
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return cost
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user