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)
{
$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;
}
}
+7 -1
View File
@@ -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';
}