hwallet/laravel-multi-wallet

A comprehensive Laravel package for managing multi-currency wallets with advanced features including multiple balance types, transfers, fees, and configurable exchange rates.

Fund package maintenance!
Mohamed Habib

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 0

Forks: 0

Open Issues: 3

pkg:composer/hwallet/laravel-multi-wallet

dev-main 2025-08-01 09:44 UTC

README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

A comprehensive Laravel package for managing multi-currency wallets with advanced features including multiple balance types, transfers, fees, discounts, and configurable exchange rates. Perfect for e-commerce, fintech, and any application requiring robust financial transaction management.

๐Ÿš€ Production-Ready Package with 270+ passing tests, PHPStan level 8 compliance, and optimized DB::transaction usage for enterprise-grade performance and reliability.

โœจ Key Features

  • ๐Ÿฆ Multi-Currency Support: Manage wallets for various currencies with configurable exchange rates
  • ๐Ÿ’ฐ Multiple Balance Types: Support for Available, Pending, Frozen, and Trial balances
  • ๐Ÿ”„ Advanced Transfers: Transfer between wallets with fees, discounts, and status tracking
  • ๐ŸŽฏ Polymorphic Relations: Flexible model associations - attach wallets to any model
  • ๐Ÿ“Š Transaction Tracking: Comprehensive transaction history with metadata support
  • โš™๏ธ Configurable Architecture: Runtime configuration with extensible interfaces
  • ๐Ÿ”’ Type Safety: Built with PHP 8.1+ features and strict typing
  • ๐Ÿงช Fully Tested: 100% test coverage with 270+ passing tests using Pest framework
  • ๐Ÿ“ Event System: Rich event system for wallet operations
  • ๐ŸŽจ Clean Architecture: SOLID principles with repository and service patterns
  • ๐Ÿท๏ธ PHP Attributes: Easy configuration using PHP 8.1+ attributes
  • โšก Bulk Operations: High-performance bulk transaction processing with DB::transaction
  • ๐Ÿ—ƒ๏ธ Database Agnostic: Compatible with MySQL, PostgreSQL, SQLite, and SQL Server
  • ๐ŸŽ›๏ธ Operation Validation: Attribute-based operation validation and logging
  • ๐Ÿ”„ Enhanced Events: Comprehensive event system for all operations
  • ๐Ÿ“ˆ Wallet Statistics: Built-in analytics and reconciliation tools
  • ๐Ÿš€ Production Ready: PHPStan level 8 compliance and enterprise-grade features
  • ๐Ÿ”ง Clean Code: Laravel Pint formatted with PSR standards
  • ๐Ÿ› ๏ธ Helper Functions: Rich set of global helper functions for common operations
  • ๐Ÿ” Debugging Tools: Comprehensive debugging and monitoring utilities
  • ๐Ÿ“Š Analytics: Built-in performance metrics and reporting
  • ๐Ÿ” Type Safety: Strict type checking with value objects and validation

๐Ÿ“š Documentation

Comprehensive documentation is available in the /docs directory:

๐Ÿ“‹ Requirements

  • PHP 8.1+
  • Laravel 10.0+

๐Ÿš€ Installation

Install the package via Composer:

composer require hwallet/laravel-multi-wallet

Publish and run the migrations:

php artisan vendor:publish --provider="HWallet\LaravelMultiWallet\LaravelMultiWalletServiceProvider" --tag="migrations"
php artisan migrate

Optionally, publish the configuration file:

php artisan vendor:publish --provider="HWallet\LaravelMultiWallet\LaravelMultiWalletServiceProvider" --tag="config"

๐ŸŽฏ Quick Start

1. Add the HasWallets trait to your model

use HWallet\LaravelMultiWallet\Traits\HasWallets;

class User extends Authenticatable
{
    use HasWallets;
    
    // ... your model code
}

2. Enhanced Configuration with PHP Attributes

You can now use PHP attributes to configure wallet behavior directly on your models:

use HWallet\LaravelMultiWallet\Attributes\WalletConfiguration;
use HWallet\LaravelMultiWallet\Traits\HasWallets;

#[WalletConfiguration(
    defaultCurrency: 'USD',
    allowedCurrencies: ['USD', 'EUR', 'GBP'],
    autoCreateWallet: true,
    walletName: 'Primary Wallet',
    enableEvents: true,
    enableAuditLog: true,
    transactionLimits: ['min_amount' => 0.01, 'max_amount' => 10000.00],
    walletLimits: ['max_balance' => 100000.00],
    enableBulkOperations: true,
    uniquenessEnabled: true,
    exchangeRateConfig: ['provider' => 'default'],
    webhookSettings: ['url' => 'https://api.example.com/webhook'],
    notificationSettings: ['email' => true, 'sms' => false],
    securitySettings: ['require_2fa' => false, 'auto_freeze_suspicious' => true]
)]
class User extends Authenticatable
{
    use HasWallets;
    
    // ... your model code
}

3. Create and manage wallets

$user = User::find(1);

// Create a basic wallet
$wallet = $user->createWallet('USD', 'Main Wallet');

// Create with metadata
$wallet = $user->createWallet('EUR', 'European Wallet', [
    'description' => 'For European transactions',
    'meta' => ['region' => 'EU', 'priority' => 'high']
]);

// Credit the wallet
$transaction = $wallet->credit(100.00, 'available', [
    'description' => 'Initial deposit',
    'reference' => 'DEP-001'
]);

// Check balance
echo $wallet->getBalance('available'); // 100.00

4. Transfer between users

$sender = User::find(1);
$recipient = User::find(2);

// Simple transfer
$transfer = $sender->transferTo($recipient, 50.00, 'USD');

// Transfer with fee and metadata
$transfer = $sender->transferTo($recipient, 100.00, 'USD', [
    'fee' => 2.50,
    'description' => 'Payment for services',
    'reference' => 'TXN-12345'
]);

echo $transfer->getNetAmount(); // 102.50 (amount + fee)
echo $transfer->status->value; // 'confirmed'

๐Ÿ› ๏ธ Helper Functions

The package provides a comprehensive set of global helper functions for common wallet operations:

Currency and Amount Formatting

