feat(loyalty): report EnakPoint apart from money received

Keeps EnakPoint out of the money in on the payment method analytics
(docs/prd-point-coin.md F9, K7, PC-308), the one report that sums payments;
the daily transaction and profit-loss PDFs do not break payments down by
method.

summary.total_amount is now only money actually received. EnakPoint stays
listed as its own method, with points_used, and the summary adds
point_amount, points_used and total_with_points. Each method row says
whether it counts_as_cash_in, and the shares are of the money received, 0
for EnakPoint. The average order value still includes what EnakPoint paid,
since that is part of what the orders were worth. How EnakPoint is booked
waits on note N2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
efrilm
2026-09-30 11:59:33 +07:00
co-authored by Claude Opus 5.5
parent d7138b8f87
commit 0b52edf84e
8 changed files with 136 additions and 35 deletions
+22 -7
View File
@@ -63,27 +63,37 @@ func (p *AnalyticsProcessorImpl) GetPaymentMethodAnalytics(ctx context.Context,
return nil, fmt.Errorf("failed to get payment method analytics: %w", err)
}
var totalAmount float64
// EnakPoint is not money in (docs/prd-point-coin.md F9, K7): it is listed as its own
// method but left out of the money received and of the shares. How it is booked
// waits on note N2.
var cashAmount, pointAmount float64
var pointsUsed int64
var totalOrders int64
var totalPayments int64
for _, data := range analyticsData {
totalAmount += data.TotalAmount
if data.PaymentMethodType == string(constants.PaymentMethodTypePoint) {
pointAmount += data.TotalAmount
pointsUsed += data.PointsUsed
} else {
cashAmount += data.TotalAmount
}
totalOrders += data.OrderCount
totalPayments += data.PaymentCount
}
// The value of an order includes what EnakPoint paid, so the average does too.
var averageOrderValue float64
if totalOrders > 0 {
averageOrderValue = totalAmount / float64(totalOrders)
averageOrderValue = (cashAmount + pointAmount) / float64(totalOrders)
}
// Calculate percentages
var resultData []models.PaymentMethodAnalyticsData
for _, data := range analyticsData {
cashIn := data.PaymentMethodType != string(constants.PaymentMethodTypePoint)
var percentage float64
if totalAmount > 0 {
percentage = (data.TotalAmount / totalAmount) * 100
if cashIn && cashAmount > 0 {
percentage = (data.TotalAmount / cashAmount) * 100
}
resultData = append(resultData, models.PaymentMethodAnalyticsData{
@@ -94,11 +104,16 @@ func (p *AnalyticsProcessorImpl) GetPaymentMethodAnalytics(ctx context.Context,
OrderCount: data.OrderCount,
PaymentCount: data.PaymentCount,
Percentage: percentage,
PointsUsed: data.PointsUsed,
CountsAsCashIn: cashIn,
})
}
summary := models.PaymentMethodSummary{
TotalAmount: totalAmount,
TotalAmount: cashAmount,
PointAmount: pointAmount,
PointsUsed: pointsUsed,
TotalWithPoints: cashAmount + pointAmount,
TotalOrders: totalOrders,
TotalPayments: totalPayments,
AverageOrderValue: averageOrderValue,