tomatophp/tomato-wallet-module
A Laravel wallet module for the TomatoPHP ecosystem, adding account balances, credits and debits, and transaction tracking to your app. Integrates with TomatoPHP admin panels for managing wallets and payment records.
Install into an existing TomatoPHP/Laravel app and pin the version:
composer require tomatophp/tomato-wallet-module:^1.0.2
Confirm the service provider is registered. With Laravel package auto-discovery this is usually automatic; if not, add the provider from the package’s composer.json to config/app.php.
Publish and run package assets/migrations:
php artisan vendor:publish --tag=tomato-wallet-config
php artisan vendor:publish --tag=tomato-wallet-migrations
php artisan migrate
Look first at:
vendor/tomatophp/tomato-wallet-module/src/ for models, services, actions, and facades.config/ for wallet-related config after publishing.database/migrations/ for wallet and transaction table structure.routes/ and resources/lang/ for admin routes, permissions, and labels.First use case: create a wallet for a user/account, credit it from an admin or payment callback, debit it for an internal purchase, and verify the transaction ledger records both movements.
Use the package’s wallet service/action layer rather than writing directly to the balance column. Confirm the actual class and method names in src/Services before copying examples.
Treat the service layer as the public API. Locate the wallet service/facade and call its credit/debit methods from your controllers, jobs, and payment handlers. Avoid $wallet->update(['balance' => ...]) because it bypasses ledger creation and any internal consistency checks.
Wrap business operations in database transactions. A purchase should atomically check balance, debit wallet, create the order/payment record, and write the ledger entry:
DB::transaction(function () use ($wallet, $amount, $order) {
// Adapt to the package's actual service/method names.
app(WalletService::class)->debit($wallet, $amount, [
'reference' => $order->id,
'type' => 'purchase',
]);
});
Use append-only ledger entries. Do not edit or delete historical transactions to correct mistakes. Add a reversal/adjustment entry with a reason, admin/user id, and reference to the original transaction.
Payment integration pattern: verify the gateway webhook first, then credit the wallet inside a transaction. Store the gateway transaction ID and enforce a unique idempotency key so retried webhooks do not double-credit.
Spend pattern: lock the wallet row before checking balance if the package does not already do so:
$wallet = Wallet::whereKey($walletId)->lockForUpdate()->firstOrFail();
Then perform the debit and ledger write in the same transaction.
Admin adjustments: require a reason, record the admin id, and expose adjustments through a permission-protected TomatoPHP admin action. Keep manual adjustments distinguishable from payment or order movements.
TomatoCRM integration: map wallet ownership to the CRM account/contact/team model deliberately. If the package is owner-polymorphic, scope all queries by owner type and id; otherwise add a mapping table rather than duplicating balances.
Reporting: use the ledger as the source of truth for history and reconciliation. Compare the wallet balance against the sum of ledger movements in scheduled checks and alert on drift.
API/UI integration: keep wallet controllers thin. Authorize access with policies/permissions, call the wallet service, and return the updated balance plus transaction reference. In TomatoPHP admin screens, add menu entries and permission checks consistent with existing modules.
Extension points: look for events, service bindings, or payment-driver interfaces in src/. Prefer listening to package events or decorating its service over forking vendor code.
Pin and smoke-test the version. v1.0.2 is a translation-only patch. Do not assume runtime or schema changes from the release notes, but verify the package against your Laravel/PHP and TomatoPHP dependency versions before production.
Publish before migrating. Missing config, migrations, or route registrations are common first-run failures. Run php artisan optimize:clear after publishing and deployment.
Check migration rollback behavior. Test migrate:rollback in a disposable database before relying on it in production, especially if the package owns wallet balance data.
Enforce idempotency. Payment gateways retry webhooks. Add a unique index on external reference/idempotency key and handle duplicate-key exceptions gracefully.
Watch concurrency. A balance read followed by an update can overspend under load. Use row locks, atomic SQL updates, or the package’s atomic credit/debit methods. Verify that the package actually provides the atomicity it claims.
Prevent negative balances unless explicitly allowed. Enforce this in the service or database layer, not only in the UI.
Use precise money handling. Confirm whether amounts are integers in minor units or decimal columns. Avoid floats in PHP; use integer cents or a money library consistently.
Locale-file conflicts. v1.0.2 changes translations. Publish translations if needed and override product-specific terminology in your app’s lang/ files rather than editing vendor files.
Permissions are part of the integration. Verify TomatoPHP permissions for wallet viewing, manual credit, debit, and adjustment. Do not expose admin wallet routes without policy checks.
Do not rely on UI routes as the API. If you need programmatic payments, wrap the service layer in your own controllers/jobs rather than calling admin routes.
Audit everything. Record actor, reason, reference, and timestamp on manual adjustments and reversals. Ledger history is your debugging and reconciliation tool.
CI checks: add tests for migrations, route registration, config caching, wallet credit/debit, duplicate webhook handling, and permission enforcement. Given low external adoption, treat upstream behavior as something to verify locally rather than assume.
How can I help you explore Laravel packages today?