From 6bb9af9893675a02d49a71ab42dd57a2f04ea5eb Mon Sep 17 00:00:00 2001 From: adonis Date: Tue, 28 Jul 2026 18:55:59 +0330 Subject: [PATCH] fix some bugs from accounting 5 --- .../Controllers/Admin/ZarinController.php | 169 ++++++++++++++++-- app/Services/ZarinSyncService.php | 8 +- 2 files changed, 166 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/Admin/ZarinController.php b/app/Http/Controllers/Admin/ZarinController.php index f9ec2ff..e5fe693 100644 --- a/app/Http/Controllers/Admin/ZarinController.php +++ b/app/Http/Controllers/Admin/ZarinController.php @@ -272,13 +272,18 @@ class ZarinController extends Controller /** * پیدا کردن کار/کالای محصول در زرین. - * اول infokarbarcodi (اگر روی آن سرور فعال باشد)؛ وگرنه infosakhte (لیست کامل). + * اولویت: listKarSakhte (کاتالوگ کار ساخته) → infosakhte → infokarbarcodi. */ private function findZarinKarForProduct(Product $product, $goroheKar = null, bool $exactOnly = false) { $goroheKar = $goroheKar ?: $this->zarinDefaultGoroheKar(); $productName = $this->normalizeZarinName($product->title); + $fromList = $this->findZarinKarInListKarSakhte($productName, $exactOnly); + if ($fromList) { + return $fromList; + } + $fromBarcode = $this->findZarinKarInInfokarbarcodi($productName, $goroheKar, $exactOnly); if ($fromBarcode) { return $fromBarcode; @@ -287,6 +292,73 @@ class ZarinController extends Controller return $this->findZarinKarInInfosakhte($productName, $goroheKar, $exactOnly); } + /** + * کاتالوگ کارهای ساخته (لیست ۴۷ زرین) — id همین idKar سند تعدادی است. + */ + private function findZarinKarInListKarSakhte(string $productName, bool $exactOnly = false): ?array + { + $response = $this->zarinRequest([ + 'kind' => 'listKarSakhte', + ], 30); + + if (!$response || !$response->successful()) { + return null; + } + + $rows = $this->zarinRowsFromBody($response->json()); + if (empty($rows)) { + return null; + } + + $exact = null; + $fuzzy = null; + + foreach ($rows as $row) { + if (!is_array($row)) { + continue; + } + + $name = $row['namFelezsakhthe'] + ?? $row['nam_kar_sakhte'] + ?? $row['nameKar'] + ?? $row['nam'] + ?? $row['name'] + ?? ''; + $rowName = $this->normalizeZarinName($name); + $idKar = $this->extractUsableZarinKarId($row); + if (!$idKar || $rowName === '') { + continue; + } + + if ($rowName === $productName) { + $exact = [ + 'idKar' => $idKar, + 'row' => $row, + 'match' => 'exact', + 'source' => 'listKarSakhte', + ]; + break; + } + + if ( + !$exactOnly + && ( + $this->containsText($rowName, $productName) + || $this->containsText($productName, $rowName) + ) + ) { + $fuzzy ??= [ + 'idKar' => $idKar, + 'row' => $row, + 'match' => 'fuzzy', + 'source' => 'listKarSakhte', + ]; + } + } + + return $exact ?? ($exactOnly ? null : $fuzzy); + } + private function matchZarinKarRow(string $productName, array $row, bool $exactOnly = false): ?array { $name = $row['nameKar'] @@ -558,6 +630,32 @@ class ZarinController extends Controller } $body = $response->json(); + if (is_array($body) && array_key_exists('state', $body) && filter_var($body['state'], FILTER_VALIDATE_BOOLEAN) === false) { + // ممکن است کالا از قبل باشد و idKar در پیام آمده باشد + $createdIdKar = $this->extractIdKarFromCreateResponse($body); + if ($createdIdKar) { + $product->finance_p_name = (string) $createdIdKar; + $product->save(); + + return [ + 'ok' => true, + 'source' => 'create_response_idKar_despite_state', + 'idKar' => $createdIdKar, + 'product' => $product->fresh(), + 'zarin_response' => $body, + 'sent_params_success' => $params, + ]; + } + + return [ + 'ok' => false, + 'message' => (string) ($body['detail'] ?? $body['msg'] ?? $body['message'] ?? 'ساخت کد کار در زرین ناموفق بود.'), + 'status_code' => 422, + 'zarin_response' => $body, + 'sent_params' => $params, + ]; + } + $createdIdKar = $this->extractIdKarFromCreateResponse(is_array($body) ? $body : null); // اولویت با idKar برگشتی از ساخت — جستجوی فازی نام می‌تواند کالای اشتباه بچسباند @@ -607,7 +705,35 @@ class ZarinController extends Controller $currentIdKar = $product->finance_p_name; $productName = $this->normalizeZarinName($product->title); - if (!$forceCreate && !empty($currentIdKar) && is_numeric($currentIdKar)) { + // بعد از «کد کار اشتباه»: کالای تازه بساز؛ اگر ساخت نشد، exact از کاتالوگ + if ($forceCreate) { + $this->clearProductZarinKar($product); + $product->refresh(); + + $created = $this->createZarinKarForProduct($product); + if (!empty($created['ok']) && !empty($created['idKar'])) { + return $created; + } + + $found = $this->findZarinKarForProduct($product, $this->zarinDefaultGoroheKar(), true); + if ($found && !empty($found['idKar']) && is_numeric($found['idKar'])) { + $product->finance_p_name = (string) $found['idKar']; + $product->save(); + + return [ + 'ok' => true, + 'source' => 'found_exact_after_create_failed', + 'idKar' => (int) $found['idKar'], + 'product' => $product->fresh(), + 'zarin_row' => $found['row'], + 'create_error' => $created, + ]; + } + + return $created; + } + + if (!empty($currentIdKar) && is_numeric($currentIdKar)) { $existingRow = $this->getZarinKarById($currentIdKar); if ($existingRow) { @@ -641,15 +767,14 @@ class ZarinController extends Controller ]; } } else { - // finance_p_name کهنه / اشتباه — پاک کن تا دوباره پیدا یا ساخته شود $this->clearProductZarinKar($product); $product->refresh(); } } - // بعد از خطای «کد کار اشتباه»: فقط تطبیق دقیق نام، نه فازی - $exactOnly = (bool) $forceCreate; - $found = $this->findZarinKarForProduct($product, $this->zarinDefaultGoroheKar(), $exactOnly); + // اول فقط exact؛ اگر نبود fuzzy از listKarSakhte/infosakhte + $found = $this->findZarinKarForProduct($product, $this->zarinDefaultGoroheKar(), true) + ?? $this->findZarinKarForProduct($product, $this->zarinDefaultGoroheKar(), false); if ($found && !empty($found['idKar']) && is_numeric($found['idKar'])) { $product->finance_p_name = (string) $found['idKar']; @@ -657,11 +782,12 @@ class ZarinController extends Controller return [ 'ok' => true, - 'source' => $exactOnly ? 'found_exact_after_invalid' : 'found_by_name', + 'source' => 'found_by_name', 'idKar' => (int) $found['idKar'], 'product' => $product->fresh(), 'zarin_row' => $found['row'], 'match' => $found['match'] ?? null, + 'list_source' => $found['source'] ?? null, ]; } @@ -1690,10 +1816,11 @@ class ZarinController extends Controller return false; } + $idKar = (int) $kar['idKar']; $http = $this->zarinRequest([ 'kind' => 'sabtSanadTedadi', 'idHesab' => $customer->moshtari_code, - 'idKar' => (int) $kar['idKar'], + 'idKar' => $idKar, 'fi' => $fi, 'tedad' => $tedad, 'parDar' => $parDar, @@ -1707,11 +1834,21 @@ class ZarinController extends Controller } [$response, $httpError] = $this->zarinDecodeResponse($http); + $diag = 'idKar=' . $idKar + . ' noeKar=' . $this->zarinDefaultNoeKar() + . ' goroheKar=' . $this->zarinDefaultGoroheKar() + . ' product=' . ($product->title ?? '') + . ' source=' . ($kar['source'] ?? ''); if ( !$retriedInvalidKar && $this->isInvalidZarinKarError($response, $httpError) ) { + Log::warning('zarin sabtSanadTedadi invalid idKar, recreating', [ + 'diag' => $diag, + 'response' => $response, + 'httpError' => $httpError, + ]); $this->clearProductZarinKar($product); $product->refresh(); $retriedInvalidKar = true; @@ -1719,7 +1856,11 @@ class ZarinController extends Controller } if ($httpError) { - $this->sync()->markFailed($zarin, $response ?? $httpError, $httpError); + $this->sync()->markFailed( + $zarin, + $response ?? $httpError, + $httpError . ' | ' . $diag + ); return false; } @@ -1733,13 +1874,21 @@ class ZarinController extends Controller !$retriedInvalidKar && $this->isInvalidZarinKarError($response) ) { + Log::warning('zarin sabtSanadTedadi invalid idKar (HTTP 200), recreating', [ + 'diag' => $diag, + 'response' => $response, + ]); $this->clearProductZarinKar($product); $product->refresh(); $retriedInvalidKar = true; continue; } - $this->sync()->markFailed($zarin, $response, 'ثبت سند تعدادی در زرین ناموفق بود'); + $this->sync()->markFailed( + $zarin, + $response, + 'ثبت سند تعدادی در زرین ناموفق بود | ' . $diag + ); return false; } } diff --git a/app/Services/ZarinSyncService.php b/app/Services/ZarinSyncService.php index 227f67d..bb2e9b0 100644 --- a/app/Services/ZarinSyncService.php +++ b/app/Services/ZarinSyncService.php @@ -236,7 +236,13 @@ class ZarinSyncService $desc = (string) $row->desc; - if (str_contains($desc, 'شارژ کیف') || str_contains($desc, 'برداشت از کیف')) { + if (str_contains($desc, 'شارژ') || str_contains($desc, 'دشارژ') || str_contains($desc, 'برداشت از کیف') || str_contains($desc, 'شارژ کیف')) { + return 'walletGold'; + } + + // نوع تعدادی ذخیره‌شده روی ردیف sync + $type = (string) $row->type; + if (in_array($type, ['سکه', 'شمش', 'کارساخته'], true)) { return 'walletGold'; }