feat: add withdraw request functionality and UI components
This commit is contained in:
@@ -3,25 +3,167 @@
|
||||
namespace App\Services\Document;
|
||||
|
||||
use App\Enums\DocumentStatusEnum;
|
||||
use App\Enums\InvoiceStatusEnum;
|
||||
use App\Enums\MediaCollectionEnum;
|
||||
use App\Enums\ReportStatusEnum;
|
||||
use App\Enums\UserEnum;
|
||||
use App\Enums\WalletTransactionReasonEnum;
|
||||
use App\Models\Document;
|
||||
use App\Models\Report;
|
||||
use App\Models\User;
|
||||
use App\Services\FileStorageService;
|
||||
use App\Services\Shift\ShiftScheduleService;
|
||||
use App\Services\Wallet\WalletService;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class CaseService
|
||||
{
|
||||
protected FileStorageService $fileStorageService;
|
||||
|
||||
protected WalletService $walletService;
|
||||
|
||||
protected ShiftScheduleService $shiftScheduleService;
|
||||
|
||||
public function __construct(FileStorageService $fileStorageService, WalletService $walletService, ShiftScheduleService $shiftScheduleService)
|
||||
{
|
||||
$this->fileStorageService = $fileStorageService;
|
||||
$this->walletService = $walletService;
|
||||
$this->shiftScheduleService = $shiftScheduleService;
|
||||
}
|
||||
|
||||
public function pendingForUser(User $user): Builder
|
||||
{
|
||||
$statuses = $this->isDoctor($user)
|
||||
? [DocumentStatusEnum::InProgress->value]
|
||||
: [DocumentStatusEnum::Registered->value, DocumentStatusEnum::InProgress->value];
|
||||
|
||||
return Document::with(['pet', 'requester'])
|
||||
->whereIn('status', [
|
||||
DocumentStatusEnum::Registered->value,
|
||||
DocumentStatusEnum::InProgress->value,
|
||||
])
|
||||
->where(function ($query) use ($user) {
|
||||
$query->where('requester_id', $user->id)
|
||||
->orWhereHas('assignments', function ($assignmentQuery) use ($user) {
|
||||
$assignmentQuery->where('user_id', $user->id);
|
||||
});
|
||||
})
|
||||
->whereIn('status', $statuses)
|
||||
->where(fn ($query) => $this->scopeVisibleTo($query, $user))
|
||||
->latest('submitted_at');
|
||||
}
|
||||
|
||||
public function canAccess(Document $document, User $user): bool
|
||||
{
|
||||
return $document->requester_id === $user->id
|
||||
|| $document->assignments()->where('user_id', $user->id)->exists();
|
||||
}
|
||||
|
||||
public function canReport(Document $document, User $user): bool
|
||||
{
|
||||
return $this->isDoctor($user)
|
||||
&& $document->status === DocumentStatusEnum::InProgress
|
||||
&& $document->assignments()->where('user_id', $user->id)->exists();
|
||||
}
|
||||
|
||||
public function submitReport(Document $document, User $doctor, array $data, array $files = []): Report
|
||||
{
|
||||
return DB::transaction(function () use ($document, $doctor, $data, $files) {
|
||||
if (!$this->canReport($document, $doctor)) {
|
||||
throw ValidationException::withMessages(['document' => 'امکان ثبت گزارش برای این پرونده وجود ندارد.']);
|
||||
}
|
||||
|
||||
$report = $document->reports()->create([
|
||||
'doctor_id' => $doctor->id,
|
||||
'status' => ReportStatusEnum::Approved->value,
|
||||
'technique' => $data['technique'] ?? null,
|
||||
'finding' => $data['finding'] ?? null,
|
||||
'diagnose' => $data['diagnose'] ?? null,
|
||||
'recommendation' => $data['recommendation'] ?? null,
|
||||
'submitted_at' => now(),
|
||||
]);
|
||||
|
||||
foreach ($files as $file) {
|
||||
$medium = $this->fileStorageService->storeFile($file);
|
||||
$report->media()->attach($medium->id, ['collection' => MediaCollectionEnum::Attachments->value]);
|
||||
}
|
||||
|
||||
$document->update([
|
||||
'status' => DocumentStatusEnum::Completed->value,
|
||||
'finalized_at' => now(),
|
||||
'finalized_by' => $doctor->id,
|
||||
]);
|
||||
|
||||
return $report;
|
||||
});
|
||||
}
|
||||
|
||||
public function reject(Document $document, User $doctor, string $reason): Document
|
||||
{
|
||||
return DB::transaction(function () use ($document, $doctor, $reason) {
|
||||
if (!$this->canReport($document, $doctor)) {
|
||||
throw ValidationException::withMessages(['document' => 'امکان رد این پرونده وجود ندارد.']);
|
||||
}
|
||||
|
||||
$document->update([
|
||||
'status' => DocumentStatusEnum::Rejected->value,
|
||||
'finalized_at' => now(),
|
||||
'finalized_by' => $doctor->id,
|
||||
'rejection_reason' => $reason,
|
||||
]);
|
||||
|
||||
$invoice = $document->invoice;
|
||||
|
||||
if ($invoice && $invoice->status === InvoiceStatusEnum::Paid) {
|
||||
$invoice->update(['status' => InvoiceStatusEnum::Canceled->value]);
|
||||
$this->walletService->deposit($document->requester, $invoice->amount, WalletTransactionReasonEnum::Refund);
|
||||
}
|
||||
|
||||
return $document;
|
||||
});
|
||||
}
|
||||
|
||||
public function statsForUser(User $user): array
|
||||
{
|
||||
$monthStart = now()->startOfMonth();
|
||||
$isDoctor = $this->isDoctor($user);
|
||||
|
||||
$reviewedQuery = Document::where('status', DocumentStatusEnum::Completed->value)
|
||||
->where('finalized_at', '>=', $monthStart);
|
||||
|
||||
if ($isDoctor) {
|
||||
$reviewedQuery->where('finalized_by', $user->id);
|
||||
} else {
|
||||
$reviewedQuery->where('requester_id', $user->id);
|
||||
}
|
||||
|
||||
$amountQuery = $isDoctor
|
||||
? Document::where('documents.finalized_by', $user->id)
|
||||
->where('documents.status', DocumentStatusEnum::Completed->value)
|
||||
->where('documents.finalized_at', '>=', $monthStart)
|
||||
->join('invoices', 'invoices.document_id', '=', 'documents.id')
|
||||
->where('invoices.status', InvoiceStatusEnum::Paid->value)
|
||||
: Document::where('documents.requester_id', $user->id)
|
||||
->join('invoices', 'invoices.document_id', '=', 'documents.id')
|
||||
->where('invoices.status', InvoiceStatusEnum::Paid->value)
|
||||
->where('invoices.paid_at', '>=', $monthStart);
|
||||
|
||||
$nextShift = $isDoctor ? $this->shiftScheduleService->nextShiftStart($user, now()) : null;
|
||||
|
||||
return [
|
||||
'pending_cases' => $this->pendingForUser($user)->count(),
|
||||
'monthly_reviewed' => $reviewedQuery->count(),
|
||||
'monthly_amount' => (int) $amountQuery->sum('invoices.amount'),
|
||||
'next_shift_hours' => $nextShift ? (int) ceil(now()->diffInMinutes($nextShift, true) / 60) : null,
|
||||
'is_doctor' => $isDoctor,
|
||||
];
|
||||
}
|
||||
|
||||
protected function scopeVisibleTo($query, User $user): void
|
||||
{
|
||||
if ($this->isDoctor($user)) {
|
||||
$query->whereHas('assignments', fn ($assignmentQuery) => $assignmentQuery->where('user_id', $user->id));
|
||||
return;
|
||||
}
|
||||
|
||||
$query->where('requester_id', $user->id)
|
||||
->orWhereHas('assignments', fn ($assignmentQuery) => $assignmentQuery->where('user_id', $user->id));
|
||||
}
|
||||
|
||||
protected function isDoctor(User $user): bool
|
||||
{
|
||||
return $user->level === UserEnum::Doctor->value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ use App\Models\Document;
|
||||
use App\Models\Pet;
|
||||
use App\Models\User;
|
||||
use App\Services\FileStorageService;
|
||||
use App\Services\Invoice\InvoiceService;
|
||||
use App\Services\Shift\ShiftScheduleService;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
@@ -19,10 +20,13 @@ class FastRequestService
|
||||
|
||||
protected ShiftScheduleService $shiftScheduleService;
|
||||
|
||||
public function __construct(FileStorageService $fileStorageService, ShiftScheduleService $shiftScheduleService)
|
||||
protected InvoiceService $invoiceService;
|
||||
|
||||
public function __construct(FileStorageService $fileStorageService, ShiftScheduleService $shiftScheduleService, InvoiceService $invoiceService)
|
||||
{
|
||||
$this->fileStorageService = $fileStorageService;
|
||||
$this->shiftScheduleService = $shiftScheduleService;
|
||||
$this->invoiceService = $invoiceService;
|
||||
}
|
||||
|
||||
public function create(User $requester, array $data, array $historyFiles = [], array $scanFiles = []): Document
|
||||
@@ -39,6 +43,8 @@ class FastRequestService
|
||||
'requester_id' => $requester->id,
|
||||
]);
|
||||
|
||||
$this->invoiceService->createForDocument($document);
|
||||
|
||||
$this->attachFiles($document, $historyFiles, MediaCollectionEnum::History);
|
||||
$this->attachFiles($document, $scanFiles, MediaCollectionEnum::Primary);
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Invoice;
|
||||
|
||||
use App\Enums\DocumentModalityEnum;
|
||||
use App\Enums\DocumentStatusEnum;
|
||||
use App\Enums\InvoicePaymentMethodEnum;
|
||||
use App\Enums\InvoiceStatusEnum;
|
||||
use App\Models\Document;
|
||||
use App\Models\Invoice;
|
||||
|
||||
class InvoiceService
|
||||
{
|
||||
public function createForDocument(Document $document): Invoice
|
||||
{
|
||||
$invoice = Invoice::create([
|
||||
'number' => 'pending',
|
||||
'amount' => DocumentModalityEnum::from($document->modality)->price(),
|
||||
'status' => InvoiceStatusEnum::Pending->value,
|
||||
'document_id' => $document->id,
|
||||
'user_id' => $document->requester_id,
|
||||
]);
|
||||
|
||||
$invoice->update(['number' => str_pad((string) $invoice->id, 5, '0', STR_PAD_LEFT)]);
|
||||
|
||||
return $invoice;
|
||||
}
|
||||
|
||||
public function markPaid(Invoice $invoice, InvoicePaymentMethodEnum $method): Invoice
|
||||
{
|
||||
$invoice->update([
|
||||
'status' => InvoiceStatusEnum::Paid->value,
|
||||
'payment_method' => $method->value,
|
||||
'paid_at' => now(),
|
||||
]);
|
||||
|
||||
$document = $invoice->document;
|
||||
|
||||
if ($document && $document->status === DocumentStatusEnum::Registered) {
|
||||
$document->update([
|
||||
'status' => DocumentStatusEnum::InProgress->value,
|
||||
'processing_deadline' => now()->addHours($document->priority->processingHours()),
|
||||
]);
|
||||
}
|
||||
|
||||
return $invoice;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Payment;
|
||||
|
||||
use App\Enums\PaymentStatusEnum;
|
||||
use App\Models\Payment;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use RuntimeException;
|
||||
|
||||
class ZibalPaymentService
|
||||
{
|
||||
protected const API_URL = 'https://gateway.zibal.ir/v1';
|
||||
protected const START_URL = 'https://gateway.zibal.ir/start';
|
||||
|
||||
public function request(User $payer, int $amount, string $orderId, array $attributes = []): Payment
|
||||
{
|
||||
$response = Http::post(self::API_URL . '/request', [
|
||||
'merchant' => $this->merchant(),
|
||||
'amount' => $amount * 10,
|
||||
'callbackUrl' => $this->callbackUrl(),
|
||||
'orderId' => $orderId,
|
||||
])->json();
|
||||
|
||||
if (($response['result'] ?? null) !== 100) {
|
||||
throw new RuntimeException('خطا در ایجاد درخواست پرداخت: ' . ($response['message'] ?? 'پاسخ نامعتبر از درگاه'));
|
||||
}
|
||||
|
||||
return Payment::create(array_merge([
|
||||
'track_id' => (string) $response['trackId'],
|
||||
'amount' => $amount,
|
||||
'status' => PaymentStatusEnum::Pending->value,
|
||||
'payer_id' => $payer->id,
|
||||
], $attributes));
|
||||
}
|
||||
|
||||
public function paymentUrl(Payment $payment): string
|
||||
{
|
||||
return self::START_URL . '/' . $payment->track_id;
|
||||
}
|
||||
|
||||
public function verify(Payment $payment): Payment
|
||||
{
|
||||
if ($payment->status !== PaymentStatusEnum::Pending) {
|
||||
return $payment;
|
||||
}
|
||||
|
||||
$response = Http::post(self::API_URL . '/verify', [
|
||||
'merchant' => $this->merchant(),
|
||||
'trackId' => $payment->track_id,
|
||||
])->json();
|
||||
|
||||
if (in_array($response['result'] ?? null, [100, 201], true)) {
|
||||
$payment->update([
|
||||
'status' => PaymentStatusEnum::Paid->value,
|
||||
'ref_number' => $response['refNumber'] ?? null,
|
||||
'verified_at' => now(),
|
||||
]);
|
||||
} else {
|
||||
$payment->update(['status' => PaymentStatusEnum::Failed->value]);
|
||||
}
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
||||
public function markFailed(Payment $payment): Payment
|
||||
{
|
||||
if ($payment->status === PaymentStatusEnum::Pending) {
|
||||
$payment->update(['status' => PaymentStatusEnum::Failed->value]);
|
||||
}
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
||||
protected function merchant(): string
|
||||
{
|
||||
return config('services.zibal.sandbox') ? 'zibal' : config('services.zibal.merchant');
|
||||
}
|
||||
|
||||
protected function callbackUrl(): string
|
||||
{
|
||||
return config('services.zibal.callback_url') ?: route('dashboard.payments.callback');
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,33 @@ class ShiftScheduleService
|
||||
->first();
|
||||
}
|
||||
|
||||
public function nextShiftStart(User $doctor, Carbon $from): ?Carbon
|
||||
{
|
||||
$shifts = Shift::active()->where('user_id', $doctor->id)->get();
|
||||
|
||||
return $shifts
|
||||
->map(function (Shift $shift) use ($from) {
|
||||
for ($offset = 0; $offset <= 7; $offset++) {
|
||||
$day = $from->copy()->addDays($offset)->startOfDay();
|
||||
|
||||
if (!$this->coversDate($shift, $day)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$start = $day->copy()->addMinutes($this->toMinutes($shift->start_time));
|
||||
|
||||
if ($start->greaterThanOrEqualTo($from)) {
|
||||
return $start;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
->filter()
|
||||
->sort()
|
||||
->first();
|
||||
}
|
||||
|
||||
public function hasConflict(array $data, ?int $ignoreId = null): bool
|
||||
{
|
||||
if (empty($data['user_id'])) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Wallet;
|
||||
|
||||
use App\Enums\WalletTransactionReasonEnum;
|
||||
use App\Enums\WithdrawRequestStatusEnum;
|
||||
use App\Models\BankCard;
|
||||
use App\Models\User;
|
||||
use App\Models\WithdrawRequest;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class WithdrawRequestService
|
||||
{
|
||||
protected WalletService $walletService;
|
||||
|
||||
public function __construct(WalletService $walletService)
|
||||
{
|
||||
$this->walletService = $walletService;
|
||||
}
|
||||
|
||||
public function request(User $user, int $amount, BankCard $bankCard): WithdrawRequest
|
||||
{
|
||||
if ($bankCard->user_id !== $user->id) {
|
||||
throw ValidationException::withMessages(['bank_card_id' => 'کارت بانکی انتخابشده معتبر نیست.']);
|
||||
}
|
||||
|
||||
$balance = $this->walletService->forUser($user)->balance;
|
||||
|
||||
$pendingAmount = WithdrawRequest::where('user_id', $user->id)
|
||||
->where('status', WithdrawRequestStatusEnum::Pending->value)
|
||||
->sum('amount');
|
||||
|
||||
if ($amount + $pendingAmount > $balance) {
|
||||
throw ValidationException::withMessages(['amount' => 'مجموع مبلغ درخواستهای برداشت از موجودی کیف پول شما بیشتر است.']);
|
||||
}
|
||||
|
||||
return WithdrawRequest::create([
|
||||
'amount' => $amount,
|
||||
'status' => WithdrawRequestStatusEnum::Pending->value,
|
||||
'user_id' => $user->id,
|
||||
'bank_card_id' => $bankCard->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function approve(WithdrawRequest $withdrawRequest, User $admin): WithdrawRequest
|
||||
{
|
||||
return DB::transaction(function () use ($withdrawRequest, $admin) {
|
||||
$this->ensurePending($withdrawRequest);
|
||||
|
||||
$this->walletService->withdraw(
|
||||
$withdrawRequest->user,
|
||||
$withdrawRequest->amount,
|
||||
WalletTransactionReasonEnum::Withdraw,
|
||||
null,
|
||||
$withdrawRequest
|
||||
);
|
||||
|
||||
$this->walletService->depositToWallet(
|
||||
$this->walletService->system(),
|
||||
$withdrawRequest->amount,
|
||||
WalletTransactionReasonEnum::Withdraw,
|
||||
null,
|
||||
$withdrawRequest
|
||||
);
|
||||
|
||||
$withdrawRequest->update([
|
||||
'status' => WithdrawRequestStatusEnum::Approved->value,
|
||||
'reviewed_at' => now(),
|
||||
'reviewed_by' => $admin->id,
|
||||
]);
|
||||
|
||||
return $withdrawRequest;
|
||||
});
|
||||
}
|
||||
|
||||
public function reject(WithdrawRequest $withdrawRequest, User $admin, ?string $note = null): WithdrawRequest
|
||||
{
|
||||
$this->ensurePending($withdrawRequest);
|
||||
|
||||
$withdrawRequest->update([
|
||||
'status' => WithdrawRequestStatusEnum::Rejected->value,
|
||||
'admin_note' => $note,
|
||||
'reviewed_at' => now(),
|
||||
'reviewed_by' => $admin->id,
|
||||
]);
|
||||
|
||||
return $withdrawRequest;
|
||||
}
|
||||
|
||||
protected function ensurePending(WithdrawRequest $withdrawRequest): void
|
||||
{
|
||||
if ($withdrawRequest->status !== WithdrawRequestStatusEnum::Pending) {
|
||||
throw ValidationException::withMessages(['withdraw_request' => 'این درخواست قبلا بررسی شده است.']);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user