diff --git a/.gitignore b/.gitignore index a7f372d..4dc59c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .idea .phpunit.cache +.DS_Store build composer.lock coverage diff --git a/README.md b/README.md index edb3f33..3b426cd 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ If the balance in `wallet_1` is 10 and the balance in `wallet_2` is 20, and you ### Deposit ```php -deposit(type: 'wallet_1', amount: 123.45, notes: null) +deposit(type: string, amount: float|int, notes: string null) ``` Deposit funds into `wallet_1` @@ -143,13 +143,13 @@ When you need to add descriptions for a specific transaction, the `$notes` param ```php $user = auth()->user(); -$user->deposit('wallet_1', 67.89, 'You ordered pizza.'); +$user->deposit('wallet_1', 67.89, 'You sold pizza.'); ``` ### Pay ```php -pay(amount: 12.34, notes: null) +pay(amount: int, allowedWallets: array [], notes: string null) ``` Pay the value using the total combined balance available across all allowed wallets @@ -168,6 +168,28 @@ $user = auth()->user(); LaravelPayPocket::pay($user, 12.34); ``` +By default the sytem will attempt to pay using all available wallets unless the `allowedWallets` param is provided. + +#### Allowed Wallets ([#8][i8]) + +Sometimes you want to mark certain wallets as allowed so that when the `pay()` method is called, the system does not attempt to charge other wallets, a possible use case is an escrow system, the `$allowedWallets` param of the pay method allows you to do just that. + +```php +$user = auth()->user(); +$user->pay(12.34, ['wallet_1']); +``` + +When the `$allowedWallets` param is provided and is not an empty array, the system would attempt to charge only the wallets specified in the array. + +#### Transaction Notes ([#8][i8]) + +In a case where you want to enter descriptions for a particular transaction, the `$note` param allows you to provide information about why a transaction happened. + +```php +$user = auth()->user(); +$user->pay(12.34, [], 'You ordered pizza.'); +``` + ### Balance - **Wallets** diff --git a/src/Interfaces/WalletOperations.php b/src/Interfaces/WalletOperations.php index 572bf82..66f0a4a 100644 --- a/src/Interfaces/WalletOperations.php +++ b/src/Interfaces/WalletOperations.php @@ -26,7 +26,7 @@ public function hasSufficientBalance(int|float $value): bool; * * @throws InsufficientBalanceException */ - public function pay(int|float $orderValue, ?string $notes = null): void; + public function pay(int|float $orderValue, array $allowedWallets = [], ?string $notes = null): void; /** * Deposit an amount to the user's wallet of a specific type. @@ -37,4 +37,4 @@ public function deposit(string $type, int|float $amount, ?string $notes = null): * Get user's wallet balance. */ public function getWalletBalance(): int|float; -} +} \ No newline at end of file diff --git a/src/Services/PocketServices.php b/src/Services/PocketServices.php index 71f5244..b81c686 100644 --- a/src/Services/PocketServices.php +++ b/src/Services/PocketServices.php @@ -20,9 +20,9 @@ public function deposit(WalletOperations $user, string $type, int|float $amount, * * @throws InsufficientBalanceException */ - public function pay(WalletOperations $user, int|float $orderValue, ?string $notes = null): void + public function pay(WalletOperations $user, int|float $orderValue, array $allowedWallets = [], ?string $notes = null): void { - $user->pay($orderValue, $notes); + $user->pay($orderValue, $allowedWallets, $notes); } /** @@ -40,4 +40,4 @@ public function walletBalanceByType(WalletOperations $user, string $type): int|f { return $user->getWalletBalanceByType($type); } -} +} \ No newline at end of file diff --git a/src/Traits/HandlesPayment.php b/src/Traits/HandlesPayment.php index 2ea0a44..8d6d203 100644 --- a/src/Traits/HandlesPayment.php +++ b/src/Traits/HandlesPayment.php @@ -12,13 +12,13 @@ trait HandlesPayment * * @throws InsufficientBalanceException */ - public function pay(int|float $orderValue, ?string $notes = null): void + public function pay(int|float $orderValue, array $allowedWallets = [], ?string $notes = null): void { if (! $this->hasSufficientBalance($orderValue)) { throw new InsufficientBalanceException('Insufficient balance to cover the order.'); } - DB::transaction(function () use ($orderValue, $notes) { + DB::transaction(function () use ($orderValue, $notes, $allowedWallets) { $remainingOrderValue = $orderValue; /** @@ -26,8 +26,21 @@ public function pay(int|float $orderValue, ?string $notes = null): void */ $walletsInOrder = $this->wallets()->whereIn('type', $this->walletsInOrder())->get(); + /** + * @param string|\App\Enums\WalletEnums + * @return bool $useWallet + * */ + $useWallet = function (string|\App\Enums\WalletEnums $wallet) use ($allowedWallets) { + return count($allowedWallets) < 1 || + in_array($wallet, $allowedWallets) || + in_array($wallet->value, $allowedWallets); + }; + + /** + * @var BalanceOperation $wallet + */ foreach ($walletsInOrder as $wallet) { - if (! $wallet || ! $wallet->hasBalance()) { + if (! $wallet || ! $wallet->hasBalance() || !$useWallet($wallet->type)) { continue; } diff --git a/tests/ExceptionsWithoutFacadeTest.php b/tests/ExceptionsWithoutFacadeTest.php index 5226676..e904c8c 100644 --- a/tests/ExceptionsWithoutFacadeTest.php +++ b/tests/ExceptionsWithoutFacadeTest.php @@ -59,8 +59,5 @@ $user = User::factory()->create(); - $type = 'wallet_1'; - $user->getWalletBalanceByType('wallet_2'); - })->throws(WalletNotFoundException::class); diff --git a/tests/OperationsWithFacadeTest.php b/tests/OperationsWithFacadeTest.php index 2421416..36f928e 100644 --- a/tests/OperationsWithFacadeTest.php +++ b/tests/OperationsWithFacadeTest.php @@ -115,7 +115,7 @@ $description = \Illuminate\Support\Str::random(); LaravelPayPocket::deposit($user, $type, 234.56); - LaravelPayPocket::pay($user, 234.56, $description); + LaravelPayPocket::pay($user, 234.56, [$type], $description); expect(WalletsLog::where('notes', $description)->exists())->toBe(true); }); @@ -129,3 +129,20 @@ expect(WalletsLog::whereNotNull('reference')->exists())->toBe(true); }); + +test('only the allowed wallets should be charged.', function () { + + $user = User::factory()->create(); + + $type = 'wallet_1'; + + LaravelPayPocket::deposit($user, $type, 234.56); + LaravelPayPocket::pay($user, 234.56, [$type]); + + $last = $user->wallets() + ->where('type', \App\Enums\WalletEnums::WALLET1) + ->first() + ->logs()->latest()->first(); + + expect($last->value)->toBeFloat(234.56); +}); diff --git a/tests/OperationsWithoutFacadeTest.php b/tests/OperationsWithoutFacadeTest.php index e64143f..28cd5ba 100644 --- a/tests/OperationsWithoutFacadeTest.php +++ b/tests/OperationsWithoutFacadeTest.php @@ -116,7 +116,7 @@ $description = \Illuminate\Support\Str::random(); $user->deposit($type, 234.56); - $user->pay(234.56, $description); + $user->pay(234.56, [$type], $description); expect(WalletsLog::where('notes', $description)->exists())->toBe(true); }); @@ -130,3 +130,20 @@ expect(WalletsLog::whereNotNull('reference')->exists())->toBe(true); }); + +test('only the allowed wallets should be charged.', function () { + + $user = User::factory()->create(); + + $type = 'wallet_1'; + + $user->deposit($type, 234.56); + $user->pay(234.56, [$type]); + + $last = $user->wallets() + ->where('type', \App\Enums\WalletEnums::WALLET1) + ->first() + ->logs()->latest()->first(); + + expect($last->value)->toBeFloat(234.56); +}); diff --git a/tests/TestCase.php b/tests/TestCase.php index 1dfaf4c..ec89c99 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -22,16 +22,16 @@ public function getEnvironmentSetUp($app) $migration->up(); */ - $migration = include __DIR__.'/database/migrations/create_users_tables.php'; + $migration = include __DIR__ . '/database/migrations/create_users_tables.php'; $migration->up(); - $migration = include __DIR__.'/../database/migrations/create_wallets_logs_table.php.stub'; + $migration = include __DIR__ . '/../database/migrations/create_wallets_logs_table.php.stub'; $migration->up(); - $migration = include __DIR__.'/../database/migrations/create_wallets_table.php.stub'; + $migration = include __DIR__ . '/../database/migrations/create_wallets_table.php.stub'; $migration->up(); - $migration = include __DIR__.'/../database/migrations/add_notes_and_reference_columns_to_wallets_logs_table.php.stub'; + $migration = include __DIR__ . '/../database/migrations/add_notes_and_reference_columns_to_wallets_logs_table.php.stub'; $migration->up(); } @@ -46,9 +46,9 @@ protected function setUp(): void */ Factory::guessFactoryNamesUsing( - fn (string $modelName) => 'HPWebdeveloper\\LaravelPayPocket\\Tests\\Database\\Factories\\'.class_basename( + fn (string $modelName) => 'HPWebdeveloper\\LaravelPayPocket\\Tests\\Database\\Factories\\' . class_basename( $modelName - ).'Factory' + ) . 'Factory' ); }