mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
[FEAT/BE] fixing overhead,sapronak,perhitungan sapronak
This commit is contained in:
@@ -2,7 +2,6 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -33,6 +32,14 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type activeKandangMetric struct {
|
||||
ProjectFlockKandangID uint
|
||||
ProjectFlockID uint
|
||||
KandangID uint
|
||||
Category string
|
||||
Metric float64
|
||||
}
|
||||
|
||||
type ClosingService interface {
|
||||
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]dto.ClosingListItemDTO, int64, error)
|
||||
GetProjectFlockByID(ctx *fiber.Ctx, id uint) (*entity.ProjectFlock, error)
|
||||
@@ -385,6 +392,11 @@ func (s closingService) GetClosingSapronak(c *fiber.Ctx, projectFlockID uint, pa
|
||||
}
|
||||
|
||||
offset := (params.Page - 1) * params.Limit
|
||||
startDate, endDate, err := s.getSapronakDateRange(c.Context(), projectFlockID, params.KandangID)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to resolve sapronak date range for project flock %d: %+v", projectFlockID, err)
|
||||
return nil, 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to resolve sapronak date range")
|
||||
}
|
||||
rows, totalResults, err := s.Repository.GetSapronak(c.Context(), repository.SapronakQueryParams{
|
||||
Type: params.Type,
|
||||
WarehouseIDs: warehouseIDs,
|
||||
@@ -392,6 +404,8 @@ func (s closingService) GetClosingSapronak(c *fiber.Ctx, projectFlockID uint, pa
|
||||
Limit: params.Limit,
|
||||
Offset: offset,
|
||||
Search: params.Search,
|
||||
StartDate: startDate,
|
||||
EndDate: endDate,
|
||||
})
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to fetch sapronak %s for project flock %d: %+v", params.Type, projectFlockID, err)
|
||||
@@ -468,11 +482,19 @@ func (s closingService) GetClosingSapronakSummary(c *fiber.Ctx, projectFlockID u
|
||||
}
|
||||
}
|
||||
|
||||
startDate, endDate, err := s.getSapronakDateRange(c.Context(), projectFlockID, params.KandangID)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to resolve sapronak date range for project flock %d: %+v", projectFlockID, err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to resolve sapronak date range")
|
||||
}
|
||||
|
||||
rows, err := s.Repository.GetSapronakSummary(c.Context(), repository.SapronakQueryParams{
|
||||
Type: params.Type,
|
||||
WarehouseIDs: warehouseIDs,
|
||||
ProjectFlockKandangIDs: projectFlockKandangIDs,
|
||||
Search: params.Search,
|
||||
StartDate: startDate,
|
||||
EndDate: endDate,
|
||||
})
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to fetch sapronak %s summary for project flock %d: %+v", params.Type, projectFlockID, err)
|
||||
@@ -542,6 +564,90 @@ func (s closingService) getProjectFlockKandangIDs(ctx context.Context, projectFl
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func (s closingService) getSapronakDateRange(ctx context.Context, projectFlockID uint, kandangID *uint) (*time.Time, *time.Time, error) {
|
||||
db := s.Repository.DB().WithContext(ctx)
|
||||
|
||||
if kandangID != nil && *kandangID > 0 {
|
||||
var pfk entity.ProjectFlockKandang
|
||||
if err := db.Select("id, created_at, closed_at").First(&pfk, *kandangID).Error; err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var minChickin *time.Time
|
||||
if err := db.Table("project_chickins").
|
||||
Select("MIN(chick_in_date)").
|
||||
Where("project_flock_kandang_id = ?", pfk.Id).
|
||||
Scan(&minChickin).Error; err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
start := pfk.CreatedAt
|
||||
if minChickin != nil && !minChickin.IsZero() {
|
||||
start = *minChickin
|
||||
}
|
||||
startDate := dateOnlyUTC(start)
|
||||
|
||||
var endDate *time.Time
|
||||
if pfk.ClosedAt != nil {
|
||||
d := dateOnlyUTC(*pfk.ClosedAt)
|
||||
endDate = &d
|
||||
}
|
||||
|
||||
return &startDate, endDate, nil
|
||||
}
|
||||
|
||||
var minCreated time.Time
|
||||
if err := db.Model(&entity.ProjectFlockKandang{}).
|
||||
Select("MIN(created_at)").
|
||||
Where("project_flock_id = ?", projectFlockID).
|
||||
Scan(&minCreated).Error; err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var minChickin *time.Time
|
||||
if err := db.Table("project_chickins pc").
|
||||
Select("MIN(pc.chick_in_date)").
|
||||
Joins("JOIN project_flock_kandangs pfk ON pfk.id = pc.project_flock_kandang_id").
|
||||
Where("pfk.project_flock_id = ?", projectFlockID).
|
||||
Scan(&minChickin).Error; err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
start := minCreated
|
||||
if minChickin != nil && !minChickin.IsZero() {
|
||||
start = *minChickin
|
||||
}
|
||||
startDate := dateOnlyUTC(start)
|
||||
|
||||
var endDate *time.Time
|
||||
var openCount int64
|
||||
if err := db.Model(&entity.ProjectFlockKandang{}).
|
||||
Where("project_flock_id = ? AND closed_at IS NULL", projectFlockID).
|
||||
Count(&openCount).Error; err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if openCount == 0 {
|
||||
var maxClosed *time.Time
|
||||
if err := db.Model(&entity.ProjectFlockKandang{}).
|
||||
Select("MAX(closed_at)").
|
||||
Where("project_flock_id = ?", projectFlockID).
|
||||
Scan(&maxClosed).Error; err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if maxClosed != nil && !maxClosed.IsZero() {
|
||||
d := dateOnlyUTC(*maxClosed)
|
||||
endDate = &d
|
||||
}
|
||||
}
|
||||
|
||||
return &startDate, endDate, nil
|
||||
}
|
||||
|
||||
func dateOnlyUTC(t time.Time) time.Time {
|
||||
u := t.UTC()
|
||||
return time.Date(u.Year(), u.Month(), u.Day(), 0, 0, 0, 0, time.UTC)
|
||||
}
|
||||
|
||||
func formatQuantity(qty float64, uom string) string {
|
||||
qtyStr := strconv.FormatFloat(qty, 'f', -1, 64)
|
||||
if uom == "" {
|
||||
@@ -616,38 +722,17 @@ func (s closingService) GetOverhead(c *fiber.Ctx, projectFlockID uint, projectFl
|
||||
return nil, err
|
||||
}
|
||||
|
||||
realizations, err = s.allocateFarmOverheadRealizations(c.Context(), projectFlockID, projectFlockKandangID, realizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectFlockKandangs, err := s.ProjectFlockKandangRepo.GetByProjectFlockID(c.Context(), projectFlockID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -688,11 +773,197 @@ func (s closingService) GetOverhead(c *fiber.Ctx, projectFlockID uint, projectFl
|
||||
|
||||
totalActualPopulation := totalChickinQty - totalDepletion
|
||||
|
||||
result := dto.ToOverheadListDTOs(budgets, realizations, totalChickinQty, totalActualPopulation, projectFlockKandangID != nil, totalKandangCount, projectFlockKandangCountMap)
|
||||
result := dto.ToOverheadListDTOs(budgets, realizations, totalChickinQty, totalActualPopulation, projectFlockKandangID != nil, totalKandangCount)
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
type activeKandangMetricRow struct {
|
||||
ProjectFlockKandangID uint `gorm:"column:project_flock_kandang_id"`
|
||||
ProjectFlockID uint `gorm:"column:project_flock_id"`
|
||||
KandangID uint `gorm:"column:kandang_id"`
|
||||
Category string `gorm:"column:category"`
|
||||
ChickinQty float64 `gorm:"column:chickin_qty"`
|
||||
DepletionQty float64 `gorm:"column:depletion_qty"`
|
||||
EggQty float64 `gorm:"column:egg_qty"`
|
||||
}
|
||||
|
||||
func (s closingService) getActiveKandangMetrics(ctx context.Context, locationID uint, transactionDate time.Time) ([]activeKandangMetric, error) {
|
||||
db := s.Repository.DB().WithContext(ctx)
|
||||
|
||||
rows := []activeKandangMetricRow{}
|
||||
rawSQL := `
|
||||
SELECT
|
||||
pfk.id AS project_flock_kandang_id,
|
||||
pfk.project_flock_id AS project_flock_id,
|
||||
pfk.kandang_id AS kandang_id,
|
||||
pf.category AS category,
|
||||
COALESCE((
|
||||
SELECT SUM(pc.usage_qty)
|
||||
FROM project_chickins pc
|
||||
WHERE pc.project_flock_kandang_id = pfk.id
|
||||
AND pc.chick_in_date::date <= ?
|
||||
), 0) AS chickin_qty,
|
||||
COALESCE((
|
||||
SELECT SUM(rd.qty)
|
||||
FROM recording_depletions rd
|
||||
JOIN recordings r ON r.id = rd.recording_id
|
||||
WHERE r.project_flock_kandangs_id = pfk.id
|
||||
AND r.record_datetime::date <= ?
|
||||
), 0) AS depletion_qty,
|
||||
COALESCE((
|
||||
SELECT SUM(re.qty)
|
||||
FROM recording_eggs re
|
||||
JOIN recordings r2 ON r2.id = re.recording_id
|
||||
WHERE r2.project_flock_kandangs_id = pfk.id
|
||||
AND r2.record_datetime::date <= ?
|
||||
), 0) AS egg_qty
|
||||
FROM project_flock_kandangs pfk
|
||||
JOIN project_flocks pf ON pf.id = pfk.project_flock_id
|
||||
WHERE pf.location_id = ?
|
||||
AND (pfk.closed_at IS NULL OR pfk.closed_at::date > ?)
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM project_chickins pc2
|
||||
WHERE pc2.project_flock_kandang_id = pfk.id
|
||||
AND pc2.chick_in_date::date <= ?
|
||||
)
|
||||
`
|
||||
if err := db.Raw(rawSQL, transactionDate, transactionDate, transactionDate, locationID, transactionDate, transactionDate).Scan(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]activeKandangMetric, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
metric := 0.0
|
||||
switch strings.ToLower(strings.TrimSpace(row.Category)) {
|
||||
case "growing":
|
||||
metric = row.ChickinQty
|
||||
case "laying":
|
||||
metric = row.EggQty
|
||||
default:
|
||||
s.Log.Warnf("Unknown project flock category for overhead allocation: %s (pfk=%d)", row.Category, row.ProjectFlockKandangID)
|
||||
}
|
||||
|
||||
result = append(result, activeKandangMetric{
|
||||
ProjectFlockKandangID: row.ProjectFlockKandangID,
|
||||
ProjectFlockID: row.ProjectFlockID,
|
||||
KandangID: row.KandangID,
|
||||
Category: row.Category,
|
||||
Metric: metric,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func round2(value float64) float64 {
|
||||
return math.Round(value*100) / 100
|
||||
}
|
||||
|
||||
func allocateFarmLevelQty(totalQty float64, metrics []activeKandangMetric) map[uint]float64 {
|
||||
allocations := make(map[uint]float64, len(metrics))
|
||||
if totalQty == 0 || len(metrics) == 0 {
|
||||
return allocations
|
||||
}
|
||||
|
||||
totalMetric := 0.0
|
||||
var maxMetric float64
|
||||
var maxMetricID uint
|
||||
for _, m := range metrics {
|
||||
if m.Metric <= 0 {
|
||||
continue
|
||||
}
|
||||
totalMetric += m.Metric
|
||||
if m.Metric > maxMetric || maxMetricID == 0 {
|
||||
maxMetric = m.Metric
|
||||
maxMetricID = m.ProjectFlockKandangID
|
||||
}
|
||||
}
|
||||
if totalMetric == 0 {
|
||||
return allocations
|
||||
}
|
||||
|
||||
sumRounded := 0.0
|
||||
for _, m := range metrics {
|
||||
if m.Metric <= 0 {
|
||||
continue
|
||||
}
|
||||
portion := totalQty * (m.Metric / totalMetric)
|
||||
rounded := round2(portion)
|
||||
allocations[m.ProjectFlockKandangID] = rounded
|
||||
sumRounded += rounded
|
||||
}
|
||||
|
||||
diff := totalQty - sumRounded
|
||||
if maxMetricID != 0 && diff != 0 {
|
||||
allocations[maxMetricID] = round2(allocations[maxMetricID] + diff)
|
||||
}
|
||||
|
||||
return allocations
|
||||
}
|
||||
|
||||
func (s closingService) allocateFarmOverheadRealizations(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint, realizations []entity.ExpenseRealization) ([]entity.ExpenseRealization, error) {
|
||||
if len(realizations) == 0 {
|
||||
return realizations, nil
|
||||
}
|
||||
|
||||
cache := make(map[string][]activeKandangMetric)
|
||||
allocated := make([]entity.ExpenseRealization, 0, len(realizations))
|
||||
|
||||
for _, realization := range realizations {
|
||||
expenseNonstock := realization.ExpenseNonstock
|
||||
if expenseNonstock == nil || expenseNonstock.Expense == nil {
|
||||
allocated = append(allocated, realization)
|
||||
continue
|
||||
}
|
||||
|
||||
// If already bound to a specific project flock kandang, don't re-allocate.
|
||||
if expenseNonstock.ProjectFlockKandangId != nil {
|
||||
allocated = append(allocated, realization)
|
||||
continue
|
||||
}
|
||||
|
||||
expense := expenseNonstock.Expense
|
||||
locationID := uint(expense.LocationId)
|
||||
txDate := expense.RealizationDate
|
||||
|
||||
cacheKey := fmt.Sprintf("%d|%s", locationID, txDate.Format("2006-01-02"))
|
||||
metrics, exists := cache[cacheKey]
|
||||
if !exists {
|
||||
var err error
|
||||
metrics, err = s.getActiveKandangMetrics(ctx, locationID, txDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cache[cacheKey] = metrics
|
||||
}
|
||||
|
||||
allocations := allocateFarmLevelQty(realization.Qty, metrics)
|
||||
allocatedQty := 0.0
|
||||
if projectFlockKandangID != nil {
|
||||
allocatedQty = allocations[*projectFlockKandangID]
|
||||
} else {
|
||||
for _, m := range metrics {
|
||||
if m.ProjectFlockID == projectFlockID {
|
||||
allocatedQty += allocations[m.ProjectFlockKandangID]
|
||||
}
|
||||
}
|
||||
allocatedQty = round2(allocatedQty)
|
||||
}
|
||||
|
||||
adj := realization
|
||||
adj.Qty = allocatedQty
|
||||
if adj.Qty == 0 {
|
||||
adj.Price = realization.Price
|
||||
}
|
||||
|
||||
allocated = append(allocated, adj)
|
||||
}
|
||||
|
||||
return allocated, nil
|
||||
}
|
||||
|
||||
func (s closingService) GetExpeditionHPP(c *fiber.Ctx, projectFlockID uint, projectFlockKandangID *uint) (*dto.ExpeditionHPPDTO, error) {
|
||||
if projectFlockKandangID != nil {
|
||||
if err := m.EnsureProjectFlockKandangAccess(c, s.Repository.DB(), projectFlockID, *projectFlockKandangID); err != nil {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
@@ -123,7 +124,7 @@ func (s sapronakService) computeSapronakReports(ctx context.Context, params *val
|
||||
continue
|
||||
}
|
||||
|
||||
// We no longer filter by date for closing sapronak report; pass nil pointers.
|
||||
// Filter sapronak data by project flock period range.
|
||||
items, groups, totalIncoming, totalUsage, err := s.buildSapronakItems(ctx, pfk, params.Flag)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to build sapronak items for pfk %d: %+v", pfk.Id, err)
|
||||
@@ -379,33 +380,33 @@ func buildSapronakDetails(
|
||||
}
|
||||
|
||||
func (s sapronakService) buildSapronakItems(ctx context.Context, pfk entity.ProjectFlockKandang, flagFilter string) ([]dto.SapronakItemDTO, []dto.SapronakGroupDTO, float64, float64, error) {
|
||||
// For sapronak closing report we intentionally ignore date range
|
||||
// and aggregate all historical transactions for the kandang/project.
|
||||
incomingRows, err := s.Repository.FetchSapronakIncoming(ctx, pfk.KandangId)
|
||||
// Filter by project flock period (start = first chickin or pfk created_at, end = closed_at if any).
|
||||
startDate, endDate := sapronakPeriodRange(pfk)
|
||||
incomingRows, err := s.Repository.FetchSapronakIncoming(ctx, pfk.KandangId, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, nil, 0, 0, err
|
||||
}
|
||||
incomingDetailsRows, err := s.Repository.FetchSapronakIncomingDetails(ctx, pfk.KandangId)
|
||||
incomingDetailsRows, err := s.Repository.FetchSapronakIncomingDetails(ctx, pfk.KandangId, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, nil, 0, 0, err
|
||||
}
|
||||
usageRows, err := s.Repository.FetchSapronakUsage(ctx, pfk.Id)
|
||||
usageRows, err := s.Repository.FetchSapronakUsage(ctx, pfk.Id, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, nil, 0, 0, err
|
||||
}
|
||||
chickinUsageRows, err := s.Repository.FetchSapronakChickinUsage(ctx, pfk.Id)
|
||||
chickinUsageRows, err := s.Repository.FetchSapronakChickinUsage(ctx, pfk.Id, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, nil, 0, 0, err
|
||||
}
|
||||
usageDetailsRows, err := s.Repository.FetchSapronakUsageDetails(ctx, pfk.Id)
|
||||
usageDetailsRows, err := s.Repository.FetchSapronakUsageDetails(ctx, pfk.Id, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, nil, 0, 0, err
|
||||
}
|
||||
chickinUsageDetailsRows, err := s.Repository.FetchSapronakChickinUsageDetails(ctx, pfk.Id)
|
||||
chickinUsageDetailsRows, err := s.Repository.FetchSapronakChickinUsageDetails(ctx, pfk.Id, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, nil, 0, 0, err
|
||||
}
|
||||
usageAllocatedDetails, err := s.Repository.FetchSapronakUsageAllocatedDetails(ctx, pfk.Id)
|
||||
usageAllocatedDetails, err := s.Repository.FetchSapronakUsageAllocatedDetails(ctx, pfk.Id, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, nil, 0, 0, err
|
||||
}
|
||||
@@ -413,15 +414,15 @@ func (s sapronakService) buildSapronakItems(ctx context.Context, pfk entity.Proj
|
||||
usageDetailsRows = usageAllocatedDetails
|
||||
chickinUsageDetailsRows = map[uint][]repository.SapronakDetailRow{}
|
||||
}
|
||||
adjIncomingRows, adjOutgoingRows, err := s.Repository.FetchSapronakAdjustments(ctx, pfk.KandangId)
|
||||
adjIncomingRows, adjOutgoingRows, err := s.Repository.FetchSapronakAdjustments(ctx, pfk.KandangId, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, nil, 0, 0, err
|
||||
}
|
||||
transIncomingRows, transOutgoingRows, err := s.Repository.FetchSapronakTransfers(ctx, pfk.KandangId)
|
||||
transIncomingRows, transOutgoingRows, err := s.Repository.FetchSapronakTransfers(ctx, pfk.KandangId, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, nil, 0, 0, err
|
||||
}
|
||||
salesOutRows, err := s.Repository.FetchSapronakSalesAllocatedDetails(ctx, pfk.Id)
|
||||
salesOutRows, err := s.Repository.FetchSapronakSalesAllocatedDetails(ctx, pfk.Id, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, nil, 0, 0, err
|
||||
}
|
||||
@@ -492,11 +493,6 @@ func (s sapronakService) buildSapronakItems(ctx context.Context, pfk entity.Proj
|
||||
chickinUsageDetailsRows = filteredDetail
|
||||
}
|
||||
|
||||
allUsageRows := append(usageRows, chickinUsageRows...)
|
||||
incoming, usage := mapIncomingUsage(incomingRows, allUsageRows)
|
||||
itemMap := make(map[uint]dto.SapronakItemDTO, len(incoming)+len(usage))
|
||||
groupMap := make(map[string]*dto.SapronakGroupDTO)
|
||||
|
||||
for pid, rows := range chickinUsageDetailsRows {
|
||||
if len(rows) == 0 {
|
||||
continue
|
||||
@@ -513,6 +509,11 @@ func (s sapronakService) buildSapronakItems(ctx context.Context, pfk entity.Proj
|
||||
transOutgoing := detailMaps.TransferOut
|
||||
salesOutgoing := detailMaps.SalesOut
|
||||
|
||||
allUsageRows := append(usageRows, chickinUsageRows...)
|
||||
incoming, usage := mapIncomingUsage(incomingRows, allUsageRows)
|
||||
itemMap := make(map[uint]dto.SapronakItemDTO, len(incoming)+len(usage))
|
||||
groupMap := make(map[string]*dto.SapronakGroupDTO)
|
||||
|
||||
transIncoming = dedupTransfers(transIncoming)
|
||||
transOutgoing = dedupTransfers(transOutgoing)
|
||||
|
||||
@@ -823,3 +824,20 @@ func (s sapronakService) buildSapronakItems(ctx context.Context, pfk entity.Proj
|
||||
|
||||
return items, groups, totalIncoming, totalUsage, nil
|
||||
}
|
||||
|
||||
func sapronakPeriodRange(pfk entity.ProjectFlockKandang) (*time.Time, *time.Time) {
|
||||
if len(pfk.Chickins) == 0 {
|
||||
start := dateOnlyUTC(pfk.CreatedAt)
|
||||
return &start, pfk.ClosedAt
|
||||
}
|
||||
|
||||
minDate := pfk.Chickins[0].ChickInDate
|
||||
for _, c := range pfk.Chickins[1:] {
|
||||
if c.ChickInDate.Before(minDate) {
|
||||
minDate = c.ChickInDate
|
||||
}
|
||||
}
|
||||
|
||||
start := dateOnlyUTC(minDate)
|
||||
return &start, pfk.ClosedAt
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user