Search by

misaf / vendra-transaction

misaf

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

Statistics

Installs: 21

Dependents: 3

Suggesters: 0

Stars: 1

Open Issues: 0

v1.12.3 2026-08-22 21:15 UTC

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

  1. Each user holds one Wallet per currency (created on first use via WalletResolver::firstOrCreateWalletFor() / firstOrCreateDefaultWalletFor()), with a cached balance in the currency's minor units.
  2. The ledger is the single source of balance truth: every movement is an immutable LedgerEntry (signed amount, balance_after snapshot, polymorphic source) written by PostLedgerEntryAction together with the cached wallet balance under a row lock. Overdrafts throw InsufficientBalanceException.
  3. A Transaction is a gateway-facing money movement created through CreateTransactionAction::execute(), which enforces per-wallet TransactionLimits and attaches optional fee and metadata rows. Its amount is always absolute; the ledger sign derives from the transaction type (deposit, withdrawal, commission, transfer, bonus).
  4. The lifecycle is a Spatie model-states machine: Pending → Processing → Review → Approved / Declined / Failed, driven by approve(), decline(), fail(), markProcessing(), and markReview(). Settlement into the ledger happens exactly once, inside the transition to Approved — principal, mirrored transfer credit, and fee commit atomically with the status change. DeclineTransactionTransition and FailTransactionTransition lock the row and dispatch TransactionDeclined or TransactionFailed, as ApproveTransactionTransition dispatches TransactionApproved. Call ApproveTransactionAction, DeclineTransactionAction, or FailTransactionAction rather than the model methods: each re-reads the transaction under a row lock, so a stale copy cannot decline a transaction another request has just approved.
  5. Gateways are admin-managed labels (translatable name and description, a scalar slug lookup key, logo, sortable position); payment-processing logic lives in the host application. Internal movements use the internal-transactions gateway.

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.4+
  • Laravel 13
  • Filament 5
  • misaf/vendra-support
  • misaf/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 project root:

php artisan test --compact --testsuite=vendra-transaction
composer stan

License

MIT. See LICENSE.