fix(client): read all customs order pages with bounded concurrency
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import { getMerchantUnifiedOrders } from '../api/unifiedOrders'
|
||||
import { getMerchantCustomsForOrder, isMerchantCustomsUnavailable, type MerchantCustomsContainer } from '../api/customs'
|
||||
import { isCustomsOrderCandidate } from './customsEligibility'
|
||||
|
||||
export interface CustomsDocumentRow {
|
||||
order: { id: string; orderNo: string | null; businessSummary: { inboundCode: string } }
|
||||
detail: MerchantCustomsContainer
|
||||
}
|
||||
|
||||
// Isolated from the shared order store: scan sequential pages, with at most
|
||||
// four document requests in flight. Inconsistent pagination must be visible.
|
||||
export async function readCustomsDocuments() {
|
||||
const records: CustomsDocumentRow[] = []
|
||||
const seen = new Set<string>()
|
||||
let expectedTotal: number | undefined
|
||||
let failedCount = 0
|
||||
const size = 200
|
||||
for (let page = 1; ; page += 1) {
|
||||
const response = await getMerchantUnifiedOrders({ page, size })
|
||||
const total = Number(response.total)
|
||||
const pages = Number(response.pages)
|
||||
if (!Number.isSafeInteger(total) || total < 0 || Number(response.page) !== page
|
||||
|| Number(response.size) !== size || pages !== Math.ceil(total / size)
|
||||
|| (expectedTotal !== undefined && total !== expectedTotal)
|
||||
|| response.records.length !== Math.min(size, Math.max(0, total - (page - 1) * size))) {
|
||||
throw new Error('订单分页数据不完整或已变化,请重新加载报关资料')
|
||||
}
|
||||
expectedTotal = total
|
||||
for (const row of response.records) {
|
||||
const id = String(row.orderId)
|
||||
if (seen.has(id)) throw new Error('订单分页存在重复记录,请重新加载报关资料')
|
||||
seen.add(id)
|
||||
}
|
||||
const candidates = response.records.filter(row => isCustomsOrderCandidate({ status: row.mainStatus, taxMode: row.taxMode ?? 'BUY_DECLARATION' }))
|
||||
for (let offset = 0; offset < candidates.length; offset += 4) {
|
||||
const results = await Promise.all(candidates.slice(offset, offset + 4).map(async row => {
|
||||
const id = String(row.orderId)
|
||||
try {
|
||||
const detail = await getMerchantCustomsForOrder(id)
|
||||
if (!detail.inbounds.some(item => item.orderId === id && item.taxMode === 'TAX_REFUND')) return null
|
||||
return { order: { id, orderNo: row.orderNo, businessSummary: { inboundCode: row.inboundCode ?? '' } }, detail }
|
||||
} catch (error) {
|
||||
if (!isMerchantCustomsUnavailable(error)) failedCount += 1
|
||||
return null
|
||||
}
|
||||
}))
|
||||
for (const result of results) if (result) records.push(result)
|
||||
}
|
||||
if (page >= pages) break
|
||||
}
|
||||
return { records, failedCount }
|
||||
}
|
||||
Reference in New Issue
Block a user