diff --git a/apps/api/src/integrations/tahesab/person-link.service.ts b/apps/api/src/integrations/tahesab/person-link.service.ts index f11dcaa..07831f8 100644 --- a/apps/api/src/integrations/tahesab/person-link.service.ts +++ b/apps/api/src/integrations/tahesab/person-link.service.ts @@ -18,8 +18,9 @@ import { import { normalizeIranMobile, SanadBuilders, type TahesabApi } from './tahesab-methods'; const LIST_ALL_CHUNK = 2000; -const LIST_ALL_MAX_CODE = 50_000; -const LIST_ALL_EMPTY_STREAK = 3; +/** سقف «همه» در یک درخواست ByCode — تکه‌تکه باعث ۵۰۲ پروکسی می‌شود */ +const LIST_ALL_MAX_CODE = 5_000; +const LIST_ALL_TIMEOUT_MS = 55_000; function asMoshtariList(raw: unknown): Array> { if (!raw) return []; @@ -316,21 +317,26 @@ export class TahesabPersonLinkService { return this.linkDto(link); } + /** + * لیست همهٔ مشتریان در یک درخواست (بازه ۱…LIST_ALL_MAX_CODE). + * تکه‌تکه کردن پشت‌سرهم معمولاً از مهلت nginx بیشتر می‌شود و ۵۰۲ می‌دهد. + */ private async listAllMoshtari(api: TahesabApi) { - const merged: Array> = []; - let emptyStreak = 0; - for (let from = 1; from <= LIST_ALL_MAX_CODE; from += LIST_ALL_CHUNK) { - const to = Math.min(from + LIST_ALL_CHUNK - 1, LIST_ALL_MAX_CODE); - const rows = asMoshtariList(await api.doListMoshtariByCode(from, to)); - if (!rows.length) { - emptyStreak += 1; - if (emptyStreak >= LIST_ALL_EMPTY_STREAK) break; - continue; - } - emptyStreak = 0; - merged.push(...rows); + try { + return asMoshtariList( + await api.doListMoshtariByCode(1, LIST_ALL_MAX_CODE, { + timeoutMs: LIST_ALL_TIMEOUT_MS, + }), + ); + } catch (err) { + // اگر بازهٔ بزرگ سمت ته‌حساب رد شد، همان سقف دستی ۲۰۰۰ را یک‌بار امتحان کن + if (LIST_ALL_MAX_CODE <= LIST_ALL_CHUNK) throw err; + return asMoshtariList( + await api.doListMoshtariByCode(1, LIST_ALL_CHUNK, { + timeoutMs: LIST_ALL_TIMEOUT_MS, + }), + ); } - return merged; } async search(organizationId: string, dto: SearchTahesabDto) { @@ -366,7 +372,8 @@ export class TahesabPersonLinkService { moshtariCode: pickCode(row), name: pickName(row), tel: pickTel(row), - raw: row, + // raw فقط برای جستجوی محدود؛ در listAll حجم پاسخ را باد می‌کند و پروکسی را می‌ترکاند + ...(dto.listAll ? {} : { raw: row }), })); const codes = mapped diff --git a/apps/api/src/integrations/tahesab/tahesab-methods.ts b/apps/api/src/integrations/tahesab/tahesab-methods.ts index 68aae0f..5562019 100644 --- a/apps/api/src/integrations/tahesab/tahesab-methods.ts +++ b/apps/api/src/integrations/tahesab/tahesab-methods.ts @@ -145,6 +145,7 @@ export class TahesabApi { bodyKey?: string, args?: unknown[], method?: 'GET' | 'POST', + timeoutMs?: number, ) { return this.http.call({ ...this.creds, @@ -152,6 +153,7 @@ export class TahesabApi { bodyKey, args, method, + timeoutMs, }); } @@ -182,12 +184,18 @@ export class TahesabApi { return this.call('DoEditMoshtari', 'DoEditMoshtari', args); } - doListMoshtariByCode(fromCode: number, toCode: number) { + doListMoshtariByCode( + fromCode: number, + toCode: number, + opts?: { timeoutMs?: number }, + ) { // OpenAPI/Postman: کلید body برای ByCode دقیقاً «Dolistmoshtari» است (حساس به حروف) return this.call( 'DoListMoshtari-ByCode', 'Dolistmoshtari', [fromCode, toCode], + 'POST', + opts?.timeoutMs, ); } diff --git a/apps/web/src/views/TahesabSettingsView.vue b/apps/web/src/views/TahesabSettingsView.vue index 87eaec7..92eae8d 100644 --- a/apps/web/src/views/TahesabSettingsView.vue +++ b/apps/web/src/views/TahesabSettingsView.vue @@ -261,6 +261,7 @@ async function searchTahesab(mode: 'filter' | 'range' = 'filter') { const { data } = await api.post<{ results: SyncResult[] }>( '/integrations/tahesab/sync/search', body, + { timeout: 60_000 }, ); syncResults.value = data.results ?? []; if (!syncResults.value.length) { @@ -502,8 +503,8 @@ onMounted(load);

۱) وارد کردن دسته‌ای با بازهٔ کد مشتری

- اگر «از» و «تا» را خالی بگذارید و نمایش بازه را بزنید، همهٔ مشتریان ته‌حساب لیست می‌شوند. - برای محدود کردن، بازه بگذارید (حداکثر ۲۰۰۰ کد در هر درخواست محدود). + اگر «از» و «تا» خالی باشند، مشتریان با کد ۱ تا ۵۰۰۰ از ته‌حساب لیست می‌شوند. + برای کدهای بالاتر بازه را دستی بگذارید (حداکثر ۲۰۰۰ کد در هر درخواست محدود).