feat: add withdraw request functionality and UI components
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Wallet;
|
||||
|
||||
use App\Enums\InvoicePaymentMethodEnum;
|
||||
use App\Enums\InvoiceStatusEnum;
|
||||
use App\Enums\WalletTransactionReasonEnum;
|
||||
use App\Enums\WalletTransactionTypeEnum;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\User;
|
||||
use App\Models\Wallet;
|
||||
use App\Models\WalletTransaction;
|
||||
use App\Models\WithdrawRequest;
|
||||
use App\Services\Invoice\InvoiceService;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class WalletService
|
||||
{
|
||||
protected InvoiceService $invoiceService;
|
||||
|
||||
public function __construct(InvoiceService $invoiceService)
|
||||
{
|
||||
$this->invoiceService = $invoiceService;
|
||||
}
|
||||
|
||||
public function forUser(User $user): Wallet
|
||||
{
|
||||
return Wallet::firstOrCreate(['user_id' => $user->id]);
|
||||
}
|
||||
|
||||
public function system(): Wallet
|
||||
{
|
||||
return Wallet::firstOrCreate(['user_id' => null]);
|
||||
}
|
||||
|
||||
public function deposit(User $user, int $amount, WalletTransactionReasonEnum $reason, ?Payment $payment = null): WalletTransaction
|
||||
{
|
||||
return $this->depositToWallet($this->forUser($user), $amount, $reason, $payment);
|
||||
}
|
||||
|
||||
public function depositToWallet(Wallet $wallet, int $amount, WalletTransactionReasonEnum $reason, ?Payment $payment = null, ?WithdrawRequest $withdrawRequest = null): WalletTransaction
|
||||
{
|
||||
return DB::transaction(function () use ($wallet, $amount, $reason, $payment, $withdrawRequest) {
|
||||
$wallet = $this->lockedWallet($wallet);
|
||||
$wallet->update(['balance' => $wallet->balance + $amount]);
|
||||
|
||||
return $wallet->transactions()->create([
|
||||
'type' => WalletTransactionTypeEnum::Deposit->value,
|
||||
'reason' => $reason->value,
|
||||
'amount' => $amount,
|
||||
'balance_after' => $wallet->balance,
|
||||
'payment_id' => $payment?->id,
|
||||
'withdraw_request_id' => $withdrawRequest?->id,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public function withdraw(User $user, int $amount, WalletTransactionReasonEnum $reason, ?Invoice $invoice = null, ?WithdrawRequest $withdrawRequest = null): WalletTransaction
|
||||
{
|
||||
return DB::transaction(function () use ($user, $amount, $reason, $invoice, $withdrawRequest) {
|
||||
$wallet = $this->lockedWallet($this->forUser($user));
|
||||
|
||||
if ($wallet->balance < $amount) {
|
||||
throw ValidationException::withMessages(['amount' => 'موجودی کیف پول کافی نیست']);
|
||||
}
|
||||
|
||||
$wallet->update(['balance' => $wallet->balance - $amount]);
|
||||
|
||||
return $wallet->transactions()->create([
|
||||
'type' => WalletTransactionTypeEnum::Withdrawal->value,
|
||||
'reason' => $reason->value,
|
||||
'amount' => $amount,
|
||||
'balance_after' => $wallet->balance,
|
||||
'invoice_id' => $invoice?->id,
|
||||
'withdraw_request_id' => $withdrawRequest?->id,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public function payInvoice(User $user, Invoice $invoice): Invoice
|
||||
{
|
||||
return DB::transaction(function () use ($user, $invoice) {
|
||||
if ($invoice->status !== InvoiceStatusEnum::Pending) {
|
||||
throw ValidationException::withMessages(['invoice' => 'این فاکتور قابل پرداخت نیست']);
|
||||
}
|
||||
|
||||
$this->withdraw($user, $invoice->amount, WalletTransactionReasonEnum::InvoicePayment, $invoice);
|
||||
|
||||
return $this->invoiceService->markPaid($invoice, InvoicePaymentMethodEnum::Wallet);
|
||||
});
|
||||
}
|
||||
|
||||
public function recordGatewayInvoicePayment(Invoice $invoice, Payment $payment): WalletTransaction
|
||||
{
|
||||
$wallet = $this->forUser($invoice->user);
|
||||
|
||||
return $wallet->transactions()->create([
|
||||
'type' => WalletTransactionTypeEnum::Withdrawal->value,
|
||||
'reason' => WalletTransactionReasonEnum::InvoicePayment->value,
|
||||
'amount' => $invoice->amount,
|
||||
'balance_after' => $wallet->balance,
|
||||
'invoice_id' => $invoice->id,
|
||||
'payment_id' => $payment->id,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function lockedWallet(Wallet $wallet): Wallet
|
||||
{
|
||||
return Wallet::whereKey($wallet->id)->lockForUpdate()->first();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user