mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
adjust common hpp v2
This commit is contained in:
@@ -28,13 +28,14 @@ const (
|
||||
hppV2PartManualCutover = "manual_cutover"
|
||||
hppV2PartDepreciationNormal = "normal_transfer"
|
||||
hppV2PartDepreciationCutover = "manual_cutover"
|
||||
hppV2PartDepreciationFarmSnapshot = "farm_snapshot"
|
||||
hppV2ProrationPopulation = "growing_population_share"
|
||||
hppV2ProrationEggWeight = "laying_egg_weight_share"
|
||||
hppV2ProrationEggPiece = "laying_egg_piece_share"
|
||||
hppV2ScopePulletCost = "pullet_cost"
|
||||
hppV2ScopeProductionCost = "production_cost"
|
||||
hppV2CutoverFlagPakan = "PAKAN-CUTOVER"
|
||||
hppV2CutoverFlagOvk = "OVK-CUTOVER"
|
||||
hppV2CutoverFlagOvk = "OVK"
|
||||
)
|
||||
|
||||
type HppV2Service interface {
|
||||
@@ -115,57 +116,101 @@ func (s *hppV2Service) CalculateHppBreakdown(projectFlockKandangId uint, date *t
|
||||
totalPulletCost := 0.0
|
||||
totalProductionCost := 0.0
|
||||
components := make([]HppV2Component, 0, 8)
|
||||
appendComponent := func(component *HppV2Component) {
|
||||
appendComponent := func(requestedCode string, component *HppV2Component) {
|
||||
pulletBefore := totalPulletCost
|
||||
productionBefore := totalProductionCost
|
||||
|
||||
if component == nil || (component.Total == 0 && len(component.Parts) == 0) {
|
||||
utils.Log.Infof(
|
||||
"HPP v2 component skipped: project_flock_kandang_id=%d period_date=%s component=%s reason=empty_or_nil total_pullet_cost=%.2f total_production_cost=%.2f",
|
||||
projectFlockKandangId,
|
||||
startOfDay.Format("2006-01-02"),
|
||||
requestedCode,
|
||||
totalPulletCost,
|
||||
totalProductionCost,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
pulletAdded := componentScopeTotal(component, hppV2ScopePulletCost)
|
||||
productionAdded := componentScopeTotal(component, hppV2ScopeProductionCost)
|
||||
components = append(components, *component)
|
||||
totalPulletCost += componentScopeTotal(component, hppV2ScopePulletCost)
|
||||
totalProductionCost += componentScopeTotal(component, hppV2ScopeProductionCost)
|
||||
totalPulletCost += pulletAdded
|
||||
totalProductionCost += productionAdded
|
||||
utils.Log.Infof(
|
||||
"HPP v2 component applied: project_flock_kandang_id=%d period_date=%s component=%s component_total=%.2f pullet_added=%.2f production_added=%.2f total_pullet_before=%.2f total_pullet_after=%.2f total_production_before=%.2f total_production_after=%.2f parts_count=%d",
|
||||
projectFlockKandangId,
|
||||
startOfDay.Format("2006-01-02"),
|
||||
component.Code,
|
||||
component.Total,
|
||||
pulletAdded,
|
||||
productionAdded,
|
||||
pulletBefore,
|
||||
totalPulletCost,
|
||||
productionBefore,
|
||||
totalProductionCost,
|
||||
len(component.Parts),
|
||||
)
|
||||
}
|
||||
appendComponent(pakanComponent)
|
||||
appendComponent(hppV2ComponentPakan, pakanComponent)
|
||||
|
||||
ovkComponent, err := s.GetOvkBreakdown(projectFlockKandangId, &endOfDay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appendComponent(ovkComponent)
|
||||
appendComponent(hppV2ComponentOvk, ovkComponent)
|
||||
|
||||
docComponent, err := s.GetDocChickinBreakdown(projectFlockKandangId, &endOfDay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appendComponent(docComponent)
|
||||
appendComponent(hppV2ComponentDocChickin, docComponent)
|
||||
|
||||
directPulletComponent, err := s.GetDirectPulletPurchaseBreakdown(projectFlockKandangId, &endOfDay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appendComponent(directPulletComponent)
|
||||
appendComponent(hppV2ComponentDirectPulletPurchase, directPulletComponent)
|
||||
|
||||
bopRegularComponent, err := s.GetBopRegularBreakdown(projectFlockKandangId, &endOfDay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appendComponent(bopRegularComponent)
|
||||
appendComponent(hppV2ComponentBopRegular, bopRegularComponent)
|
||||
|
||||
bopEkspedisiComponent, err := s.GetBopEkspedisiBreakdown(projectFlockKandangId, &endOfDay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appendComponent(bopEkspedisiComponent)
|
||||
appendComponent(hppV2ComponentBopEksp, bopEkspedisiComponent)
|
||||
|
||||
manualPulletComponent, err := s.getManualPulletCostComponent(projectFlockKandangId, contextRow, startOfDay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appendComponent(manualPulletComponent)
|
||||
appendComponent(hppV2ComponentManualPulletCost, manualPulletComponent)
|
||||
|
||||
depreciationComponent, err := s.getDepreciationComponent(projectFlockKandangId, contextRow, startOfDay, totalPulletCost)
|
||||
depreciationComponent, err := s.getDepreciationComponent(projectFlockKandangId, contextRow, startOfDay, endOfDay, totalPulletCost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appendComponent(depreciationComponent)
|
||||
|
||||
depreciationCostToProduction := componentScopeTotal(depreciationComponent, hppV2ScopeProductionCost)
|
||||
depreciationSource := ""
|
||||
if depreciationComponent != nil && len(depreciationComponent.Parts) > 0 {
|
||||
depreciationSource = depreciationComponent.Parts[0].Code
|
||||
}
|
||||
productionCostBeforeDepreciation := totalProductionCost
|
||||
appendComponent(hppV2ComponentDepreciation, depreciationComponent)
|
||||
utils.Log.Infof(
|
||||
"HPP v2 depreciation cost applied: project_flock_kandang_id=%d period_date=%s depreciation_source=%s depreciation_cost=%.2f production_cost_before=%.2f production_cost_after=%.2f",
|
||||
projectFlockKandangId,
|
||||
startOfDay.Format("2006-01-02"),
|
||||
depreciationSource,
|
||||
depreciationCostToProduction,
|
||||
productionCostBeforeDepreciation,
|
||||
totalProductionCost,
|
||||
)
|
||||
|
||||
hppCost, err := s.GetHppEstimationDanRealisasi(totalProductionCost, projectFlockKandangId, &startOfDay, &endOfDay)
|
||||
if err != nil {
|
||||
@@ -179,6 +224,7 @@ func (s *hppV2Service) CalculateHppBreakdown(projectFlockKandangId uint, date *t
|
||||
ProjectFlockKandangID: projectFlockKandangId,
|
||||
ProjectFlockID: contextRow.ProjectFlockID,
|
||||
ProjectFlockCategory: contextRow.ProjectFlockCategory,
|
||||
HouseType: contextRow.HouseType,
|
||||
KandangID: contextRow.KandangID,
|
||||
KandangName: contextRow.KandangName,
|
||||
LocationID: contextRow.LocationID,
|
||||
@@ -1022,9 +1068,28 @@ func (s *hppV2Service) getDepreciationComponent(
|
||||
projectFlockKandangId uint,
|
||||
contextRow *commonRepo.HppV2ProjectFlockKandangContext,
|
||||
periodDate time.Time,
|
||||
endDate time.Time,
|
||||
totalPulletCost float64,
|
||||
) (*HppV2Component, error) {
|
||||
if s.hppRepo == nil || contextRow == nil || totalPulletCost <= 0 {
|
||||
if s.hppRepo == nil || contextRow == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
snapshotPart, err := s.buildFarmSnapshotDepreciationPart(projectFlockKandangId, contextRow, periodDate, endDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if snapshotPart != nil {
|
||||
return &HppV2Component{
|
||||
Code: hppV2ComponentDepreciation,
|
||||
Title: "Depreciation",
|
||||
Scopes: []string{hppV2ScopeProductionCost},
|
||||
Total: snapshotPart.Total,
|
||||
Parts: []HppV2ComponentPart{*snapshotPart},
|
||||
}, nil
|
||||
}
|
||||
|
||||
if totalPulletCost <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -1058,6 +1123,101 @@ func (s *hppV2Service) getDepreciationComponent(
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *hppV2Service) buildFarmSnapshotDepreciationPart(
|
||||
projectFlockKandangId uint,
|
||||
contextRow *commonRepo.HppV2ProjectFlockKandangContext,
|
||||
periodDate time.Time,
|
||||
endDate time.Time,
|
||||
) (*HppV2ComponentPart, error) {
|
||||
if contextRow == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
snapshot, err := s.hppRepo.GetFarmDepreciationSnapshotByProjectFlockIDAndPeriod(context.Background(), contextRow.ProjectFlockID, periodDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if snapshot == nil || snapshot.DepreciationValue <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
farmPFKIDs, err := s.hppRepo.GetProjectFlockKandangIDs(context.Background(), contextRow.ProjectFlockID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(farmPFKIDs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
end := endDate
|
||||
targetPieces, targetWeight, err := s.hppRepo.GetEggProduksiPiecesAndWeightKgByProjectFlockKandangIds(context.Background(), []uint{projectFlockKandangId}, &end)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
farmPieces, farmWeight, err := s.hppRepo.GetEggProduksiPiecesAndWeightKgByProjectFlockKandangIds(context.Background(), farmPFKIDs, &end)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
basis := hppV2ProrationEggWeight
|
||||
numerator := targetWeight
|
||||
denominator := farmWeight
|
||||
if denominator <= 0 {
|
||||
basis = hppV2ProrationEggPiece
|
||||
numerator = targetPieces
|
||||
denominator = farmPieces
|
||||
}
|
||||
if denominator <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ratio := numerator / denominator
|
||||
if ratio <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
appliedDepreciation := snapshot.DepreciationValue * ratio
|
||||
if appliedDepreciation <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
appliedPulletCostDayN := snapshot.PulletCostDayNTotal * ratio
|
||||
depreciationPercent := snapshot.DepreciationPercentEffective
|
||||
if appliedPulletCostDayN > 0 {
|
||||
depreciationPercent = (appliedDepreciation / appliedPulletCostDayN) * 100
|
||||
}
|
||||
|
||||
return &HppV2ComponentPart{
|
||||
Code: hppV2PartDepreciationFarmSnapshot,
|
||||
Title: "Farm Snapshot",
|
||||
Scopes: []string{hppV2ScopeProductionCost},
|
||||
Total: appliedDepreciation,
|
||||
Proration: &HppV2Proration{
|
||||
Basis: basis,
|
||||
Numerator: numerator,
|
||||
Denominator: denominator,
|
||||
Ratio: ratio,
|
||||
},
|
||||
Details: map[string]any{
|
||||
"basis_total": snapshot.DepreciationValue,
|
||||
"pullet_cost_day_n": appliedPulletCostDayN,
|
||||
"depreciation_percent": depreciationPercent,
|
||||
"snapshot_id": snapshot.ID,
|
||||
"snapshot_period_date": formatDateOnly(snapshot.PeriodDate),
|
||||
"snapshot_project_flock": snapshot.ProjectFlockID,
|
||||
},
|
||||
References: []HppV2Reference{
|
||||
{
|
||||
Type: "farm_depreciation_snapshot",
|
||||
ID: snapshot.ID,
|
||||
Date: formatDateOnly(snapshot.PeriodDate),
|
||||
Qty: 1,
|
||||
Total: snapshot.DepreciationValue,
|
||||
AppliedTotal: appliedDepreciation,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *hppV2Service) buildNormalTransferDepreciationPart(
|
||||
contextRow *commonRepo.HppV2ProjectFlockKandangContext,
|
||||
transferInput *commonRepo.HppV2LatestTransferInputRow,
|
||||
@@ -1211,17 +1371,40 @@ func (s *hppV2Service) buildManualCutoverDepreciationPart(
|
||||
}
|
||||
|
||||
func (s *hppV2Service) GetHppEstimationDanRealisasi(totalProductionCost float64, projectFlockKandangId uint, startDate *time.Time, endDate *time.Time) (*HppCostResponse, error) {
|
||||
utils.Log.Infof(
|
||||
"GetHppEstimationDanRealisasi started: project_flock_kandang_id=%d total_production_cost=%.2f start_date=%s end_date=%s",
|
||||
projectFlockKandangId,
|
||||
totalProductionCost,
|
||||
formatTimePtr(startDate),
|
||||
formatTimePtr(endDate),
|
||||
)
|
||||
|
||||
if s.hppRepo == nil {
|
||||
utils.Log.Warnf(
|
||||
"GetHppEstimationDanRealisasi skipped: hpp repository is nil (project_flock_kandang_id=%d)",
|
||||
projectFlockKandangId,
|
||||
)
|
||||
return &HppCostResponse{}, nil
|
||||
}
|
||||
|
||||
estimPieces, estimWeightKg, err := s.hppRepo.GetEggProduksiPiecesAndWeightKgByProjectFlockKandangIds(context.Background(), []uint{projectFlockKandangId}, endDate)
|
||||
if err != nil {
|
||||
utils.Log.WithError(err).Errorf(
|
||||
"GetHppEstimationDanRealisasi failed to get estimation egg production: project_flock_kandang_id=%d end_date=%s",
|
||||
projectFlockKandangId,
|
||||
formatTimePtr(endDate),
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
realPieces, realWeightKg, err := s.hppRepo.GetEggTerjualPiecesAndWeightKgByProjectFlockKandangIds(context.Background(), []uint{projectFlockKandangId}, startDate, endDate)
|
||||
if err != nil {
|
||||
utils.Log.WithError(err).Errorf(
|
||||
"GetHppEstimationDanRealisasi failed to get realization egg sales: project_flock_kandang_id=%d start_date=%s end_date=%s",
|
||||
projectFlockKandangId,
|
||||
formatTimePtr(startDate),
|
||||
formatTimePtr(endDate),
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1249,6 +1432,20 @@ func (s *hppV2Service) GetHppEstimationDanRealisasi(totalProductionCost float64,
|
||||
real.HargaButir = roundToTwoDecimals(totalProductionCost / realPieces)
|
||||
}
|
||||
|
||||
utils.Log.Infof(
|
||||
"GetHppEstimationDanRealisasi success: project_flock_kandang_id=%d estimation_butir=%.2f estimation_kg=%.2f estimation_harga_butir=%.2f estimation_harga_kg=%.2f real_butir=%.2f real_kg=%.2f real_harga_butir=%.2f real_harga_kg=%.2f totalProductionCost=%.2f",
|
||||
projectFlockKandangId,
|
||||
estimation.Butir,
|
||||
estimation.Kg,
|
||||
estimation.HargaButir,
|
||||
estimation.HargaKg,
|
||||
real.Butir,
|
||||
real.Kg,
|
||||
real.HargaButir,
|
||||
real.HargaKg,
|
||||
totalProductionCost,
|
||||
)
|
||||
|
||||
return &HppCostResponse{
|
||||
Estimation: estimation,
|
||||
Real: real,
|
||||
|
||||
Reference in New Issue
Block a user