diff --git a/README.md b/README.md index d344f8c..54e116b 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ LaravelPayPocket::deposit($user, 'wallet_1', 123.45); Note: `wallet_1` and `wallet_2` must already be defined in the `WalletEnums`. -#### Transaction Notes ([#8][i8]) +#### Transaction Info ([#8][i8]) When you need to add descriptions for a specific transaction, the `$notes` parameter enables you to provide details explaining the reason behind the transaction. diff --git a/config/pay-pocket.php b/config/pay-pocket.php index 5c8e375..9dd0dbe 100644 --- a/config/pay-pocket.php +++ b/config/pay-pocket.php @@ -14,6 +14,7 @@ */ return [ 'log_reference_length' => 12, - 'log_reference_prefix' => null, - 'log_reference_generator' => null, + 'log_reference_prefix' => '', + 'log_reference_generator_class' => Illuminate\Support\Str::class, + 'log_reference_generator_method' => 'random', ]; diff --git a/src/Exceptions/InsufficientBalanceException.php b/src/Exceptions/InsufficientBalanceException.php index 1e87b6f..d77402c 100644 --- a/src/Exceptions/InsufficientBalanceException.php +++ b/src/Exceptions/InsufficientBalanceException.php @@ -3,16 +3,11 @@ namespace HPWebdeveloper\LaravelPayPocket\Exceptions; use Exception; +use Throwable; class InsufficientBalanceException extends Exception { - /** - * Construct the exception. - * - * @param string $message - * @param int $code - */ - public function __construct($message = 'Insufficient balance to cover the order', $code = 0, ?\Throwable $previous = null) + public function __construct(string $message = 'Insufficient balance to cover the order', int $code = 0, ?Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/src/Exceptions/InvalidDepositException.php b/src/Exceptions/InvalidDepositException.php index 937011e..4f5f1a6 100644 --- a/src/Exceptions/InvalidDepositException.php +++ b/src/Exceptions/InvalidDepositException.php @@ -3,16 +3,11 @@ namespace HPWebdeveloper\LaravelPayPocket\Exceptions; use Exception; +use Throwable; class InvalidDepositException extends Exception { - /** - * Construct the exception. - * - * @param string $message - * @param int $code - */ - public function __construct($message = 'Invalid deposit operation', $code = 0, ?\Throwable $previous = null) + public function __construct(string $message = 'Invalid deposit operation', int $code = 0, ?Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/src/Exceptions/InvalidValueException.php b/src/Exceptions/InvalidValueException.php index 7c351db..f5b48ca 100644 --- a/src/Exceptions/InvalidValueException.php +++ b/src/Exceptions/InvalidValueException.php @@ -3,16 +3,11 @@ namespace HPWebdeveloper\LaravelPayPocket\Exceptions; use Exception; +use Throwable; class InvalidValueException extends Exception { - /** - * Construct the exception. - * - * @param string $message - * @param int $code - */ - public function __construct($message = 'Invalie value to deposit', $code = 0, ?\Throwable $previous = null) + public function __construct(string $message = 'Invalie value to deposit', int $code = 0, ?Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/src/Exceptions/InvalidWalletTypeException.php b/src/Exceptions/InvalidWalletTypeException.php index 5f35ef9..be6cd5d 100644 --- a/src/Exceptions/InvalidWalletTypeException.php +++ b/src/Exceptions/InvalidWalletTypeException.php @@ -3,10 +3,11 @@ namespace HPWebdeveloper\LaravelPayPocket\Exceptions; use Exception; +use Throwable; class InvalidWalletTypeException extends Exception { - public function __construct($message = 'Invalid wallet type', $code = 0, ?\Throwable $previous = null) + public function __construct(string $message = 'Invalid wallet type', int $code = 0, ?Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/src/Exceptions/WalletNotFoundException.php b/src/Exceptions/WalletNotFoundException.php index 4b314a6..56139d7 100644 --- a/src/Exceptions/WalletNotFoundException.php +++ b/src/Exceptions/WalletNotFoundException.php @@ -3,10 +3,11 @@ namespace HPWebdeveloper\LaravelPayPocket\Exceptions; use Exception; +use Throwable; class WalletNotFoundException extends Exception { - public function __construct($message = 'Wallet not found', $code = 0, ?\Throwable $previous = null) + public function __construct(string $message = 'Wallet not found', int $code = 0, ?Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/src/Facades/LaravelPayPocket.php b/src/Facades/LaravelPayPocket.php index 1c33b5f..8d7092a 100644 --- a/src/Facades/LaravelPayPocket.php +++ b/src/Facades/LaravelPayPocket.php @@ -2,14 +2,20 @@ namespace HPWebdeveloper\LaravelPayPocket\Facades; +use HPWebdeveloper\LaravelPayPocket\Interfaces\WalletOperations; use Illuminate\Support\Facades\Facade; /** * @see \HPWebdeveloper\LaravelPayPocket\Services\PocketServices + * + * @method static void 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) */ class LaravelPayPocket extends Facade { - protected static function getFacadeAccessor() + protected static function getFacadeAccessor(): string { return \HPWebdeveloper\LaravelPayPocket\Services\PocketServices::class; } diff --git a/src/Interfaces/WalletOperations.php b/src/Interfaces/WalletOperations.php index 47e132d..572bf82 100644 --- a/src/Interfaces/WalletOperations.php +++ b/src/Interfaces/WalletOperations.php @@ -2,15 +2,39 @@ namespace HPWebdeveloper\LaravelPayPocket\Interfaces; +use HPWebdeveloper\LaravelPayPocket\Exceptions\InsufficientBalanceException; + interface WalletOperations { - public function getWalletBalanceAttribute(); + /** + * Get User's Wallet Balance + */ + public function getWalletBalanceAttribute(): int|float; - public function getWalletBalanceByType(string $walletType); + /** + * Get the balance of a specific wallet type. + */ + public function getWalletBalanceByType(string $walletType): int|float; - public function hasSufficientBalance($value): bool; + /** + * Check if User's wallet balance is more than given value + */ + public function hasSufficientBalance(int|float $value): bool; - public function pay(int|float $orderValue, ?string $notes = null); + /** + * Pay the order value from the user's wallets. + * + * @throws InsufficientBalanceException + */ + public function pay(int|float $orderValue, ?string $notes = null): void; + /** + * Deposit an amount to the user's wallet of a specific type. + */ public function deposit(string $type, int|float $amount, ?string $notes = null): bool; + + /** + * Get user's wallet balance. + */ + public function getWalletBalance(): int|float; } diff --git a/src/Models/WalletsLog.php b/src/Models/WalletsLog.php index b7a4130..91038e6 100644 --- a/src/Models/WalletsLog.php +++ b/src/Models/WalletsLog.php @@ -10,6 +10,14 @@ * HPWebdeveloper\LaravelPayPocket\Models\WalletsLog * * @property string $status + * @property int|float $from + * @property int|float $to + * @property string $type + * @property string $ip + * @property int|float $value + * @property string $wallet_name + * @property string $notes + * @property string $reference */ class WalletsLog extends Model { diff --git a/src/Services/PocketServices.php b/src/Services/PocketServices.php index 91db495..71f5244 100644 --- a/src/Services/PocketServices.php +++ b/src/Services/PocketServices.php @@ -2,24 +2,41 @@ namespace HPWebdeveloper\LaravelPayPocket\Services; +use HPWebdeveloper\LaravelPayPocket\Exceptions\InsufficientBalanceException; +use HPWebdeveloper\LaravelPayPocket\Interfaces\WalletOperations; + class PocketServices { - public function deposit($user, $type, $amount, $notes = null) + /** + * Deposit an amount to the user's wallet of a specific type. + */ + public function deposit(WalletOperations $user, string $type, int|float $amount, ?string $notes = null): bool { return $user->deposit($type, $amount, $notes); } - public function pay($user, $orderValue, $notes = null) + /** + * Pay the order value from the user's wallets. + * + * @throws InsufficientBalanceException + */ + public function pay(WalletOperations $user, int|float $orderValue, ?string $notes = null): void { - return $user->pay($orderValue, $notes); + $user->pay($orderValue, $notes); } - public function checkBalance($user) + /** + * Get the balance of the user. + */ + public function checkBalance(WalletOperations $user): int|float { - return $user->walletBalance; + return $user->getWalletBalance(); } - public function walletBalanceByType($user, $type) + /** + * Get the balance of a specific wallet type. + */ + public function walletBalanceByType(WalletOperations $user, string $type): int|float { return $user->getWalletBalanceByType($type); } diff --git a/src/Traits/BalanceOperation.php b/src/Traits/BalanceOperation.php index abbd4a5..c0ec100 100644 --- a/src/Traits/BalanceOperation.php +++ b/src/Traits/BalanceOperation.php @@ -2,14 +2,15 @@ namespace HPWebdeveloper\LaravelPayPocket\Traits; -use Illuminate\Support\Str; +use HPWebdeveloper\LaravelPayPocket\Models\WalletsLog; +use InvalidArgumentException; trait BalanceOperation { - protected $createdLog; + protected WalletsLog $createdLog; /** - * Check if Balance is more than zero. + * Check if Balance is more than zero. */ public function hasBalance(): bool { @@ -17,51 +18,62 @@ public function hasBalance(): bool } /** - * Decrement Balance and create a log entry. + * Decrement Balance and create a log entry. */ - public function decrementAndCreateLog($value, $notes = null): void + public function decrementAndCreateLog(int|float $value, ?string $notes = null): void { $this->createLog('dec', $value, $notes); $this->decrement('balance', $value); } /** - * Increment Balance and create a log entry. + * Increment Balance and create a log entry. */ - public function incrementAndCreateLog($value, $notes = null): void + public function incrementAndCreateLog(int|float $value, ?string $notes = null): void { $this->createLog('inc', $value, $notes); $this->increment('balance', $value); } /** - * Create a new log record + * Create a new log record */ - protected function createLog($logType, $value, $notes = null): void + protected function createLog(string $logType, int|float $value, ?string $notes = null): void { $currentBalance = $this->balance ?? 0; $newBalance = $logType === 'dec' ? $currentBalance - $value : $currentBalance + $value; - $refGen = config('pay-pocket.log_reference_generator', [ - Str::class, 'random', [config('pay-pocket.log_reference_length', 12)], - ]); - $reference = config('pay-pocket.reference_string_prefix', ''); - $reference .= isset($refGen[0], $refGen[1]) - ? $refGen[0]::{$refGen[1]}(...$refGen[2] ?? []) - : Str::random(config('pay-pocket.log_reference_length', 12)); - $this->createdLog = $this->logs()->create([ 'wallet_name' => $this->type->value, 'from' => $currentBalance, 'to' => $newBalance, 'type' => $logType, - 'ip' => \Request::ip(), + 'ip' => request()->ip(), 'value' => $value, 'notes' => $notes, - 'reference' => $reference, + 'reference' => $this->generateReference(), ]); $this->createdLog->changeStatus('Done'); } + + /** + * @throws InvalidArgumentException + */ + protected function generateReference(): string + { + $className = config('pay-pocket.log_reference_generator_class'); + $methodName = config('pay-pocket.log_reference_generator_method'); + $length = config('pay-pocket.log_reference_length'); + $prefix = config('pay-pocket.log_reference_prefix'); + + if (! is_callable([$className, $methodName])) { + throw new InvalidArgumentException('Invalid configuration: The combination of log_reference_generator_class and log_reference_generator_method is not callable.'); + } + + $reference = call_user_func([$className, $methodName], $length); + + return $prefix.$reference; + } } diff --git a/src/Traits/GetWallets.php b/src/Traits/GetWallets.php index 4606dd4..7c42a98 100644 --- a/src/Traits/GetWallets.php +++ b/src/Traits/GetWallets.php @@ -6,12 +6,10 @@ trait GetWallets { - private function walletsInOrder() + private function walletsInOrder(): array { return array_map( - function ($enumCase) { - return $enumCase->value; - }, + fn ($enumCase) => $enumCase->value, WalletEnums::cases() ); } diff --git a/src/Traits/HandlesDeposit.php b/src/Traits/HandlesDeposit.php index 03cbaf8..87c817a 100644 --- a/src/Traits/HandlesDeposit.php +++ b/src/Traits/HandlesDeposit.php @@ -8,12 +8,14 @@ use HPWebdeveloper\LaravelPayPocket\Exceptions\InvalidWalletTypeException; use Illuminate\Support\Facades\DB; -// Use your defined exception - trait HandlesDeposit { /** * Deposit an amount to the user's wallet of a specific type. + * + * @throws InvalidDepositException + * @throws InvalidValueException + * @throws InvalidWalletTypeException */ public function deposit(string $type, int|float $amount, ?string $notes = null): bool { @@ -50,12 +52,11 @@ private function getDepositableTypes(): array } /** - * Check if the given tyep is valid. + * Check if the given type is valid. * - * @param string $type - * @return bool + * @throws InvalidWalletTypeException */ - private function isRequestValid($type, array $depositable) + private function isRequestValid($type, array $depositable): bool { if (! array_key_exists($type, $depositable)) { throw new InvalidWalletTypeException('Invalid deposit type.'); diff --git a/src/Traits/HandlesPayment.php b/src/Traits/HandlesPayment.php index 4bfa835..2ea0a44 100644 --- a/src/Traits/HandlesPayment.php +++ b/src/Traits/HandlesPayment.php @@ -10,7 +10,6 @@ trait HandlesPayment /** * Pay the order value from the user's wallets. * - * * @throws InsufficientBalanceException */ public function pay(int|float $orderValue, ?string $notes = null): void @@ -22,6 +21,9 @@ public function pay(int|float $orderValue, ?string $notes = null): void DB::transaction(function () use ($orderValue, $notes) { $remainingOrderValue = $orderValue; + /** + * @var \Illuminate\Support\Collection + */ $walletsInOrder = $this->wallets()->whereIn('type', $this->walletsInOrder())->get(); foreach ($walletsInOrder as $wallet) { diff --git a/src/Traits/HasWallet.php b/src/Traits/HasWallet.php index d30ca89..d3826f6 100644 --- a/src/Traits/HasWallet.php +++ b/src/Traits/HasWallet.php @@ -6,6 +6,7 @@ use HPWebdeveloper\LaravelPayPocket\Exceptions\InvalidWalletTypeException; use HPWebdeveloper\LaravelPayPocket\Exceptions\WalletNotFoundException; use HPWebdeveloper\LaravelPayPocket\Models\Wallet; +use Illuminate\Database\Eloquent\Relations\MorphMany; trait HasWallet { @@ -16,17 +17,16 @@ trait HasWallet /** * Has Many Relation with Wallet Model */ - public function wallets() + public function wallets(): MorphMany { return $this->morphMany(Wallet::class, 'owner'); } /** - * Get User's Wallet Balance + * Get User's Wallet Balance */ - public function getWalletBalanceAttribute() + public function getWalletBalanceAttribute(): int|float { - $totalBalance = 0; foreach ($this->walletsInOrder() as $walletInOrder) { @@ -39,13 +39,12 @@ public function getWalletBalanceAttribute() } return $totalBalance; - } /** * Check if User's wallet balance is more than given value */ - public function hasSufficientBalance($value): bool + public function hasSufficientBalance(int|float $value): bool { return (int) $this->walletBalance >= (int) $value; } @@ -53,9 +52,9 @@ public function hasSufficientBalance($value): bool /** * Get the balance of a specific wallet type. * - * @return float|int + * @throws InvalidWalletTypeException|WalletNotFoundException */ - public function getWalletBalanceByType(string $walletType) + public function getWalletBalanceByType(string $walletType): int|float { if (! WalletEnums::isValid($walletType)) { throw new InvalidWalletTypeException("Invalid wallet type '{$walletType}'."); @@ -69,4 +68,9 @@ public function getWalletBalanceByType(string $walletType) return $wallet->balance; } + + public function getWalletBalance(): int|float + { + return $this->walletBalance; + } } diff --git a/src/Traits/Loggable.php b/src/Traits/Loggable.php index deddcf9..09b567c 100644 --- a/src/Traits/Loggable.php +++ b/src/Traits/Loggable.php @@ -3,10 +3,11 @@ namespace HPWebdeveloper\LaravelPayPocket\Traits; use HPWebdeveloper\LaravelPayPocket\Models\WalletsLog; +use Illuminate\Database\Eloquent\Relations\MorphMany; trait Loggable { - public function logs() + public function logs(): MorphMany { return $this->morphMany(WalletsLog::class, 'loggable'); } diff --git a/tests/Models/User.php b/tests/Models/User.php index 7a10991..5c07e35 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -11,8 +11,9 @@ class User extends Authenticatable implements WalletOperations { - use HasFactory, Notifiable; + use HasFactory; use ManagesWallet; + use Notifiable; /** * The attributes that are mass assignable.