feat(loyalty): show what an order earned on the order and receipt
Adds points_earned and coins_earned to the order response (docs/prd-point-coin.md F3, PC-205). The POS prints the receipt from this response, so the receipt gets them too. The values are the sums of the order's EARN rows, read in one query for a list of orders. They are filled for create, add items, update, detail and list, and are 0 for an order that earned nothing. UpdateOrder earns before building its response, so a payment completed there already shows the earning. A failure to read them is logged and leaves them at 0 rather than failing the order read. The self-order session listing reads orders directly from the repository and still shows 0. The two order hooks are merged into one OrderLoyalty interface (paid, refunded, earned by orders) with a single SetLoyalty. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
eb5b63677f
commit
fc97c78300
@@ -59,6 +59,9 @@ type EarningRepository interface {
|
||||
ReversalRequested(ctx context.Context, earnTransactionID uuid.UUID) (int64, error)
|
||||
// LotIDsCreatedBy returns the lots a credit created.
|
||||
LotIDsCreatedBy(ctx context.Context, transactionID uuid.UUID) ([]uuid.UUID, error)
|
||||
// EarnedByOrders sums the EARN rows of each order per currency, as
|
||||
// map[order]map[currency]amount. Orders that earned nothing are absent.
|
||||
EarnedByOrders(ctx context.Context, orderIDs []uuid.UUID) (map[uuid.UUID]map[string]int64, error)
|
||||
}
|
||||
|
||||
type earningRepository struct {
|
||||
@@ -232,3 +235,35 @@ func (r *earningRepository) LotIDsCreatedBy(ctx context.Context, transactionID u
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (r *earningRepository) EarnedByOrders(ctx context.Context, orderIDs []uuid.UUID) (map[uuid.UUID]map[string]int64, error) {
|
||||
earned := map[uuid.UUID]map[string]int64{}
|
||||
if len(orderIDs) == 0 {
|
||||
return earned, nil
|
||||
}
|
||||
var rows []struct {
|
||||
OrderID string
|
||||
Currency string
|
||||
Amount int64
|
||||
}
|
||||
err := DBFromContext(ctx, r.db).WithContext(ctx).Raw(`
|
||||
SELECT reference_id::text AS order_id, currency, SUM(amount) AS amount
|
||||
FROM wallet_transactions
|
||||
WHERE reference_type = ? AND type = ? AND reference_id IN ?
|
||||
GROUP BY reference_id, currency`,
|
||||
constants.WalletRefTypeOrder, constants.WalletTxTypeEarn, orderIDs).Scan(&rows).Error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to sum earnings of orders: %w", err)
|
||||
}
|
||||
for _, row := range rows {
|
||||
id, err := uuid.Parse(row.OrderID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if earned[id] == nil {
|
||||
earned[id] = map[string]int64{}
|
||||
}
|
||||
earned[id][row.Currency] = row.Amount
|
||||
}
|
||||
return earned, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user