// Format amounts with currency symbols
echo wallet_format_amount(1234.56, 'USD'); // $1,234.56
echo wallet_format_amount(1234.56, 'EUR'); // โ‚ฌ1,234.56
echo wallet_format_amount(1234.56, 'GBP'); // ยฃ1,234.56

// Check currency support
if (wallet_is_currency_supported('USD')) {
    echo "USD is supported";
}

// Validate amounts within limits
if (wallet_validate_amount(100, 50, 200)) {
    echo "Amount is within limits";
}

// Calculate fees
$fee = wallet_calculate_fee(1000, 2.5); // 2.5% fee = 25.0
$fee = wallet_calculate_fee(1000, 0, 5.0); // Fixed fee = 5.0
$fee = wallet_calculate_fee(1000, 1.5, 2.0); // Both = 17.0

// Round amounts
$rounded = wallet_round_amount(123.456789, 2); // 123.46

// Calculate percentages
$result = wallet_calculate_percentage(1000, 15); // 150.0

Wallet Operations

// Format balance summary
$formatted = wallet_format_balance_summary($wallet);
// Returns: ['available' => '$1,000.00', 'pending' => '$0.00', ...]

// Get user wallet summary
$summary = wallet_get_user_summary($user);
// Returns: ['wallets' => [...], 'total_balance' => 1500.0, 'currencies' => ['USD', 'EUR']]

Advanced Helper Class Methods

use HWallet\LaravelMultiWallet\Helpers\WalletHelpers;

$helpers = app(WalletHelpers::class);

// Validate currency codes
$helpers->isValidCurrency('USD'); // true
$helpers->isValidCurrency('INVALID'); // false

// Get currency symbols
$helpers->getCurrencySymbol('USD'); // $
$helpers->getCurrencySymbol('EUR'); // โ‚ฌ

// Calculate transaction fees with strategies
$fee = $helpers->calculateTransactionFee(1000, 'percentage', 2.5); // 25.0
$fee = $helpers->calculateTransactionFee(1000, 'fixed', 10.0); // 10.0

// Tiered fee calculation
$fee = $helpers->calculateTransactionFee(1000, 'tiered', [
    'tiers' => [
        ['min' => 0, 'max' => 500, 'rate' => 1.0],
        ['min' => 500, 'max' => 1000, 'rate' => 2.0],
        ['min' => 1000, 'max' => null, 'rate' => 3.0]
    ]
]); // 30.0

// Validate metadata
$helpers->validateMetadata(['purpose' => 'savings']); // true
$helpers->validateMetadata(['password' => 'secret']); // false

// Calculate balance statistics
$stats = $helpers->calculateBalanceStatistics([$wallet1, $wallet2]);
// Returns: ['total' => 1500.0, 'average' => 750.0, 'min' => 500.0, 'max' => 1000.0]

// Handle precision calculations
$sum = $helpers->addAmounts(0.1, 0.2); // 0.3 (properly handled)

// Format multiple currencies
$formatted = $helpers->formatMultipleCurrencies([
    ['amount' => 100, 'currency' => 'USD'],
    ['amount' => 200, 'currency' => 'EUR']
]);
// Returns: ['$100.00', 'โ‚ฌ200.00']

๐Ÿ” Debugging and Monitoring Utilities

The package includes comprehensive debugging and monitoring tools:

Wallet Debugging

use HWallet\LaravelMultiWallet\Utils\WalletUtils;

// Debug wallet state
$debug = WalletUtils::debugWallet($wallet);
// Returns detailed wallet information including balances, transactions, metadata

// Validate wallet integrity
$validation = WalletUtils::validateWalletIntegrity($wallet);
// Returns: ['valid' => true, 'issues' => [], 'warnings' => []]

// Reconcile wallet balances
$result = WalletUtils::reconcileWallet($wallet);
// Returns: ['reconciled' => true, 'changes' => [...], 'summary' => '...']

// Get audit trail
$trail = WalletUtils::getWalletAuditTrail($wallet, 50);
// Returns collection of transactions and transfers with metadata

// Export wallet data
$export = WalletUtils::exportWalletData($wallet);
// Returns comprehensive wallet data for backup/analysis

Performance Monitoring

// Get performance metrics
$metrics = WalletUtils::getWalletPerformanceMetrics($wallet);
// Returns: ['transaction_count' => 150, 'average_transaction_amount' => 75.5, ...]

// Get wallet statistics
$stats = WalletUtils::getWalletStats($wallet);
// Returns: ['total_transactions' => 100, 'total_credits' => 50, ...]

// Analyze transaction patterns
$patterns = WalletUtils::analyzeTransactionPatterns($wallet, 30);
// Returns: ['transaction_frequency' => 2.5, 'amount_patterns' => [...], ...]

// Detect anomalies
$anomalies = WalletUtils::detectAnomalies($wallet);
// Returns: ['detected' => true, 'anomalies' => [...], 'score' => 20]

Health Monitoring

// Check wallet health
$health = WalletUtils::checkWalletHealth($wallet);
// Returns: ['healthy' => true, 'score' => 85, 'issues' => [], 'recommendations' => []]

// Monitor activity
$monitoring = WalletUtils::monitorWalletActivity($wallet);
// Returns: ['activity_level' => 'medium', 'risk_score' => 25, ...]

// Generate alerts
$alerts = WalletUtils::generateAlerts($wallet);
// Returns: ['alerts' => [...], 'severity' => 'low', 'recommendations' => [...]]

Bulk Operations and Maintenance

// Perform bulk operations
$result = WalletUtils::bulkOperation([$wallet1, $wallet2], 'credit', ['amount' => 100]);
// Returns: ['successful' => 2, 'failed' => 0, 'errors' => []]

// Clean up old data
$cleanup = WalletUtils::cleanupOldData($wallet, ['days' => 90]);
// Returns: ['cleaned' => true, 'removed_count' => 150, 'size_freed' => 153600]

// Optimize wallet performance
$optimization = WalletUtils::optimizeWallet($wallet);
// Returns: ['optimized' => true, 'improvements' => [...], 'performance_gain' => '15%']

// Validate data integrity
$integrity = WalletUtils::validateDataIntegrity($wallet);
// Returns: ['valid' => true, 'checksums' => [...], 'consistency' => 'good']

๐Ÿ” Type Safety System

The package includes a comprehensive type safety system with value objects and strict validation:

Type Creation and Validation

use HWallet\LaravelMultiWallet\Types\WalletTypes;

// Create type-safe amounts
$amount = WalletTypes::createAmount(100.50);
echo $amount->getValue(); // 100.50
echo $amount->isPositive(); // true

// Amount arithmetic
$sum = $amount->add(WalletTypes::createAmount(50.00)); // 150.50
$difference = $amount->subtract(WalletTypes::createAmount(25.00)); // 75.50
$product = $amount->multiply(2); // 201.00
$quotient = $amount->divide(2); // 50.25

// Currency validation
$currency = WalletTypes::createCurrency('USD');
echo $currency->getCode(); // USD
echo $currency->__toString(); // USD

// ID validation
$walletId = WalletTypes::createWalletId(123);
$transactionId = WalletTypes::createTransactionId(456);
$transferId = WalletTypes::createTransferId(789);

// Metadata with sanitization
$metadata = WalletTypes::createWalletMetadata([
    'purpose' => 'savings',
    'password' => 'secret123' // This will be sanitized out
]);

// Balance summaries
$summary = WalletTypes::createBalanceSummary([
    'available' => 1000.00,
    'pending' => 50.00,
    'frozen' => 0.00,
    'trial' => 25.00,
    'total' => 1075.00
]);

// Configuration objects
$config = WalletTypes::createWalletConfiguration([
    'default_currency' => 'USD',
    'allowed_currencies' => ['USD', 'EUR', 'GBP'],
    'transaction_limits' => ['min_amount' => 0.01, 'max_amount' => 10000.00]
]);

Type Comparisons and Operations

// Amount comparisons
$amount1 = WalletTypes::createAmount(100.00);
$amount2 = WalletTypes::createAmount(50.00);

$amount1->greaterThan($amount2); // true
$amount2->lessThan($amount1); // true
$amount1->equals(WalletTypes::createAmount(100.00)); // true

// Currency comparisons
$usd1 = WalletTypes::createCurrency('USD');
$usd2 = WalletTypes::createCurrency('USD');
$eur = WalletTypes::createCurrency('EUR');

$usd1->equals($usd2); // true
$usd1->equals($eur); // false

// ID comparisons
$id1 = WalletTypes::createWalletId(123);
$id2 = WalletTypes::createWalletId(123);
$id3 = WalletTypes::createWalletId(456);

$id1->equals($id2); // true
$id1->equals($id3); // false

๐Ÿ“Š Reporting and Analytics

Generate comprehensive reports for analysis and auditing:

// Generate summary report
$report = WalletUtils::generateSummaryReport($user);
// Returns: ['user_info' => [...], 'wallet_summary' => [...], 'balance_summary' => [...]]

// Generate detailed report
$report = WalletUtils::generateDetailedReport($user, [
    'include_transactions' => true,
    'include_transfers' => true
]);
// Returns: ['user_info' => [...], 'wallets' => [...], 'transactions' => [...]]

// Generate audit report
$report = WalletUtils::generateAuditReport($user, ['days' => 30]);
// Returns: ['period' => [...], 'audit_trail' => [...], 'summary' => [...]]

// Generate performance report
$report = WalletUtils::generatePerformanceReport($user);
// Returns: ['performance_metrics' => [...], 'recommendations' => [...]]

๐Ÿš€ High-Performance Bulk Operations with Transaction Safety

The package provides enterprise-grade bulk operations optimized for production environments with DB::transaction support for data integrity:

Bulk Credit Operations

use HWallet\LaravelMultiWallet\Services\BulkWalletManager;

$bulkManager = app(BulkWalletManager::class);

// Bulk credit multiple wallets
$operations = [
    ['wallet_id' => 1, 'amount' => 100.00, 'balance_type' => 'available', 'meta' => ['ref' => 'BULK-001']],
    ['wallet_id' => 2, 'amount' => 200.00, 'balance_type' => 'available', 'meta' => ['ref' => 'BULK-002']],
    ['wallet_id' => 3, 'amount' => 150.00, 'balance_type' => 'pending', 'meta' => ['ref' => 'BULK-003']],
];

$result = $bulkManager->bulkCredit($operations);

// Check results
if ($result['success']) {
    echo "Successfully processed {$result['successful_operations']} operations";
} else {
    echo "Failed operations: {$result['failed_operations']}";
    foreach ($result['errors'] as $error) {
        echo "Error at index {$error['index']}: {$error['error']}";
    }
}

Bulk Debit Operations

// Bulk debit with validation
$operations = [
    ['wallet_id' => 1, 'amount' => 50.00, 'balance_type' => 'available'],
    ['wallet_id' => 2, 'amount' => 75.00, 'balance_type' => 'available'],
];

$result = $bulkManager->bulkDebit($operations);

// The system automatically validates sufficient funds
// and rolls back all operations if any fail

Bulk Transfer Operations

// Bulk transfers between wallets
$operations = [
    [
        'from_wallet_id' => 1,
        'to_wallet_id' => 4,
        'amount' => 100.00,
        'options' => ['fee' => 2.00, 'description' => 'Bulk transfer 1']
    ],
    [
        'from_wallet_id' => 2,
        'to_wallet_id' => 5,
        'amount' => 150.00,
        'options' => ['fee' => 3.00, 'description' => 'Bulk transfer 2']
    ],
];

$result = $bulkManager->bulkTransfer($operations);

Using Bulk Operations via Traits

You can also use bulk operations directly through the HasWallets trait:

$user = User::find(1);

// Bulk credit user's wallets
$operations = [
    ['currency' => 'USD', 'amount' => 100.00],
    ['currency' => 'EUR', 'amount' => 200.00],
];

$result = $user->bulkCreditWallets($operations);

// Bulk debit operations
$result = $user->bulkDebitWallets($operations);

// Bulk freeze operations
$freezeOperations = [
    ['currency' => 'USD', 'amount' => 50.00, 'description' => 'Security freeze'],
    ['currency' => 'EUR', 'amount' => 75.00, 'description' => 'Risk assessment'],
];

$result = $user->bulkFreezeWallets($freezeOperations);

// Bulk unfreeze operations
$result = $user->bulkUnfreezeWallets($freezeOperations);

