diff --git a/app/Console/Commands/PollPendingColleagueOrdersCommand.php b/app/Console/Commands/PollPendingColleagueOrdersCommand.php deleted file mode 100644 index 4415ebd..0000000 --- a/app/Console/Commands/PollPendingColleagueOrdersCommand.php +++ /dev/null @@ -1,23 +0,0 @@ -pollDueOrders(); - sleep(ColleagueOrderCallbackService::POLL_SECONDS); - $second = $service->pollDueOrders(); - $this->info(json_encode(['first' => $first, 'second' => $second], JSON_UNESCAPED_UNICODE)); - - return self::SUCCESS; - } -} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 058a9ee..c65df72 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -53,11 +53,6 @@ class Kernel extends ConsoleKernel ->everyMinute() ->name('automations_run') ->withoutOverlapping(50); - - $schedule->command('colleague:poll-pending-orders') - ->everyMinute() - ->name('colleague_poll_pending_orders') - ->withoutOverlapping(58); } protected function commands() diff --git a/app/Http/Controllers/Single/SingleOrderController.php b/app/Http/Controllers/Single/SingleOrderController.php index 36ffaca..fa70fc9 100644 --- a/app/Http/Controllers/Single/SingleOrderController.php +++ b/app/Http/Controllers/Single/SingleOrderController.php @@ -2054,20 +2054,27 @@ class SingleOrderController extends Controller public function pendingColleague() { - $order = app(ColleagueOrderCallbackService::class) - ->pendingForCustomer((int) auth('customer')->id()); + $service = app(ColleagueOrderCallbackService::class); + $order = $service->pendingForCustomer((int) auth('customer')->id()); + if ($order) { + $order = $service->refreshIfDue($order); + } - return response()->json(app(ColleagueOrderCallbackService::class)->publicStatusPayload($order)); + return response()->json($service->publicStatusPayload($order)); } public function colleagueStatus(int $id) { + $service = app(ColleagueOrderCallbackService::class); $order = Order::query() ->where('id', $id) ->where('customer_id', auth('customer')->id()) ->first(); + if ($order) { + $order = $service->refreshIfDue($order); + } - return response()->json(app(ColleagueOrderCallbackService::class)->publicStatusPayload($order)); + return response()->json($service->publicStatusPayload($order)); } /** diff --git a/app/Services/ColleagueOrderCallbackService.php b/app/Services/ColleagueOrderCallbackService.php index 3db7244..9e2013a 100644 --- a/app/Services/ColleagueOrderCallbackService.php +++ b/app/Services/ColleagueOrderCallbackService.php @@ -52,42 +52,27 @@ class ColleagueOrderCallbackService return $this->applyProviderSts($order, $sts, $body); } - public function pollDueOrders(): int + public function refreshIfDue(Order $order): Order { - if (!Schema::hasTable('orders') || !Schema::hasColumn('orders', 'sts')) { - return 0; + if ((int) $order->sts !== 4) { + return $order; } - $cutoff = now()->subSeconds(self::POLL_SECONDS); - $handled = 0; - - $query = Order::query()->where('sts', 4)->whereNotNull('provider_id'); - if (Schema::hasColumn('orders', 'colleague_last_poll_at')) { - $query->where(function ($q) use ($cutoff) { - $q->where(function ($inner) use ($cutoff) { - $inner->whereNull('colleague_last_poll_at') - ->where('created_at', '<=', $cutoff); - })->orWhere('colleague_last_poll_at', '<=', $cutoff); - }); - } else { - $query->where('created_at', '<=', $cutoff); + if (!$this->isPollDue($order)) { + return $order; } - $orders = $query->orderBy('id')->limit(80)->get(); - foreach ($orders as $order) { - try { - $this->pollOne($order); - $handled++; - } catch (\Throwable $e) { - Log::warning('Colleague pending poll failed', [ - 'order_id' => $order->id, - 'error' => $e->getMessage(), - ]); - $this->touchPollAt($order); - } + try { + $this->pollOne($order); + } catch (\Throwable $e) { + Log::warning('Colleague pending poll failed', [ + 'order_id' => $order->id, + 'error' => $e->getMessage(), + ]); + $this->touchPollAt($order); } - return $handled; + return Order::query()->find($order->id) ?? $order; } public function pollOne(Order $order): array @@ -110,7 +95,17 @@ class ColleagueOrderCallbackService return ['ok' => true, 'state' => 'wait']; } - return $this->applyProviderSts($order, $sts, $body); + // جدول سفارش همکار همان sts مدل است (۲ موفق / ۳ ناموفق / ۴ هنوز باز). + // کالبک جداست: آن‌جا ۴ و ۶ یعنی رد. + if (in_array($sts, [3, 6], true)) { + return $this->rejectPending($order, $body); + } + + if ($sts === 2) { + return $this->approvePending($order, $body); + } + + return ['ok' => true, 'state' => 'wait', 'sts' => (int) $order->sts]; } /** @@ -286,12 +281,32 @@ class ColleagueOrderCallbackService $order->save(); } + private function isPollDue(Order $order): bool + { + $cutoff = now()->subSeconds(self::POLL_SECONDS); + $last = $order->colleague_last_poll_at ?? null; + if ($last) { + return $last <= $cutoff; + } + + $created = $order->created_at; + + return !$created || $created <= $cutoff; + } + /** * @param array $body */ public function providerStsFromBody(array $body): ?int { $rows = [$body, $body['data'] ?? null, $body['order'] ?? null]; + if (isset($body['rows']) && is_array($body['rows'])) { + foreach ($body['rows'] as $row) { + if (is_array($row)) { + $rows[] = $row; + } + } + } foreach ($body as $item) { if (!is_array($item)) { continue; diff --git a/app/Services/MontzarService.php b/app/Services/MontzarService.php index 70ce271..429d2ab 100644 --- a/app/Services/MontzarService.php +++ b/app/Services/MontzarService.php @@ -638,7 +638,7 @@ class MontzarService } /** - * GET وضعیت سفارش روی نود همکار — مسیر از setting + شناسه سفارش همکار. + * وضعیت سفارش روی نود همکار — اول GET مسیر+شناسه، اگر sts نبود POST جدول همان مسیر. * * @return array|null */ @@ -652,12 +652,97 @@ class MontzarService if ($path === '') { $path = '/server/customer/order'; } + $path = rtrim($path, '/'); - $url = $this->endpoint(rtrim($path, '/') . '/' . $providerOrderId); + $got = $this->montzarJson('GET', $this->endpoint($path . '/' . $providerOrderId)); + $row = $this->colleagueOrderRowFromBody($got, $providerOrderId); + if ($row) { + return $row; + } + + foreach ($this->colleagueOrderTableUrls($path) as $url) { + $body = $this->montzarJson('POST', $url, [ + 'filters' => [[ + 'field' => 'id', + 'cr' => 'and', + 'type' => 'text', + 'op' => 'eq', + 'value' => (string) $providerOrderId, + ]], + 'limit' => 12, + 'page' => 1, + 'search' => '', + ]); + $row = $this->colleagueOrderRowFromBody($body, $providerOrderId); + if ($row) { + return $row; + } + } + + return is_array($got) ? $got : null; + } + + /** + * @return list + */ + private function colleagueOrderTableUrls(string $path): array + { + $urls = [$this->endpoint($path . '/table')]; + if (str_ends_with($path, '/order') && !str_contains($path, '/single/')) { + $urls[] = $this->endpoint(str_replace('/customer/order', '/customer/single/order', $path) . '/table'); + } + + return array_values(array_unique($urls)); + } + + /** + * @param array|null $body + * @return array|null + */ + private function colleagueOrderRowFromBody(?array $body, int $providerOrderId): ?array + { + if (!is_array($body)) { + return null; + } + + $candidates = [$body, $body['data'] ?? null, $body['order'] ?? null]; + if (isset($body['rows']) && is_array($body['rows'])) { + foreach ($body['rows'] as $row) { + if (is_array($row)) { + $candidates[] = $row; + } + } + } + + $matched = null; + foreach ($candidates as $row) { + if (!is_array($row) || !array_key_exists('sts', $row)) { + continue; + } + $id = (int) ($row['id'] ?? $row['order_id'] ?? 0); + if ($id === $providerOrderId) { + return $row; + } + if ($id === 0 && $matched === null) { + $matched = $row; + } + } + + return $matched; + } + + /** + * @param array $payload + * @return array|null + */ + private function montzarJson(string $method, string $url, array $payload = []): ?array + { $token = $this->getToken(); - try { - $httpResponse = $this->http(15)->withToken($token)->get($url); + $http = $this->http(15)->withToken($token); + $httpResponse = strtoupper($method) === 'POST' + ? $http->post($url, $payload) + : $http->get($url); } catch (\Throwable $e) { Log::warning('Montzar order status request failed', [ 'url' => $url, @@ -670,7 +755,10 @@ class MontzarService $body = $this->decodeMontzarHttpBody($httpResponse); if (is_array($body) && ($body['message'] ?? null) === 'no authorised') { $token = $this->montzarLogin(); - $httpResponse = $this->http(15)->withToken($token)->get($url); + $http = $this->http(15)->withToken($token); + $httpResponse = strtoupper($method) === 'POST' + ? $http->post($url, $payload) + : $http->get($url); $body = $this->decodeMontzarHttpBody($httpResponse); }