Files
boursecu_server/app/Console/Commands/PargarRequeueWalletDocumentsCommand.php
2026-08-01 14:13:19 +03:30

169 lines
6.5 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Models\Customer;
use App\Services\PargarSyncService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Rooyesh\Wallet\models\Transaction;
/**
* ساخت دوبارهٔ سند ریالی برای واریز/برداشت‌هایی که سندشان به پرگار نرسیده است.
*
* تا وقتی سند نرسد، ماندهٔ پرگار این پول را ندارد و تطبیق مانده موجودی کیف را صفر می‌کند.
*
* فقط تراکنش‌های بعد از اولین لاگ پرگار همان مشتری بررسی می‌شوند
* (قبل از اتصال به پرگار سند نمی‌خواسته‌اند).
*/
class PargarRequeueWalletDocumentsCommand extends Command
{
protected $signature = 'pargar:requeue-wallet-documents
{--customer= : فقط همین مشتری}
{--days=30 : چند روز اخیر؛ با --all نادیده گرفته می‌شود}
{--all : همهٔ مشتریان از ابتدای اتصال پرگار (بدون سقف روز)}
{--execute : ثبت واقعی سندها (بدون این فلگ فقط پیش‌نمایش است)}';
protected $description = 'صف‌کردن دوبارهٔ اسناد ریالی جاافتادهٔ پرگار (واریز/برداشت بدون سند)';
public function handle(PargarSyncService $sync): int
{
if (! $sync->isSyncEnabled()) {
$this->error('همگام‌سازی پرگار فعال نیست.');
return self::FAILURE;
}
if (! $sync->hasSyncTable()) {
$this->error('جدول pargar_sync_logs موجود نیست.');
return self::FAILURE;
}
$scanAll = (bool) $this->option('all');
$days = max(1, (int) $this->option('days'));
$execute = (bool) $this->option('execute');
$customerId = (int) $this->option('customer');
$query = Transaction::query()
->whereIn('type', [3, 4])
->whereNotNull('withdraw_id')
->where(function ($q) {
$q->where('cash', '>=', 1)->orWhere('cash', '<=', -1);
})
// فقط بعد از شروع اتصال همین مشتری به پرگار
->whereRaw(
'transactions.created_at > (
SELECT MIN(psl.created_at)
FROM pargar_sync_logs AS psl
WHERE psl.customer_id = transactions.customer_id
)'
)
->whereNotExists(function ($q) {
$q->select(DB::raw(1))
->from('pargar_sync_logs')
->whereColumn('pargar_sync_logs.withdraw_id', 'transactions.withdraw_id')
->where('pargar_sync_logs.type', PargarSyncService::TYPE_WALLET_CASH);
})
->orderBy('id');
if (! $scanAll) {
$query->where('created_at', '>=', now()->subDays($days));
}
if ($customerId > 0) {
$query->where('customer_id', $customerId);
}
$rows = $query->get(['id', 'customer_id', 'withdraw_id', 'cash', 'note', 'created_at']);
if ($rows->isEmpty()) {
$this->info('سند جاافتاده‌ای پیدا نشد.');
return self::SUCCESS;
}
$byCustomer = $rows->groupBy('customer_id');
$this->info(sprintf(
'پیدا شد: %d تراکنش روی %d مشتری%s',
$rows->count(),
$byCustomer->count(),
$scanAll ? ' (اسکن کامل)' : " (آخرین {$days} روز)"
));
$customers = Customer::whereIn('id', $byCustomer->keys())->get()->keyBy('id');
$table = [];
$queued = 0;
$skipped = 0;
$affectedCustomerIds = [];
foreach ($rows as $row) {
$customer = $customers->get((int) $row->customer_id);
$status = 'آماده';
if ($customer === null || ! $customer->hasValidPargarAccountId()) {
$status = 'بدون کد پرگار — رد شد';
$skipped++;
} elseif ($execute) {
$queuedCount = $sync->queueMissingCashDocuments($customer, [$row], 'requeue_missing');
$status = $queuedCount > 0 ? 'ثبت/موجود شد' : 'ثبت نشد';
if ($queuedCount > 0) {
$queued++;
$affectedCustomerIds[(int) $row->customer_id] = true;
} else {
$skipped++;
}
} else {
$affectedCustomerIds[(int) $row->customer_id] = true;
}
$table[] = [
$row->id,
$row->customer_id,
$customer->name ?? '—',
$row->withdraw_id,
number_format((float) $row->cash),
(string) $row->created_at,
$status,
];
}
// جدول کامل ممکن است خیلی بلند باشد؛ تا ۲۰۰ ردیف نشان بده
$this->table(
['تراکنش', 'مشتری', 'نام', 'سند برداشت', 'مبلغ', 'تاریخ', 'وضعیت'],
array_slice($table, 0, 200)
);
if (count($table) > 200) {
$this->warn('فقط ۲۰۰ ردیف اول نمایش داده شد از ' . count($table) . ' ردیف.');
}
$summary = [];
foreach ($byCustomer as $cid => $customerRows) {
$c = $customers->get((int) $cid);
$summary[] = [
$cid,
$c->name ?? '—',
$customerRows->count(),
number_format((float) $customerRows->sum(fn ($r) => abs((float) $r->cash))),
($c !== null && $c->hasValidPargarAccountId()) ? 'دارد' : 'ندارد',
];
}
$this->info('خلاصه به تفکیک مشتری:');
$this->table(['مشتری', 'نام', 'تعداد سند جاافتاده', 'جمع قدرمطلق ریال', 'کد پرگار'], $summary);
if (! $execute) {
$this->warn('پیش‌نمایش بود. برای ثبت واقعی همه: php artisan pargar:requeue-wallet-documents --all --execute');
return self::SUCCESS;
}
$this->info(sprintf(
'ثبت‌شده: %d — ردشده: %d — مشتریان ترمیم‌شده: %d',
$queued,
$skipped,
count($affectedCustomerIds)
));
return self::SUCCESS;
}
}