Skip to content

Commit

Permalink
Merge pull request #16 from flavorly/next-2
Browse files Browse the repository at this point in the history
  • Loading branch information
nikuscs authored Oct 6, 2024
2 parents 6dd0d3d + 876e054 commit 79231c7
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 94 deletions.
36 changes: 0 additions & 36 deletions src/Concerns/InteractsWithWallet.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
);
}
}
14 changes: 0 additions & 14 deletions src/Contracts/HasWallet.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,6 @@ public function getBalanceAttribute(): Math;
*/
public function getBalanceFormattedAttribute(): string;

/**
* Credits the user or model with the given amount
*
* @param array<string,mixed> $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<string,mixed> $meta
*/
public function debit(float|int|string $amount, array $meta = [], ?string $endpoint = null, bool $throw = false): bool;

/**
* Get the balance service instance
*/
Expand Down
2 changes: 1 addition & 1 deletion src/Data/WalletOperationData.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<string,mixed> */
public array $meta = [],
) {}
Expand Down
2 changes: 1 addition & 1 deletion src/Models/Transaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 6 additions & 4 deletions src/Services/BalanceService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -58,18 +58,20 @@ protected function refresh(): void
if ($this->cache->isWithin()) {
$closure();

return;
return $this;
}

$this->cache->blockAndWrapInTransaction($closure);

return $this;
}

/**
* Returns the balance without any formatting or casting
*/
public function raw(bool $cached = true): int|float|string|null
{
if (! $cached) {
if (! $cached || $this->localCachedRawBalance === null) {
$this->refresh();
}

Expand Down Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion src/Services/CacheService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down
28 changes: 22 additions & 6 deletions src/Services/OperationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -103,19 +103,19 @@ final class OperationService
/**
* Stores the transaction if it was successful
*/
protected ?Transaction $transaction = null;
public ?Transaction $transaction = null;

/**
* Related Model of the transaction
*/
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;
}
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
*
Expand Down Expand Up @@ -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;

Expand Down
72 changes: 41 additions & 31 deletions src/Wallet.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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, [
Expand All @@ -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();
}

/**
Expand All @@ -90,40 +94,45 @@ 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();
}

/**
* Credit the user quietly without exceptions
*
* @param array<string,mixed> $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;
}
}

Expand All @@ -132,17 +141,19 @@ public function creditQuietly(float|int|string $amount, array $meta = [], ?strin
*
* @param array<string,mixed> $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;
}
}

Expand All @@ -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,
Expand Down

0 comments on commit 79231c7

Please sign in to comment.