Align DoListAsnad with Hamkar (4 args) and treat empty ERROR as [].

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-05 11:18:37 +03:30
co-authored by Cursor
parent 1ac23e13c1
commit 3ab102ddae
3 changed files with 49 additions and 19 deletions
@@ -12,6 +12,16 @@ import {
SanadBuilders, SanadBuilders,
} from './tahesab-methods'; } from './tahesab-methods';
function normalizeShamsiYmd(input: string): string {
const m = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(input.trim());
if (!m) {
throw new BadRequestException(
'تاریخ از/تا باید شمسی با قالب YYYY-MM-DD باشد.',
);
}
return `${m[1]}-${m[2]!.padStart(2, '0')}-${m[3]!.padStart(2, '0')}`;
}
function asAsnadList(raw: unknown): Array<Record<string, unknown>> { function asAsnadList(raw: unknown): Array<Record<string, unknown>> {
if (!raw) return []; if (!raw) return [];
if (Array.isArray(raw)) return raw as Array<Record<string, unknown>>; if (Array.isArray(raw)) return raw as Array<Record<string, unknown>>;
@@ -66,25 +76,27 @@ export class TahesabDocumentsService {
to: string, to: string,
connectionId?: string, connectionId?: string,
) { ) {
if (!/^\d{4}-\d{1,2}-\d{1,2}$/.test(from) || !/^\d{4}-\d{1,2}-\d{1,2}$/.test(to)) { const fromNorm = normalizeShamsiYmd(from);
throw new BadRequestException( const toNorm = normalizeShamsiYmd(to);
'تاریخ از/تا باید شمسی با قالب YYYY-MM-DD باشد.',
);
}
const resolvedId = await this.connections.resolveConnectionId( const resolvedId = await this.connections.resolveConnectionId(
organizationId, organizationId,
connectionId, connectionId,
); );
const link = await this.requireLink(organizationId, personId, resolvedId); const link = await this.requireLink(organizationId, personId, resolvedId);
const { api } = await this.connections.getApi(organizationId, resolvedId); const { api } = await this.connections.getApi(organizationId, resolvedId);
// Count_Last = سقف تعداد سند برگشتی (۰ در نمونه گاهی خالی برمی‌گرداند) // Count_Last = -1 مثل همکار (مانده ردیف‌به‌ردیف / همه در بازه)
const raw = await api.doListAsnad(500, link.moshtariCode, from, to); const raw = await api.doListAsnad(
-1,
link.moshtariCode,
fromNorm,
toNorm,
);
const items = asAsnadList(raw); const items = asAsnadList(raw);
return { return {
connectionId: resolvedId, connectionId: resolvedId,
moshtariCode: link.moshtariCode, moshtariCode: link.moshtariCode,
from, from: fromNorm,
to, to: toNorm,
items, items,
count: items.length, count: items.length,
}; };
@@ -20,6 +20,11 @@ export type TahesabCallOptions = {
method?: 'GET' | 'POST'; method?: 'GET' | 'POST';
allowInsecureTls?: boolean; allowInsecureTls?: boolean;
timeoutMs?: number; timeoutMs?: number;
/**
* اگر ته‌حساب با فیلد ERROR و متن منطبق جواب داد، به‌جای ۵۰۲
* مقدار خالی ([] ) برگردان — مثل «رکوردی یافت نشد» در DoListAsnad.
*/
emptyResultOnError?: RegExp;
}; };
function extractTahesabError(json: unknown, text: string): string { function extractTahesabError(json: unknown, text: string): string {
@@ -109,6 +114,17 @@ export class TahesabHttpClient {
// بعضی متدها با ۲۰۰ و فیلد ERROR برمی‌گردند // بعضی متدها با ۲۰۰ و فیلد ERROR برمی‌گردند
if (json && typeof json === 'object' && 'ERROR' in (json as object)) { if (json && typeof json === 'object' && 'ERROR' in (json as object)) {
const detail = extractTahesabError(json, text); const detail = extractTahesabError(json, text);
if (
detail &&
opts.emptyResultOnError &&
opts.emptyResultOnError.test(detail)
) {
this.logger.debug(
`Tahesab ${path} empty-on-error: ${detail.slice(0, 120)}`,
);
resolve([] as T);
return;
}
reject( reject(
new BadGatewayException( new BadGatewayException(
detail ? `ته‌حساب: ${detail}` : `خطای ته‌حساب برای ${path}`, detail ? `ته‌حساب: ${detail}` : `خطای ته‌حساب برای ${path}`,
@@ -1,5 +1,5 @@
import { randomBytes } from 'crypto'; import { randomBytes } from 'crypto';
import type { TahesabHttpClient } from './tahesab-http.client'; import type { TahesabHttpClient, TahesabCallOptions } from './tahesab-http.client';
export type ConnCreds = { export type ConnCreds = {
baseUrl: string; baseUrl: string;
@@ -146,6 +146,7 @@ export class TahesabApi {
args?: unknown[], args?: unknown[],
method?: 'GET' | 'POST', method?: 'GET' | 'POST',
timeoutMs?: number, timeoutMs?: number,
extra?: Pick<TahesabCallOptions, 'emptyResultOnError'>,
) { ) {
return this.http.call<T>({ return this.http.call<T>({
...this.creds, ...this.creds,
@@ -154,6 +155,7 @@ export class TahesabApi {
args, args,
method, method,
timeoutMs, timeoutMs,
...extra,
}); });
} }
@@ -222,15 +224,15 @@ export class TahesabApi {
fromShamsi: string, fromShamsi: string,
toShamsi: string, toShamsi: string,
) { ) {
// OpenAPI: Count_Last, Moshtari_Code, AzTarikhShamsi, TaTarikhShamsi, FilterNoSanad, Mande_Jens_Felez // مثل همکار: فقط ۴ پارامتر (Count_Last, Code, از, تا) — پارامتر اضافه باعث خطای ته‌حساب می‌شود
return this.call('DoListAsnad', 'DoListAsnad', [ return this.call(
countLast, 'DoListAsnad',
moshtariCode, 'DoListAsnad',
fromShamsi, [countLast, moshtariCode, fromShamsi, toShamsi],
toShamsi, 'POST',
'', 55_000,
0, { emptyResultOnError: /رکوردی یافت نشد/i },
]); );
} }
doListNameSekeh() { doListNameSekeh() {