Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Wallet Laravel Package

bavix/laravel-wallet

Virtual wallet system for Laravel: manage balances, deposits/withdrawals, transfers, and multi-wallet support with robust transaction history and concurrency safety. Well-tested, benchmarked, and extensible for payments, loyalty points, and in-app credits.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**:
   ```bash
   composer require bavix/laravel-wallet

Publish the config file (if needed):

php artisan vendor:publish --provider="Bavix\Wallet\WalletServiceProvider"
  1. Model Integration: Add the HasWallet trait and Wallet interface to your model (e.g., User):

    use Bavix\Wallet\Traits\HasWallet;
    use Bavix\Wallet\Interfaces\Wallet;
    
    class User extends Model implements Wallet
    {
        use HasWallet;
    }
    

    Run migrations:

    php artisan migrate
    
  2. First Use Case: Deposit and withdraw funds:

    $user = User::first();
    $user->deposit(100); // Deposit 100 units
    $user->withdraw(20); // Withdraw 20 units
    

Key Configuration

  • Check config/wallet.php for settings like:
    • precision (default: 2 for decimal places).
    • currency (default: USD).
    • decimal_class (supports float, string, or Brick\Math\BigDecimal).

Implementation Patterns

Core Workflows

  1. Basic Transactions:

    • Use deposit(), withdraw(), and forceWithdraw() for direct balance adjustments.
    • Example:
      $user->deposit(50, ['description' => 'Top-up']);
      $user->withdraw(10, ['description' => 'Payment']);
      
  2. Purchases:

    • Implement CanPay trait for customers and ProductInterface/ProductLimitedInterface for items:
      // User model (Customer)
      use Bavix\Wallet\Traits\CanPay;
      use Bavix\Wallet\Interfaces\Customer;
      
      class User extends Model implements Customer
      {
          use CanPay;
      }
      
      // Item model (Product)
      use Bavix\Wallet\Interfaces\ProductInterface;
      
      class Item extends Model implements ProductInterface
      {
          use HasWallet;
      
          public function getAmountProduct(Customer $customer): int|string
          {
              return 100;
          }
      }
      
    • Execute purchases:
      $user->pay($item); // Throws exception if insufficient balance
      $user->safePay($item); // Returns bool (false if failed)
      
  3. Refunds and Checks:

    • Refund a purchase:
      $user->refund($item);
      
    • Check purchase history:
      app(\Bavix\Wallet\External\Api\PurchaseQueryHandlerInterface::class)
          ->one(\Bavix\Wallet\External\Api\PurchaseQuery::create($user, $item));
      
  4. Eager Loading:

    • Optimize queries with:
      User::with('wallet')->get(); // Single wallet
      User::with('wallets')->get(); // Multi-wallet
      

Advanced Patterns

  1. Multi-Wallet Support:

    • Use HasWallets trait for models needing multiple wallets (e.g., User with USD and EUR wallets).
    • Access wallets via:
      $user->wallets()->where('currency', 'EUR')->first();
      
  2. Fractional Currency:

    • Use HasWalletFloat for decimal precision (e.g., 1.37):
      use Bavix\Wallet\Traits\HasWalletFloat;
      use Bavix\Wallet\Interfaces\WalletFloat;
      
      class User extends Model implements Wallet, WalletFloat
      {
          use HasWalletFloat;
      }
      
    • Transactions:
      $user->depositFloat(1.37);
      $user->balanceFloat; // 1.37
      
  3. Custom Purchase Logic:

    • Override PurchaseServiceInterface for complex validation (e.g., cart-based purchases).
    • Example:
      class CustomPurchaseService implements PurchaseServiceInterface
      {
          public function validate(PurchaseQuery $query): bool
          {
              // Custom logic (e.g., check cart items)
              return true;
          }
      }
      
    • Bind the service in AppServiceProvider:
      $this->app->bind(PurchaseServiceInterface::class, CustomPurchaseService::class);
      
  4. Extensions:

    • Integrate extensions like laravel-wallet-swap for exchange rates or laravel-wallet-warmup for balance caching:
      composer require bavix/laravel-wallet-swap
      

Gotchas and Tips

Common Pitfalls

  1. Precision Handling:

    • Default precision is 2 (e.g., 100.00). For fractional currencies, use HasWalletFloat or configure decimal_class in config/wallet.php:
      'decimal_class' => \Brick\Math\BigDecimal::class,
      
    • Gotcha: Floating-point arithmetic can cause rounding errors. Use BigDecimal for accuracy.
  2. Negative Balances:

    • withdraw() throws an exception if balance is insufficient. Use forceWithdraw() to bypass checks (e.g., for admin actions):
      $user->forceWithdraw(1000, ['description' => 'Admin override']);
      
  3. Purchase Validation:

    • ProductLimitedInterface requires implementing canBuy(). Forgetting this will cause runtime errors.
    • Tip: Use PurchaseQueryHandlerInterface for centralized purchase checks to avoid N+1 queries.
  4. Eager Loading:

    • Always eager-load wallets when iterating over collections to avoid N+1 queries:
      // Bad (N+1 queries)
      foreach (User::all() as $user) {
          $user->balance; // Triggers a query per user
      }
      
      // Good
      User::with('wallet')->get();
      
  5. Multi-Wallet Conflicts:

    • Ensure currency fields are unique in the wallets table when using multi-wallet. Duplicate currencies may cause silent failures.

Debugging Tips

  1. Transaction Logs:

    • Enable debug mode in config/wallet.php:
      'debug' => env('WALLET_DEBUG', false),
      
    • Logs transactions to storage/logs/wallet.log.
  2. Balance Mismatches:

    • Verify balance vs. balanceInt/balanceFloat if discrepancies arise. Use balanceInt for integer-based systems:
      $user->balanceInt; // Always returns integer (e.g., 100 for 1.00)
      
  3. Extension Conflicts:

    • Clear cached views and configs after installing extensions:
      php artisan cache:clear
      php artisan view:clear
      

Performance Optimization

  1. Caching:

    • Use laravel-wallet-warmup to cache balances:
      composer require bavix/laravel-wallet-warmup
      
    • Configure in config/wallet.php:
      'warmup' => [
          'enabled' => true,
          'ttl' => 60, // Cache TTL in minutes
      ],
      
  2. Database Indexes:

    • Ensure wallets.user_id and wallets.currency are indexed for multi-wallet queries.
  3. Batch Operations:

    • Use Wallet::batchDeposit() or Wallet::batchWithdraw() for bulk transactions:
      Wallet::batchDeposit([$user1, $user2], 100);
      

Extension Points

  1. Custom Events:

    • Listen for wallet events (e.g., wallet.deposited, wallet.withdrawn):
      event(new \Bavix\Wallet\Events\WalletDeposited($user, $amount));
      
    • Register listeners in EventServiceProvider:
      protected $listen = [
          \Bavix\Wallet\Events\WalletDeposited::class => [
              \App\Listeners\LogDeposit::class,
          ],
      ];
      
  2. Middleware:

    • Add middleware to validate wallet balances before routes:
      public function handle(Request $request, Closure $next)
      {
          $user = $request->user();
          if ($user->balance < 100) {
              abort(403, 'Insufficient balance');
          }
          return $next($request);
      }
      
  3. API Responses:

    • Format wallet data in API responses:
      return response()->json([
          'balance' => $user->balanceFloat,
          'currency' => $user->wallet->currency,
      ]);
      
  4. Testing:

    • Use WalletTestCase for unit tests:
      use Bavix\Wallet
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai