### Install laravel-wallet with Composer Source: https://github.com/bavix/laravel-wallet/blob/master/docs/_include/composer.md Run this command in your project root to install the package. Ensure your project is set up to autoload Composer-installed packages. ```bash composer req bavix/laravel-wallet ``` -------------------------------- ### Install Laravel Wallet Swap Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/additions/swap.md Install the package using Composer. This command adds the swap functionality to your Laravel Wallet setup. ```bash composer req bavix/laravel-wallet-swap ``` -------------------------------- ### Performing a Refund Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/refund.md Initiate a refund by finding the user and item, then calling the refund method on the user. This example shows the balance changes before and after the refund. ```php $user = User::first(); $user->balance; // 0 ``` ```php $item = Item::first(); $item->balance; // 100 ``` ```php (bool) app(PurchaseQueryHandlerInterface::class)->one(PurchaseQuery::create($user, $item)); // bool(true) (bool)$user->refund($item); // bool(true) $item->balance; // 0 $user->balance; // 100 ``` -------------------------------- ### Example Transfer Contract Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/fractional/transfer.md Demonstrates how to set up a transfer with additional options for deposit, withdrawal, and extra data. ```php $transfer = $user1->transferFloat( $user2, 5.11, new Extra( deposit: [ 'type' => 'extra-deposit', ], withdraw: new Option( [ 'type' => 'extra-withdraw', ], false // confirmed ), extra: [ 'msg' => 'hello world', ], ) ); ``` -------------------------------- ### Lazy Loading Example (N+1 Problem) Source: https://github.com/bavix/laravel-wallet/blob/master/docs/_include/eager_loading.md This code demonstrates the N+1 query problem where each user's wallet is loaded in a separate query within the loop. ```php $users = User::all(); foreach ($users as $user) { // echo $user->wallet->balance; echo $user->balance; // Abbreviated notation } ``` -------------------------------- ### User Model Setup for Wallets Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/cqrs/create-wallet.md Implement the HasWallet, HasWallets traits, and the Wallet interface on your User model to enable wallet functionality. ```php use Bavix\Wallet\Traits\HasWallet; use Bavix\Wallet\Traits\HasWallets; use Bavix\Wallet\Interfaces\Wallet; class User extends Model implements Wallet { use HasWallet, HasWallets; } ``` -------------------------------- ### Example Transfer Contract Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/single/transfer.md Demonstrates how to initiate a transfer with additional options for deposit, withdraw, and extra data. ```php $transfer = $user1->transfer( $user2, 511, new Extra( deposit: [ 'type' => 'extra-deposit', ], withdraw: new Option( [ 'type' => 'extra-withdraw', ], false // confirmed ), extra: [ 'msg' => 'hello world', ], ) ); ``` -------------------------------- ### User Model Setup for Multi-Wallets Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/additions/swap.md Configure your User model to support multiple wallets by using the HasWallet and HasWallets traits. ```php use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Traits\HasWallets; use Bavix\Wallet\Traits\HasWallet; class User extends Model implements Wallet { use HasWallet, HasWallets; } ``` -------------------------------- ### Implement Custom Exchange Service Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/single/exchange.md Create a custom service that implements the ExchangeServiceInterface to handle currency conversions. This example uses a hardcoded array for rates and leverages MathServiceInterface for calculations. ```php use Bavix\Wallet\Internal\Service\MathServiceInterface; use Bavix\Wallet\Services\ExchangeServiceInterface; class MyExchangeService implements ExchangeServiceInterface { private array $rates = [ 'USD' => [ 'RUB' => 67.61, ], ]; private MathServiceInterface $mathService; public function __construct(MathServiceInterface $mathService) { $this->mathService = $mathService; foreach ($this->rates as $from => $rates) { foreach ($rates as $to => $rate) { if (empty($this->rates[$to][$from])) { $this->rates[$to][$from] = $this->mathService->div(1, $rate); } } } } /** @param float|int|string $amount */ public function convertTo(string $fromCurrency, string $toCurrency, $amount): string { return $this->mathService->mul($amount, $this->rates[$fromCurrency][$toCurrency] ?? 1); } } ``` -------------------------------- ### User Model Setup for Confirmation Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/single/cancel.md Ensure your User model implements the Confirmable interface and uses the CanConfirm trait to enable transaction confirmation features. ```php use Bavix\Wallet\Interfaces\Confirmable; use Bavix\Wallet\Interfaces\Wallet; use Bavix\Wallet\Traits\CanConfirm; use Bavix\Wallet\Traits\HasWallet; class UserConfirm extends Model implements Wallet, Confirmable { use HasWallet, CanConfirm; } ``` -------------------------------- ### Install Laravel Wallet UUID with Composer Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/additions/uuid.md Use this command to add the UUID functionality to your Laravel Wallet installation. ```bash composer req bavix/laravel-wallet-uuid ``` -------------------------------- ### Filter Transactions by Wallet Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/multi/transaction-filter.md Demonstrates how to use `transactions` and `walletTransactions` methods to count all owner transactions versus specific wallet transactions. This example highlights multi-wallet scenarios and default wallet behavior. ```php $user->transactions()->count(); // 0 // Multi wallets and default wallet can be used together // default wallet $user->deposit(100); $user->wallet->deposit(200); $user->wallet->withdraw(1); // usd $usd = $user->createWallet(['name' => 'USD']); $usd->deposit(100); // eur $eur = $user->createWallet(['name' => 'EUR']); $eur->deposit(100); $user->transactions()->count(); // 5 $user->wallet->transactions()->count(); // 5 $usd->transactions()->count(); // 5 $eur->transactions()->count(); // 5 // the transactions method returns data relative to the owner of the wallet, for all transactions $user->walletTransactions()->count(); // 3. we get the default wallet $user->wallet->walletTransactions()->count(); // 3 $usd->walletTransactions()->count(); // 1 $eur->walletTransactions()->count(); // 1 ``` -------------------------------- ### Perform Transactions with Fractional Numbers Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/basic-usage.md Demonstrates how to perform deposits and check balances using fractional numbers. Access the `amountFloat` attribute on a transaction model to get the float amount. ```php $user = User::first(); $user->balance; // 100 $user->balanceFloat; // 1.00 $user->depositFloat(1.37); $user->balance; // 237 $user->balanceFloat; // 2.37 ``` ```php $transaction->amount; // 137 $transaction->amountFloat; // 1.37 ``` -------------------------------- ### Perform Purchase Checks Using PurchaseQuery Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/upgrade.md This example demonstrates how to check if a customer has already purchased a product using the PurchaseQuery and PurchaseQueryHandlerInterface. It replaces the deprecated `Customer::paid()` and `CartPay::paid()` methods. ```php use Bavix\Wallet\External\Api\PurchaseQuery; use Bavix\Wallet\External\Api\PurchaseQueryHandlerInterface; $transfer = app(PurchaseQueryHandlerInterface::class) ->one(PurchaseQuery::create($customer, $product)); $isPurchased = (bool) $transfer; ``` -------------------------------- ### Implement ProductInterface for Item Model (Unlimited Products) Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/basic-usage.md Demonstrates how to implement the `ProductInterface` for an `Item` model, allowing it to be purchased. This is suitable for an unlimited number of products. ```php use Bavix\Wallet\Traits\HasWallet; use Bavix\Wallet\Interfaces\Customer; use Bavix\Wallet\Interfaces\ProductInterface; class Item extends Model implements ProductInterface { use HasWallet; public function getAmountProduct(Customer $customer): int|string { return 100; } public function getMetaProduct(): ?array { return [ 'title' => $this->title, 'description' => 'Purchase of Product #' . $this->id, ]; } } ``` -------------------------------- ### Implement ProductLimitedInterface for Item Model (Limited Products) Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/basic-usage.md Shows how to implement the `ProductLimitedInterface` for an `Item` model, enabling purchase with quantity constraints. Use this for a limited number of products. ```php use Bavix\Wallet\Traits\HasWallet; use Bavix\Wallet\Interfaces\Customer; use Bavix\Wallet\Interfaces\ProductLimitedInterface; use Bavix\Wallet\External\Api\PurchaseQuery; use Bavix\Wallet\External\Api\PurchaseQueryHandlerInterface; class Item extends Model implements ProductLimitedInterface { use HasWallet; public function canBuy(Customer $customer, int $quantity = 1, bool $force = false): bool { /** * This is where you implement the constraint logic. * * If the service can be purchased once, then * return ! app(PurchaseQueryHandlerInterface::class)->one(PurchaseQuery::create($customer, $this)); */ return true; } public function getAmountProduct(Customer $customer): int|string { return 100; } public function getMetaProduct(): ?array { return [ 'title' => $this->title, 'description' => 'Purchase of Product #' . $this->id, ]; } } ``` -------------------------------- ### Get Current User Balance Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/single/refresh.md Displays the current balance of a user before any operations. ```php $user->id; // 5 $user->balance; // 27 ``` -------------------------------- ### Implement ProductInterface for Unlimited Products Source: https://github.com/bavix/laravel-wallet/blob/master/README.md Use the `ProductInterface` for items that can be purchased an unlimited number of times. Define the product's price and metadata. ```php use Bavix\Wallet\Traits\HasWallet; use Bavix\Wallet\Interfaces\Customer; use Bavix\Wallet\Interfaces\ProductInterface; class Item extends Model implements ProductInterface { use HasWallet; public function getAmountProduct(Customer $customer): int|string { return 100; } public function getMetaProduct(): ?array { return [ 'title' => $this->title, 'description' => 'Purchase of Product #' . $this->id, ]; } } ``` -------------------------------- ### Implement ProductInterface for Unlimited Products Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/receiving.md Add the `HasWallet` and `HasWallets` traits to your Item model and implement the `ProductInterface` for products with an unlimited supply. Define `getAmountProduct` and `getMetaProduct` methods. ```php use Bavix\Wallet\Traits\HasWallet; use Bavix\Wallet\Traits\HasWallets; use Bavix\Wallet\Interfaces\Customer; use Bavix\Wallet\Interfaces\ProductInterface; class Item extends Model implements ProductInterface { use HasWallet, HasWallets; public function getAmountProduct(Customer $customer): int|string { return 100; } public function getMetaProduct(): ?array { return [ 'title' => $this->title, 'description' => 'Purchase of Product #' . $this->id, ]; } } ``` -------------------------------- ### Implement ProductLimitedInterface for Limited Products Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/receiving.md For products with a limited quantity, implement the `ProductLimitedInterface` and add the `HasWallet` and `HasWallets` traits to your Item model. Implement `canBuy`, `getAmountProduct`, and `getMetaProduct` methods. ```php use Bavix\Wallet\Traits\HasWallet; use Bavix\Wallet\Traits\HasWallets; use Bavix\Wallet\Interfaces\Customer; use Bavix\Wallet\Interfaces\ProductLimitedInterface; class Item extends Model implements ProductLimitedInterface { use HasWallet, HasWallets; public function canBuy(Customer $customer, int $quantity = 1, bool $force = false): bool { return true; } public function getAmountProduct(Customer $customer): int|string { return 100; } public function getMetaProduct(): ?array { return [ 'title' => $this->title, 'description' => 'Purchase of Product #' . $this->id, ]; } } ``` -------------------------------- ### Get Wallet Transactions Query Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/multi/transaction-filter.md Obtain a query builder instance for transactions associated with a specific wallet. This is useful for further customization before execution. ```php /** @var \Bavix\Wallet\Models\Wallet $wallet */ $query = $wallet->walletTransactions(); ``` -------------------------------- ### Get a Specific Wallet by Slug Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/multi/new-wallet.md Retrieve a specific wallet associated with a user using its unique slug. This is useful for accessing and managing individual wallets. ```php $myWallet = $user->getWallet('my-wallet'); $myWallet->balance; // 100 $myWallet->balanceFloatNum; // 1.00 ``` -------------------------------- ### Create Wallet with Currency Meta Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/single/exchange.md Set the currency for a wallet using the 'meta' option during creation. ```php $user->createWallet([ 'name' => 'My USD Wallet', 'meta' => ['currency' => 'USD'], ]); ``` -------------------------------- ### Creating Wallets and Initial Deposit Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/multi/transfer.md Create wallets for users and make an initial deposit to the sender's wallet. This sets up the accounts for the transfer. ```php $firstWallet = $first->createWallet(['name' => 'First User Wallet']); $lastWallet = $last->createWallet(['name' => 'Second User Wallet']); $firstWallet->deposit(100); $firstWallet->balance; // 100 $lastWallet->balance; // 0 ``` -------------------------------- ### Implement ProductLimitedInterface for Limited Products Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/cart.md Use the `ProductLimitedInterface` for items with quantity constraints. Implement the `canBuy` method to define purchase logic, and `getAmountProduct` and `getMetaProduct` for pricing and metadata. ```php use Bavix\Wallet\Traits\HasWallet; use Bavix\Wallet\Interfaces\Customer; use Bavix\Wallet\Interfaces\ProductLimitedInterface; use Bavix\Wallet\External\Api\PurchaseQuery; use Bavix\Wallet\External\Api\PurchaseQueryHandlerInterface; class Item extends Model implements ProductLimitedInterface { use HasWallet; public function canBuy(Customer $customer, int $quantity = 1, bool $force = false): bool { /** * This is where you implement the constraint logic. * * If the service can be purchased once, then * return ! app(PurchaseQueryHandlerInterface::class)->one(PurchaseQuery::create($customer, $this)); */ return true; } public function getAmountProduct(Customer $customer): int|string { return round($this->price * 100); } public function getMetaProduct(): ?array { return [ 'title' => $this->title, 'description' => 'Purchase of Product #' . $this->id, ]; } } ``` -------------------------------- ### Perform Purchase and Refund Operations Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/basic-usage.md Illustrates how to purchase an item using the `pay` method and handle potential exceptions if funds are insufficient. Also shows how to check purchase status and perform refunds. ```php $user = User::first(); $user->balance; // 100 $item = Item::first(); $user->pay($item); // If you do not have enough money, throw an exception var_dump($user->balance); // 0 if ($user->safePay($item)) { // try to buy again ) } var_dump((bool) app(PurchaseQueryHandlerInterface::class)->one(PurchaseQuery::create($user, $item))); // bool(true) var_dump($user->refund($item)); // bool(true) var_dump((bool) app(PurchaseQueryHandlerInterface::class)->one(PurchaseQuery::create($user, $item))); // bool(false) ``` -------------------------------- ### Perform Transactions with Fractional Numbers Source: https://github.com/bavix/laravel-wallet/blob/master/README.md Demonstrates how to interact with balances using `balanceFloat` and perform deposits with fractional amounts. ```php $user = User::first(); $user->balance; // 100 $user->balanceFloat; // 1.00 $user->depositFloat(1.37); $user->balance; // 237 $user->balanceFloat; // 2.37 ``` -------------------------------- ### Implement ProductInterface for Unlimited Products Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/cart.md Add the `HasWallet` trait and `ProductInterface` to your Item model for products available in unlimited quantities. Implement `getAmountProduct` and `getMetaProduct` methods. ```php use Bavix\Wallet\Traits\HasWallet; use Bavix\Wallet\Interfaces\Customer; use Bavix\Wallet\Interfaces\ProductInterface; class Item extends Model implements ProductInterface { use HasWallet; public function getAmountProduct(Customer $customer): int|string { return round($this->price * 100); } public function getMetaProduct(): ?array { return [ 'title' => $this->title, 'description' => 'Purchase of Product #' . $this->id, ]; } } ``` -------------------------------- ### Perform Atomic Operation on a Single Wallet Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/db/atomic-service.md Use the `block` method to perform atomic operations on a single wallet. This method starts a transaction and locks the wallet. If the closure fails, the transaction rolls back and the lock is released. ```php use Bavix\Wallet\Services\AtomicServiceInterface; app(AtomicServiceInterface::class)->block($wallet, function () use ($wallet, $entity) { $entity->increaseSales(); // update entity set sort_at=NOW() where id=123; $wallet->withdraw(100); }); ``` -------------------------------- ### Publish Laravel Wallet Migrations Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/installation.md Run this Artisan command to publish the package's migration files. ```bash php artisan vendor:publish --tag=laravel-wallet-migrations ``` -------------------------------- ### Action Handler for Creating Wallets Asynchronously Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/cqrs/create-wallet.md Dispatch a CreateWalletCommandMessage to the queue to handle wallet creation asynchronously. This handler receives user details, wallet name, and UUID from the request. ```php use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\Support\Facades\Response as ResponseFactory; public function __invoke(User $user, Request $request): Response { $name = $request->get('wallet_name'); $uuid = $request->get('wallet_uuid'); $message = new CreateWalletCommandMessage($user, $name, $uuid); dispatch($message); return ResponseFactory::json([], 202); } ``` -------------------------------- ### Implement ProductLimitedInterface for Limited Products Source: https://github.com/bavix/laravel-wallet/blob/master/README.md Use the `ProductLimitedInterface` for items with purchase constraints. Implement `canBuy` to define the logic for whether a customer can purchase the item. ```php use Bavix\Wallet\Traits\HasWallet; use Bavix\Wallet\Interfaces\Customer; use Bavix\Wallet\Interfaces\ProductLimitedInterface; use Bavix\Wallet\External\Api\PurchaseQuery; use Bavix\Wallet\External\Api\PurchaseQueryHandlerInterface; class Item extends Model implements ProductLimitedInterface { use HasWallet; public function canBuy(Customer $customer, int $quantity = 1, bool $force = false): bool { /** * This is where you implement the constraint logic. * * If the service can be purchased once, then * return ! app(PurchaseQueryHandlerInterface::class)->one(PurchaseQuery::create($customer, $this)); */ return true; } public function getAmountProduct(Customer $customer): int|string { return 100; } public function getMetaProduct(): ?array { return [ 'title' => $this->title, 'description' => 'Purchase of Product #' . $this->id, ]; } } ``` -------------------------------- ### Make a Deposit - PHP Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/single/deposit.md Credit the user's wallet with a specified amount using the `deposit` method. The balance is updated accordingly. ```php $user->deposit(10); $user->balance; // 10 $user->balanceInt; // 10 ``` -------------------------------- ### Create Wallets with Currency Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/additions/swap.md Create new wallets for a user, specifying their name, slug, and associated currency meta-data. ```php $usd = $user->createWallet([ 'name' => 'My Dollars', 'slug' => 'usd', 'meta' => ['currency' => 'USD'], ]); $rub = $user->createWallet([ 'name' => 'My Ruble', 'slug' => 'rub', 'meta' => ['currency' => 'RUB'], ]); ``` -------------------------------- ### Configure Default Wallet Settings Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/configuration.md Set the name, slug, and meta information for the default wallet in `config/wallet.php`. ```php 'default' => [ 'name' => 'Ethereum', 'slug' => 'ETH', 'meta' => [], ], ``` -------------------------------- ### Initialize User Balance Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/cart.md Retrieve the first user from the database and check their current balance, which is initially 0. ```php $user = User::first(); $user->balance; // 0 ``` -------------------------------- ### Implementing Wallet Created Event Listener Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/events/wallet-created-event.md Create a listener class that implements the `handle` method to process the `WalletCreatedEventInterface`. This method receives the event object, allowing you to access wallet details. ```php use Bavix\Wallet\Internal\Events\WalletCreatedEventInterface; class MyWalletCreatedListener { public function handle(WalletCreatedEventInterface $event): void { // And then the implementation... } } ``` -------------------------------- ### Configure Lock Service for Race Conditions Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/db/race-condition.md Configure the 'lock' driver in your `wallet.php` configuration file to manage race conditions. Setting 'driver' to 'array' is a basic option, but 'redis' is recommended for production environments. The 'seconds' parameter defines the lock duration. ```php /** * A system for dealing with race conditions. */ 'lock' => [ 'driver' => 'array', 'seconds' => 1, ], ``` -------------------------------- ### Publish and Update Configuration Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/upgrade.md When upgrading to version 7.x.x, publish the new configuration file using `php artisan vendor:publish` and re-apply your custom settings. ```bash php artisan vendor:publish --tag=laravel-wallet-config --force ``` -------------------------------- ### Configure Cache Service for Wallet State Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/db/race-condition.md Configure the 'cache' driver in your `wallet.php` configuration file to store the state of wallet balances. While 'array' is shown, 'redis' is recommended for better performance and consistency, especially when dealing with concurrent operations. ```php /** * Storage of the state of the balance of wallets. */ 'cache' => ['driver' => 'array'], ``` -------------------------------- ### Command Handler for Wallet Creation Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/cqrs/create-wallet.md Process the CreateWalletCommandMessage to create a wallet for the user with the provided UUID and name. The database enforces UUID uniqueness. ```php public function __invoke(CreateWalletCommandMessage $message): void { $user = $message->getUser(); $user->createWallet([ 'uuid' => $message->getWalletUuid(), 'name' => $message->getWalletName(), ]); } ``` -------------------------------- ### Fill and Pay for Cart Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/cart.md Populate a cart with multiple items, calculate the total cost, deposit funds to the user's balance, and then pay for the entire cart. This demonstrates adding items, calculating totals, and executing a cart purchase. ```php use Bavix\Wallet\Objects\Cart; $list = [ 'potato' => 3, 'carrot' => 10, ]; $products = Item::query() ->whereIn('slug', ['potato', 'carrot']) ->get(); $cart = app(Cart::class); foreach ($products as $product) { $cart = $cart->withItem($product, quantity: $list[$product->slug]); } $cartTotal = $cart->getTotal($user); // 15127 $user->deposit($cartTotal); $user->balanceInt; // 15127 $user->balanceFloat; // 151.27 $cart = $cart->withItem(current($products), pricePerItem: 500); // 15127+500 $user->deposit(500); $user->balanceInt; // 15627 $user->balanceFloat; // 156.27 (bool)$user->payCart($cart); // true $user->balanceFloat; // 0 ``` -------------------------------- ### Perform Simple Wallet Transactions Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/basic-usage.md Demonstrates basic deposit and withdrawal operations on a user's wallet. Shows how to check the balance before and after transactions, including forced withdrawals. ```php $user = User::first(); $user->balance; // 0 $user->deposit(10); $user->balance; // 10 $user->withdraw(1); $user->balance; // 9 $user->forceWithdraw(200, ['description' => 'payment of taxes']); $user->balance; // -191 ``` -------------------------------- ### Eager Loading Wallets Source: https://github.com/bavix/laravel-wallet/blob/master/README.md Shows how to eager load wallet data for single or multiple wallets associated with a User model using Eloquent's `with` method. ```php // When working with one wallet User::with('wallet'); // When using the multi-wallet functionality User::with('wallets'); ``` -------------------------------- ### Performing a Free Payment Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/payment-free.md Retrieve the user and item, then use the `payFree` method on the user to complete the transaction. Verify the purchase status and balances afterward. ```php $user = User::first(); $user->balance; // 100 ``` ```php $item = Item::first(); $item->getAmountProduct($user); // 100 $item->balance; // 0 ``` ```php $user->payFree($item); (bool) app(PurchaseQueryHandlerInterface::class)->one(PurchaseQuery::create($user, $item)); // bool(true) $user->balance; // 100 $item->balance; // 0 ``` -------------------------------- ### Item Model Configuration for Purchases Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/commissions.md Add the `HasWallet` trait and `ProductInterface` (or `ProductLimitedInterface`) to your Item model. Implement methods to define product amount, metadata, and commission fee. ```php use Bavix\Wallet\Traits\HasWallet; use Bavix\Wallet\Interfaces\Customer; use Bavix\Wallet\Interfaces\Taxable; use Bavix\Wallet\Interfaces\ProductLimitedInterface; use Bavix\Wallet\External\Api\PurchaseQuery; use Bavix\Wallet\External\Api\PurchaseQueryHandlerInterface; class Item extends Model implements ProductLimitedInterface, Taxable { use HasWallet; public function canBuy(Customer $customer, int $quantity = 1, bool $force = false): bool { /** * If the service can be purchased once, then * return ! app(PurchaseQueryHandlerInterface::class)->one(PurchaseQuery::create($customer, $this)); */ return true; } public function getAmountProduct(Customer $customer): int|string { return 100; } public function getMetaProduct(): ?array { return [ 'title' => $this->title, 'description' => 'Purchase of Product #' . $this->id, ]; } public function getFeePercent() { return 0.03; // 3% } } ``` -------------------------------- ### Use Custom Wallet Model Method Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/configuration.md Access methods from your extended wallet model, such as `helloWorld()`, directly through the user's wallet instance. ```php echo $user->wallet->helloWorld(); ``` -------------------------------- ### Item Model Configuration for Minimal Tax Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/commissions.md Implement the `MinimalTaxable` interface in your Item model to set a minimum fee percentage for purchases. This ensures a minimum commission is always charged. ```php use Bavix\Wallet\Traits\HasWallet; use Bavix\Wallet\Interfaces\Customer; use Bavix\Wallet\Interfaces\MinimalTaxable; use Bavix\Wallet\Interfaces\ProductInterface; class Item extends Model implements ProductInterface, MinimalTaxable { use HasWallet; public function getAmountProduct(Customer $customer): int|string { return 100; } public function getMetaProduct(): ?array { return [ 'title' => $this->title, 'description' => 'Purchase of Product #' . $this->id, ]; } public function getFeePercent() { return 0.03; // 3% } public function getMinimalFee() { return 5; // 3%, minimum 5 } } ``` -------------------------------- ### Publish Laravel Wallet Configuration Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/db/race-condition.md Run this command to publish the Laravel Wallet configuration file to your project. This is necessary before you can modify settings like race condition handling. ```bash php artisan vendor:publish --tag=laravel-wallet-config ``` -------------------------------- ### Payment Process with Minimal Fee Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/merchant-fee-deductible.md Demonstrates the payment process when MerchantFeeDeductible is combined with MinimalTaxable. The customer pays the product price, and the merchant receives the product price minus the minimal fee. ```php $user = User::first(); $user->balance; // 100 ``` ```php $item = Item::first(); $item->getAmountProduct($user); // 100 ``` ```php $user->pay($item); // success, customer pays $100 $user->balance; // 0 ``` -------------------------------- ### Performing a Purchase with Commission Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/commissions.md After configuring the User and Item models, a user can pay for an item. The `pay` method handles the product cost plus the commission fee. ```php $user = User::first(); $user->balance; // 103 $item = Item::first(); $item->getAmountProduct($user); // 100 $user->pay($item); // success, 100 (product) + 3 (fee) = 103 $user->balance; // 0 ``` -------------------------------- ### Implement Wallet State Projection Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/events/wallet-state-projection.md Implement the WalletBatchProjectorInterface to define custom logic for projecting wallet states. This method calculates and returns custom fields for each wallet. ```php use Bavix\Wallet\Internal\Projector\WalletBatchProjectorInterface; final readonly class WalletStateBatchProjector implements WalletBatchProjectorInterface { public function project(array $balances, array $walletsById): array { $rows = []; foreach ($balances as $walletId => $resultingBalance) { $wallet = $walletsById[$walletId] ?? null; if ($wallet === null) { continue; } $heldBalance = (string) ($wallet->getAttribute('held_balance') ?? '0'); $rows[$walletId] = [ 'balance_after' => $resultingBalance, 'held_balance' => $heldBalance, 'state_hash' => hash('sha256', $wallet->uuid.':'.$resultingBalance.':'.$heldBalance), ]; } return $rows; } } ``` -------------------------------- ### Process Purchases and Refunds Source: https://github.com/bavix/laravel-wallet/blob/master/README.md Demonstrates how to use `pay`, `safePay`, and `refund` methods to manage transactions. Includes checks for balance and purchase status. ```php $user = User::first(); $user->balance; // 100 $item = Item::first(); $user->pay($item); // If you do not have enough money, throw an exception var_dump($user->balance); // 0 if ($user->safePay($item)) { // try to buy again } var_dump((bool) app(PurchaseQueryHandlerInterface::class)->one(PurchaseQuery::create($user, $item))); // bool(true) var_dump($user->refund($item)); // bool(true) var_dump((bool) app(PurchaseQueryHandlerInterface::class)->one(PurchaseQuery::create($user, $item))); // bool(false) ``` -------------------------------- ### Configure Custom Event Assembler Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/events/customize.md Register your custom event assembler in the `config/wallet.php` configuration file under the 'assemblers' key. This tells the package to use your assembler for creating balance updated events. ```php 'assemblers' => [ 'balance_updated_event' => MyUpdatedEventAssembler::class, ], ``` -------------------------------- ### Create New Wallet with Credit Limit Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/single/credit-limits.md When creating a new wallet, you can specify a credit limit by including it in the 'meta' array of the creation parameters. This is useful for setting initial credit allowances for new users or wallets. ```php /** @var \Bavix\Wallet\Traits\HasWallets $user */ $wallet = $user->createWallet([ 'name' => 'My Wallet', 'meta' => ['credit' => 500], ]); ``` -------------------------------- ### Initiate a Gift Purchase Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/gift.md Use the `gift` method on the sender's user model to transfer a product to a recipient. The sender's balance decreases, the recipient's balance remains unchanged, and the item's balance increases. Taxes and fees are handled if the product implements relevant interfaces. ```php $item = Item::first(); $item->getAmountProduct($first); // 100 $item->balance; // 0 $first->gift($last, $item); (bool) app(PurchaseQueryHandlerInterface::class)->one(PurchaseQuery::create($last, $item, true)); // bool(true) $first->balance; // 15 $last->balance; // 0 $item->balance; // 100 ``` -------------------------------- ### Register Wallet State Projector Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/events/wallet-state-projection.md Register your custom wallet state projector in the application's configuration. This tells the package where to find your custom projection logic. ```php 'projectors' => [ 'wallet' => \App\Wallet\WalletStateBatchProjector::class, ], ``` -------------------------------- ### Implement Custom Broadcastable Event Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/events/customize.md Implement the `BalanceUpdatedEventInterface` and `ShouldBroadcast` to create a custom event that can be broadcast. This allows for real-time updates when a wallet's balance changes. ```php use Bavix\Wallet\Internal\Events\BalanceUpdatedEventInterface; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; final class MyUpdatedEvent implements BalanceUpdatedEventInterface, ShouldBroadcast { public function __construct( private \Bavix\Wallet\Models\Wallet $wallet, private DateTimeImmutable $updatedAt, ) {} public function getWalletId(): int { return $this->wallet->getKey(); } public function getWalletUuid(): string { return $this->wallet->uuid; } public function getBalance(): string { return $this->wallet->balanceInt; } public function getUpdatedAt(): DateTimeImmutable { return $this->updatedAt; } public function broadcastOn(): array { return $this->wallet->getAttributes(); } } ``` -------------------------------- ### Implement Custom Transaction Assembler with State Tracking Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/upgrade.md Use this pattern for transaction state projections, tracking balance changes before and after confirmation. Requires injecting TransactionStateService and MathServiceInterface. ```php final class StateAwareAssembler implements TransactionDtoAssemblerInterface { public function __construct( private TransactionDtoAssembler $base, private TransactionStateService $stateService, // Your instance private RegulatorServiceInterface $regulator, private MathServiceInterface $mathService, ) {} public function create(...): TransactionDtoInterface { $dto = $this->base->create(...); $before = $this->regulator->amount($payable); $after = $ confirmado ? $this->mathService->add($before, $amount) // or sub for withdraw : $before; $this->stateService->push($dto->getUuid(), $walletId, [ 'balance' => $before, ], [ 'balance' => $after, ]); return $dto; } } ``` ```php 'assemblers' => [ 'transaction' => \App\Wallet\StateAwareAssembler::class, ], ``` -------------------------------- ### Create and Confirm a Transaction Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/single/confirm.md Create a transaction without immediate confirmation by passing `false` as the third argument to `deposit`. You can then confirm this transaction later using the `confirm` method. Note that you can only confirm a transaction with the wallet it was paid with. ```php $user->balance; // 0 $transaction = $user->deposit(100, null, false); // not confirm $transaction->confirmed; // bool(false) $user->balance; // 0 $user->confirm($transaction); // bool(true) $transaction->confirmed; // bool(true) $user->balance; // 100 ``` -------------------------------- ### Implement State-Aware Transaction Assembler Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/events/transaction-state-projection.md Create a custom assembler that computes and pushes transaction state changes using TransactionStateService. ```php use Bavix\Wallet\Enums\TransactionType; use Bavix\Wallet\Internal\Assembler\TransactionDtoAssembler; use Bavix\Wallet\Internal\Assembler\TransactionDtoAssemblerInterface; use Bavix\Wallet\Internal\Dto\TransactionDtoInterface; use Bavix\Wallet\Internal\Service\MathServiceInterface; use Bavix\Wallet\Internal\Service\TransactionStateService; use Bavix\Wallet\Services\RegulatorServiceInterface; use Illuminate\Database\Eloquent\Model; final readonly class StateAwareTransactionAssembler implements TransactionDtoAssemblerInterface { public function __construct( private TransactionDtoAssembler $base, private TransactionStateService $stateService, // Your service instance private RegulatorServiceInterface $regulator, private MathServiceInterface $mathService, ) {} public function create( Model $payable, int $walletId, TransactionType $type, float|int|string $amount, bool $confirmed, ?array $meta, ?string $uuid ): TransactionDtoInterface { $dto = $this->base->create($payable, $walletId, $type, $amount, $confirmed, $meta, $uuid); $before = $this->regulator->amount($payable); $after = $before; if ($confirmed) { $after = $type === TransactionType::Deposit ? $this->mathService->add($before, $amount) : $this->mathService->sub($before, $amount); } // Push state to your service $this->stateService->push($dto->getUuid(), $walletId, [ 'balance' => $before, ], [ 'balance' => $after, ]); return $dto; } } ``` -------------------------------- ### Create Wallets for Exchange Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/single/exchange.md Create two distinct wallets, each with a different currency specified in their meta data, to prepare for an exchange operation. ```php $usd = $user->createWallet([ 'name' => 'My Dollars', 'meta' => ['currency' => 'USD'], ]); $rub = $user->createWallet([ 'name' => 'My Ruble', 'meta' => ['currency' => 'RUB'], ]); ``` -------------------------------- ### Extend Base Wallet Model Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/configuration.md Create a custom wallet model by extending `Bavix\Wallet\Models\Wallet` and register it in `config/wallet.php`. ```php use Bavix\Wallet\Models\Wallet as WalletBase; class MyWallet extends WalletBase { public function helloWorld(): string { return "hello world"; } } ``` -------------------------------- ### Eager Loading with `with` Method Source: https://github.com/bavix/laravel-wallet/blob/master/docs/_include/eager_loading.md Use the `with` method to eager load the 'wallet' relationship, reducing the number of database queries from N+1 to just 2. ```php $users = User::with('wallet')->all(); foreach ($users as $user) { // echo $user->wallet->balance; echo $user->balance; // Abbreviated notation } ``` -------------------------------- ### Create a BalanceUpdatedEvent Listener Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/events/balance-updated-event.md Implement a custom listener class to handle the BalanceUpdatedEventInterface. This class will contain the logic to execute whenever a balance update occurs. ```php use Bavix\Wallet\Internal\Events\BalanceUpdatedEventInterface; class MyBalanceUpdatedListener { public function handle(BalanceUpdatedEventInterface $event): void { // And then the implementation... } } ``` -------------------------------- ### Basic Transaction with Wallet Operation Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/db/transaction.md Demonstrates a typical transaction flow where a wallet operation is performed. Note that accessing the balance or performing other wallet actions blocks the wallet until the transaction is committed or rolled back. Minimize the time between `beginTransaction` and `commit`. ```php use Illuminate\Support\Facades\DB; DB::beginTransaction(); $wallet->balanceInt; // now the wallet is blocked doingMagic(); // running for a long time. DB::commit(); // here will unlock the wallet ``` -------------------------------- ### Update Math Class Configuration Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/upgrade.md When upgrading to version 6.0.x, update the `mathable` configuration in `config/wallet.php` to use `BrickMath::class`. ```php // Your code on 5.x: 'mathable' => $mathClass, ``` ```php // Your code on 6.x: 'mathable' => BrickMath::class, ``` -------------------------------- ### Register Custom Assembler Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/events/transaction-state-projection.md Configure your application to use a custom assembler for transaction data by updating the 'config/wallet.php' file. ```php // config/wallet.php 'assemblers' => [ 'transaction' => \App\Wallet\StateAwareTransactionAssembler::class, ], ``` -------------------------------- ### Run Artisan Command for Transfer Fix Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/upgrade.md Execute the `bx:transfer:fix` Artisan command to migrate transfer storage logic to the new structure, ensuring all transactions go strictly between wallets. Repeat the command until it executes immediately. ```bash artisan bx:transfer:fix ``` -------------------------------- ### Successful Purchase with Minimal Fee Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/commissions.md When a user purchases an item configured with `MinimalTaxable`, the transaction includes the product cost plus the minimum fee if it exceeds the calculated percentage. ```php $user = User::first(); $user->balance; // 105 $item = Item::first(); $item->getAmountProduct($user); // 100 $user->pay($item); // success, 100 (product) + 5 (minimal fee) = 105 $user->balance; // 0 ``` -------------------------------- ### Find User Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/fractional/deposit.md Retrieve a user model from the database. This is the first step before interacting with their wallet. ```php $user = User::first(); ``` -------------------------------- ### Performing a Standard Transfer Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/multi/transfer.md Execute a standard transfer of funds from one wallet to another. The balances are updated accordingly after the transaction. ```php $firstWallet->transfer($lastWallet, 5); $firstWallet->balance; // 95 $lastWallet->balance; // 5 ``` -------------------------------- ### Implement HasWallet Trait for User Model Source: https://github.com/bavix/laravel-wallet/blob/master/docs/_include/models/user_simple.md Extend your User model to implement the Wallet interface and use the HasWallet trait to enable wallet functionality. Ensure the necessary imports are included. ```php use Bavix\Wallet\Traits\HasWallet; use Bavix\Wallet\Interfaces\Wallet; class User extends Model implements Wallet { use HasWallet; } ``` -------------------------------- ### Registering Wallet Created Event Listener Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/events/wallet-created-event.md Configure your Laravel application's event service provider to listen for the `WalletCreatedEventInterface` and map it to your custom listener class. ```php use Bavix\Wallet\Internal\Events\WalletCreatedEventInterface; protected $listen = [ WalletCreatedEventInterface::class => [ MyWalletCreatedListener::class, ], ]; ``` -------------------------------- ### Check User Balance Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/fractional/deposit.md Access and inspect the user's balance using different properties. The balance is initially zero. ```php $user->balance; // 0 $user->balanceInt; // 0 $user->balanceFloatNum; // 0 ``` -------------------------------- ### Register Custom Exchange Service Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/single/exchange.md Register your custom exchange service by adding its class name to the 'services.exchange' key in the `config/wallet.php` configuration file. ```php return [ // ... 'services' => [ 'exchange' => MyExchangeService::class, // ... ], // ... ]; ``` -------------------------------- ### Create a Specific Receiving Wallet Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/receiving.md Create a new wallet for a specific item to receive funds. This allows for custom currency and meta information for the receiving wallet. ```php $item = Item::first(); $item->getAmountProduct($user); // 100 $receiving = $item->createWallet([ 'name' => 'Dollar', 'meta' => [ 'currency' => 'USD', ], ]); ``` -------------------------------- ### Make a Standard Withdraw Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/single/withdraw.md Withdraw funds from the user's balance. This method will throw an `InsufficientFunds` exception if the balance is insufficient. ```php $user->withdraw(10); $user->balance; // 90 $user->balanceInt; // 90 ``` -------------------------------- ### Check User Balance - PHP Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/single/deposit.md Access the user's wallet balance using the `balance` or `balanceInt` properties. The balance is initially zero. ```php $user->balance; // 0 $user->balanceInt; // 0 ``` -------------------------------- ### Create a New Wallet for a User Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/multi/new-wallet.md Create a new wallet for a user with a specified name and a unique slug. This method returns the created wallet instance and updates the user's wallet count. ```php $user->hasWallet('my-wallet'); // bool(false) $wallet = $user->createWallet([ 'name' => 'New Wallet', 'slug' => 'my-wallet', ]); $user->hasWallet('my-wallet'); // bool(true) $wallet->deposit(100); $wallet->balance; // 100 $wallet->balanceFloatNum; // 1.00 ``` -------------------------------- ### User Model Implementation Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/purchases/merchant-fee-deductible.md Add the CanPay trait and Customer interface to your User model. Ensure the CanPay trait is not duplicated if HasWallet is already inherited. ```php use Bavix\Wallet\Traits\CanPay; use Bavix\\\Wallet\\Interfaces\\Customer; class User extends Model implements Customer { use CanPay; } ``` -------------------------------- ### Register Custom Wallet Model Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/introduction/configuration.md Specify your custom wallet model class in the `config/wallet.php` file under the 'wallet' configuration. ```php 'wallet' => [ 'table' => 'wallets', 'model' => MyWallet::class, 'creating' => [], 'default' => [ 'name' => 'Default Wallet', 'slug' => 'default', 'meta' => [], ], ], ``` -------------------------------- ### Perform Wallet Transactions in Laravel Source: https://github.com/bavix/laravel-wallet/blob/master/README.md Demonstrates basic wallet operations including checking balance, depositing, withdrawing, and force withdrawing funds. Ensure the `HasWallet` trait and `Wallet` interface are implemented on the model. ```php $user = User::first(); $user->balanceInt; // 0 $user->deposit(10); $user->balance; // 10 $user->balanceInt; // int(10) $user->withdraw(1); $user->balance; // 9 $user->forceWithdraw(200, ['description' => 'payment of taxes']); $user->balance; // -191 ``` -------------------------------- ### Optimized Batch Transfers with TransferQueryHandlerInterface Source: https://github.com/bavix/laravel-wallet/blob/master/docs/guide/high-performance/batch-transfers.md Use `TransferQueryHandlerInterface` to report transfers in a single transaction, optimizing database and cache interactions. Ensure you manage wallet balances manually before execution. ```php use Bavix\Wallet\External\Api\TransferQuery; use Bavix\Wallet\External\Api\TransferQueryHandlerInterface; app(TransferQueryHandlerInterface::class)->apply( array_map( static fn (Wallet $wallet) => new TransferQuery($from, $wallet, $amount, null), $wallets ) ); ```