Wallet Module Documentation
Overview
The Wallet Module provides a closed-loop digital payment system for the hotel. Every customer has a "Wallet" that can hold funds (Deposits, Refunds, Loyalty Rewards). These funds can be used to settle Folios instantly. It acts as a Liability Ledger ($ held on behalf of guests).
Key Features
- Store of Value: Holds prepaid funds in local currency.
- Loyalty Integration: Automatically awards points for deposits (incentivizing cash flow).
- Accounting & Liability: Real-time GL posting. Deposits are Liabilities (IOUs), Payments reduce Liability.
- Fraud Prevention: Transactions are immutable. Wallets can be frozen.
Architecture
Domain Layer (app/Domain/Wallet)
Models (2 Models)
CustomerWallet (CustomerWallet.php)
- Table:
customer_wallets - Description: The container for balance.
- Key Fields:
customer_id: Owner.balance: Current funds (Decimal 10,2).is_active: Freeze switch.
- Relationships:
transactions(): History.
WalletTransaction (WalletTransaction.php)
- Table:
wallet_transactions - Description: The immutable ledger line.
- Key Fields:
type: DEPOSIT | PAYMENT | REFUND.amount: Transaction value.balance_after: Snapshot of wallet at that moment.description: Context (e.g. "Payment for Invoice #102").somxchange_ref: External gateway reference.
Services
WalletService (WalletService.php)
Purpose: High-security financial state management.
Key Methods:
deposit(wallet, amount, ref)
Adds funds.
- Logic:
- Checks
is_active. - Updates Balance:
balance += amount. - Creates Transaction (DEPOSIT).
- Accounting:
- Dr Asset (102-SX: SomXchange Clearing).
- Cr Liability (205: Guest Deposits).
- Loyalty: Calls
awardLoyaltyPoints().
- Checks
deduct(wallet, amount, desc)
Spends funds.
- Logic:
- Checks
is_active. - Funds Check: Throws exception if
balance < amount. - Updates Balance:
balance -= amount. - Creates Transaction (PAYMENT).
- Accounting:
- Dr Liability (205: Guest Deposits).
- Cr Asset/Receivable (103: Accounts Receivable).
- Checks
refund(wallet, amount, desc)
Returns funds (reversal).
- Logic:
- Updates Balance:
balance += amount. - Creates Transaction (REFUND).
- Accounting:
- Dr Asset/Receivable (103).
- Cr Liability (205).
- Updates Balance:
Accounting Integration
The module relies on specific General Ledger codes to function.
| Transaction | Debit Account Key | Credit Account Key | Logic |
|---|---|---|---|
| Deposit | asset.cash.somxchange | liability.wallet | We received cash (Asset), but owe service (Liability). |
| Payment | liability.wallet | asset.ar | We fulfilled service (Liability reduced), offsetting the AR Invoice (Asset reduced). |
Implementation: Accounts are resolved dynamically via AccountingMapService.
Audit Findings & Improvements
Strengths
- Loyalty Hook: The
awardLoyaltyPointsintegration is a clever feature for "Financial Gamification", encouraging guests to keep money in the ecosystem. - Immutable History: The service never "edits" a transaction. It only creates new ones. This is correct for financial auditing.
Issues Identified
Major
- Critical Race Condition: [FIXED]
depositanddeductmethods now uselockingForUpdate()to prevent race conditions during concurrent transactions.
Minor
- Hardcoded Accounts: [FIXED] Logic now uses
AccountingMapServiceto resolveASSET_CASH_SOMXCHANGEandLIABILITY_WALLETkeys. - Loyalty Config: Uses
config('somxchange.loyalty...'). This couples the generic Wallet module to a specific Gateway provider (SomXchange) in naming.
Configuration
Config: config/somxchange.php (Legacy naming)
php
return [
'loyalty' => [
'points_per_deposit' => 1,
'minimum_deposit_for_points' => 10,
]
];Module Version: 2.0 Status: Stable (Race condition fixed with lockForUpdate())