misaf / vendra-transaction
Wallet and ledger based financial transaction system with multi-gateway support, state-machine lifecycle and per-currency balances
Package info
github.com/misaf/vendra-transaction
Type:vendra-module
pkg:composer/misaf/vendra-transaction
Requires
- php: ^8.3
- flowframe/laravel-trend: ^0.5.0
- lara-zeus/spatie-translatable: ^2.0.1
- misaf/vendra-multimedia: v1.10.0
- misaf/vendra-support: v1.10.0
- spatie/eloquent-sortable: ^5.0.1
- spatie/laravel-activitylog: ^5.0
- spatie/laravel-model-states: ^2.11
- spatie/laravel-package-tools: ^1.93.1
- spatie/laravel-queueable-action: ^2.17
- spatie/laravel-sluggable: ^4.0.2
Requires (Dev)
- fakerphp/faker: ^1.24.1
- larastan/larastan: ^3.10.0
- laravel/boost: ^2.4.12
- laravel/pint: ^1.29.3
- misaf/vendra-currency: v1.10.0
- misaf/vendra-testing: v1.10.0
- mockery/mockery: ^1.6.12
- nunomaduro/collision: ^8.9.4
- orchestra/testbench: ^11.1
- pestphp/pest: ^5.0
- pestphp/pest-plugin-arch: ^5.0
- pestphp/pest-plugin-laravel: ^5.0
- pestphp/pest-plugin-profanity: ^5.0
- pestphp/pest-plugin-type-coverage: ^5.0
- phpstan/extension-installer: ^1.4.3
Suggests
- misaf/vendra-currency: Install this in the host application to manage active currencies used by wallet provisioning and transaction forms.
README
Wallet and ledger based financial transactions for Vendra: per-user, per-currency wallet balances, an immutable ledger, a state-machine transaction lifecycle with multi-gateway support, and a Filament admin cluster for transactions, gateways, and wallets.
Features
- Each user holds one
Walletper currency (created on first use viaTransactionService::walletFor()/defaultWalletFor()), with a cachedbalancein the currency's minor units. - The ledger is the single source of balance truth: every movement is an
immutable
LedgerEntry(signed amount,balance_aftersnapshot, polymorphic source) written byPostLedgerEntryActiontogether with the cached wallet balance under a row lock. Overdrafts throwInsufficientBalanceException. - A
Transactionis a gateway-facing money movement created throughCreateTransactionAction::execute(), which enforces per-walletTransactionLimits and attaches optional fee and metadata rows. Itsamountis always absolute; the ledger sign derives from the transaction type (deposit, withdrawal, commission, transfer, bonus). - The lifecycle is a Spatie model-states machine:
Pending → Processing → Review → Approved / Declined / Failed, driven byapprove(),decline(),fail(),markProcessing(), andmarkReview(). Settlement into the ledger happens exactly once, inside the transition toApproved— principal, mirrored transfer credit, and fee commit atomically with the status change. - Gateways are admin-managed labels (translatable name and description, a
scalar
sluglookup key, logo, sortable position); payment-processing logic lives in the host application. Internal movements use theinternal-transactionsgateway.
The module is decoupled from concrete user and currency packages. The wallet
owner model resolves from auth.providers.users.model; currency options resolve
through the provider-neutral capability in misaf/vendra-support.
Requirements
- PHP 8.3+
- Laravel 13
- Filament 5
misaf/vendra-supportmisaf/vendra-multimedia
Optional:
misaf/vendra-currency— supplies managed active/default currency options to the shared Support resolver
Installation
composer require misaf/vendra-transaction php artisan vendor:publish --tag=vendra-transaction-migrations php artisan migrate
Optional translations publish:
php artisan vendor:publish --tag=vendra-transaction-translations
Balance verification
Recompute cached wallet balances from the ledger and report (or repair) drift:
php artisan vendra-transaction:verify-balances php artisan vendra-transaction:verify-balances --repair
Testing
Run the package checks from the package directory:
composer test
composer analyse
License
MIT. See LICENSE.