feat[BE]: enhance customer payment report with vehicle numbers and pickup info, add date filtering

This commit is contained in:
aguhh18
2026-01-14 15:15:29 +07:00
parent 7daa509cd0
commit 804ff45dbd
4 changed files with 141 additions and 78 deletions
@@ -359,7 +359,7 @@ func (s *repportService) GetCustomerPayment(ctx *fiber.Ctx, params *validation.C
// Process each customer
var result []dto.CustomerPaymentReportItem
for _, customerID := range customerIDs {
item, err := s.processCustomerPayment(ctx.Context(), customerID)
item, err := s.processCustomerPayment(ctx.Context(), customerID, params)
if err != nil {
return nil, 0, err
}
@@ -369,7 +369,7 @@ func (s *repportService) GetCustomerPayment(ctx *fiber.Ctx, params *validation.C
return result, totalCustomers, nil
}
func (s *repportService) processCustomerPayment(ctx context.Context, customerID uint) (dto.CustomerPaymentReportItem, error) {
func (s *repportService) processCustomerPayment(ctx context.Context, customerID uint, params *validation.CustomerPaymentQuery) (dto.CustomerPaymentReportItem, error) {
customer := entity.Customer{}
if err := s.DB.WithContext(ctx).
Where("id = ?", customerID).
@@ -392,28 +392,11 @@ func (s *repportService) processCustomerPayment(ctx context.Context, customerID
runningBalance := initialBalance
for i, tx := range transactions {
row := dto.CustomerPaymentReportRow{
TransactionType: tx.TransactionType,
TransactionID: tx.TransactionID,
TransDate: tx.TransDate,
DeliveryDate: tx.DeliveryDate,
Reference: tx.Reference,
VehicleNumbers: tx.VehicleNumbers,
Qty: tx.Qty,
Weight: tx.Weight,
AverageWeight: tx.AverageWeight,
Price: tx.Price,
CreditNote: tx.CreditNote,
FinalPrice: tx.FinalPrice,
PPN: tx.PPN,
TotalPrice: tx.TotalPrice,
PaymentAmount: tx.PaymentAmount,
PickupInfo: tx.PickupInfo,
SalesPerson: tx.SalesPerson,
}
previousBalance := runningBalance
row := dto.ToCustomerPaymentReportRow(tx)
if tx.TransactionType == "SALES" {
runningBalance -= tx.TotalPrice
status, paymentDate := s.determineSalesStatusAndPaymentDate(transactions, i, previousBalance, runningBalance)
@@ -452,51 +435,58 @@ func (s *repportService) processCustomerPayment(ctx context.Context, customerID
rows = append(rows, row)
}
summary := s.calculateSummary(rows, initialBalance)
if params.StartDate != "" || params.EndDate != "" {
filteredRows := make([]dto.CustomerPaymentReportRow, 0, len(rows))
location, err := time.LoadLocation("Asia/Jakarta")
if err != nil {
return dto.CustomerPaymentReportItem{}, err
}
customerDTO := customerDTO.CustomerRelationDTO{
Id: customer.Id,
Name: customer.Name,
Type: customer.Type,
AccountNumber: customer.AccountNumber,
Balance: customer.Balance,
var startDate, endDate *time.Time
if params.StartDate != "" {
parsed, err := time.ParseInLocation("2006-01-02", params.StartDate, location)
if err != nil {
return dto.CustomerPaymentReportItem{}, err
}
startDate = &parsed
}
if params.EndDate != "" {
parsed, err := time.ParseInLocation("2006-01-02", params.EndDate, location)
if err != nil {
return dto.CustomerPaymentReportItem{}, err
}
// End date should be inclusive, so set to end of day
endOfDay := time.Date(parsed.Year(), parsed.Month(), parsed.Day(), 23, 59, 59, 999999999, location)
endDate = &endOfDay
}
for _, row := range rows {
transDate := row.TransDate.In(location)
// Check if transaction date is within range
if startDate != nil && transDate.Before(*startDate) {
continue
}
if endDate != nil && transDate.After(*endDate) {
continue
}
filteredRows = append(filteredRows, row)
}
rows = filteredRows
}
summary := dto.CalculateCustomerPaymentSummary(rows, initialBalance)
return dto.CustomerPaymentReportItem{
Customer: customerDTO,
Customer: customerDTO.ToCustomerRelationDTO(customer),
InitialBalance: initialBalance,
Rows: rows,
Summary: summary,
}, nil
}
func (s *repportService) calculateSummary(rows []dto.CustomerPaymentReportRow, initialBalance float64) dto.CustomerPaymentReportSummary {
summary := dto.CustomerPaymentReportSummary{}
for _, row := range rows {
summary.TotalQty += row.Qty
summary.TotalWeight += row.Weight
summary.TotalCreditNote += row.CreditNote
summary.TotalPPN += row.PPN
if row.TransactionType == "SALES" {
summary.TotalInitialAmount += row.TotalPrice
summary.TotalFinalAmount += row.FinalPrice
summary.TotalGrandAmount += row.TotalPrice
} else if row.TransactionType == "PAYMENT" {
summary.TotalPayment += row.PaymentAmount
}
}
// Formula: Total AR = Initial Balance - Total Sales + Total Payment
// - Initial balance: positive (customer deposit)
// - Sales: reduces balance (customer debt)
// - Payment: increases balance (customer pays)
summary.TotalAccountsReceivable = initialBalance - summary.TotalGrandAmount + summary.TotalPayment
return summary
}
func (s *repportService) determineSalesStatusAndPaymentDate(transactions []repportRepo.CustomerPaymentTransaction, currentIndex int, previousBalance, currentBalance float64) (string, *time.Time) {
currentSales := transactions[currentIndex]