mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
445 lines
17 KiB
Go
445 lines
17 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"math"
|
|
"time"
|
|
|
|
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
|
)
|
|
|
|
type HppService interface {
|
|
CalculateHppCost(projectFlockKandangId uint, date *time.Time) (*HppCostResponse, error)
|
|
GetTotalDepresiasiFlockGrowing(sourceProjectFlockID uint, date *time.Time) (float64, error)
|
|
GetTotalProductionCost(projectFlockKandangId uint, endDate *time.Time, depresiasiTransfer float64) (float64, error)
|
|
GetBudgetKandangLaying(projectFlockKandangId uint, endDate *time.Time) (float64, error)
|
|
GetDepresiasiTransfer(projectFlockKandangId uint, date *time.Time) (float64, error)
|
|
GetHppEstimationDanRealisasi(totalProductionCost float64, projectFlockKandangId uint, startDate *time.Time, endDate *time.Time) (*HppCostResponse, error)
|
|
}
|
|
|
|
type HppCostResponse struct {
|
|
Estimation HppCostDetail `json:"estimation"`
|
|
Real HppCostDetail `json:"real"`
|
|
}
|
|
|
|
type HppCostDetail struct {
|
|
HargaKg float64 `json:"harga_kg"`
|
|
HargaButir float64 `json:"harga_butir"`
|
|
Total float64 `json:"total"`
|
|
Kg float64 `json:"kg"`
|
|
Butir float64 `json:"butir"`
|
|
}
|
|
|
|
type hppService struct {
|
|
hppRepo commonRepo.HppCostRepository
|
|
}
|
|
|
|
func NewHppService(hppRepo commonRepo.HppCostRepository) HppService {
|
|
return &hppService{hppRepo: hppRepo}
|
|
}
|
|
|
|
func (s *hppService) CalculateHppCost(projectFlockKandangId uint, date *time.Time) (*HppCostResponse, error) {
|
|
logHpp("CalculateHppCost", "start project_flock_kandang_id=%d input_date=%s", projectFlockKandangId, formatTimePtr(date))
|
|
if date == nil {
|
|
now := time.Now()
|
|
date = &now
|
|
}
|
|
logHpp("CalculateHppCost", "normalized_date=%s", formatTimePtr(date))
|
|
|
|
location, err := time.LoadLocation("Asia/Jakarta")
|
|
if err != nil {
|
|
logHpp("CalculateHppCost", "load_location_error=%v", err)
|
|
return nil, err
|
|
}
|
|
logHpp("CalculateHppCost", "location=%s", location.String())
|
|
|
|
startOfDay := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, location)
|
|
endOfDay := startOfDay.Add(24 * time.Hour)
|
|
logHpp("CalculateHppCost", "start_of_day=%s end_of_day=%s", startOfDay.Format(time.RFC3339), endOfDay.Format(time.RFC3339))
|
|
|
|
depresiasiTransfer, err := s.GetDepresiasiTransfer(projectFlockKandangId, &endOfDay)
|
|
if err != nil {
|
|
logHpp("CalculateHppCost", "get_depresiasi_transfer_error=%v", err)
|
|
return nil, err
|
|
}
|
|
logHpp("CalculateHppCost", "depresiasi_transfer=%f", depresiasiTransfer)
|
|
|
|
totalProductionCost, err := s.GetTotalProductionCost(projectFlockKandangId, &endOfDay, depresiasiTransfer)
|
|
if err != nil {
|
|
logHpp("CalculateHppCost", "get_total_production_cost_error=%v", err)
|
|
return nil, err
|
|
}
|
|
logHpp("CalculateHppCost", "total_production_cost=%f", totalProductionCost)
|
|
result, err := s.GetHppEstimationDanRealisasi(totalProductionCost, projectFlockKandangId, &startOfDay, &endOfDay)
|
|
if err != nil {
|
|
logHpp("CalculateHppCost", "get_hpp_estimation_dan_realisasi_error=%v", err)
|
|
return nil, err
|
|
}
|
|
logHpp("CalculateHppCost", "done estimation=%+v real=%+v", result.Estimation, result.Real)
|
|
return result, nil
|
|
}
|
|
|
|
func (s *hppService) GetTotalDepresiasiFlockGrowing(sourceProjectFlockID uint, date *time.Time) (float64, error) {
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "start source_project_flock_id=%d input_date=%s", sourceProjectFlockID, formatTimePtr(date))
|
|
if date == nil {
|
|
now := time.Now()
|
|
date = &now
|
|
}
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "normalized_date=%s", formatTimePtr(date))
|
|
|
|
if s.hppRepo == nil {
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "repo_nil return=0")
|
|
return 0, nil
|
|
}
|
|
|
|
kandangIDs, err := s.hppRepo.GetProjectFlockKandangIDs(context.Background(), sourceProjectFlockID)
|
|
if err != nil {
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "get_project_flock_kandang_ids_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "kandang_ids=%v", kandangIDs)
|
|
|
|
docCost, err := s.hppRepo.GetDocCost(context.Background(), kandangIDs)
|
|
if err != nil {
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "get_doc_cost_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "doc_cost=%f", docCost)
|
|
|
|
budgetCost, err := s.hppRepo.GetBudgetCostByProjectFlockId(context.Background(), sourceProjectFlockID)
|
|
if err != nil {
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "get_budget_cost_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "budget_cost=%f", budgetCost)
|
|
|
|
expedisionCost, err := s.hppRepo.GetExpedisionCost(context.Background(), kandangIDs)
|
|
if err != nil {
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "get_expedision_cost_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "expedision_cost=%f", expedisionCost)
|
|
|
|
feedCost, err := s.hppRepo.GetFeedUsageCost(context.Background(), kandangIDs, date)
|
|
if err != nil {
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "get_feed_usage_cost_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "feed_cost=%f", feedCost)
|
|
|
|
ovkCost, err := s.hppRepo.GetOvkUsageCost(context.Background(), kandangIDs, date)
|
|
if err != nil {
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "get_ovk_usage_cost_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "ovk_cost=%f", ovkCost)
|
|
|
|
total := docCost + budgetCost + expedisionCost + feedCost + ovkCost
|
|
logHpp("GetTotalDepresiasiFlockGrowing", "done total=%f", total)
|
|
return total, nil
|
|
}
|
|
|
|
func (s *hppService) GetTotalProductionCost(projectFlockKandangId uint, endDate *time.Time, depresiasiTransfer float64) (float64, error) {
|
|
logHpp("GetTotalProductionCost", "start project_flock_kandang_id=%d end_date=%s depresiasi_transfer=%f", projectFlockKandangId, formatTimePtr(endDate), depresiasiTransfer)
|
|
// if date == nil {
|
|
// now := time.Now()
|
|
// date = &now
|
|
// }
|
|
|
|
costPullet, err := s.hppRepo.GetPulletCost(context.Background(), projectFlockKandangId)
|
|
if err != nil {
|
|
logHpp("GetTotalProductionCost", "get_pullet_cost_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetTotalProductionCost", "cost_pullet=%f", costPullet)
|
|
|
|
costFeed, err := s.hppRepo.GetFeedUsageCost(context.Background(), []uint{projectFlockKandangId}, endDate)
|
|
if err != nil {
|
|
logHpp("GetTotalProductionCost", "get_feed_usage_cost_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetTotalProductionCost", "cost_feed=%f", costFeed)
|
|
|
|
costOvk, err := s.hppRepo.GetOvkUsageCost(context.Background(), []uint{projectFlockKandangId}, endDate)
|
|
if err != nil {
|
|
logHpp("GetTotalProductionCost", "get_ovk_usage_cost_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetTotalProductionCost", "cost_ovk=%f", costOvk)
|
|
|
|
costExpedision, err := s.hppRepo.GetExpedisionCost(context.Background(), []uint{projectFlockKandangId})
|
|
if err != nil {
|
|
logHpp("GetTotalProductionCost", "get_expedision_cost_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetTotalProductionCost", "cost_expedision=%f", costExpedision)
|
|
|
|
costBudget, err := s.GetBudgetKandangLaying(projectFlockKandangId, endDate)
|
|
if err != nil {
|
|
logHpp("GetTotalProductionCost", "get_budget_kandang_laying_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetTotalProductionCost", "cost_budget=%f", costBudget)
|
|
|
|
// fmt.Println(costBudget, costExpedision, costOvk, costFeed, costPullet, depresiasiTransfer)
|
|
|
|
// depresiasiTransfer = 0
|
|
|
|
total := depresiasiTransfer + costPullet + costFeed + costOvk + costExpedision + costBudget
|
|
logHpp("GetTotalProductionCost", "done total=%f", total)
|
|
return total, nil
|
|
}
|
|
|
|
func (s *hppService) GetBudgetKandangLaying(projectFlockKandangId uint, endDate *time.Time) (float64, error) {
|
|
logHpp("GetBudgetKandangLaying", "start project_flock_kandang_id=%d end_date=%s", projectFlockKandangId, formatTimePtr(endDate))
|
|
// if date == nil {
|
|
// now := time.Now()
|
|
// date = &now
|
|
// }
|
|
|
|
if s.hppRepo == nil {
|
|
logHpp("GetBudgetKandangLaying", "repo_nil return=0")
|
|
return 0, nil
|
|
}
|
|
|
|
projectFlockId, err := s.hppRepo.GetProjectFlockIDByProjectFlockKandangID(context.Background(), projectFlockKandangId)
|
|
if err != nil {
|
|
logHpp("GetBudgetKandangLaying", "get_project_flock_id_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetBudgetKandangLaying", "project_flock_id=%d", projectFlockId)
|
|
|
|
projectFlockKandangIds, err := s.hppRepo.GetProjectFlockKandangIDs(context.Background(), projectFlockId)
|
|
if err != nil {
|
|
logHpp("GetBudgetKandangLaying", "get_project_flock_kandang_ids_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetBudgetKandangLaying", "project_flock_kandang_ids=%v", projectFlockKandangIds)
|
|
|
|
eggProduksiPiecesFlock, _, err := s.hppRepo.GetEggProduksiPiecesAndWeightKgByProjectFlockKandangIds(context.Background(), projectFlockKandangIds, endDate)
|
|
if err != nil {
|
|
logHpp("GetBudgetKandangLaying", "get_egg_produksi_pieces_flock_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetBudgetKandangLaying", "egg_produksi_pieces_flock=%f", eggProduksiPiecesFlock)
|
|
|
|
eggProduksiPiecesKandang, _, err := s.hppRepo.GetEggProduksiPiecesAndWeightKgByProjectFlockKandangIds(context.Background(), []uint{projectFlockKandangId}, endDate)
|
|
if err != nil {
|
|
logHpp("GetBudgetKandangLaying", "get_egg_produksi_pieces_kandang_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetBudgetKandangLaying", "egg_produksi_pieces_kandang=%f", eggProduksiPiecesKandang)
|
|
|
|
totalBudgetCost, err := s.hppRepo.GetBudgetCostByProjectFlockId(context.Background(), projectFlockId)
|
|
if err != nil {
|
|
logHpp("GetBudgetKandangLaying", "get_budget_cost_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetBudgetKandangLaying", "total_budget_cost=%f", totalBudgetCost)
|
|
|
|
if eggProduksiPiecesFlock == 0 {
|
|
logHpp("GetBudgetKandangLaying", "egg_produksi_pieces_flock_zero return=0")
|
|
return 0, nil
|
|
}
|
|
|
|
result := (totalBudgetCost * eggProduksiPiecesKandang) / eggProduksiPiecesFlock
|
|
logHpp("GetBudgetKandangLaying", "done result=%f", result)
|
|
return result, nil
|
|
}
|
|
|
|
func (s *hppService) GetDepresiasiTransfer(projectFlockKandangId uint, endDate *time.Time) (float64, error) {
|
|
logHpp("GetDepresiasiTransfer", "start project_flock_kandang_id=%d end_date=%s", projectFlockKandangId, formatTimePtr(endDate))
|
|
if endDate == nil {
|
|
now := time.Now()
|
|
endDate = &now
|
|
}
|
|
logHpp("GetDepresiasiTransfer", "normalized_end_date=%s", formatTimePtr(endDate))
|
|
|
|
if s.hppRepo == nil {
|
|
logHpp("GetDepresiasiTransfer", "repo_nil return=0")
|
|
return 0, nil
|
|
}
|
|
|
|
sourceProjectFlockID, transferTotalQty, err := s.hppRepo.GetTransferSourceSummary(context.Background(), projectFlockKandangId)
|
|
if err != nil {
|
|
logHpp("GetDepresiasiTransfer", "get_transfer_source_summary_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetDepresiasiTransfer", "source_project_flock_id=%d transfer_total_qty=%f", sourceProjectFlockID, transferTotalQty)
|
|
if sourceProjectFlockID == 0 || transferTotalQty <= 0 {
|
|
logHpp("GetDepresiasiTransfer", "use_manual_fallback=true")
|
|
result, fallbackErr := s.getManualDepresiasiTransferFallback(projectFlockKandangId)
|
|
if fallbackErr != nil {
|
|
logHpp("GetDepresiasiTransfer", "manual_fallback_error=%v", fallbackErr)
|
|
return 0, fallbackErr
|
|
}
|
|
logHpp("GetDepresiasiTransfer", "done_fallback result=%f", result)
|
|
return result, nil
|
|
}
|
|
|
|
kandangIDsGrowing, err := s.hppRepo.GetProjectFlockKandangIDs(context.Background(), sourceProjectFlockID)
|
|
if err != nil {
|
|
logHpp("GetDepresiasiTransfer", "get_project_flock_kandang_ids_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetDepresiasiTransfer", "kandang_ids_growing=%v", kandangIDsGrowing)
|
|
|
|
totalPopulationFlockGrowing, err := s.hppRepo.GetTotalPopulation(context.Background(), kandangIDsGrowing)
|
|
if err != nil {
|
|
logHpp("GetDepresiasiTransfer", "get_total_population_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetDepresiasiTransfer", "total_population_flock_growing=%f", totalPopulationFlockGrowing)
|
|
if totalPopulationFlockGrowing == 0 {
|
|
logHpp("GetDepresiasiTransfer", "total_population_flock_growing_zero return=0")
|
|
return 0, nil
|
|
}
|
|
|
|
totalDepresiasiFlockGrowing, err := s.GetTotalDepresiasiFlockGrowing(sourceProjectFlockID, endDate)
|
|
if err != nil {
|
|
logHpp("GetDepresiasiTransfer", "get_total_depresiasi_flock_growing_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("GetDepresiasiTransfer", "total_depresiasi_flock_growing=%f", totalDepresiasiFlockGrowing)
|
|
|
|
result := (totalDepresiasiFlockGrowing * transferTotalQty) / totalPopulationFlockGrowing
|
|
logHpp("GetDepresiasiTransfer", "done result=%f", result)
|
|
return result, nil
|
|
}
|
|
|
|
func (s *hppService) getManualDepresiasiTransferFallback(projectFlockKandangId uint) (float64, error) {
|
|
logHpp("getManualDepresiasiTransferFallback", "start project_flock_kandang_id=%d", projectFlockKandangId)
|
|
projectFlockID, err := s.hppRepo.GetProjectFlockIDByProjectFlockKandangID(context.Background(), projectFlockKandangId)
|
|
if err != nil {
|
|
logHpp("getManualDepresiasiTransferFallback", "get_project_flock_id_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("getManualDepresiasiTransferFallback", "project_flock_id=%d", projectFlockID)
|
|
if projectFlockID == 0 {
|
|
logHpp("getManualDepresiasiTransferFallback", "project_flock_id_zero return=0")
|
|
return 0, nil
|
|
}
|
|
|
|
manualCost, err := s.hppRepo.GetManualDepreciationCostByProjectFlockID(context.Background(), projectFlockID)
|
|
if err != nil {
|
|
logHpp("getManualDepresiasiTransferFallback", "get_manual_depreciation_cost_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("getManualDepresiasiTransferFallback", "manual_cost=%f", manualCost)
|
|
if manualCost <= 0 {
|
|
logHpp("getManualDepresiasiTransferFallback", "manual_cost_non_positive return=0")
|
|
return 0, nil
|
|
}
|
|
|
|
kandangIDs, err := s.hppRepo.GetProjectFlockKandangIDs(context.Background(), projectFlockID)
|
|
if err != nil {
|
|
logHpp("getManualDepresiasiTransferFallback", "get_project_flock_kandang_ids_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("getManualDepresiasiTransferFallback", "kandang_ids=%v", kandangIDs)
|
|
if len(kandangIDs) == 0 {
|
|
logHpp("getManualDepresiasiTransferFallback", "kandang_ids_empty return=0")
|
|
return 0, nil
|
|
}
|
|
|
|
totalUsageQty, err := s.hppRepo.GetTotalPopulation(context.Background(), kandangIDs)
|
|
if err != nil {
|
|
logHpp("getManualDepresiasiTransferFallback", "get_total_usage_qty_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("getManualDepresiasiTransferFallback", "total_usage_qty=%f", totalUsageQty)
|
|
if totalUsageQty <= 0 {
|
|
logHpp("getManualDepresiasiTransferFallback", "total_usage_qty_non_positive return=0")
|
|
return 0, nil
|
|
}
|
|
|
|
kandangUsageQty, err := s.hppRepo.GetTotalPopulation(context.Background(), []uint{projectFlockKandangId})
|
|
if err != nil {
|
|
logHpp("getManualDepresiasiTransferFallback", "get_kandang_usage_qty_error=%v", err)
|
|
return 0, err
|
|
}
|
|
logHpp("getManualDepresiasiTransferFallback", "kandang_usage_qty=%f", kandangUsageQty)
|
|
if kandangUsageQty <= 0 {
|
|
logHpp("getManualDepresiasiTransferFallback", "kandang_usage_qty_non_positive return=0")
|
|
return 0, nil
|
|
}
|
|
|
|
result := manualCost * (kandangUsageQty / totalUsageQty)
|
|
logHpp("getManualDepresiasiTransferFallback", "done result=%f", result)
|
|
return result, nil
|
|
}
|
|
|
|
func (s *hppService) GetHppEstimationDanRealisasi(totalProductionCost float64, projectFlockKandangId uint, startDate *time.Time, endDate *time.Time) (*HppCostResponse, error) {
|
|
logHpp("GetHppEstimationDanRealisasi", "start total_production_cost=%f project_flock_kandang_id=%d start_date=%s end_date=%s", totalProductionCost, projectFlockKandangId, formatTimePtr(startDate), formatTimePtr(endDate))
|
|
|
|
if s.hppRepo == nil {
|
|
logHpp("GetHppEstimationDanRealisasi", "repo_nil return_empty_response")
|
|
return &HppCostResponse{}, nil
|
|
}
|
|
|
|
estimPieces, estimWeightKg, err := s.hppRepo.GetEggProduksiPiecesAndWeightKgByProjectFlockKandangIds(context.Background(), []uint{projectFlockKandangId}, endDate)
|
|
if err != nil {
|
|
logHpp("GetHppEstimationDanRealisasi", "get_egg_produksi_error=%v", err)
|
|
return nil, err
|
|
}
|
|
logHpp("GetHppEstimationDanRealisasi", "estim_pieces=%f estim_weight_kg=%f", estimPieces, estimWeightKg)
|
|
|
|
realPieces, realWeightKg, err := s.hppRepo.GetEggTerjualPiecesAndWeightKgByProjectFlockKandangIds(context.Background(), []uint{projectFlockKandangId}, startDate, endDate)
|
|
if err != nil {
|
|
logHpp("GetHppEstimationDanRealisasi", "get_egg_terjual_error=%v", err)
|
|
return nil, err
|
|
}
|
|
logHpp("GetHppEstimationDanRealisasi", "real_pieces=%f real_weight_kg=%f", realPieces, realWeightKg)
|
|
|
|
estimation := HppCostDetail{
|
|
Total: totalProductionCost,
|
|
Kg: estimWeightKg,
|
|
Butir: estimPieces,
|
|
}
|
|
if estimWeightKg > 0 {
|
|
estimation.HargaKg = roundToTwoDecimals(totalProductionCost / estimWeightKg)
|
|
}
|
|
if estimPieces > 0 {
|
|
estimation.HargaButir = roundToTwoDecimals(totalProductionCost / estimPieces)
|
|
}
|
|
logHpp("GetHppEstimationDanRealisasi", "estimation=%+v", estimation)
|
|
|
|
real := HppCostDetail{
|
|
Total: totalProductionCost,
|
|
Kg: realWeightKg,
|
|
Butir: realPieces,
|
|
}
|
|
if realWeightKg > 0 {
|
|
real.HargaKg = roundToTwoDecimals(totalProductionCost / realWeightKg)
|
|
}
|
|
if realPieces > 0 {
|
|
real.HargaButir = roundToTwoDecimals(totalProductionCost / realPieces)
|
|
}
|
|
logHpp("GetHppEstimationDanRealisasi", "real=%+v", real)
|
|
|
|
result := &HppCostResponse{
|
|
Estimation: estimation,
|
|
Real: real,
|
|
}
|
|
logHpp("GetHppEstimationDanRealisasi", "done response=%+v", *result)
|
|
return result, nil
|
|
}
|
|
|
|
func roundToTwoDecimals(value float64) float64 {
|
|
result := math.Round(value*100) / 100
|
|
logHpp("roundToTwoDecimals", "input=%f output=%f", value, result)
|
|
return result
|
|
}
|
|
|
|
func formatTimePtr(value *time.Time) string {
|
|
if value == nil {
|
|
return "<nil>"
|
|
}
|
|
return value.Format(time.RFC3339)
|
|
}
|
|
|
|
func logHpp(method, format string, args ...any) {
|
|
log.Printf("[HPP][%s] "+format, append([]any{method}, args...)...)
|
|
}
|