$ref, 'res' => is_array($response) ? json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : (is_string($response) ? $response : null), 'sync_status' => self::STATUS_SUCCESS, 'sync_log' => null, ]; if ($payload !== null) { $update['data'] = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); } PargarSyncLog::where('id', $log->id)->update($update); } public function markFailed(PargarSyncLog $log, mixed $response = null, ?string $extra = null): void { PargarSyncLog::where('id', $log->id)->update([ 'res' => is_array($response) ? json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : (is_string($response) ? $response : null), 'sync_status' => self::STATUS_FAILED, 'sync_log' => $this->buildLog($response, $extra), ]); } public function isFailed(PargarSyncLog $log): bool { return ($log->sync_status ?? null) === self::STATUS_FAILED || (empty($log->pargar_ref) && ($log->sync_status ?? null) !== self::STATUS_SUCCESS); } public function registerOnCreate(Customer $customer): void { if (! empty($customer->pargar_account_id) || ! $this->isSyncEnabled()) { return; } $customerId = (int) $customer->id; dispatch(function () use ($customerId) { $service = app(self::class); if (! $service->isSyncEnabled()) { return; } $customer = Customer::find($customerId); if ($customer === null || ! empty($customer->pargar_account_id)) { return; } try { $service->queueCustomerExport($customer); } catch (\Throwable $e) { Log::warning('Pargar auto-queue on customer create failed', [ 'customer_id' => $customerId, 'error' => $e->getMessage(), ]); } })->afterResponse(); } public function queueCustomerExport(Customer $customer): PargarSyncLog { $existing = PargarSyncLog::query() ->where('customer_id', $customer->id) ->where('type', 'customer') ->where('sync_status', self::STATUS_PENDING) ->latest('id') ->first(); if ($existing) { return $existing; } return PargarSyncLog::create([ 'customer_id' => $customer->id, 'desc' => 'در انتظار دریافت توسط پرگار', 'type' => 'customer', 'sync_status' => self::STATUS_PENDING, 'data' => json_encode(['handler' => 'exportCustomer'], JSON_UNESCAPED_UNICODE), ]); } public function registerCustomer(Customer $customer): array { $customer->refresh(); if (! empty($customer->pargar_account_id)) { return [ 'ok' => true, 'message' => 'مشتری قبلاً در پرگار ثبت شده است', 'pargar_account_id' => $customer->pargar_account_id, ]; } $this->queueCustomerExport($customer); return [ 'ok' => true, 'message' => 'مشتری در صف دریافت پرگار قرار گرفت', 'pargar_account_id' => null, ]; } public function recordTrade(?Order $order, bool $fromCart = false): ?PargarSyncLog { if (! $order || ! $order->id || ! $this->isSyncEnabled()) { return null; } $existing = PargarSyncLog::where('order_id', $order->id)->first(); if ($existing) { return $existing; } $direction = (int) ($order->direction ?? 0); $desc = $fromCart ? 'سبد خرید' : ($direction === 1 ? 'خرید آبشده' : 'فروش آبشده'); return PargarSyncLog::create([ 'customer_id' => $order->customer_id, 'amount' => $order->amount, 'desc' => $desc, 'order_id' => $order->id, 'date' => $order->pay_at ?? $order->created_at, 'type' => 'order', 'sync_status' => self::STATUS_PENDING, 'data' => json_encode([ 'handler' => 'exportOrder', 'direction' => $direction, 'price' => $order->price, 'total_price' => $order->total_price, ], JSON_UNESCAPED_UNICODE), ]); } public function confirmOrders(array $orderIds): array { $confirmed = 0; foreach ($orderIds as $orderId) { $order = Order::find($orderId); if (! $order) { continue; } $order->pargar_confirmed_at = now(); $order->save(); $log = PargarSyncLog::where('order_id', $order->id)->latest('id')->first(); if ($log) { $this->markSuccess($log, (string) $order->id, ['OrderId' => (string) $order->id]); } $confirmed++; } return ['confirmed' => $confirmed]; } public function retry(PargarSyncLog $log): array { if (! $this->isFailed($log) && ! empty($log->pargar_ref)) { return ['ok' => false, 'message' => 'این سند قبلاً در پرگار ثبت شده است']; } $payload = json_decode((string) $log->data, true) ?: []; $handler = $payload['handler'] ?? $this->inferHandler($log); if ($handler === 'exportOrder' && $log->order_id) { Order::where('id', $log->order_id)->update(['pargar_confirmed_at' => null]); PargarSyncLog::where('id', $log->id)->update([ 'sync_status' => self::STATUS_PENDING, 'sync_log' => null, 'pargar_ref' => null, ]); $log->refresh(); return [ 'ok' => true, 'message' => 'سفارش دوباره در صف ارسال به پرگار قرار گرفت', 'pargar' => $log, ]; } if ($handler === 'exportCustomer' && $log->customer_id) { PargarSyncLog::where('id', $log->id)->update([ 'sync_status' => self::STATUS_PENDING, 'sync_log' => null, 'pargar_ref' => null, ]); $log->refresh(); return [ 'ok' => true, 'message' => 'مشتری دوباره در صف دریافت پرگار قرار گرفت', 'pargar' => $log, ]; } return [ 'ok' => false, 'message' => $log->sync_log ?: 'ارسال مجدد به پرگار ناموفق بود', 'pargar' => $log, ]; } private function inferHandler(PargarSyncLog $log): string { if ($log->order_id) { return 'exportOrder'; } if ($log->type === 'customer') { return 'exportCustomer'; } if ($log->type === 'mande') { return 'importMande'; } return 'importDocument'; } public function isSyncEnabled(): bool { $config = app(ConfigService::class); return $config->isPargarAccounting() && trim($config->getString('pargar_username', '')) !== '' && trim($config->getString('pargar_password', '')) !== ''; } public function hasSyncTable(): bool { return Schema::hasTable('pargar_sync_logs'); } }