diff --git a/README.md b/README.md index cbc1c18..4515a0b 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,13 @@ **Demo:** https://github.com/HPWebdeveloper/demo-pay-pocket -**Videos:** +**Videos:** -- [Laravel Pay Pocket Package: Virtual Wallets in Your Project](https://www.youtube.com/watch?v=KoQyURiwsA4) +- [Laravel Pay Pocket Package: Virtual Wallets in Your Project](https://www.youtube.com/watch?v=KoQyURiwsA4) -- [Laravel Exceptions: Why and How to Use? Practical Example.](https://www.youtube.com/watch?v=-Sr18w91v8Q) - -- [PHP Enums in Laravel: Practical Example from Package](https://www.youtube.com/watch?v=iUOb-3HQtK8) +- [Laravel Exceptions: Why and How to Use? Practical Example.](https://www.youtube.com/watch?v=-Sr18w91v8Q) +- [PHP Enums in Laravel: Practical Example from Package](https://www.youtube.com/watch?v=iUOb-3HQtK8) **Note:** This package does not handle payments from payment platforms, but instead offers the concept of virtual money, deposit, and withdrawal. @@ -33,11 +32,10 @@ ### Support Policy -| Version | Laravel | PHP | Release date | End of improvements | End of support | -|-------------------------------------------------|--------------|-------------|---------------|---------------------| -------------- | -| 1.x | ^10.0 | 8.1, 8.2, 8.3 | Nov 30, 2023 | Mar 1, 2024 | | -| 2.x | ^10.0, ^11.0 |8.2, 8.3| June 27, 2024 | January 30, 2025 | | -| 3.x (atomic operations and restricted wallets) | ^11.0 |8.2, 8.3| comming soon | | | +| Version | Laravel | PHP | Release date | End of improvements | End of support | +| ------- | ------------ | ------------- | ------------- | ------------------- | -------------- | +| 1.x | ^10.0 | 8.1, 8.2, 8.3 | Nov 30, 2023 | Mar 1, 2024 | | +| 2.x | ^10.0, ^11.0 | 8.2, 8.3 | June 27, 2024 | January 30, 2025 | | ## Installation: @@ -178,6 +176,71 @@ $user = auth()->user(); LaravelPayPocket::pay($user, 12.34); ``` +#### Payment Transaction Logs + +The `pay()` method returns a collection of `WalletsLog` instances representing all wallet transactions that occurred during the payment. This enables you to track exactly which wallets were used and access detailed transaction information. + +**Return Value:** + +```php +@return \Illuminate\Database\Eloquent\Collection +``` + +**Basic Usage:** + +```php +$user = auth()->user(); +$logs = $user->pay(120.00, 'Order #1234'); + +// Access transaction details +foreach ($logs as $log) { + echo "Wallet: {$log->wallet_name}, Amount: {$log->value}"; +} +``` + +**Practical Examples:** + +```php +// Get the number of wallets used in the payment +$walletCount = $logs->count(); + +// Calculate total amount deducted (verification) +$totalDeducted = $logs->sum('value'); + +// Get all wallet names used in the transaction +$walletsUsed = $logs->pluck('wallet_name'); + +// Access specific log details +$firstLog = $logs->first(); +echo "From: {$firstLog->from}, To: {$firstLog->to}"; +echo "Reference: {$firstLog->reference}"; +``` + +**Use Cases:** + +- **Receipt Generation:** Display detailed payment breakdown showing amounts from each wallet +- **Audit Trail:** Maintain comprehensive records of payment sources +- **Transaction Verification:** Confirm the exact amount deducted from each wallet +- **Analytics:** Track wallet usage patterns across payments + +**Example: Multi-Wallet Payment** + +```php +$user = auth()->user(); + +// User has: wallet_1 = $100, wallet_2 = $50 +$logs = $user->pay(120.00, 'Premium subscription'); + +// Returns collection with 2 logs: +// Log 1: wallet_1 deducted $100 (100.00 -> 0.00) +// Log 2: wallet_2 deducted $20 (50.00 -> 30.00) + +echo "Payment completed using {$logs->count()} wallet(s)"; +// Output: Payment completed using 2 wallet(s) +``` + +**Note:** This feature is backward compatible. Existing code that doesn't capture the return value will continue to work without any modifications. + ### Balance - **Wallets** diff --git a/config/pay-pocket.php b/config/pay-pocket.php index a6a8124..c245102 100644 --- a/config/pay-pocket.php +++ b/config/pay-pocket.php @@ -12,10 +12,10 @@ | This configuration allows you to customize the generation of log reference strings | within the LaravelPayPocket package. | - | - [array] log_reference_params: An array of parameters to pass to the log_reference_generator_method. - | - [string] log_reference_prefix: Prefix for the generated reference string. - | - [class-string] log_reference_generator_class: Fully qualified name of the class containing static methods for generation. - | - [string] log_reference_generator_method: Name of the static method available in the generator class. + | - [array] log_reference_params: The parameters to pass to the log reference generator. + | - [string] log_reference_prefix: The prefix for the generated reference string. + | - [class-string] log_reference_generator_class: The fully qualified name of the class containing static methods for generation. + | - [string] log_reference_generator_method: The name of the static method available in the generator class. | | By default, the following generator is set up: | Illuminate\Support\Str::random(12) diff --git a/src/Facades/LaravelPayPocket.php b/src/Facades/LaravelPayPocket.php index 8d7092a..897f3ca 100644 --- a/src/Facades/LaravelPayPocket.php +++ b/src/Facades/LaravelPayPocket.php @@ -8,7 +8,7 @@ /** * @see \HPWebdeveloper\LaravelPayPocket\Services\PocketServices * - * @method static void pay(WalletOperations $user, int|float $orderValue, ?string $notes = null) + * @method static \Illuminate\Support\Collection pay(WalletOperations $user, int|float $orderValue, ?string $notes = null) * @method static bool deposit(WalletOperations $user, string $type, int|float $amount, ?string $notes = null) * @method static int|float checkBalance(WalletOperations $user) * @method static int|float walletBalanceByType(WalletOperations $user, string $type) diff --git a/src/Interfaces/WalletOperations.php b/src/Interfaces/WalletOperations.php index 572bf82..4cff7ce 100644 --- a/src/Interfaces/WalletOperations.php +++ b/src/Interfaces/WalletOperations.php @@ -3,6 +3,7 @@ namespace HPWebdeveloper\LaravelPayPocket\Interfaces; use HPWebdeveloper\LaravelPayPocket\Exceptions\InsufficientBalanceException; +use HPWebdeveloper\LaravelPayPocket\Models\WalletsLog; interface WalletOperations { @@ -24,9 +25,11 @@ public function hasSufficientBalance(int|float $value): bool; /** * Pay the order value from the user's wallets. * + * @return \Illuminate\Support\Collection + * * @throws InsufficientBalanceException */ - public function pay(int|float $orderValue, ?string $notes = null): void; + public function pay(int|float $orderValue, ?string $notes = null): \Illuminate\Support\Collection; /** * Deposit an amount to the user's wallet of a specific type. diff --git a/src/Services/PocketServices.php b/src/Services/PocketServices.php index 71f5244..0b9a78b 100644 --- a/src/Services/PocketServices.php +++ b/src/Services/PocketServices.php @@ -4,6 +4,7 @@ use HPWebdeveloper\LaravelPayPocket\Exceptions\InsufficientBalanceException; use HPWebdeveloper\LaravelPayPocket\Interfaces\WalletOperations; +use HPWebdeveloper\LaravelPayPocket\Models\WalletsLog; class PocketServices { @@ -18,11 +19,13 @@ public function deposit(WalletOperations $user, string $type, int|float $amount, /** * Pay the order value from the user's wallets. * + * @return \Illuminate\Support\Collection + * * @throws InsufficientBalanceException */ - public function pay(WalletOperations $user, int|float $orderValue, ?string $notes = null): void + public function pay(WalletOperations $user, int|float $orderValue, ?string $notes = null): \Illuminate\Support\Collection { - $user->pay($orderValue, $notes); + return $user->pay($orderValue, $notes); } /** diff --git a/src/Traits/BalanceOperation.php b/src/Traits/BalanceOperation.php index 247fb26..fe3bbdf 100644 --- a/src/Traits/BalanceOperation.php +++ b/src/Traits/BalanceOperation.php @@ -20,19 +20,23 @@ public function hasBalance(): bool /** * Decrement Balance and create a log entry. */ - public function decrementAndCreateLog(int|float $value, ?string $notes = null): void + public function decrementAndCreateLog(int|float $value, ?string $notes = null): WalletsLog { $this->createLog('dec', $value, $notes); $this->decrement('balance', $value); + + return $this->createdLog; } /** * Increment Balance and create a log entry. */ - public function incrementAndCreateLog(int|float $value, ?string $notes = null): void + public function incrementAndCreateLog(int|float $value, ?string $notes = null): WalletsLog { $this->createLog('inc', $value, $notes); $this->increment('balance', $value); + + return $this->createdLog; } /** diff --git a/src/Traits/HandlesDeposit.php b/src/Traits/HandlesDeposit.php index 87c817a..562b72d 100644 --- a/src/Traits/HandlesDeposit.php +++ b/src/Traits/HandlesDeposit.php @@ -13,6 +13,7 @@ trait HandlesDeposit /** * Deposit an amount to the user's wallet of a specific type. * + * * @throws InvalidDepositException * @throws InvalidValueException * @throws InvalidWalletTypeException @@ -26,7 +27,7 @@ public function deposit(string $type, int|float $amount, ?string $notes = null): } if ($amount <= 0) { - throw new InvalidValueException(); + throw new InvalidValueException; } DB::transaction(function () use ($type, $amount, $notes) { diff --git a/src/Traits/HandlesPayment.php b/src/Traits/HandlesPayment.php index 2ea0a44..5187e13 100644 --- a/src/Traits/HandlesPayment.php +++ b/src/Traits/HandlesPayment.php @@ -3,6 +3,7 @@ namespace HPWebdeveloper\LaravelPayPocket\Traits; use HPWebdeveloper\LaravelPayPocket\Exceptions\InsufficientBalanceException; +use HPWebdeveloper\LaravelPayPocket\Models\WalletsLog; use Illuminate\Support\Facades\DB; trait HandlesPayment @@ -10,15 +11,18 @@ trait HandlesPayment /** * Pay the order value from the user's wallets. * + * + * @return \Illuminate\Support\Collection + * * @throws InsufficientBalanceException */ - public function pay(int|float $orderValue, ?string $notes = null): void + public function pay(int|float $orderValue, ?string $notes = null): \Illuminate\Database\Eloquent\Collection { if (! $this->hasSufficientBalance($orderValue)) { throw new InsufficientBalanceException('Insufficient balance to cover the order.'); } - DB::transaction(function () use ($orderValue, $notes) { + return DB::transaction(function () use ($orderValue, $notes) { $remainingOrderValue = $orderValue; /** @@ -26,13 +30,15 @@ public function pay(int|float $orderValue, ?string $notes = null): void */ $walletsInOrder = $this->wallets()->whereIn('type', $this->walletsInOrder())->get(); + $logs = (new WalletsLog)->newCollection(); + foreach ($walletsInOrder as $wallet) { if (! $wallet || ! $wallet->hasBalance()) { continue; } $amountToDeduct = min($wallet->balance, $remainingOrderValue); - $wallet->decrementAndCreateLog($amountToDeduct, $notes); + $logs->push($wallet->decrementAndCreateLog($amountToDeduct, $notes)); $remainingOrderValue -= $amountToDeduct; if ($remainingOrderValue <= 0) { @@ -43,6 +49,8 @@ public function pay(int|float $orderValue, ?string $notes = null): void if ($remainingOrderValue > 0) { throw new InsufficientBalanceException('Insufficient total wallet balance to cover the order.'); } + + return $logs; }); } } diff --git a/tests/OperationsWithFacadeTest.php b/tests/OperationsWithFacadeTest.php index 2421416..41c56b2 100644 --- a/tests/OperationsWithFacadeTest.php +++ b/tests/OperationsWithFacadeTest.php @@ -129,3 +129,15 @@ expect(WalletsLog::whereNotNull('reference')->exists())->toBe(true); }); + +test('Payment returns log', function () { + $user = User::factory()->create(); + + $type = 'wallet_2'; + + LaravelPayPocket::deposit($user, $type, 234.56); + + $log = LaravelPayPocket::pay($user, 100.16); + + expect($log->sum('value'))->toBe(100.16); +}); diff --git a/tests/OperationsWithoutFacadeTest.php b/tests/OperationsWithoutFacadeTest.php index e64143f..1b3fee0 100644 --- a/tests/OperationsWithoutFacadeTest.php +++ b/tests/OperationsWithoutFacadeTest.php @@ -130,3 +130,15 @@ expect(WalletsLog::whereNotNull('reference')->exists())->toBe(true); }); + +test('Payment returns log', function () { + $user = User::factory()->create(); + + $type = 'wallet_2'; + + $user->deposit($type, 234.56); + + $log = $user->pay(100.16); + + expect($log->sum('value'))->toBe(100.16); +}); diff --git a/tests/database/migrations/create_users_tables.php b/tests/database/migrations/create_users_tables.php index 2bf4180..8efafc6 100644 --- a/tests/database/migrations/create_users_tables.php +++ b/tests/database/migrations/create_users_tables.php @@ -4,7 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class() extends Migration +return new class extends Migration { public function up(): void {