[FIX/BE-US-390] changes counting debt supplier

This commit is contained in:
ragilap
2026-01-13 19:54:47 +07:00
parent f37bf4d22d
commit 5730053e04
3 changed files with 36 additions and 69 deletions
@@ -31,11 +31,9 @@ func NewDebtSupplierRepository(db *gorm.DB) DebtSupplierRepository {
func resolveDebtSupplierDateColumn(filterBy string) string { func resolveDebtSupplierDateColumn(filterBy string) string {
switch strings.ToLower(strings.TrimSpace(filterBy)) { switch strings.ToLower(strings.TrimSpace(filterBy)) {
case "receive_date":
return "purchases.receive_date"
case "po_date": case "po_date":
return "purchases.po_date" return "purchases.po_date"
case "do_date", "received_date", "": case "received_date", "":
return "purchase_items.received_date" return "purchase_items.received_date"
default: default:
return "purchase_items.received_date" return "purchase_items.received_date"
@@ -130,7 +128,7 @@ func (r *debtSupplierRepositoryImpl) GetPurchasesBySuppliers(ctx context.Context
Preload("Warehouse.Area"). Preload("Warehouse.Area").
Order("purchase_items.id ASC") Order("purchase_items.id ASC")
if strings.EqualFold(strings.TrimSpace(filters.FilterBy), "do_date") || strings.EqualFold(strings.TrimSpace(filters.FilterBy), "received_date") || strings.TrimSpace(filters.FilterBy) == "" { if strings.EqualFold(strings.TrimSpace(filters.FilterBy), "received_date") || strings.TrimSpace(filters.FilterBy) == "" {
if filters.StartDate != "" { if filters.StartDate != "" {
if dateFrom, err := utils.ParseDateString(filters.StartDate); err == nil { if dateFrom, err := utils.ParseDateString(filters.StartDate); err == nil {
db = db.Where("DATE(purchase_items.received_date) >= ?", dateFrom) db = db.Where("DATE(purchase_items.received_date) >= ?", dateFrom)
@@ -642,7 +642,7 @@ func (s *repportService) GetPurchaseSupplier(c *fiber.Ctx, params *validation.Pu
} }
func (s *repportService) GetDebtSupplier(c *fiber.Ctx, params *validation.DebtSupplierQuery) ([]dto.DebtSupplierDTO, int64, error) { func (s *repportService) GetDebtSupplier(c *fiber.Ctx, params *validation.DebtSupplierQuery) ([]dto.DebtSupplierDTO, int64, error) {
if params.FilterBy == "" || strings.EqualFold(strings.TrimSpace(params.FilterBy), "do_date") { if params.FilterBy == "" {
params.FilterBy = "received_date" params.FilterBy = "received_date"
} }
@@ -681,25 +681,8 @@ func (s *repportService) GetDebtSupplier(c *fiber.Ctx, params *validation.DebtSu
} }
purchasesBySupplier := make(map[uint][]entity.Purchase, len(supplierIDs)) purchasesBySupplier := make(map[uint][]entity.Purchase, len(supplierIDs))
references := make([]string, 0)
seenRefs := make(map[string]struct{})
for _, purchase := range purchases { for _, purchase := range purchases {
supplierID := purchase.SupplierId purchasesBySupplier[purchase.SupplierId] = append(purchasesBySupplier[purchase.SupplierId], purchase)
purchasesBySupplier[supplierID] = append(purchasesBySupplier[supplierID], purchase)
reference := purchase.PrNumber
if purchase.PoNumber != nil && strings.TrimSpace(*purchase.PoNumber) != "" {
reference = *purchase.PoNumber
}
if _, exists := seenRefs[reference]; !exists {
seenRefs[reference] = struct{}{}
references = append(references, reference)
}
}
paymentTotals, err := s.DebtSupplierRepo.GetPaymentTotalsByReferences(c.Context(), supplierIDs, references)
if err != nil {
return nil, 0, err
} }
paymentsBySupplier := make(map[uint][]entity.Payment, len(supplierIDs)) paymentsBySupplier := make(map[uint][]entity.Payment, len(supplierIDs))
@@ -724,6 +707,14 @@ func (s *repportService) GetDebtSupplier(c *fiber.Ctx, params *validation.DebtSu
now := time.Now().In(location) now := time.Now().In(location)
result := make([]dto.DebtSupplierDTO, 0, len(supplierIDs)) result := make([]dto.DebtSupplierDTO, 0, len(supplierIDs))
type debtSupplierRowItem struct {
Row dto.DebtSupplierRowDTO
SortTime time.Time
Order int
DeltaBalance float64
CountTotals bool
}
for _, supplierID := range supplierIDs { for _, supplierID := range supplierIDs {
supplier, exists := supplierMap[supplierID] supplier, exists := supplierMap[supplierID]
if !exists { if !exists {
@@ -731,23 +722,13 @@ func (s *repportService) GetDebtSupplier(c *fiber.Ctx, params *validation.DebtSu
} }
initialBalance := initialPaymentTotals[supplierID] - initialPurchaseTotals[supplierID] initialBalance := initialPaymentTotals[supplierID] - initialPurchaseTotals[supplierID]
items := purchasesBySupplier[supplierID] items := purchasesBySupplier[supplierID]
paymentItems := paymentsBySupplier[supplierID] paymentItems := paymentsBySupplier[supplierID]
rows := make([]dto.DebtSupplierRowDTO, 0, len(items)+len(paymentItems))
total := dto.DebtSupplierTotalDTO{} total := dto.DebtSupplierTotalDTO{}
type debtSupplierRowItem struct {
Row dto.DebtSupplierRowDTO
SortTime time.Time
Order int
DeltaBalance float64
CountTotals bool
}
combinedRows := make([]debtSupplierRowItem, 0, len(items)+len(paymentItems)) combinedRows := make([]debtSupplierRowItem, 0, len(items)+len(paymentItems))
for _, purchase := range items { for _, purchase := range items {
row := buildDebtSupplierRow(purchase, paymentTotals, now, location) row := buildDebtSupplierRow(purchase, now, location)
sortTime := resolveDebtSupplierSortTime(purchase, params.FilterBy, location) sortTime := resolveDebtSupplierSortTime(purchase, params.FilterBy, location)
combinedRows = append(combinedRows, debtSupplierRowItem{ combinedRows = append(combinedRows, debtSupplierRowItem{
Row: row, Row: row,
@@ -780,6 +761,7 @@ func (s *repportService) GetDebtSupplier(c *fiber.Ctx, params *validation.DebtSu
balance := initialBalance balance := initialBalance
for i := range combinedRows { for i := range combinedRows {
balance += combinedRows[i].DeltaBalance balance += combinedRows[i].DeltaBalance
combinedRows[i].Row.DebtPrice = balance
combinedRows[i].Row.Balance = balance combinedRows[i].Row.Balance = balance
if combinedRows[i].CountTotals { if combinedRows[i].CountTotals {
@@ -788,13 +770,13 @@ func (s *repportService) GetDebtSupplier(c *fiber.Ctx, params *validation.DebtSu
total.Aging = row.Aging total.Aging = row.Aging
} }
total.TotalPrice += row.TotalPrice total.TotalPrice += row.TotalPrice
total.PaymentPrice += row.PaymentPrice
total.DebtPrice += row.DebtPrice
} else { } else {
combinedRows[i].Row.DebtPrice = balance total.PaymentPrice += combinedRows[i].Row.PaymentPrice
} }
} }
total.DebtPrice = balance
rows := make([]dto.DebtSupplierRowDTO, 0, len(combinedRows))
sortDesc := strings.EqualFold(params.SortOrder, "desc") sortDesc := strings.EqualFold(params.SortOrder, "desc")
if sortDesc { if sortDesc {
for i := len(combinedRows) - 1; i >= 0; i-- { for i := len(combinedRows) - 1; i >= 0; i-- {
@@ -823,18 +805,13 @@ func (s *repportService) GetDebtSupplier(c *fiber.Ctx, params *validation.DebtSu
return result, totalSuppliers, nil return result, totalSuppliers, nil
} }
func buildDebtSupplierRow(purchase entity.Purchase, paymentTotals map[string]float64, now time.Time, loc *time.Location) dto.DebtSupplierRowDTO { func buildDebtSupplierRow(purchase entity.Purchase, now time.Time, loc *time.Location) dto.DebtSupplierRowDTO {
prNumber := purchase.PrNumber prNumber := purchase.PrNumber
poNumber := "" poNumber := ""
if purchase.PoNumber != nil { if purchase.PoNumber != nil {
poNumber = *purchase.PoNumber poNumber = *purchase.PoNumber
} }
reference := prNumber
if strings.TrimSpace(poNumber) != "" {
reference = poNumber
}
prDate := purchase.CreatedAt.In(loc) prDate := purchase.CreatedAt.In(loc)
startDate := time.Date(prDate.Year(), prDate.Month(), prDate.Day(), 0, 0, 0, 0, loc) startDate := time.Date(prDate.Year(), prDate.Month(), prDate.Day(), 0, 0, 0, 0, loc)
endDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, loc) endDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, loc)
@@ -877,9 +854,6 @@ func buildDebtSupplierRow(purchase entity.Purchase, paymentTotals map[string]flo
} }
} }
paymentPrice := paymentTotals[reference]
debtPrice := paymentPrice - totalPrice
dueDate := "" dueDate := ""
dueStatus := "-" dueStatus := "-"
if purchase.DueDate != nil && !purchase.DueDate.IsZero() { if purchase.DueDate != nil && !purchase.DueDate.IsZero() {
@@ -893,10 +867,6 @@ func buildDebtSupplierRow(purchase entity.Purchase, paymentTotals map[string]flo
} }
status := "Belum Lunas" status := "Belum Lunas"
if debtPrice >= 0 {
status = "Lunas"
}
poDate := "" poDate := ""
if purchase.PoDate != nil && !purchase.PoDate.IsZero() { if purchase.PoDate != nil && !purchase.PoDate.IsZero() {
poDate = purchase.PoDate.In(loc).Format("2006-01-02") poDate = purchase.PoDate.In(loc).Format("2006-01-02")
@@ -913,10 +883,11 @@ func buildDebtSupplierRow(purchase entity.Purchase, paymentTotals map[string]flo
DueDate: dueDate, DueDate: dueDate,
DueStatus: dueStatus, DueStatus: dueStatus,
TotalPrice: totalPrice, TotalPrice: totalPrice,
PaymentPrice: paymentPrice, PaymentPrice: 0,
DebtPrice: debtPrice, DebtPrice: 0,
Status: status, Status: status,
TravelNumber: travelNumber, TravelNumber: travelNumber,
Balance: 0,
} }
} }
@@ -946,32 +917,30 @@ func buildDebtSupplierPaymentRow(payment entity.Payment, loc *time.Location) dto
DebtPrice: 0, DebtPrice: 0,
Status: "Pembayaran", Status: "Pembayaran",
TravelNumber: "-", TravelNumber: "-",
Balance: 0,
} }
} }
func resolveDebtSupplierSortTime(purchase entity.Purchase, filterBy string, loc *time.Location) time.Time { func resolveDebtSupplierSortTime(purchase entity.Purchase, filterBy string, loc *time.Location) time.Time {
switch strings.ToLower(strings.TrimSpace(filterBy)) { if strings.EqualFold(strings.TrimSpace(filterBy), "po_date") {
case "po_date":
if purchase.PoDate != nil && !purchase.PoDate.IsZero() { if purchase.PoDate != nil && !purchase.PoDate.IsZero() {
return purchase.PoDate.In(loc) return purchase.PoDate.In(loc)
} }
case "pr_date": }
return purchase.CreatedAt.In(loc)
default: earliest := time.Time{}
earliest := time.Time{} for _, item := range purchase.Items {
for _, item := range purchase.Items { if item.ReceivedDate == nil || item.ReceivedDate.IsZero() {
if item.ReceivedDate == nil || item.ReceivedDate.IsZero() { continue
continue
}
received := item.ReceivedDate.In(loc)
if earliest.IsZero() || received.Before(earliest) {
earliest = received
}
} }
if !earliest.IsZero() { received := item.ReceivedDate.In(loc)
return earliest if earliest.IsZero() || received.Before(earliest) {
earliest = received
} }
} }
if !earliest.IsZero() {
return earliest
}
return purchase.CreatedAt.In(loc) return purchase.CreatedAt.In(loc)
} }
@@ -49,7 +49,7 @@ type DebtSupplierQuery struct {
SupplierIDs []int64 `query:"-" validate:"omitempty,dive,gt=0"` SupplierIDs []int64 `query:"-" validate:"omitempty,dive,gt=0"`
StartDate string `query:"start_date" validate:"omitempty,datetime=2006-01-02"` StartDate string `query:"start_date" validate:"omitempty,datetime=2006-01-02"`
EndDate string `query:"end_date" validate:"omitempty,datetime=2006-01-02"` EndDate string `query:"end_date" validate:"omitempty,datetime=2006-01-02"`
FilterBy string `query:"filter_by" validate:"omitempty,oneof=received_date po_date pr_date do_date"` FilterBy string `query:"filter_by" validate:"omitempty,oneof=received_date po_date"`
SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc"` SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc"`
} }