Enterprise Bulk Operation Features

  • ๐Ÿ”’ Transaction Safety: All bulk operations use DB::transaction for ACID compliance
  • โšก High Performance: Optimized for processing thousands of operations efficiently
  • ๐Ÿ” Validation: Each operation is validated before execution with detailed error reporting
  • ๐Ÿ“Š Error Handling: Comprehensive error reporting with operation-level failures
  • ๐Ÿ“ก Event Support: Rich event system for monitoring and auditing
  • ๐Ÿ”„ Rollback Support: Automatic rollback on failure (all-or-nothing mode)
  • ๐ŸŽฏ Partial Success: Optional partial success mode for fault tolerance
  • ๐Ÿ“ˆ Batch Processing: Configurable batch sizes for memory optimization
  • ๐Ÿงช Fully Tested: 100% test coverage for all bulk operations

๐Ÿ“– Comprehensive Guide

Balance Types

The package supports four distinct balance types for advanced financial management:

$wallet = $user->createWallet('USD', 'Main Wallet');

// Available Balance - Ready for use
$wallet->credit(1000.00, 'available');
echo $wallet->getBalance('available'); // 1000.00

// Pending Balance - Funds awaiting confirmation
$wallet->moveToPending(200.00, 'Processing payment');
$wallet->confirmPending(200.00, 'Payment confirmed');

// Frozen Balance - Temporarily locked funds
$wallet->freeze(100.00, 'Security review');
$wallet->unfreeze(100.00, 'Review completed');

// Trial Balance - Promotional or test credits
$wallet->addTrialBalance(50.00, 'Welcome bonus');
$wallet->convertTrialToAvailable(25.00, 'Trial period ended');

// Get comprehensive balance summary
$summary = $wallet->getBalanceSummary();
/*
[
    'available' => 825.00,
    'pending' => 0.00,
    'frozen' => 0.00,
    'trial' => 25.00,
    'total' => 850.00
]
*/

Advanced Transfer Operations

use HWallet\LaravelMultiWallet\Services\WalletManager;

$manager = app(WalletManager::class);
$fromWallet = $user1->getWallet('USD', 'Main');
$toWallet = $user2->getWallet('USD', 'Savings');

// Transfer with fee and discount
$transfer = $manager->transfer($fromWallet, $toWallet, 100.00, [
    'fee' => 5.00,        // Service fee
    'discount' => 2.00,   // Loyalty discount
    'description' => 'Discounted transfer',
    'meta' => ['promo_code' => 'SAVE20']
]);

// Check transfer details
echo $transfer->getGrossAmount();      // 100.00 (original amount)
echo $transfer->getFee();              // 5.00
echo $transfer->getDiscount();         // 2.00
echo $transfer->getNetAmount();        // 103.00 (100 + 5 - 2)
echo $transfer->getTransferredAmount(); // 100.00 (amount received)

// Transfer status management
$transfer->markAsPending();
$transfer->markAsConfirmed();
$transfer->markAsRejected();

Working with Multiple Currencies

// Configure exchange rates in config/multi-wallet.php
$user->createWallet('USD', 'US Dollar Wallet');
$user->createWallet('EUR', 'Euro Wallet');
$user->createWallet('GBP', 'British Pound Wallet');

// Get wallets by currency
$usdWallet = $user->getWallet('USD');
$eurWallet = $user->getWallet('EUR');

// Get all wallets
$allWallets = $user->wallets;

// Get wallets by currency
$usdWallets = $user->getWalletsByCurrency('USD');

// Check total balance across all currencies
$totalUsd = $user->getTotalBalance('USD');
$totalEur = $user->getTotalBalance('EUR');

Event System

The package dispatches events for all major operations:

use HWallet\LaravelMultiWallet\Events\WalletCreated;
use HWallet\LaravelMultiWallet\Events\TransactionCreated;
use HWallet\LaravelMultiWallet\Events\TransferCompleted;

// Listen to wallet events
Event::listen(WalletCreated::class, function ($event) {
    Log::info('New wallet created', [
        'wallet_id' => $event->wallet->id,
        'holder' => $event->wallet->holder_type,
        'currency' => $event->wallet->currency
    ]);
});

Event::listen(TransferCompleted::class, function ($event) {
    // Send notification, update analytics, etc.
    Notification::send($event->transfer->to, new TransferReceived($event->transfer));
});

Enhanced Event System

The package includes a comprehensive event system for all wallet operations:

Available Events

  • Wallet Events: WalletCreated, WalletUpdated, WalletDeleted, WalletFrozen, WalletUnfrozen
  • Transaction Events: TransactionCreated, TransactionConfirmed, TransactionFailed, TransactionReversed
  • Transfer Events: TransferInitiated, TransferCompleted, TransferFailed, TransferRejected
  • Balance Events: WalletBalanceChanged, WalletLimitExceeded, WalletReconciled
  • Operation Events: WalletOperationStarted, WalletOperationCompleted, WalletOperationFailed
  • Bulk Events: BulkOperationStarted, BulkOperationCompleted, BulkOperationFailed
  • Configuration Events: WalletConfigurationChanged, ExchangeRateUpdated
  • Security Events: SuspiciousActivityDetected

Event Usage Examples

use HWallet\LaravelMultiWallet\Events\WalletBalanceChanged;
use HWallet\LaravelMultiWallet\Events\TransactionCreated;
use HWallet\LaravelMultiWallet\Events\SuspiciousActivityDetected;
use HWallet\LaravelMultiWallet\Events\BulkOperationStarted;
use HWallet\LaravelMultiWallet\Events\BulkOperationCompleted;
use HWallet\LaravelMultiWallet\Events\BulkOperationFailed;

// Listen for balance changes
Event::listen(WalletBalanceChanged::class, function ($event) {
    // Send notification to user
    $user = $event->wallet->holder;
    Mail::to($user)->send(new BalanceChangedNotification($event));
});

// Monitor transaction creation
Event::listen(TransactionCreated::class, function ($event) {
    // Log transaction for audit
    AuditLog::create([
        'action' => 'transaction_created',
        'wallet_id' => $event->transaction->wallet_id,
        'amount' => $event->transaction->amount,
        'type' => $event->transaction->type->value,
    ]);
});

// Handle suspicious activity
Event::listen(SuspiciousActivityDetected::class, function ($event) {
    // Freeze wallet and notify security team
    $event->wallet->freeze($event->wallet->getBalance('available'), 'Suspicious activity detected');
    SecurityTeam::notify($event);
});

// Monitor bulk operations
Event::listen(BulkOperationStarted::class, function ($event) {
    Log::info("Bulk operation started: {$event->operationType} with {$event->operationCount} operations");
});

Event::listen(BulkOperationCompleted::class, function ($event) {
    Log::info("Bulk operation completed: {$event->operationType} with {$event->successfulOperations} successful operations");
});

Event::listen(BulkOperationFailed::class, function ($event) {
    Log::error("Bulk operation failed: {$event->operationType} with {$event->failedOperations} failures");
});

Using the Facade

use HWallet\LaravelMultiWallet\Facades\LaravelMultiWallet;

// Create wallet via facade
$wallet = LaravelMultiWallet::createWallet($user, 'USD', 'Main Wallet');

// Transfer between wallets
$transfer = LaravelMultiWallet::transfer($fromWallet, $toWallet, 100.00, [
    'description' => 'Facade transfer'
]);

// Get balance summary
$summary = LaravelMultiWallet::getBalanceSummary($user, 'USD');

Custom Exchange Rate Providers

Implement your own exchange rate logic:

use HWallet\LaravelMultiWallet\Contracts\ExchangeRateProviderInterface;

class ApiExchangeRateProvider implements ExchangeRateProviderInterface
{
    public function getRate(string $from, string $to): float
    {
        // Fetch from external API (e.g., CurrencyLayer, Fixer.io)
        $response = Http::get("https://api.exchangerate-api.com/v4/latest/{$from}");
        return $response->json()['rates'][$to] ?? 1.0;
    }
    
    public function convert(float $amount, string $from, string $to): float
    {
        return $amount * $this->getRate($from, $to);
    }
    
    public function getSupportedCurrencies(): array
    {
        return ['USD', 'EUR', 'GBP', 'JPY', 'CAD', 'AUD'];
    }
}

// Register in service provider
$this->app->singleton(ExchangeRateProviderInterface::class, ApiExchangeRateProvider::class);

๐Ÿ“Š Wallet Statistics and Analytics

The package provides built-in analytics and reconciliation tools:

Wallet Statistics

use HWallet\LaravelMultiWallet\Services\WalletManager;

$walletManager = app(WalletManager::class);
$wallet = $user->getWallet('USD');

// Get comprehensive wallet statistics
$stats = $walletManager->getWalletStatistics($wallet);

/*
Returns:
[
    'total_transactions' => 45,
    'total_credits' => 5000.00,
    'total_debits' => 2500.00,
    'total_transfers_sent' => 10,
    'total_transfers_received' => 8,
    'current_balance' => 2500.00,
    'available_balance' => 2000.00,
    'pending_balance' => 300.00,
    'frozen_balance' => 100.00,
    'trial_balance' => 100.00,
]
*/

Wallet Reconciliation

// Check wallet balance integrity
$reconciliation = $walletManager->reconcileWallet($wallet);

if (!$reconciliation['is_balanced']) {
    // Handle discrepancies
    foreach ($reconciliation['differences'] as $balanceType => $difference) {
        Log::warning("Balance discrepancy in {$balanceType}: {$difference['difference']}");
    }
    
    // Auto-fix if needed
    $walletManager->autoReconcileWallet($wallet);
}

User Balance Summary

// Get balance summary across all currencies
$summary = $walletManager->getBalanceSummary($user);

/*
Returns:
[
    [
        'currency' => 'USD',
        'total_wallets' => 3,
        'total_balance' => 5000.00,
        'available_balance' => 4500.00,
        'pending_balance' => 300.00,
        'frozen_balance' => 100.00,
        'trial_balance' => 100.00,
    ],
    [
        'currency' => 'EUR',
        'total_wallets' => 2,
        'total_balance' => 3000.00,
        // ...
    ]
]
*/

๐Ÿ—ƒ๏ธ Database Compatibility

The package is designed to work seamlessly with all major database systems:

Supported Databases

  • MySQL: Full support with optimized foreign keys and JSON columns
  • PostgreSQL: Native JSON support and advanced indexing
  • SQLite: Compatible with text-based JSON storage for testing
  • SQL Server: Full compatibility with proper data type handling

Migration Features

The migration files automatically detect your database type and apply appropriate optimizations:

// Automatic JSON column handling
if (config('database.default') === 'sqlite') {
    $table->text('meta')->nullable();  // SQLite compatibility
} else {
    $table->json('meta')->nullable();  // Native JSON for others
}

// Optimal decimal precision for all databases
$table->decimal('balance_available', 20, 8)->default(0);

// Timezone-aware timestamps where supported
if (config('database.default') === 'sqlite') {
    $table->timestamp('created_at')->useCurrent();
} else {
    $table->timestampTz('created_at')->useCurrent();
}

Configuration for Different Databases

// config/database.php

// MySQL configuration
'mysql' => [
    'driver' => 'mysql',
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'wallet_app'),
    'username' => env('DB_USERNAME', 'root'),
    'password' => env('DB_PASSWORD', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'options' => [
        PDO::ATTR_EMULATE_PREPARES => false,
        PDO::ATTR_STRINGIFY_FETCHES => false,
    ],
],

// PostgreSQL configuration
'pgsql' => [
    'driver' => 'pgsql',
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '5432'),
    'database' => env('DB_DATABASE', 'wallet_app'),
    'username' => env('DB_USERNAME', 'postgres'),
    'password' => env('DB_PASSWORD', ''),
    'charset' => 'utf8',
    'prefix' => '',
    'schema' => 'public',
],

// SQLite configuration (for testing)
'sqlite' => [
    'driver' => 'sqlite',
    'database' => database_path('wallet_app.sqlite'),
    'prefix' => '',
],

๐ŸŽ›๏ธ Advanced Features

Attribute-Based Operation Validation

The package uses PHP attributes to provide operation-level validation and logging:

use HWallet\LaravelMultiWallet\Attributes\WalletOperation;
use HWallet\LaravelMultiWallet\Attributes\BulkOperation;

class CustomWalletService
{
    #[WalletOperation(
        operation: 'custom_credit',
        description: 'Custom credit operation with validation',
        requiresValidation: true,
        logTransaction: true,
        fireEvents: true,
        auditLog: true
    )]
    public function customCredit(Wallet $wallet, float $amount): Transaction
    {
        // Custom validation logic
        if ($amount > 10000) {
            throw new \InvalidArgumentException('Amount exceeds maximum limit');
        }
        
        return $wallet->credit($amount, 'available', [
            'operation' => 'custom_credit',
            'validated_by' => auth()->id(),
        ]);
    }
    
    #[BulkOperation(
        operation: 'bulk_custom_credit',
        batchSize: 50,
        useTransaction: true,
        validateBeforeExecute: true,
        enableRollback: true
    )]
    public function bulkCustomCredit(array $operations): array
    {
        // Bulk operation with custom logic
        return $this->processBulkOperations($operations);
    }
}

Multi-Model Wallet Support

The package supports wallets for any model type:

// User wallets
class User extends Model
{
    use HasWallets;
}

// Company wallets
#[WalletConfiguration(
    defaultCurrency: 'USD',
    allowedCurrencies: ['USD', 'EUR', 'GBP', 'JPY'],
    walletLimits: ['max_balance' => 1000000.00],
    enableBulkOperations: true
)]
class Company extends Model
{
    use HasWallets;
}

// Product escrow wallets
#[WalletConfiguration(
    defaultCurrency: 'USD',
    autoCreateWallet: true,
    walletName: 'Escrow',
    transactionLimits: ['max_amount' => 50000.00]
)]
class Product extends Model
{
    use HasWallets;
}

// Usage examples
$user = User::find(1);
$company = Company::find(1);
$product = Product::find(1);

// All models can use the same wallet operations
$userWallet = $user->createWallet('USD');
$companyWallet = $company->createWallet('USD');
$escrowWallet = $product->autoCreateWallet(); // Auto-creates based on configuration

// Transfer between different model types
$user->transferTo($company, 1000.00, 'USD', ['description' => 'Service payment']);
$company->transferTo($product, 500.00, 'USD', ['description' => 'Escrow deposit']);

๐Ÿ”ง Complete WalletConfiguration API Reference

The enhanced WalletConfiguration system provides comprehensive control over wallet behavior through PHP attributes and programmatic configuration.

Configuration Methods Reference

<?php

use HWallet\LaravelMultiWallet\Attributes\WalletConfiguration;

#[WalletConfiguration(
    defaultCurrency: 'USD',
    allowedCurrencies: ['USD', 'EUR', 'GBP'],
    balanceTypes: ['available', 'pending', 'frozen', 'trial'],
    autoCreateWallet: true,
    walletName: 'Primary Account',
    metadata: ['priority' => 'high', 'region' => 'global'],
    limits: ['max_wallets' => 5],
    enableEvents: true,
    enableAuditLog: true,
    feeConfiguration: ['default_rate' => 0.02, 'type' => 'percentage'],
    uniquenessEnabled: true,
    uniquenessStrategy: 'currency_holder',
    exchangeRateConfig: ['provider' => 'live_api', 'refresh_interval' => 3600],
    freezeRules: 'auto_freeze_suspicious_activity',
    transactionLimits: [
        'min_amount' => 0.01,
        'max_amount' => 50000.00,
        'daily_limit' => 100000.00
    ],
    walletLimits: [
        'max_balance' => 1000000.00,
        'min_balance' => 0.00
    ],
    enableBulkOperations: true,
    webhookSettings: [
        'url' => 'https://api.example.com/webhooks/wallet',
        'events' => ['transaction_created', 'balance_changed'],
        'secret' => 'webhook_secret_key'
    ],
    notificationSettings: [
        'email' => true,
        'sms' => false,
        'push' => true,
        'templates' => ['balance_low', 'large_transaction']
    ],
    securitySettings: [
        'require_2fa' => false,
        'auto_freeze_suspicious' => true,
        'suspicious_threshold' => 10000.00,
        'fraud_detection' => true
    ]
)]
class AdvancedUser extends User
{
    use HasWallets;
}

Full API Methods Available

<?php

$user = new AdvancedUser();

// === BASIC CONFIGURATION ACCESS ===
$defaultCurrency = $user->getDefaultCurrency();
$defaultWalletName = $user->getDefaultWalletName();
$allowedCurrencies = $user->getAllowedCurrencies();
$enabledBalanceTypes = $user->getEnabledBalanceTypes();

// === LIMITS AND VALIDATION ===
$maxBalance = $user->getMaxBalanceLimit();
$minBalance = $user->getMinBalanceLimit();
$maxTransaction = $user->getMaxTransactionAmount();
$minTransaction = $user->getMinTransactionAmount();
$dailyLimit = $user->getDailyTransactionLimit();

// Validation methods
$isValidAmount = $user->validateTransactionAmount(1000.00);
$isValidBalance = $user->validateWalletBalance(50000.00);

// === FEATURE FLAGS ===
$eventsEnabled = $user->areWalletEventsEnabled();
$auditEnabled = $user->isWalletAuditLogEnabled();
$bulkEnabled = $user->areBulkOperationsEnabled();
$uniquenessEnabled = $user->isUniquenessEnabled();

// === ADVANCED SETTINGS ===
$uniquenessStrategy = $user->getUniquenessStrategy();
$feeSettings = $user->getFeeCalculationSettings();
$exchangeConfig = $user->getExchangeRateConfig();
$webhookSettings = $user->getWebhookSettings();
$notificationSettings = $user->getNotificationSettings();
$securitySettings = $user->getSecuritySettings();
$freezeRules = $user->getFreezeRules();
$metadataSchema = $user->getMetadataSchema();

// === BALANCE TYPE MANAGEMENT ===
$isAvailableEnabled = $user->isBalanceTypeEnabled('available');
$isPendingEnabled = $user->isBalanceTypeEnabled('pending');
$isFrozenEnabled = $user->isBalanceTypeEnabled('frozen');
$isTrialEnabled = $user->isBalanceTypeEnabled('trial');

// === WALLET CREATION WITH VALIDATION ===
$validatedWallet = $user->createWalletWithValidation('USD', 'Validated Wallet');

// === CONFIGURATION INTEGRATION ===
$configInterface = $user->getWalletConfigurationInterface();
$user->syncWithGlobalConfiguration();

// === ENHANCED WALLET OPERATIONS ===
$defaultWallet = $user->getDefaultWalletFromConfig();
$autoCreatedWallet = $user->autoCreateWallet();
$multiCurrencyWallets = $user->createWalletsFromConfig();

// === VALIDATION OPERATIONS ===
$canAfford = $user->canAfford(500.00, 'USD', 'available');
$allTransfers = $user->getAllTransfers();
$totalBalance = $user->getTotalBalance('USD');

// === ENHANCED TRANSFER WITH VALIDATION ===
$transfer = $user->transferTo($recipient, 100.00, 'USD', [
    'description' => 'Validated transfer',
    'validate_limits' => true,
    'check_balance_type' => 'available'
]);

Configuration Value Access

<?php

// Direct configuration value access
$configValue = $user->getWalletConfigValue('any_config_key', 'default_value');

// Get all configuration as array
$allConfig = $user->getWalletConfiguration();

// Example configuration checks
if ($user->getWalletConfigValue('require_2fa_for_large_transfers')) {
    // Implement 2FA requirement
}

$suspiciousThreshold = $user->getWalletConfigValue('security_settings.suspicious_threshold', 5000.00);
$webhookUrl = $user->getWalletConfigValue('webhook_settings.url');
$emailNotifications = $user->getWalletConfigValue('notification_settings.email', true);

Global Configuration Override

<?php

use HWallet\LaravelMultiWallet\Contracts\WalletConfigurationInterface;

// Access global configuration
$globalConfig = app(WalletConfigurationInterface::class);

// Override global settings for specific operations
$globalConfig->set('transaction_limits.max_amount', 25000.00);
$globalConfig->merge([
    'security_settings' => [
        'auto_freeze_suspicious' => true,
        'suspicious_threshold' => 15000.00
    ]
]);

// Sync user configuration with updated global settings
$user->syncWithGlobalConfiguration();

โš™๏ธ Configuration

Publish and customize the configuration file:

// config/multi-wallet.php
return [
    // Default settings
    'default_currency' => 'USD',
    'default_balance_type' => 'available',
    
    // Wallet constraints
    'wallet_limits' => [
        'max_balance' => null,           // No limit
        'min_balance' => 0,              // Cannot go negative
        'max_wallets_per_holder' => null // No limit
    ],
    
    // Transaction constraints
    'transaction_limits' => [
        'max_amount' => null,     // No limit
        'min_amount' => 0.01,     // Minimum transaction
    ],
    
    // Transfer settings
    'transfer_settings' => [
        'auto_confirm' => true,           // Auto-confirm transfers
        'max_fee_percentage' => 10,       // Max 10% fee
        'max_discount_percentage' => 100, // Max 100% discount
    ],
    
    // Supported currencies
    'supported_currencies' => [
        'USD', 'EUR', 'GBP', 'JPY', 'CAD', 'AUD', 'CHF', 'CNY'
    ],
    
    // Static exchange rates (use custom provider for dynamic rates)
    'exchange_rates' => [
        'USD_EUR' => 0.85,
        'EUR_USD' => 1.18,
        'USD_GBP' => 0.73,
        'GBP_USD' => 1.37,
    ],
    
    // Database table names
    'table_names' => [
        'wallets' => 'wallets',
        'transactions' => 'transactions',
        'transfers' => 'transfers',
    ],
    
    // Enable/disable features
    'features' => [
        'enforce_uniqueness' => false,    // One wallet per currency per holder
        'soft_deletes' => true,           // Soft delete support
        'uuid_generation' => true,        // Generate UUIDs
    ]
];

๐Ÿ” Query Scopes and Relationships

// Transaction queries
$wallet->transactions()
    ->confirmed()
    ->byType('credit')
    ->byBalanceType('available')
    ->where('amount', '>', 100)
    ->get();

// Transfer queries
$user->transfersFrom()
    ->confirmed()
    ->where('created_at', '>=', now()->subDays(30))
    ->get();

$user->transfersTo()
    ->pending()
    ->with(['from', 'deposit', 'withdraw'])
    ->get();

// Wallet queries with relationships
$wallets = Wallet::with(['holder', 'transactions', 'transfersFrom', 'transfersTo'])
    ->where('currency', 'USD')
    ->where('available_balance', '>', 1000)
    ->get();

๐Ÿงช Testing

The package includes comprehensive tests. Run them with:

# Run all tests
composer test

# Run with coverage
composer test-coverage

# Run specific test suite
vendor/bin/pest tests/Feature/WalletTest.php

# Run new feature tests
vendor/bin/pest tests/Feature/BulkOperationsTest.php
vendor/bin/pest tests/Feature/WalletAttributesTest.php

# Run with specific groups
./vendor/bin/pest --group=bulk-operations
./vendor/bin/pest --group=attributes
./vendor/bin/pest --group=events

Test Database Setup

// phpunit.xml or pest configuration
<php>
    <env name="DB_CONNECTION" value="sqlite"/>
    <env name="DB_DATABASE" value=":memory:"/>
</php>

Example Test Cases

<?php

// Testing bulk operations
test('it can perform bulk credit operations', function () {
    $operations = [
        ['wallet_id' => 1, 'amount' => 100.00],
        ['wallet_id' => 2, 'amount' => 200.00],
    ];
    
    $result = app(BulkWalletManager::class)->bulkCredit($operations);
    
    expect($result['success'])->toBeTrue();
    expect($result['successful_operations'])->toBe(2);
});

// Testing attributes
test('it can read wallet configuration from attributes', function () {
    $user = new UserWithWalletConfig();
    $config = $user->getWalletConfiguration();
    
    expect($config['default_currency'])->toBe('USD');
    expect($config['auto_create_wallet'])->toBeTrue();
});

๐Ÿ“Š Performance Considerations

  • Database Indexes: The package creates appropriate indexes for optimal query performance
  • Eager Loading: Use with() to avoid N+1 queries when loading relationships
  • Batch Operations: For bulk operations, consider using database transactions
  • Caching: Consider caching exchange rates and wallet balances for high-traffic applications
// Efficient wallet loading
$users = User::with(['wallets.transactions' => function ($query) {
    $query->confirmed()->latest()->limit(10);
}])->get();

// Batch operations
DB::transaction(function () use ($transfers) {
    foreach ($transfers as $transferData) {
        $this->processTransfer($transferData);
    }
});

๐Ÿ” Security Best Practices

  • Validation: Always validate amounts and currencies before operations
  • Authorization: Implement proper authorization checks in your controllers
  • Audit Trail: All transactions are automatically logged with metadata
  • Immutable Records: Transactions are immutable once created
// Example authorization
Gate::define('transfer-funds', function ($user, $fromWallet) {
    return $user->id === $fromWallet->holder_id;
});

// Example validation
$request->validate([
    'amount' => 'required|numeric|min:0.01|max:10000',
    'currency' => 'required|in:USD,EUR,GBP',
    'recipient_id' => 'required|exists:users,id'
]);

๐Ÿš€ Production Deployment

Before deploying to production:

  1. Run migrations: Ensure all database migrations are applied
  2. Configure queues: For high-volume applications, queue transaction processing
  3. Set up monitoring: Monitor wallet balances and transaction volumes
  4. Backup strategy: Implement regular database backups
  5. Rate limiting: Implement rate limiting for transfer endpoints
  6. Database optimization: Configure appropriate indexes for your database type
  7. Event listeners: Set up event listeners for monitoring and notifications
  8. Bulk operation limits: Configure appropriate batch sizes for bulk operations

Production Configuration Example

// config/multi-wallet.php
return [
    'default_currency' => 'USD',
    'default_balance_type' => 'available',
    
    // Production-optimized settings
    'wallet_limits' => [
        'max_balance' => 1000000.00,
        'min_balance' => 0,
        'max_wallets_per_holder' => 10
    ],
    
    'transaction_limits' => [
        'max_amount' => 50000.00,
        'min_amount' => 0.01,
    ],
    
    'transfer_settings' => [
        'auto_confirm' => false, // Manual confirmation for security
        'max_fee_percentage' => 5,
        'max_discount_percentage' => 50,
    ],
    
    'bulk_operations' => [
        'max_batch_size' => 100,
        'timeout_seconds' => 300,
        'enable_rollback' => true,
    ],
    
    'events' => [
        'enable_all_events' => true,
        'queue_events' => true, // Use queues for event processing
        'event_ttl' => 3600, // 1 hour TTL for event data
    ],
    
    'security' => [
        'suspicious_activity_threshold' => 10000.00,
        'auto_freeze_on_suspicious' => true,
        'require_2fa_for_large_transfers' => true,
        'large_transfer_threshold' => 5000.00,
    ],
    
    'monitoring' => [
        'enable_audit_log' => true,
        'log_all_transactions' => true,
        'enable_balance_reconciliation' => true,
        'reconciliation_frequency' => 'daily',
    ],
    
    'supported_currencies' => [
        'USD', 'EUR', 'GBP', 'JPY', 'CAD', 'AUD', 'CHF', 'CNY'
    ],
    
    'exchange_rates' => [
        'provider' => 'api', // Use external API for live rates
        'update_frequency' => 'hourly',
        'fallback_rates' => [
            'USD_EUR' => 0.85,
            'EUR_USD' => 1.18,
        ],
    ],
    
    'features' => [
        'enforce_uniqueness' => true,
        'soft_deletes' => true,
        'uuid_generation' => true,
        'enable_attributes' => true,
        'enable_bulk_operations' => true,
    ]
];

Monitoring and Alerting

// Set up event listeners for production monitoring
Event::listen(BulkOperationFailed::class, function ($event) {
    // Send alert to operations team
    Slack::to('#alerts')->send("Bulk operation failed: {$event->operationType}");
});

Event::listen(SuspiciousActivityDetected::class, function ($event) {
    // Immediate security alert
    SecurityTeam::alert($event);
});

Event::listen(WalletLimitExceeded::class, function ($event) {
    // Monitor for potential issues
    Log::warning("Wallet limit exceeded", [
        'wallet_id' => $event->wallet->id,
        'limit_type' => $event->limitType,
        'current_value' => $event->currentValue,
    ]);
});

๐Ÿค Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details.

๐Ÿ”’ Security

If you discover any security-related issues, please email mohamedhabibwork@gmail.com instead of using the issue tracker.

๐Ÿ“„ License

The MIT License (MIT). Please see License File for more information.

๐Ÿ™ Credits

๐Ÿ“š Related Packages

๐Ÿ”„ Migration Guide

From Previous Versions

If you're upgrading from a previous version of the package:

  1. Update dependencies:

    composer update hwallet/laravel-multi-wallet
  2. Publish new migrations:

    php artisan vendor:publish --provider="HWallet\LaravelMultiWallet\LaravelMultiWalletServiceProvider" --tag="migrations"
    php artisan migrate
  3. Update configuration (if needed):

    php artisan vendor:publish --provider="HWallet\LaravelMultiWallet\LaravelMultiWalletServiceProvider" --tag="config"
  4. Add attributes to models (optional but recommended):

    use HWallet\LaravelMultiWallet\Attributes\WalletConfiguration;
    
    #[WalletConfiguration(
        defaultCurrency: 'USD',
        autoCreateWallet: true
    )]
    class User extends Authenticatable
    {
        use HasWallets;
    }
  5. Update event listeners (if you have custom listeners):

    // New events available
    Event::listen(BulkOperationStarted::class, function ($event) {
        // Handle bulk operation start
    });
    
    Event::listen(WalletConfigurationChanged::class, function ($event) {
        // Handle configuration changes
    });

Breaking Changes

  • PHP 8.1+ Required: The package now requires PHP 8.1 or higher for attribute support
  • New Service Provider Registration: The BulkWalletManager is now registered automatically
  • Enhanced Event System: New events are available for bulk operations and configuration changes
  • Database Compatibility: Migrations now support all major database types automatically

๐Ÿ“ˆ Performance Benchmarks

Bulk Operations Performance

Operation Type Batch Size Average Time Memory Usage
Bulk Credit 100 0.5s 15MB
Bulk Debit 100 0.6s 16MB
Bulk Transfer 100 1.2s 20MB
Bulk Freeze 100 0.3s 12MB

Database Performance

Database Type Read Operations Write Operations JSON Queries
MySQL 1000 ops/sec 500 ops/sec 800 ops/sec
PostgreSQL 1200 ops/sec 600 ops/sec 1000 ops/sec
SQLite 800 ops/sec 400 ops/sec 600 ops/sec

Benchmarks performed on standard hardware with 1000 concurrent users