63 lines
6.6 KiB
TypeScript
63 lines
6.6 KiB
TypeScript
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
|
|
import type { ProcurementFile, ProcurementFileCategory, ProcurementRemainingKind } from '../procurementTypes'
|
|
|
|
export type ProcurementCommand = 'review' | 'purchase' | 'purchase/confirm' | 'budget-authorizations' | 'planned-warehouse' | 'cancel' | 'overseas-receipts' | 'domestic-receipts' | 'overseas-receipts/complete' | 'domestic-receipts/complete' | 'packing' | 'packing/confirm' | 'packing/withdraw' | 'dispositions' | 'receipts/correct' | 'dispositions/revoke' | 'labels' | 'international-estimate' | 'labels/apply' | 'domestic-repack' | 'overseas-shipment' | 'customer-shipment' | 'charges/confirm' | 'fees/retry' | 'fees/terminate' | 'fees/release-estimate' | 'fees/correct-target' | 'fees/refund' | 'fees/replace-failed' | 'fees/additional' | 'control-notes' | 'control-notes/resolve' | 'actual-warehouse/correct' | 'exception-close'
|
|
export interface ProcurementCommandBody {
|
|
name?: string
|
|
targetType?: 'PURCHASE' | 'WAREHOUSE' | 'RECEIPT' | 'SHIPMENT'; targetId?: string; blocking?: boolean; clientSummary?: string; noteId?: string
|
|
resolutions?: ProcurementResolution[]; customerVoucherFileId?: string; financialConclusion?: string
|
|
feeId?: string; targetOriginalAmount?: string; internationalFreight?: ProcurementFeeSelection; duty?: ProcurementFeeSelection; domesticFreight?: ProcurementFeeSelection
|
|
otherDetermination?: 'NOT_APPLICABLE' | 'ITEMIZED'; otherFees?: { code: string; name: string; selection: ProcurementFeeSelection }[]
|
|
version: number; idempotencyKey: string; reason?: string; decision?: 'APPROVE' | 'REJECT' | 'ACCEPT_SHORTAGE' | 'DISPOSE_DAMAGED' | 'RETURN_EXTRA'; remark?: string
|
|
purchaseWarehouseId?: string; warehouseId?: string; productName?: string; specification?: string
|
|
leg?: 'OVERSEAS' | 'DOMESTIC'; sourceCartonId?: string; receiptId?: string; dispositionId?: string
|
|
goodQuantity?: number; damagedQuantity?: number; extraQuantity?: number; receivedAt?: string
|
|
labelVersion?: number; receiver?: { name: string; phone: string; address: string }; addressVoucherFileId?: string
|
|
labels?: { cartonId: string; fileId: string; page: number; carrier: string; trackingNo: string }[]
|
|
cartonIds?: string[]; businessDate?: string; appliedAt?: string; shippedAt?: string; cartonId?: string
|
|
lengthCm?: string; widthCm?: string; heightCm?: string; grossWeightKg?: string
|
|
kind?: 'SHORTAGE' | 'DAMAGED' | 'EXTRA'; packingVersion?: number; cartons?: ProcurementPackingCarton[]
|
|
quantity?: number; amount?: string; currency?: 'CNY' | 'USD'; purchasedAt?: string; estimatedArrivalAt?: string; voucherFileId?: string
|
|
}
|
|
export interface ProcurementResolution { kind: ProcurementRemainingKind; sourceId: string | null; quantity: number; decision: string; destination: string; voucherFileId: string }
|
|
export interface ProcurementChargeAmount { determination: 'POSITIVE' | 'ZERO' | 'NOT_APPLICABLE'; amount: string; currency: 'CNY' | 'USD'; businessDate: string; voucherFileId?: string; reason: string }
|
|
export interface ProcurementFeeSelection { feeId?: string; value?: ProcurementChargeAmount }
|
|
export interface ProcurementPackingCarton { cartonNo: string; lengthCm: string; widthCm: string; heightCm: string; grossWeightKg: string; sources: { receiptId: string; quantity: number }[] }
|
|
const base = '/platform/v1/last-leg/overseas-procurements'
|
|
export async function submitProcurementCommand(orderNo: string, customerId: string, command: ProcurementCommand, payload: ProcurementCommandBody) {
|
|
let path: string = command; let body: unknown = payload
|
|
if (command === 'receipts/correct') {
|
|
if (!payload.receiptId || !/^[1-9]\d*$/.test(payload.receiptId)) throw new Error('缺少有效实收来源')
|
|
path = `receipts/${payload.receiptId}/correct`
|
|
body = { receipt: { version: payload.version, idempotencyKey: payload.idempotencyKey, reason: payload.reason, leg: payload.leg, warehouseId: payload.warehouseId, sourceCartonId: payload.sourceCartonId, goodQuantity: payload.goodQuantity, damagedQuantity: payload.damagedQuantity, extraQuantity: payload.extraQuantity, receivedAt: payload.receivedAt }, voucherFileId: payload.voucherFileId }
|
|
} else if (command === 'dispositions/revoke') {
|
|
if (!payload.dispositionId || !/^[1-9]\d*$/.test(payload.dispositionId)) throw new Error('缺少有效差异处置来源')
|
|
path = `dispositions/${payload.dispositionId}/revoke`
|
|
body = { version: payload.version, idempotencyKey: payload.idempotencyKey, reason: payload.reason, voucherFileId: payload.voucherFileId }
|
|
}
|
|
if (command === 'control-notes/resolve') {
|
|
if (!payload.noteId || !/^[1-9]\d*$/.test(payload.noteId)) throw new Error('缺少有效阻断异常来源')
|
|
path = `control-notes/${payload.noteId}/resolve`
|
|
body = { version: payload.version, idempotencyKey: payload.idempotencyKey, reason: payload.reason, voucherFileId: payload.voucherFileId }
|
|
}
|
|
if (command === 'fees/additional') body = { version: payload.version, idempotencyKey: payload.idempotencyKey, name: payload.name, amount: payload.amount, currency: payload.currency, businessDate: payload.businessDate, voucherFileId: payload.voucherFileId, reason: payload.reason }
|
|
if (command.startsWith('fees/') && command !== 'fees/additional') {
|
|
if (!payload.feeId || !/^[1-9]\d*$/.test(payload.feeId)) throw new Error('缺少有效费用来源')
|
|
path = `fees/${payload.feeId}/${command.slice(5)}`
|
|
body = { version: payload.version, idempotencyKey: payload.idempotencyKey, reason: payload.reason,
|
|
...(['fees/correct-target', 'fees/replace-failed'].includes(command) ? { targetOriginalAmount: payload.targetOriginalAmount, voucherFileId: payload.voucherFileId } : {}),
|
|
...(command === 'fees/refund' ? { amount: payload.amount, voucherFileId: payload.voucherFileId } : {}) }
|
|
}
|
|
const response = await http.post<ApiEnvelope<unknown>, ApiEnvelope<unknown>>(`${base}/${encodeURIComponent(orderNo)}/${path}`, body, { params: { customerId } })
|
|
unwrapApiResponse(response)
|
|
}
|
|
export async function uploadProcurementFile(orderNo: string, customerId: string, category: ProcurementFileCategory, file: File) {
|
|
const data = new FormData(); data.append('file', file)
|
|
const response = await http.post<ApiEnvelope<ProcurementFile>, ApiEnvelope<ProcurementFile>>(`${base}/${encodeURIComponent(orderNo)}/files/${category}`, data, { params: { customerId } })
|
|
const result = unwrapApiResponse(response)
|
|
return { ...result, id: String(result.id), fileId: String(result.fileId) }
|
|
}
|
|
export async function downloadProcurementFile(orderNo: string, customerId: string, fileId: string) {
|
|
return http.get<Blob, Blob>(`${base}/${encodeURIComponent(orderNo)}/files/${encodeURIComponent(fileId)}/content`, { params: { customerId }, responseType: 'blob' })
|
|
}
|