fix some bugs from accounting 5
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user