141 lines
4.5 KiB
PHP
141 lines
4.5 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace Modules\RestaurantDelivery\Jobs;
|
||
|
|
|
||
|
|
use Illuminate\Bus\Queueable;
|
||
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||
|
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||
|
|
use Illuminate\Queue\InteractsWithQueue;
|
||
|
|
use Illuminate\Queue\SerializesModels;
|
||
|
|
use Illuminate\Support\Facades\DB;
|
||
|
|
use Illuminate\Support\Facades\Log;
|
||
|
|
use Modules\RestaurantDelivery\Models\Rider;
|
||
|
|
use Modules\RestaurantDelivery\Models\RiderEarning;
|
||
|
|
use Modules\RestaurantDelivery\Models\RiderPayout;
|
||
|
|
|
||
|
|
class ProcessPayoutJob implements ShouldQueue
|
||
|
|
{
|
||
|
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The number of times the job may be attempted.
|
||
|
|
*/
|
||
|
|
public int $tries = 3;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create a new job instance.
|
||
|
|
*/
|
||
|
|
public function __construct(
|
||
|
|
public readonly Rider $rider,
|
||
|
|
public readonly ?string $paymentMethod = null
|
||
|
|
) {
|
||
|
|
$this->onQueue(config('restaurant-delivery.queue.queues.earnings', 'restaurant-delivery-earnings'));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Execute the job.
|
||
|
|
*/
|
||
|
|
public function handle(): void
|
||
|
|
{
|
||
|
|
// Get pending earnings
|
||
|
|
$pendingEarnings = $this->rider->earnings()
|
||
|
|
->where('status', 'pending')
|
||
|
|
->whereNull('payout_id')
|
||
|
|
->get();
|
||
|
|
|
||
|
|
if ($pendingEarnings->isEmpty()) {
|
||
|
|
Log::info('No pending earnings for rider', [
|
||
|
|
'rider_id' => $this->rider->id,
|
||
|
|
]);
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Calculate total
|
||
|
|
$totalAmount = $pendingEarnings->sum('net_amount');
|
||
|
|
$minimumPayout = config('restaurant-delivery.earnings.payout.minimum_amount', 500);
|
||
|
|
|
||
|
|
if ($totalAmount < $minimumPayout) {
|
||
|
|
Log::info('Pending amount below minimum payout threshold', [
|
||
|
|
'rider_id' => $this->rider->id,
|
||
|
|
'pending_amount' => $totalAmount,
|
||
|
|
'minimum' => $minimumPayout,
|
||
|
|
]);
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
DB::transaction(function () use ($pendingEarnings, $totalAmount) {
|
||
|
|
// Create payout record
|
||
|
|
$payout = RiderPayout::create([
|
||
|
|
'rider_id' => $this->rider->id,
|
||
|
|
'restaurant_id' => $this->rider->restaurant_id,
|
||
|
|
'amount' => $totalAmount,
|
||
|
|
'currency' => config('restaurant-delivery.pricing.currency', 'BDT'),
|
||
|
|
'payment_method' => $this->paymentMethod ?? $this->rider->preferred_payment_method,
|
||
|
|
'payment_details' => $this->getPaymentDetails(),
|
||
|
|
'status' => 'pending',
|
||
|
|
'earnings_count' => $pendingEarnings->count(),
|
||
|
|
'period_start' => $pendingEarnings->min('earned_at'),
|
||
|
|
'period_end' => $pendingEarnings->max('earned_at'),
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Link earnings to payout
|
||
|
|
RiderEarning::whereIn('id', $pendingEarnings->pluck('id'))
|
||
|
|
->update([
|
||
|
|
'payout_id' => $payout->id,
|
||
|
|
'status' => 'processing',
|
||
|
|
]);
|
||
|
|
|
||
|
|
Log::info('Payout created for rider', [
|
||
|
|
'payout_id' => $payout->id,
|
||
|
|
'rider_id' => $this->rider->id,
|
||
|
|
'amount' => $totalAmount,
|
||
|
|
'earnings_count' => $pendingEarnings->count(),
|
||
|
|
]);
|
||
|
|
});
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
Log::error('Failed to create payout', [
|
||
|
|
'rider_id' => $this->rider->id,
|
||
|
|
'error' => $e->getMessage(),
|
||
|
|
]);
|
||
|
|
throw $e;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get payment details based on payment method.
|
||
|
|
*/
|
||
|
|
protected function getPaymentDetails(): array
|
||
|
|
{
|
||
|
|
$method = $this->paymentMethod ?? $this->rider->preferred_payment_method;
|
||
|
|
|
||
|
|
return match ($method) {
|
||
|
|
'bank_transfer' => [
|
||
|
|
'bank_name' => $this->rider->bank_name,
|
||
|
|
'account_number' => $this->rider->bank_account_number,
|
||
|
|
'branch' => $this->rider->bank_branch,
|
||
|
|
],
|
||
|
|
'bkash', 'nagad', 'rocket' => [
|
||
|
|
'provider' => $method,
|
||
|
|
'number' => $this->rider->mobile_banking_number,
|
||
|
|
],
|
||
|
|
default => [],
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Handle a job failure.
|
||
|
|
*/
|
||
|
|
public function failed(\Throwable $exception): void
|
||
|
|
{
|
||
|
|
Log::error('Payout processing job failed', [
|
||
|
|
'rider_id' => $this->rider->id,
|
||
|
|
'error' => $exception->getMessage(),
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
}
|