fix(client): count only pending customs uploads

This commit is contained in:
2026-10-02 12:38:28 +08:00
parent 1bd1664e9c
commit 2f1babae45
3 changed files with 41 additions and 3 deletions
@@ -0,0 +1,33 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import ts from 'typescript'
import { computed, ref } from 'vue'
const source = readFileSync(new URL('./customsEligibility.ts', import.meta.url), 'utf8')
const exports = {}
new Function('exports', ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS } }).outputText)(exports)
test('upload queue contains only customer uploads still required, while completed documents stay accessible', () => {
const states = [null, {}, { status: 'WAITING_CUSTOMER_DOCUMENTS', merchantStatus: 'DOCUMENT_UPLOADED' },
{ status: 'READY_TO_START', merchantStatus: 'DOCUMENT_UPLOADED' },
{ status: 'DECLARING', merchantStatus: 'DECLARING' }, { status: 'COMPLETED', merchantStatus: 'CUSTOMS_COMPLETED' }]
for (const detail of states) assert.equal(exports.needsCustomsUpload(detail), false)
assert.equal(exports.needsCustomsUpload({ status: 'WAITING_CUSTOMER_DOCUMENTS', merchantStatus: 'WAITING_UPLOAD' }), true)
for (const status of ['LOADED', 'DELIVERED', 'COMPLETED']) assert.equal(exports.isCustomsOrderCandidate({ status, taxMode: 'TAX_REFUND' }), true)
})
test('actual page count and queue filter both drop a record when its upload is complete', () => {
const page = readFileSync(new URL('../views/FirstLegOrdersView.vue', import.meta.url), 'utf8')
const block = page.slice(page.indexOf('const orderQueueCounts ='), page.indexOf('const pagedOrders ='))
const rows = ref([{ id: 'waiting', businessSummary: {} }, { id: 'completed', businessSummary: {} }])
const states = ref({ waiting: { status: 'WAITING_CUSTOMER_DOCUMENTS', merchantStatus: 'WAITING_UPLOAD' }, completed: { status: 'COMPLETED', merchantStatus: 'CUSTOMS_COMPLETED' } })
const queue = ref('customs')
const read = new Function('computed', 'queryMatchedOrders', 'activeOrderQueue', 'eligibleCustomsDetail', 'needsCustomsUpload', block + '\nreturn { orderQueueCounts, filteredOrders }')
const view = read(computed, rows, queue, order => states.value[order.id], exports.needsCustomsUpload)
assert.equal(view.orderQueueCounts.value.customs, 1)
assert.deepEqual(view.filteredOrders.value.map(row => row.id), ['waiting'])
states.value.waiting.merchantStatus = 'DOCUMENT_UPLOADED'
assert.equal(view.orderQueueCounts.value.customs, 0); assert.equal(view.filteredOrders.value.length, 0)
queue.value = 'all'; assert.equal(view.filteredOrders.value.length, 2)
})
@@ -1,6 +1,11 @@
import type { FirstLegOrder } from '../types/firstLegOrder' import type { FirstLegOrder } from '../types/firstLegOrder'
import type { MerchantCustomsContainer } from '../api/customs'
export function isCustomsOrderCandidate(order: Pick<FirstLegOrder, 'status' | 'taxMode'>): boolean { export function isCustomsOrderCandidate(order: Pick<FirstLegOrder, 'status' | 'taxMode'>): boolean {
return order.taxMode === 'TAX_REFUND' return order.taxMode === 'TAX_REFUND'
&& (order.status === 'LOADED' || order.status === 'DELIVERED' || order.status === 'COMPLETED') && (order.status === 'LOADED' || order.status === 'DELIVERED' || order.status === 'COMPLETED')
} }
export function needsCustomsUpload(detail: MerchantCustomsContainer | null | undefined): boolean {
return detail?.status === 'WAITING_CUSTOMER_DOCUMENTS' && detail.merchantStatus === 'WAITING_UPLOAD'
}
@@ -15,7 +15,7 @@ import OrderProgressPanel from '@/modules/first-leg/components/OrderProgressPane
import CustomsDocumentsDialog from '@/modules/first-leg/components/CustomsDocumentsDialog.vue' import CustomsDocumentsDialog from '@/modules/first-leg/components/CustomsDocumentsDialog.vue'
import { getMerchantInboundBilling } from '@/modules/first-leg/api/inboundBilling' import { getMerchantInboundBilling } from '@/modules/first-leg/api/inboundBilling'
import { getMerchantCustomsForOrder, isMerchantCustomsUnavailable, type MerchantCustomsContainer } from '@/modules/first-leg/api/customs' import { getMerchantCustomsForOrder, isMerchantCustomsUnavailable, type MerchantCustomsContainer } from '@/modules/first-leg/api/customs'
import { isCustomsOrderCandidate } from '../utils/customsEligibility' import { isCustomsOrderCandidate, needsCustomsUpload } from '../utils/customsEligibility'
import { import {
estimateMerchantFirstLegPrice, estimateMerchantFirstLegPrice,
createIdempotencyKey, createIdempotencyKey,
@@ -477,12 +477,12 @@ const queryMatchedOrders = computed(() => store.orders.filter(matchesAppliedFilt
const orderQueueCounts = computed(() => ({ const orderQueueCounts = computed(() => ({
all: queryMatchedOrders.value.length, all: queryMatchedOrders.value.length,
fee: queryMatchedOrders.value.filter((order) => order.businessSummary.customerFeeConfirmationRequired).length, fee: queryMatchedOrders.value.filter((order) => order.businessSummary.customerFeeConfirmationRequired).length,
customs: queryMatchedOrders.value.filter((order) => Boolean(eligibleCustomsDetail(order))).length, customs: queryMatchedOrders.value.filter((order) => needsCustomsUpload(eligibleCustomsDetail(order))).length,
draft: queryMatchedOrders.value.filter((order) => order.status === 'DRAFT').length, draft: queryMatchedOrders.value.filter((order) => order.status === 'DRAFT').length,
})) }))
const filteredOrders = computed(() => queryMatchedOrders.value.filter((order) => { const filteredOrders = computed(() => queryMatchedOrders.value.filter((order) => {
if (activeOrderQueue.value === 'fee') return order.businessSummary.customerFeeConfirmationRequired if (activeOrderQueue.value === 'fee') return order.businessSummary.customerFeeConfirmationRequired
if (activeOrderQueue.value === 'customs') return Boolean(eligibleCustomsDetail(order)) if (activeOrderQueue.value === 'customs') return needsCustomsUpload(eligibleCustomsDetail(order))
if (activeOrderQueue.value === 'draft') return order.status === 'DRAFT' if (activeOrderQueue.value === 'draft') return order.status === 'DRAFT'
return true return true
})) }))