diff --git a/src/Concerns/InteractsWithWallet.php b/src/Concerns/InteractsWithWallet.php index 17f65b5..1013b12 100644 --- a/src/Concerns/InteractsWithWallet.php +++ b/src/Concerns/InteractsWithWallet.php @@ -4,13 +4,11 @@ use Exception; use Flavorly\LaravelHelpers\Helpers\Math\Math; -use Flavorly\Wallet\Exceptions\WalletLockedException; use Flavorly\Wallet\Models\Transaction; use Flavorly\Wallet\Services\BalanceService; use Flavorly\Wallet\Wallet; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphMany; -use Throwable; /** * @mixin Model @@ -77,38 +75,4 @@ public function balance(): BalanceService { return $this->wallet()->balance(); } - - /** - * Alias for Credit - * - * - * @throws WalletLockedException - * @throws Throwable - */ - public function credit(float|int|string $amount, array $meta = [], ?string $endpoint = null, bool $throw = false): bool - { - return $this->wallet()->credit( - amount: $amount, - meta: $meta, - endpoint: $endpoint, - throw: $throw - ); - } - - /** - * Alias for debit - * - * - * @throws WalletLockedException - * @throws Throwable - */ - public function debit(float|int|string $amount, array $meta = [], ?string $endpoint = null, bool $throw = false): bool - { - return $this->wallet()->debit( - amount: $amount, - meta: $meta, - endpoint: $endpoint, - throw: $throw - ); - } } diff --git a/src/Contracts/HasWallet.php b/src/Contracts/HasWallet.php index 6fcf7ce..0d18b58 100644 --- a/src/Contracts/HasWallet.php +++ b/src/Contracts/HasWallet.php @@ -36,20 +36,6 @@ public function getBalanceAttribute(): Math; */ public function getBalanceFormattedAttribute(): string; - /** - * Credits the user or model with the given amount - * - * @param array $meta - */ - public function credit(float|int|string $amount, array $meta = [], ?string $endpoint = null, bool $throw = false): bool; - - /** - * Debits the user or model with the given amount - * - * @param array $meta - */ - public function debit(float|int|string $amount, array $meta = [], ?string $endpoint = null, bool $throw = false): bool; - /** * Get the balance service instance */ diff --git a/src/Data/WalletOperationData.php b/src/Data/WalletOperationData.php index 216e4f8..77c5a40 100644 --- a/src/Data/WalletOperationData.php +++ b/src/Data/WalletOperationData.php @@ -10,9 +10,9 @@ final class WalletOperationData extends Data public function __construct( public bool $credit, public float|int|string $amount, + public string $endpoint, public ?Model $owner = null, public ?Model $subject = null, - public ?string $endpoint = null, /** @var array */ public array $meta = [], ) {} diff --git a/src/Models/Transaction.php b/src/Models/Transaction.php index a51ab32..abaf7ec 100644 --- a/src/Models/Transaction.php +++ b/src/Models/Transaction.php @@ -16,7 +16,7 @@ * @property int|null $subject_id * @property bool $credit * @property int|string|float $amount - * @property string|null $endpoint + * @property string $endpoint * @property array|null $meta * @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $updated_at diff --git a/src/Services/BalanceService.php b/src/Services/BalanceService.php index 4185c36..7c7ed28 100644 --- a/src/Services/BalanceService.php +++ b/src/Services/BalanceService.php @@ -36,7 +36,7 @@ public function __construct( * the cache()->isWithin() will return true if we are currently performing * a transaction and so we have already applied a lock inside it. */ - protected function refresh(): void + public function refresh(): BalanceService { $closure = function () { // Sum all the balance @@ -58,10 +58,12 @@ protected function refresh(): void if ($this->cache->isWithin()) { $closure(); - return; + return $this; } $this->cache->blockAndWrapInTransaction($closure); + + return $this; } /** @@ -69,7 +71,7 @@ protected function refresh(): void */ public function raw(bool $cached = true): int|float|string|null { - if (! $cached) { + if (! $cached || $this->localCachedRawBalance === null) { $this->refresh(); } @@ -118,11 +120,11 @@ public function hasEnoughFor(float|int|string $amount): bool { try { (new OperationService( - credit: false, model: $this->model, cache: $this->cache, configuration: $this->configuration, balance: $this, + credit: false, )) ->debit($amount) ->throw(false) diff --git a/src/Services/CacheService.php b/src/Services/CacheService.php index cfee914..e65a7d4 100644 --- a/src/Services/CacheService.php +++ b/src/Services/CacheService.php @@ -170,7 +170,9 @@ public function locked(): bool /** @var CacheManager $lockConnection */ $lockConnection = $store->lockConnection(); - return $lockConnection->get(Cache::getPrefix().$this->blockPrefix()) !== null; + $prefix = Cache::getPrefix() ?? config('cache.prefix', 'redis__'); + + return $lockConnection->get($prefix.$this->blockPrefix()) !== null; } /** diff --git a/src/Services/OperationService.php b/src/Services/OperationService.php index 04cd673..9296b59 100644 --- a/src/Services/OperationService.php +++ b/src/Services/OperationService.php @@ -83,7 +83,7 @@ final class OperationService /** * Stores the endpoint */ - protected ?string $endpoint = null; + protected string $endpoint = 'default'; /** * How much times to retry before failing @@ -103,7 +103,7 @@ final class OperationService /** * Stores the transaction if it was successful */ - protected ?Transaction $transaction = null; + public ?Transaction $transaction = null; /** * Related Model of the transaction @@ -111,11 +111,11 @@ final class OperationService protected ?Model $subject = null; public function __construct( - bool $credit, public readonly WalletInterface $model, public readonly CacheService $cache, public readonly ConfigurationService $configuration, public readonly BalanceService $balance, + bool $credit = false, ) { $this->credit = $credit; } @@ -397,11 +397,15 @@ protected function compileDefaultCallbacks(): OperationService ]; if ($this->subject) { + $morphClass = method_exists($this->subject, 'getMorphClass') ? $this->subject->getMorphClass() : get_class($this->subject); $payload['subject_id'] = $this->subject->getKey(); - $payload['subject_type'] = get_class($this->subject); + $payload['subject_type'] = $morphClass; } - $this->transaction = $this->model->transactions()->create($payload); + $this->transaction = $this + ->model + ->transactions() + ->create($payload); // Dispatch Transaction Created Event event(new TransactionCreatedEvent( @@ -474,6 +478,18 @@ protected function callback(?callable $callback, bool $shift = false): Operation return $this; } + /** + * Instructs the amount of the transaction + * + * @return $this + */ + public function amount(float|int|string $amount): OperationService + { + $this->amount = $amount; + + return $this; + } + /** * Instructs that a credit should be made * @@ -545,7 +561,7 @@ public function throw(bool|Closure $condition = true): OperationService * * @return $this */ - public function endpoint(?string $endpoint = null): OperationService + public function endpoint(string $endpoint = 'default'): OperationService { $this->endpoint = $endpoint; diff --git a/src/Wallet.php b/src/Wallet.php index cd0e78c..6e314e4 100755 --- a/src/Wallet.php +++ b/src/Wallet.php @@ -4,6 +4,7 @@ use Closure; use Flavorly\Wallet\Contracts\HasWallet as WalletInterface; +use Flavorly\Wallet\Exceptions\InvalidOperationArgumentsException; use Flavorly\Wallet\Exceptions\WalletLockedException; use Flavorly\Wallet\Services\BalanceService; use Flavorly\Wallet\Services\CacheService; @@ -43,6 +44,10 @@ final class Wallet */ public function __construct(public readonly WalletInterface $model) { + $key = $model->getKey(); + if (! $key) { + throw new InvalidOperationArgumentsException('Model must have a primary key'); + } $this->configuration = app(ConfigurationService::class, ['model' => $model]); $this->cache = app(CacheService::class, ['prefix' => $model->getKey()]); $this->balance = app(BalanceService::class, [ @@ -62,22 +67,21 @@ public function __construct(public readonly WalletInterface $model) */ public function credit( float|int|string $amount, + string $endpoint = 'default', array $meta = [], - ?string $endpoint = null, bool $throw = false, ?Closure $after = null, ?Model $subject = null, - ): bool { + ): OperationService { return $this - ->operation(true) - ->meta($meta) + ->operation() ->credit($amount) + ->meta($meta) ->throw($throw) ->after($after) ->subject($subject) ->endpoint($endpoint) - ->dispatch() - ->ok(); + ->dispatch(); } /** @@ -90,22 +94,21 @@ public function credit( */ public function debit( float|int|string $amount, + string $endpoint = 'default', array $meta = [], - ?string $endpoint = null, bool $throw = false, ?Closure $after = null, ?Model $subject = null, - ): bool { + ): OperationService { return $this - ->operation(false) - ->meta($meta) + ->operation() ->debit($amount) + ->meta($meta) ->throw($throw) ->after($after) ->subject($subject) ->endpoint($endpoint) - ->dispatch() - ->ok(); + ->dispatch(); } /** @@ -113,17 +116,23 @@ public function debit( * * @param array $meta */ - public function creditQuietly(float|int|string $amount, array $meta = [], ?string $endpoint = null): bool - { + public function creditQuietly( + float|int|string $amount, + string $endpoint = 'default', + ?Model $subject = null, + array $meta = [] + ): OperationService { + $operation = $this + ->operation() + ->credit($amount) + ->meta($meta) + ->throw(false) + ->subject($subject) + ->endpoint($endpoint); try { - return $this->credit( - amount: $amount, - meta: $meta, - endpoint: $endpoint, - throw: true - ); + return $operation->dispatch(); } catch (Throwable $e) { - return false; + return $operation; } } @@ -132,17 +141,19 @@ public function creditQuietly(float|int|string $amount, array $meta = [], ?strin * * @param array $meta */ - public function debitQuietly(float|int|string $amount, array $meta = [], ?string $endpoint = null): bool + public function debitQuietly(float|int|string $amount, string $endpoint = 'default', ?Model $subject = null, array $meta = []): OperationService { + $operation = $this + ->operation() + ->debit($amount) + ->meta($meta) + ->throw(false) + ->subject($subject) + ->endpoint($endpoint); try { - return $this->debit( - amount: $amount, - meta: $meta, - endpoint: $endpoint, - throw: true - ); + return $operation->dispatch(); } catch (Throwable $e) { - return false; + return $operation; } } @@ -151,10 +162,9 @@ public function debitQuietly(float|int|string $amount, array $meta = [], ?string * This is the main entry point to create transaction * Wallet class is just an API for the actual underlying operation object */ - public function operation(bool $credit): OperationService + public function operation(): OperationService { return new OperationService( - $credit, $this->model, $this->cache, $this->configuration,