all customer from pargar fixing ۲

This commit is contained in:
2026-07-22 00:31:10 +03:30
parent 21dbaa1e31
commit 94ad66d32b
3 changed files with 21 additions and 11 deletions
@@ -529,7 +529,7 @@ async function importAll() {
importStore.expand() importStore.expand()
return return
} }
await importStore.start(pending) await importStore.start(pending, 'pargar')
} }
// با پیشرفت عملیات سراسری، ردیف‌های وارد شده را همین‌جا هم تیک بزن // با پیشرفت عملیات سراسری، ردیف‌های وارد شده را همین‌جا هم تیک بزن
@@ -526,7 +526,7 @@ async function importAll() {
importStore.expand() importStore.expand()
return return
} }
await importStore.start(pending) await importStore.start(pending, 'tahesab')
} }
// با پیشرفت عملیات سراسری، ردیف‌های وارد شده را همین‌جا هم تیک بزن // با پیشرفت عملیات سراسری، ردیف‌های وارد شده را همین‌جا هم تیک بزن
+19 -9
View File
@@ -1,6 +1,7 @@
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { importFromTahesab, type TahesabOnlyCustomer } from '@/api/tahesab' import { importFromTahesab, type TahesabOnlyCustomer } from '@/api/tahesab'
import { importFromPargar, type PargarOnlyCustomer } from '@/api/pargar'
export interface ImportError { export interface ImportError {
code: number code: number
@@ -9,23 +10,27 @@ export interface ImportError {
} }
export type ImportStatus = 'idle' | 'running' | 'done' | 'canceled' export type ImportStatus = 'idle' | 'running' | 'done' | 'canceled'
export type ImportProvider = 'tahesab' | 'pargar'
/** نتیجهٔ نهایی برای نمایش آیکن/متن مناسب */ /** نتیجهٔ نهایی برای نمایش آیکن/متن مناسب */
export type ImportOutcome = 'running' | 'success' | 'error' | 'partial' | 'canceled' export type ImportOutcome = 'running' | 'success' | 'error' | 'partial' | 'canceled'
type ImportCustomer = TahesabOnlyCustomer | PargarOnlyCustomer
/** تعداد مشتری در هر درخواست (برای جلوگیری از محدودیت نرخ سرور) */ /** تعداد مشتری در هر درخواست (برای جلوگیری از محدودیت نرخ سرور) */
const CHUNK_SIZE = 50 const CHUNK_SIZE = 50
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)) const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
/** /**
* فروشگاه سراسری برای فرایند «وارد کردن همه» مشتریان ته‌حساب. * فروشگاه سراسری برای فرایند «وارد کردن همه» مشتریان حسابداری.
* چون به‌صورت singleton است، با جابه‌جایی بین صفحات از بین نمی‌رود و * چون به‌صورت singleton است، با جابه‌جایی بین صفحات از بین نمی‌رود و
* عملیات در پس‌زمینه ادامه پیدا می‌کند. * عملیات در پس‌زمینه ادامه پیدا می‌کند.
*/ */
export const useCustomerImportStore = defineStore('customerImport', () => { export const useCustomerImportStore = defineStore('customerImport', () => {
const status = ref<ImportStatus>('idle') const status = ref<ImportStatus>('idle')
const queue = ref<TahesabOnlyCustomer[]>([]) const provider = ref<ImportProvider>('tahesab')
const queue = ref<ImportCustomer[]>([])
const total = ref(0) const total = ref(0)
const processed = ref(0) const processed = ref(0)
const success = ref(0) const success = ref(0)
@@ -56,6 +61,7 @@ export const useCustomerImportStore = defineStore('customerImport', () => {
function reset() { function reset() {
status.value = 'idle' status.value = 'idle'
provider.value = 'tahesab'
queue.value = [] queue.value = []
total.value = 0 total.value = 0
processed.value = 0 processed.value = 0
@@ -86,10 +92,14 @@ export const useCustomerImportStore = defineStore('customerImport', () => {
reset() reset()
} }
async function start(customers: TahesabOnlyCustomer[]) { async function start(
customers: ImportCustomer[],
importProvider: ImportProvider = 'tahesab',
) {
if (status.value === 'running') return if (status.value === 'running') return
if (!customers.length) return if (!customers.length) return
provider.value = importProvider
queue.value = customers.slice() queue.value = customers.slice()
total.value = customers.length total.value = customers.length
processed.value = 0 processed.value = 0
@@ -105,10 +115,12 @@ export const useCustomerImportStore = defineStore('customerImport', () => {
await runLoop() await runLoop()
} }
// ارسال یک دسته با تلاش مجدد در صورت خطا (مثلاً محدودیت نرخ موقتی) async function importChunkWithRetry(chunk: ImportCustomer[], attempt = 0): Promise<any> {
async function importChunkWithRetry(chunk: TahesabOnlyCustomer[], attempt = 0): Promise<any> {
try { try {
return await importFromTahesab(chunk) if (provider.value === 'pargar') {
return await importFromPargar(chunk as PargarOnlyCustomer[])
}
return await importFromTahesab(chunk as TahesabOnlyCustomer[])
} catch (e) { } catch (e) {
if (attempt < 2 && !cancelRequested) { if (attempt < 2 && !cancelRequested) {
await sleep(1500 * (attempt + 1)) await sleep(1500 * (attempt + 1))
@@ -140,23 +152,21 @@ export const useCustomerImportStore = defineStore('customerImport', () => {
} }
} }
} catch (e) { } catch (e) {
// کل دسته ناموفق شد (مثلاً محدودیت نرخ یا قطع ارتباط)
for (const c of chunk) { for (const c of chunk) {
failed.value++ failed.value++
errors.value.push({ code: c.code, name: c.name, error: 'خطا در ارتباط با سرور' }) errors.value.push({ code: c.code, name: c.name, error: 'خطا در ارتباط با سرور' })
} }
} }
processed.value += chunk.length processed.value += chunk.length
// مکث کوتاه بین دسته‌ها برای جلوگیری از محدودیت نرخ سرور
if (processed.value < queue.value.length) await sleep(250) if (processed.value < queue.value.length) await sleep(250)
} }
status.value = 'done' status.value = 'done'
// پس از تکمیل محو نمی‌شود؛ تا زمانی که کاربر گزارش را ببندد باقی می‌ماند
} }
return { return {
status, status,
provider,
queue, queue,
total, total,
processed, processed,