Models overview
LoyaltyProgram
Per-tenant configuration: earn ratio, redemption ratio, expiry policy. One program per tenant.
LoyaltyReward
Catalog of redeemable items with a points cost and optional stock limit.
LoyaltyLedger
Append-only transaction log. Never updated — corrections insert new rows.
LoyaltyProgram
tenant_id).
Point calculation
earn_ratio = 10, a customer spending L.100 earns 10 points. With redemption_ratio = 100, those 10 points are worth L.0.10.
LoyaltyReward
Rewards are the items customers can redeem from the catalog:Availability check
decrementStock() reduces the count atomically:
available scope to fetch rewards customers can currently redeem:
LoyaltyLedger
The ledger is an append-only audit log of all point transactions.amountis always an integer — no floating-point point math.- A user’s active balance is
SUM(amount) WHERE tenant_id = X AND (expires_at IS NULL OR expires_at > NOW()). - Never update existing ledger rows. Insert a corrective entry with
TYPE_ADJUSTMENT.
Useful scopes
How points flow
- Earn: When an order is completed, the system calls
LoyaltyProgram::calculatePoints($order->total)and inserts anearnledger entry linked to the order. - Redeem: Customer selects a
LoyaltyReward. The system inserts aredeementry with a negativeamountequal to$reward->points_cost. - Expire: A scheduled process queries
expiredscope and insertsexpireentries to zero out lapsed points. - Adjust: Admins can insert
adjustmententries directly to correct discrepancies.
Panel management
The Filament tenant panel at/app includes:
LoyaltyProgramResource— configure earn ratio, redemption ratio, expiry policy, and toggle the program active state.LoyaltyRewardResource— manage the rewards catalog with stock tracking.
/admin can view ledger data across all tenants for audit purposes.