Files
admin-web/src/modules/container-loading/api/platformContainerCustoms.test.ts
T

67 lines
4.7 KiB
TypeScript
Raw Normal View History

2026-08-28 16:54:02 +08:00
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { http } from '@/shared/api/http'
import { completeAllBuyContainerCustoms, downloadContainerCustomsReceipt, downloadContainerCustomsDocument, getContainerCustoms, startContainerCustoms, uploadContainerCustomsReceipt } from './platformContainerCustoms'
2026-08-28 16:54:02 +08:00
const customs = {
aggregateId: 2092438843630391401n, loadingPlanId: 2092438843630391402n, containerBookingId: 2092438843630391403n,
2026-09-24 16:29:31 +08:00
planNo: 'LP-1', cabinetNo: 'CB-1', containerNo: 'MSCU-1', status: 'READY_TO_START', hasActualCargo: true, version: '3', taxRefundCount: 1, coveredTaxRefundCount: 1, actualBoxCount: 12,
2026-08-28 16:54:02 +08:00
inbounds: [{ inboundId: 2092438843630391404n, orderId: 2092438843630391405n, orderNo: 'O-1', inboundCode: 'RK-1', tenantId: 2092438843630391406n, customerName: '客户一', taxMode: 'TAX_REFUND', covered: true }],
documents: [{ documentId: 2092438843630391407n, tenantId: 2092438843630391406n, source: { fileId: '2092438843630391408', fileName: 'source.pdf', fileHash: 'hash', sizeBytes: 1, version: 2, uploadedAt: '2026-08-28T10:00:00' }, inboundIds: ['2092438843630391404'], inboundCodes: ['RK-1'], frozen: true, receipt: null, finalDocument: null }],
2026-08-28 16:54:02 +08:00
startedAt: null, completedAt: null,
}
describe('platform container customs API', () => {
beforeEach(() => vi.restoreAllMocks())
it('uses the frozen customs-v1 paths and preserves long ids as strings', async () => {
const get = vi.spyOn(http, 'get').mockResolvedValue({ code: '200', message: 'ok', data: customs })
const result = await getContainerCustoms('2092438843630391402')
2026-09-10 14:17:08 +08:00
expect(result).not.toBeNull()
if (!result) throw new Error('expected completed loading plan customs view')
2026-08-28 16:54:02 +08:00
expect(get).toHaveBeenCalledWith('/platform/v1/customs/loading-plans/2092438843630391402')
expect(result).toMatchObject({ aggregateId: '2092438843630391401', loadingPlanId: '2092438843630391402', containerBookingId: '2092438843630391403' })
expect(result.inbounds[0]).toMatchObject({ inboundId: '2092438843630391404', orderId: '2092438843630391405', tenantId: '2092438843630391406' })
expect(result.documents[0]?.documentId).toBe('2092438843630391407')
})
2026-09-10 14:16:20 +08:00
it('returns null while the loading plan is not completed', async () => {
vi.spyOn(http, 'get').mockResolvedValue({ code: '200', message: 'ok', data: null })
await expect(getContainerCustoms('2097922185010147329')).resolves.toBeNull()
})
2026-08-28 16:54:02 +08:00
it('sends confirmed start and all-buy completion with optimistic version and idempotency', async () => {
const post = vi.spyOn(http, 'post').mockResolvedValue({ code: '200', message: 'ok', data: customs })
await startContainerCustoms('2092438843630391402', 3)
await completeAllBuyContainerCustoms('2092438843630391402', 4)
expect(post.mock.calls[0]?.slice(0, 2)).toEqual(['/platform/v1/customs/loading-plans/2092438843630391402/start', { expectedVersion: 3, confirm: true, remark: null }])
expect(post.mock.calls[1]?.slice(0, 2)).toEqual(['/platform/v1/customs/loading-plans/2092438843630391402/complete-all-buy', { expectedVersion: 4, confirm: true, remark: null }])
expect(post.mock.calls[0]?.[2]).toMatchObject({ headers: { 'Idempotency-Key': expect.any(String) } })
})
2026-09-24 16:29:31 +08:00
it('uploads one receipt file without completing the container', async () => {
2026-08-28 16:54:02 +08:00
const document = { ...customs.documents[0], documentId: '2092438843630391407', tenantId: '2092438843630391406' }
const post = vi.spyOn(http, 'post').mockResolvedValue({ code: '200', message: 'ok', data: document })
const completion = new File(['done'], 'done.pdf')
await uploadContainerCustomsReceipt('2092438843630391407', completion, 0)
expect(post.mock.calls[0]?.[0]).toBe('/platform/v1/customs/loading-plans/documents/2092438843630391407/receipt/upload')
2026-08-28 16:54:02 +08:00
expect((post.mock.calls[0]?.[1] as FormData).get('file')).toBe(completion)
2026-09-24 16:29:31 +08:00
expect(post.mock.calls[0]?.[2]).toMatchObject({ params: { expectedVersion: 0 }, headers: { 'Content-Type': 'multipart/form-data', 'Idempotency-Key': expect.any(String) } })
2026-08-28 16:54:02 +08:00
})
it('keeps source and completion downloads isolated on the long document id', async () => {
const source = new Blob(['source'])
const completion = new Blob(['completion'])
const get = vi.spyOn(http, 'get').mockResolvedValueOnce(source).mockResolvedValueOnce(completion)
const documentId = '2092438843630391407'
await expect(downloadContainerCustomsDocument(documentId)).resolves.toBe(source)
await expect(downloadContainerCustomsReceipt(documentId)).resolves.toBe(completion)
expect(get.mock.calls).toEqual([
[`/platform/v1/customs/loading-plans/documents/${documentId}/download`, { responseType: 'blob' }],
[`/platform/v1/customs/loading-plans/documents/${documentId}/receipt/download`, { responseType: 'blob' }],
])
})
2026-08-28 16:54:02 +08:00
})