# Customer Value Automation & Return Settlement v43

v43 turns the v42 customer-value ledgers into explicit business orchestration.

## Automatic loyalty and cashback

A completed customer sale earns rewards only when its payment state is:
- `paid`
- `on_account`

Rules are tenant-scoped and can optionally target branch/customer-group.

Loyalty:
- `loyalty.earn_rules`
- points-per-currency-unit
- minimum sale amount
- optional expiry days
- priority

Cashback:
- `wallet.cashback_rules`
- percentage + optional fixed amount
- optional maximum
- minimum sale amount
- optional expiry days
- priority

No active rule means no automatic reward.

## Expiry lots

v42 ledger entries already had `expires_at`, but correct expiry requires tracking how much
of each expiring award remains after customer spending.

v43 adds:
- `loyalty.lots`
- `wallet.lots`

Normal redeem/debit consumes expiring lots FEFO.

`customer-value:expire` posts immutable `expire` ledger entries only for remaining value.

## Reward reversals on returns

Posted returns reverse the proportional earned reward.

If the customer already spent points/cashback, the return is not blocked.
The system recovers what remains available and records the rest in:
- `loyalty.reward_recoveries`
- `wallet.reward_recoveries`

This avoids allowing negative customer balances while preserving the recovery obligation.

## Wallet refunds

Wallet payments are real captured payments in v42.

v43 extends `payments.refunds.method_type` with `wallet`.

Wallet refunds:
- credit the same customer's wallet synchronously
- create normal payment refund rows
- never pass through cash/register shift
- are idempotent

Cash remains synchronous through Cash Shift.
Card/external remain pending until provider/manual resolution.

## Credit / AR sale subledger

v42 maintained customer-level AR.

v43 adds `credit.sale_balances`, allowing the system to know the remaining receivable for
each sale.

Credit charges increase:
- customer AR
- sale-linked AR

Credit account payments allocate FIFO across open sale balances.

A sales return can therefore reduce only the receivable belonging to that original sale.

## Mixed-tender return settlement

`sales.return_settlements` is the durable settlement allocation record.

If the client explicitly supplies payment refund instructions, they remain authoritative.

If no instructions are supplied, v43 allocates the return automatically using:
**reverse settlement order (latest settlement first)** across:
- cash
- card
- external
- wallet
- customer credit

Each allocation records pending/completed/failed state.

Cash/wallet/credit settle synchronously.
Card/external are pending until refund resolution.

`SaleRefundStatusUpdater` now reads this mixed-tender settlement ledger and retains legacy
v39 fallback behavior.

## Important boundary

Reward rules and expiry are explicit application services. They are not Eloquent hooks.

Payment-state synchronization calls the reward orchestrator through the existing explicit
settlement service, and credit settlement calls it directly.
