fix some bugs from accounting 5

This commit is contained in:
2026-07-28 18:55:59 +03:30
parent 5122d7e2b7
commit 6bb9af9893
2 changed files with 166 additions and 11 deletions
+159 -10
View File
@@ -272,13 +272,18 @@ class ZarinController extends Controller
/** /**
* پیدا کردن کار/کالای محصول در زرین. * پیدا کردن کار/کالای محصول در زرین.
* اول infokarbarcodi (اگر روی آن سرور فعال باشد)؛ وگرنه infosakhte (لیست کامل). * اولویت: listKarSakhte (کاتالوگ کار ساخته) → infosakhte → infokarbarcodi.
*/ */
private function findZarinKarForProduct(Product $product, $goroheKar = null, bool $exactOnly = false) private function findZarinKarForProduct(Product $product, $goroheKar = null, bool $exactOnly = false)
{ {
$goroheKar = $goroheKar ?: $this->zarinDefaultGoroheKar(); $goroheKar = $goroheKar ?: $this->zarinDefaultGoroheKar();
$productName = $this->normalizeZarinName($product->title); $productName = $this->normalizeZarinName($product->title);
$fromList = $this->findZarinKarInListKarSakhte($productName, $exactOnly);
if ($fromList) {
return $fromList;
}
$fromBarcode = $this->findZarinKarInInfokarbarcodi($productName, $goroheKar, $exactOnly); $fromBarcode = $this->findZarinKarInInfokarbarcodi($productName, $goroheKar, $exactOnly);
if ($fromBarcode) { if ($fromBarcode) {
return $fromBarcode; return $fromBarcode;
@@ -287,6 +292,73 @@ class ZarinController extends Controller
return $this->findZarinKarInInfosakhte($productName, $goroheKar, $exactOnly); 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 private function matchZarinKarRow(string $productName, array $row, bool $exactOnly = false): ?array
{ {
$name = $row['nameKar'] $name = $row['nameKar']
@@ -558,6 +630,32 @@ class ZarinController extends Controller
} }
$body = $response->json(); $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); $createdIdKar = $this->extractIdKarFromCreateResponse(is_array($body) ? $body : null);
// اولویت با idKar برگشتی از ساخت — جستجوی فازی نام می‌تواند کالای اشتباه بچسباند // اولویت با idKar برگشتی از ساخت — جستجوی فازی نام می‌تواند کالای اشتباه بچسباند
@@ -607,7 +705,35 @@ class ZarinController extends Controller
$currentIdKar = $product->finance_p_name; $currentIdKar = $product->finance_p_name;
$productName = $this->normalizeZarinName($product->title); $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); $existingRow = $this->getZarinKarById($currentIdKar);
if ($existingRow) { if ($existingRow) {
@@ -641,15 +767,14 @@ class ZarinController extends Controller
]; ];
} }
} else { } else {
// finance_p_name کهنه / اشتباه — پاک کن تا دوباره پیدا یا ساخته شود
$this->clearProductZarinKar($product); $this->clearProductZarinKar($product);
$product->refresh(); $product->refresh();
} }
} }
// بعد از خطای «کد کار اشتباه»: فقط تطبیق دقیق نام، نه فازی // اول فقط exact؛ اگر نبود fuzzy از listKarSakhte/infosakhte
$exactOnly = (bool) $forceCreate; $found = $this->findZarinKarForProduct($product, $this->zarinDefaultGoroheKar(), true)
$found = $this->findZarinKarForProduct($product, $this->zarinDefaultGoroheKar(), $exactOnly); ?? $this->findZarinKarForProduct($product, $this->zarinDefaultGoroheKar(), false);
if ($found && !empty($found['idKar']) && is_numeric($found['idKar'])) { if ($found && !empty($found['idKar']) && is_numeric($found['idKar'])) {
$product->finance_p_name = (string) $found['idKar']; $product->finance_p_name = (string) $found['idKar'];
@@ -657,11 +782,12 @@ class ZarinController extends Controller
return [ return [
'ok' => true, 'ok' => true,
'source' => $exactOnly ? 'found_exact_after_invalid' : 'found_by_name', 'source' => 'found_by_name',
'idKar' => (int) $found['idKar'], 'idKar' => (int) $found['idKar'],
'product' => $product->fresh(), 'product' => $product->fresh(),
'zarin_row' => $found['row'], 'zarin_row' => $found['row'],
'match' => $found['match'] ?? null, 'match' => $found['match'] ?? null,
'list_source' => $found['source'] ?? null,
]; ];
} }
@@ -1690,10 +1816,11 @@ class ZarinController extends Controller
return false; return false;
} }
$idKar = (int) $kar['idKar'];
$http = $this->zarinRequest([ $http = $this->zarinRequest([
'kind' => 'sabtSanadTedadi', 'kind' => 'sabtSanadTedadi',
'idHesab' => $customer->moshtari_code, 'idHesab' => $customer->moshtari_code,
'idKar' => (int) $kar['idKar'], 'idKar' => $idKar,
'fi' => $fi, 'fi' => $fi,
'tedad' => $tedad, 'tedad' => $tedad,
'parDar' => $parDar, 'parDar' => $parDar,
@@ -1707,11 +1834,21 @@ class ZarinController extends Controller
} }
[$response, $httpError] = $this->zarinDecodeResponse($http); [$response, $httpError] = $this->zarinDecodeResponse($http);
$diag = 'idKar=' . $idKar
. ' noeKar=' . $this->zarinDefaultNoeKar()
. ' goroheKar=' . $this->zarinDefaultGoroheKar()
. ' product=' . ($product->title ?? '')
. ' source=' . ($kar['source'] ?? '');
if ( if (
!$retriedInvalidKar !$retriedInvalidKar
&& $this->isInvalidZarinKarError($response, $httpError) && $this->isInvalidZarinKarError($response, $httpError)
) { ) {
Log::warning('zarin sabtSanadTedadi invalid idKar, recreating', [
'diag' => $diag,
'response' => $response,
'httpError' => $httpError,
]);
$this->clearProductZarinKar($product); $this->clearProductZarinKar($product);
$product->refresh(); $product->refresh();
$retriedInvalidKar = true; $retriedInvalidKar = true;
@@ -1719,7 +1856,11 @@ class ZarinController extends Controller
} }
if ($httpError) { if ($httpError) {
$this->sync()->markFailed($zarin, $response ?? $httpError, $httpError); $this->sync()->markFailed(
$zarin,
$response ?? $httpError,
$httpError . ' | ' . $diag
);
return false; return false;
} }
@@ -1733,13 +1874,21 @@ class ZarinController extends Controller
!$retriedInvalidKar !$retriedInvalidKar
&& $this->isInvalidZarinKarError($response) && $this->isInvalidZarinKarError($response)
) { ) {
Log::warning('zarin sabtSanadTedadi invalid idKar (HTTP 200), recreating', [
'diag' => $diag,
'response' => $response,
]);
$this->clearProductZarinKar($product); $this->clearProductZarinKar($product);
$product->refresh(); $product->refresh();
$retriedInvalidKar = true; $retriedInvalidKar = true;
continue; continue;
} }
$this->sync()->markFailed($zarin, $response, 'ثبت سند تعدادی در زرین ناموفق بود'); $this->sync()->markFailed(
$zarin,
$response,
'ثبت سند تعدادی در زرین ناموفق بود | ' . $diag
);
return false; return false;
} }
} }
+7 -1
View File
@@ -236,7 +236,13 @@ class ZarinSyncService
$desc = (string) $row->desc; $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'; return 'walletGold';
} }