diff --git a/app/Services/PargarInboundWalletService.php b/app/Services/PargarInboundWalletService.php index 747177c..508ca1e 100644 --- a/app/Services/PargarInboundWalletService.php +++ b/app/Services/PargarInboundWalletService.php @@ -3,6 +3,7 @@ namespace App\Services; use App\Models\Customer; +use App\Models\Order; use App\Models\PargarSyncLog; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Cache; @@ -60,7 +61,19 @@ class PargarInboundWalletService */ public function hasPendingOutboundToPargar(Customer $customer): bool { - return PargarSyncLog::query() + return $this->blockingOutboundLog($customer) !== null; + } + + /** + * سند پنلی که واقعاً منتظر ثبت در پرگار است. + * + * لاگ pending که دیگر قابل ارسال نیست (سفارش حذف شده یا از حالت «موفق» درآمده) + * هیچ‌وقت تأیید نمی‌شود و اگر بشمریمش، مانده برای همیشه قفل می‌ماند؛ پس آن را + * failed می‌کنیم تا از صف بیرون برود. + */ + public function blockingOutboundLog(Customer $customer): ?PargarSyncLog + { + $logs = PargarSyncLog::query() ->where('customer_id', $customer->id) ->whereIn('type', [ PargarSyncService::TYPE_WALLET_CASH, @@ -68,9 +81,57 @@ class PargarInboundWalletService PargarSyncService::TYPE_ORDER, ]) ->where('sync_status', PargarSyncService::STATUS_PENDING) + ->orderBy('id') + ->get(); + + foreach ($logs as $log) { + if ($this->isDeliverableOutbound($log)) { + return $log; + } + + $this->retireDeadOutbound($log); + } + + return null; + } + + /** + * آیا این لاگ در نوبت ارسال به پرگار (GET /pargar/orders) قرار می‌گیرد؟ + */ + private function isDeliverableOutbound(PargarSyncLog $log): bool + { + if ($log->type !== PargarSyncService::TYPE_ORDER) { + // سند کیف تا وقتی pending است در هر بار fetch پرگار فرستاده می‌شود + return true; + } + + $orderId = (int) ($log->order_id ?? 0); + if ($orderId <= 0) { + return false; + } + + return Order::query() + ->where('id', $orderId) + ->where('sts', 2) + ->whereNull('pargar_confirmed_at') ->exists(); } + private function retireDeadOutbound(PargarSyncLog $log): void + { + app(PargarSyncService::class)->markFailed( + $log, + null, + 'سفارش این سند دیگر در نوبت ارسال به پرگار نیست (حذف یا تغییر وضعیت) — از صف خارج شد' + ); + + Log::warning('Pargar outbound log retired', [ + 'log_id' => $log->id, + 'customer_id' => $log->customer_id, + 'order_id' => $log->order_id, + ]); + } + /** * دکمهٔ ادمین / همگام‌سازی خودکار: * ۱) علامت مصرف دسته‌های سند inbound (بدون نوشتن روی کیف) @@ -160,18 +221,29 @@ class PargarInboundWalletService 'errors' => [], ]; - $batches = PargarSyncLog::query() + // فقط شناسهٔ دسته‌های علامت‌نخورده — payload دسته‌های تأییدشده می‌تواند مگابایتی باشد + // و کشیدن دوبارهٔ آن‌ها در هر کلیک همان کندی/۵۰۴ است. + $batchIds = PargarSyncLog::query() ->where('type', PargarSyncService::TYPE_DOCUMENT) ->where('customer_id', $customer->id) + ->whereNotNull('data') + ->where('data', 'not like', '%wallet_batch_applied%') + ->where('data', 'not like', '%"wallet_applied": true%') + ->where('data', 'not like', '%"wallet_applied":true%') ->orderBy('id') - ->limit(200) - ->get(); + ->limit(self::MAX_BATCHES_PER_SYNC) + ->pluck('id'); - foreach ($batches as $batch) { + foreach ($batchIds as $batchId) { if ($result['batches'] >= self::MAX_BATCHES_PER_SYNC) { break; } + $batch = PargarSyncLog::find($batchId); + if ($batch === null) { + continue; + } + $data = json_decode((string) $batch->data, true); if (! is_array($data)) { continue; @@ -398,10 +470,12 @@ class PargarInboundWalletService */ private function mandeBlockReason(Customer $customer, PargarSyncLog $log, array $data): ?array { - if ($this->hasPendingOutboundToPargar($customer)) { + $blocking = $this->blockingOutboundLog($customer); + if ($blocking !== null) { return [ 'reason' => 'pending_outbound', - 'message' => 'سند پنل هنوز در پرگار ثبت نشده — مانده اعمال نمی‌شود', + 'message' => 'سند پنل شمارهٔ ' . $blocking->id + . ' (' . $this->outboundLogLabel($blocking) . ') هنوز در پرگار ثبت نشده — مانده اعمال نمی‌شود', ]; } @@ -450,6 +524,16 @@ class PargarInboundWalletService return null; } + private function outboundLogLabel(PargarSyncLog $log): string + { + return match ($log->type) { + PargarSyncService::TYPE_ORDER => 'سفارش ' . $log->order_id, + PargarSyncService::TYPE_WALLET_GOLD => 'شارژ طلای کیف', + PargarSyncService::TYPE_WALLET_CASH => 'سند ریالی کیف', + default => (string) $log->type, + }; + } + /** * واریز/برداشت ریالی که سند پرگارش ساخته نشده است. *