import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http' export type ContainerCustomsStatus = 'WAITING_CUSTOMER_DOCUMENTS' | 'READY_TO_START' | 'DECLARING' | 'COMPLETED' export type ContainerCustomsTaxMode = 'TAX_REFUND' | 'BUY_DECLARATION' export interface ContainerCustomsFile { fileId: string fileName: string fileHash: string sizeBytes: number version: number uploadedAt: string } export interface ContainerCustomsInbound { inboundId: string orderId: string orderNo: string inboundCode: string tenantId: string customerName: string taxMode: ContainerCustomsTaxMode covered: boolean } export interface ContainerCustomsDocument { documentId: string tenantId: string source: ContainerCustomsFile inboundIds: string[] inboundCodes: string[] frozen: boolean completion: ContainerCustomsFile | null } export interface ContainerCustomsView { aggregateId: string loadingPlanId: string containerBookingId: string planNo: string cabinetNo: string containerNo: string | null status: ContainerCustomsStatus version: number taxRefundCount: number coveredTaxRefundCount: number inbounds: ContainerCustomsInbound[] documents: ContainerCustomsDocument[] startedAt: string | null completedAt: string | null } interface RawContainerCustomsView extends Omit { aggregateId: string | number loadingPlanId: string | number containerBookingId: string | number version: string | number inbounds: Array & { inboundId: string | number; orderId: string | number; tenantId: string | number }> documents: Array & { documentId: string | number; tenantId: string | number; source: ContainerCustomsFile; completion: ContainerCustomsFile | null }> } const basePath = '/platform/v1/customs/loading-plans' function operationId(prefix: string) { return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}` } function file(value: ContainerCustomsFile | null): ContainerCustomsFile | null { return value ? { ...value, fileId: String(value.fileId), sizeBytes: Number(value.sizeBytes), version: Number(value.version) } : null } function normalize(value: RawContainerCustomsView): ContainerCustomsView { return { ...value, aggregateId: String(value.aggregateId), loadingPlanId: String(value.loadingPlanId), containerBookingId: String(value.containerBookingId), version: Number(value.version), inbounds: value.inbounds.map((item) => ({ ...item, inboundId: String(item.inboundId), orderId: String(item.orderId), tenantId: String(item.tenantId) })), documents: value.documents.map((item) => ({ ...item, documentId: String(item.documentId), tenantId: String(item.tenantId), source: file(item.source)!, completion: file(item.completion) })), } } export async function getContainerCustoms(loadingPlanId: string) { const response = await http.get, ApiEnvelope>(`${basePath}/${encodeURIComponent(loadingPlanId)}`) return normalize(unwrapApiResponse(response)) } async function action(loadingPlanId: string, name: 'start' | 'complete-all-buy', expectedVersion: number, remark?: string) { const response = await http.post, ApiEnvelope>( `${basePath}/${encodeURIComponent(loadingPlanId)}/${name}`, { expectedVersion, confirm: true, remark: remark?.trim() || null }, { headers: { 'Idempotency-Key': operationId(`container-customs-${name}`) } }, ) return normalize(unwrapApiResponse(response)) } export function startContainerCustoms(loadingPlanId: string, expectedVersion: number) { return action(loadingPlanId, 'start', expectedVersion) } export function completeAllBuyContainerCustoms(loadingPlanId: string, expectedVersion: number) { return action(loadingPlanId, 'complete-all-buy', expectedVersion) } export async function uploadContainerCustomsCompletion(documentId: string, fileValue: File, expectedVersion: number, finalConfirmation: boolean) { const body = new FormData() body.append('file', fileValue) const response = await http.post, ApiEnvelope>( `${basePath}/documents/${encodeURIComponent(documentId)}/completion/upload`, body, { params: { expectedVersion, finalConfirmation }, headers: { 'Content-Type': 'multipart/form-data', 'Idempotency-Key': operationId('container-customs-completion') } }, ) const result = unwrapApiResponse(response) return { ...result, documentId: String(result.documentId), tenantId: String(result.tenantId), source: file(result.source)!, completion: file(result.completion) } }