Files
hoshpoint-backend/app/Services/WalletService.php

82 lines
2.5 KiB
PHP

<?php
namespace App\Services;
use App\Enums\WalletTransactionType;
use App\Models\User;
use App\Models\Wallet;
use App\Models\WalletTransaction;
use Illuminate\Support\Facades\DB;
use InvalidArgumentException;
use RuntimeException;
class WalletService
{
public function createForUser(User $user): Wallet
{
return Wallet::query()->firstOrCreate(
['user_id' => $user->id],
['balance' => 0, 'is_active' => true],
);
}
public function credit(
Wallet $wallet,
int $amount,
?string $description = null,
?User $performedBy = null,
): WalletTransaction {
return $this->apply($wallet, WalletTransactionType::Credit, $amount, $description, $performedBy);
}
public function debit(
Wallet $wallet,
int $amount,
?string $description = null,
?User $performedBy = null,
): WalletTransaction {
return $this->apply($wallet, WalletTransactionType::Debit, $amount, $description, $performedBy);
}
private function apply(
Wallet $wallet,
WalletTransactionType $type,
int $amount,
?string $description,
?User $performedBy,
): WalletTransaction {
if ($amount <= 0) {
throw new InvalidArgumentException('مبلغ باید بزرگ‌تر از صفر باشد.');
}
return DB::transaction(function () use ($wallet, $type, $amount, $description, $performedBy): WalletTransaction {
$wallet = Wallet::query()->lockForUpdate()->findOrFail($wallet->id);
if (! $wallet->is_active) {
throw new RuntimeException('کیف پول غیرفعال است.');
}
$balanceBefore = $wallet->balance;
$balanceAfter = $type === WalletTransactionType::Credit
? $balanceBefore + $amount
: $balanceBefore - $amount;
if ($balanceAfter < 0) {
throw new RuntimeException('موجودی کیف پول کافی نیست.');
}
$wallet->update(['balance' => $balanceAfter]);
return WalletTransaction::query()->create([
'wallet_id' => $wallet->id,
'type' => $type,
'amount' => $amount,
'balance_before' => $balanceBefore,
'balance_after' => $balanceAfter,
'description' => $description,
'created_by' => $performedBy?->id,
]);
});
}
}