mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-23 23:05:44 +00:00
feat[BE]: enhance GetOverhead functionality with project flock kandang count mapping and update related DTOs
This commit is contained in:
@@ -184,7 +184,7 @@ func (u *ClosingController) GetPenjualanByProjectFlockKandang(c *fiber.Ctx) erro
|
|||||||
|
|
||||||
func (u *ClosingController) GetOverhead(c *fiber.Ctx) error {
|
func (u *ClosingController) GetOverhead(c *fiber.Ctx) error {
|
||||||
projectParam := c.Params("project_flock_id")
|
projectParam := c.Params("project_flock_id")
|
||||||
kandangParam := c.Params("project_flock_kandang_id") // bisa kosong
|
kandangParam := c.Params("project_flock_kandang_id")
|
||||||
|
|
||||||
projectFlockID, err := strconv.Atoi(projectParam)
|
projectFlockID, err := strconv.Atoi(projectParam)
|
||||||
if err != nil || projectFlockID <= 0 {
|
if err != nil || projectFlockID <= 0 {
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ func ToOverheadDTO(budget *entity.ProjectBudget, realization *entity.ExpenseReal
|
|||||||
return dto
|
return dto
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToOverheadListDTOs(budgets []entity.ProjectBudget, realizations []entity.ExpenseRealization, totalChickinQty, totalActualPopulation float64, isPerKandang bool, totalKandangCount int) OverheadListDTO {
|
func ToOverheadListDTOs(budgets []entity.ProjectBudget, realizations []entity.ExpenseRealization, totalChickinQty, totalActualPopulation float64, isPerKandang bool, totalKandangCount int, projectFlockKandangCountMap map[uint]int) OverheadListDTO {
|
||||||
overheadsByNonstockID := make(map[uint]*OverheadDTO)
|
overheadsByNonstockID := make(map[uint]*OverheadDTO)
|
||||||
latestDateByNonstockID := make(map[uint]string)
|
latestDateByNonstockID := make(map[uint]string)
|
||||||
|
|
||||||
@@ -89,6 +89,7 @@ func ToOverheadListDTOs(budgets []entity.ProjectBudget, realizations []entity.Ex
|
|||||||
budgetPrice := budgets[i].Price
|
budgetPrice := budgets[i].Price
|
||||||
budgetTotal := calculateTotal(budgets[i].Qty, budgets[i].Price)
|
budgetTotal := calculateTotal(budgets[i].Qty, budgets[i].Price)
|
||||||
|
|
||||||
|
// Budget division: per kandang view only
|
||||||
if isPerKandang && totalKandangCount > 0 {
|
if isPerKandang && totalKandangCount > 0 {
|
||||||
budgetQty = budgetQty / float64(totalKandangCount)
|
budgetQty = budgetQty / float64(totalKandangCount)
|
||||||
budgetTotal = budgetTotal / float64(totalKandangCount)
|
budgetTotal = budgetTotal / float64(totalKandangCount)
|
||||||
@@ -109,17 +110,35 @@ func ToOverheadListDTOs(budgets []entity.ProjectBudget, realizations []entity.Ex
|
|||||||
overheadsByNonstockID[nonstockID] = &OverheadDTO{}
|
overheadsByNonstockID[nonstockID] = &OverheadDTO{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this is farm-level expense (multiple project flocks)
|
|
||||||
qty := realizations[i].Qty
|
qty := realizations[i].Qty
|
||||||
totalAmount := calculateTotal(realizations[i].Qty, realizations[i].Price)
|
totalAmount := calculateTotal(realizations[i].Qty, realizations[i].Price)
|
||||||
|
|
||||||
|
// Farm-level expense division
|
||||||
if realizations[i].ExpenseNonstock.Expense != nil &&
|
if realizations[i].ExpenseNonstock.Expense != nil &&
|
||||||
realizations[i].ExpenseNonstock.Expense.ProjectFlockId != nil {
|
realizations[i].ExpenseNonstock.Expense.ProjectFlockId != nil {
|
||||||
projectFlockCount := countProjectFlocksInJSON(*realizations[i].ExpenseNonstock.Expense.ProjectFlockId)
|
projectFlockIDs := parseProjectFlockIDsFromJSON(*realizations[i].ExpenseNonstock.Expense.ProjectFlockId)
|
||||||
if projectFlockCount > 1 {
|
|
||||||
// Bagi biaya sesuai jumlah project flock
|
if len(projectFlockIDs) > 0 {
|
||||||
qty = qty / float64(projectFlockCount)
|
totalKandangInAllProjects := 0
|
||||||
totalAmount = totalAmount / float64(projectFlockCount)
|
for _, pfID := range projectFlockIDs {
|
||||||
|
if count, exists := projectFlockKandangCountMap[pfID]; exists {
|
||||||
|
totalKandangInAllProjects += count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if totalKandangInAllProjects > 0 {
|
||||||
|
if isPerKandang {
|
||||||
|
qty = qty / float64(totalKandangInAllProjects)
|
||||||
|
totalAmount = totalAmount / float64(totalKandangInAllProjects)
|
||||||
|
} else {
|
||||||
|
// Overhead ALL: divide by total kandang then multiply by this project's kandang count
|
||||||
|
perKandangAmount := totalAmount / float64(totalKandangInAllProjects)
|
||||||
|
perKandangQty := qty / float64(totalKandangInAllProjects)
|
||||||
|
|
||||||
|
qty = perKandangQty * float64(totalKandangCount)
|
||||||
|
totalAmount = perKandangAmount * float64(totalKandangCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,22 +191,24 @@ func ToOverheadListDTOs(budgets []entity.ProjectBudget, realizations []entity.Ex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Helper Functions ===
|
func parseProjectFlockIDsFromJSON(projectFlockJSON string) []uint {
|
||||||
|
if projectFlockJSON == "" {
|
||||||
|
return []uint{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var projectFlocks []uint
|
||||||
|
if err := json.Unmarshal([]byte(projectFlockJSON), &projectFlocks); err != nil {
|
||||||
|
return []uint{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return projectFlocks
|
||||||
|
}
|
||||||
|
|
||||||
func countProjectFlocksInJSON(projectFlockJSON string) int {
|
func countProjectFlocksInJSON(projectFlockJSON string) int {
|
||||||
if projectFlockJSON == "" {
|
projectFlocks := parseProjectFlockIDsFromJSON(projectFlockJSON)
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var projectFlocks []int
|
|
||||||
if err := json.Unmarshal([]byte(projectFlockJSON), &projectFlocks); err != nil {
|
|
||||||
return 1 // default to 1 if parsing fails
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(projectFlocks) == 0 {
|
if len(projectFlocks) == 0 {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return len(projectFlocks)
|
return len(projectFlocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -368,13 +369,38 @@ func (s closingService) GetOverhead(c *fiber.Ctx, projectFlockID uint, projectFl
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count total kandang in project flock (for budget division if per kandang)
|
|
||||||
projectFlockKandangs, err := s.ProjectFlockKandangRepo.GetByProjectFlockID(c.Context(), projectFlockID)
|
projectFlockKandangs, err := s.ProjectFlockKandangRepo.GetByProjectFlockID(c.Context(), projectFlockID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
totalKandangCount := len(projectFlockKandangs)
|
totalKandangCount := len(projectFlockKandangs)
|
||||||
|
|
||||||
|
// Build kandang count map for farm expense division
|
||||||
|
projectFlockKandangCountMap := make(map[uint]int)
|
||||||
|
projectFlockKandangCountMap[projectFlockID] = totalKandangCount
|
||||||
|
|
||||||
|
involvedProjectFlocks := make(map[uint]bool)
|
||||||
|
for _, realization := range realizations {
|
||||||
|
if realization.ExpenseNonstock != nil &&
|
||||||
|
realization.ExpenseNonstock.Expense != nil &&
|
||||||
|
realization.ExpenseNonstock.Expense.ProjectFlockId != nil {
|
||||||
|
var projectFlockIDs []uint
|
||||||
|
if err := json.Unmarshal([]byte(*realization.ExpenseNonstock.Expense.ProjectFlockId), &projectFlockIDs); err == nil {
|
||||||
|
for _, pfID := range projectFlockIDs {
|
||||||
|
if pfID != projectFlockID {
|
||||||
|
involvedProjectFlocks[pfID] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for pfID := range involvedProjectFlocks {
|
||||||
|
if pfKandangs, err := s.ProjectFlockKandangRepo.GetByProjectFlockID(c.Context(), pfID); err == nil {
|
||||||
|
projectFlockKandangCountMap[pfID] = len(pfKandangs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
chickins, err := s.ChickinRepo.GetByProjectFlockID(c.Context(), projectFlockID)
|
chickins, err := s.ChickinRepo.GetByProjectFlockID(c.Context(), projectFlockID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -384,7 +410,6 @@ func (s closingService) GetOverhead(c *fiber.Ctx, projectFlockID uint, projectFl
|
|||||||
var totalDepletion float64
|
var totalDepletion float64
|
||||||
|
|
||||||
if projectFlockKandangID != nil {
|
if projectFlockKandangID != nil {
|
||||||
|
|
||||||
for _, chickin := range chickins {
|
for _, chickin := range chickins {
|
||||||
if chickin.ProjectFlockKandangId == *projectFlockKandangID {
|
if chickin.ProjectFlockKandangId == *projectFlockKandangID {
|
||||||
totalChickinQty += chickin.UsageQty
|
totalChickinQty += chickin.UsageQty
|
||||||
@@ -404,7 +429,6 @@ func (s closingService) GetOverhead(c *fiber.Ctx, projectFlockID uint, projectFl
|
|||||||
totalDepletion = depletionResult
|
totalDepletion = depletionResult
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
for _, chickin := range chickins {
|
for _, chickin := range chickins {
|
||||||
totalChickinQty += chickin.UsageQty
|
totalChickinQty += chickin.UsageQty
|
||||||
}
|
}
|
||||||
@@ -417,7 +441,7 @@ func (s closingService) GetOverhead(c *fiber.Ctx, projectFlockID uint, projectFl
|
|||||||
|
|
||||||
totalActualPopulation := totalChickinQty - totalDepletion
|
totalActualPopulation := totalChickinQty - totalDepletion
|
||||||
|
|
||||||
result := dto.ToOverheadListDTOs(budgets, realizations, totalChickinQty, totalActualPopulation, projectFlockKandangID != nil, totalKandangCount)
|
result := dto.ToOverheadListDTOs(budgets, realizations, totalChickinQty, totalActualPopulation, projectFlockKandangID != nil, totalKandangCount, projectFlockKandangCountMap)
|
||||||
|
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,18 +72,14 @@ func (r *ExpenseRealizationRepositoryImpl) GetClosingOverhead(ctx context.Contex
|
|||||||
Joins("LEFT JOIN kandangs ON kandangs.id = expense_nonstocks.kandang_id").
|
Joins("LEFT JOIN kandangs ON kandangs.id = expense_nonstocks.kandang_id").
|
||||||
Where("expenses.realization_date IS NOT NULL")
|
Where("expenses.realization_date IS NOT NULL")
|
||||||
|
|
||||||
// Build WHERE clause for project flock filtering
|
|
||||||
if projectFlockKandangID != nil {
|
if projectFlockKandangID != nil {
|
||||||
// Per kandang: hanya ambil expense yang specific ke kandang tersebut
|
|
||||||
// SKIP expense level farm (yang punya multiple project flocks di JSON array)
|
|
||||||
// IMPORTANT: Untuk kandang_id, pastikan kandang tersebut belong to project_flock_kandang ini
|
|
||||||
db = db.Where(`(
|
db = db.Where(`(
|
||||||
expense_nonstocks.project_flock_kandang_id = ? OR
|
expense_nonstocks.project_flock_kandang_id = ? OR
|
||||||
(expense_nonstocks.kandang_id = (SELECT kandang_id FROM project_flock_kandangs WHERE id = ?) AND
|
(expense_nonstocks.kandang_id = (SELECT kandang_id FROM project_flock_kandangs WHERE id = ?) AND
|
||||||
expense_nonstocks.project_flock_kandang_id IS NULL)
|
expense_nonstocks.project_flock_kandang_id IS NULL) OR
|
||||||
)`, *projectFlockKandangID, *projectFlockKandangID)
|
(expenses.project_flock_id IS NOT NULL AND expenses.project_flock_id::jsonb @> ?::jsonb)
|
||||||
|
)`, *projectFlockKandangID, *projectFlockKandangID, fmt.Sprintf("[%d]", projectFlockID))
|
||||||
} else {
|
} else {
|
||||||
// All kandang: include expense kandang-specific DAN expense level farm
|
|
||||||
db = db.Where(`(
|
db = db.Where(`(
|
||||||
project_flock_kandangs.project_flock_id = ? OR
|
project_flock_kandangs.project_flock_id = ? OR
|
||||||
kandangs.id IN (SELECT kandang_id FROM project_flock_kandangs WHERE project_flock_id = ?) OR
|
kandangs.id IN (SELECT kandang_id FROM project_flock_kandangs WHERE project_flock_id = ?) OR
|
||||||
|
|||||||
Reference in New Issue
Block a user