import { overseasHttp } from '@/shared/api/overseasHttp' import { unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http' const basePath = '/platform/v1/last-leg/finance-fee-sources' type RawResource = Record export type OverseasContainerFeeItem = 'PORT_FEE' | 'STORAGE_FEE' | 'CONTAINER_REPAIR_FEE' | 'CRANE_FEE' | 'TERMINAL_DRAYAGE_FEE' | 'OTHER' export type OverseasContainerFeeDirection = 'RECEIVABLE' | 'PAYABLE' export interface OverseasContainerCustomer { customerId: string; customerName: string | null } export interface OverseasContainerFeeSource { id: string; sourceFeeId: string; sourceVersion: number; customerId: string; customerName: string | null sourceType: 'OVERSEAS_CONTAINER_FEE'; businessType: 'OVERSEAS_CONTAINER'; businessId: string; businessNo: string containerBookingId: string; containerNo: string; feeItemCode: OverseasContainerFeeItem; feeItemName: string direction: OverseasContainerFeeDirection; supplierId: string | null; supplierName: string | null; supplierCategory: string | null settlementMode: string | null; paidAt: string | null; paymentMethod: string | null; paymentReferenceNo: string | null paymentVoucherFileIds: string[]; businessDate: string; currency: 'CNY'; amount: number reviewStatus: 'DRAFT' | 'PENDING' | 'APPROVED' | 'REJECTED'; sourceStatus: 'ACTIVE' | 'SUPERSEDED' | 'VOIDED' reviewReason: string | null; reviewedAt: string | null } export interface OverseasContainerFeeSaveRequest { customerId: string; customerName: string | null; sourceType: 'OVERSEAS_CONTAINER_FEE'; businessType: 'OVERSEAS_CONTAINER' businessId: string; businessNo: string; orderId: null; inboundId: null; inboundCode: null; containerId: null containerBookingId: string; containerNo: string; warehouseId: null; feeItemCode: OverseasContainerFeeItem; feeItemName: string direction: OverseasContainerFeeDirection; supplierId: string | null; supplierName: string | null; supplierCategory: string | null settlementMode: 'ON_ACCOUNT' | 'DIRECT_PAID' | null; paidAt: string | null paymentMethod: 'ONLINE' | 'BANK_TRANSFER' | 'CASH' | 'OTHER' | null; paymentReferenceNo: string | null; paymentVoucherFileIds: string[] | null businessDate: string; currency: 'CNY'; amount: number } const text = (value: unknown) => value == null || value === '' ? null : String(value) const requiredText = (value: unknown) => String(value ?? '') const numberValue = (value: unknown) => Number.isFinite(Number(value)) ? Number(value) : 0 function normalizeFee(raw: RawResource): OverseasContainerFeeSource { return { id: requiredText(raw.id), sourceFeeId: requiredText(raw.sourceFeeId), sourceVersion: numberValue(raw.sourceVersion), customerId: requiredText(raw.customerId), customerName: text(raw.customerName), sourceType: 'OVERSEAS_CONTAINER_FEE', businessType: 'OVERSEAS_CONTAINER', businessId: requiredText(raw.businessId), businessNo: requiredText(raw.businessNo), containerBookingId: requiredText(raw.containerBookingId), containerNo: requiredText(raw.containerNo), feeItemCode: raw.feeItemCode as OverseasContainerFeeItem, feeItemName: requiredText(raw.feeItemName), direction: raw.direction as OverseasContainerFeeDirection, supplierId: text(raw.supplierId), supplierName: text(raw.supplierName), supplierCategory: text(raw.supplierCategory), settlementMode: text(raw.settlementMode), paidAt: text(raw.paidAt), paymentMethod: text(raw.paymentMethod), paymentReferenceNo: text(raw.paymentReferenceNo), paymentVoucherFileIds: Array.isArray(raw.paymentVoucherFileIds) ? raw.paymentVoucherFileIds.map(String) : [], businessDate: requiredText(raw.businessDate), currency: 'CNY', amount: numberValue(raw.amount), reviewStatus: raw.reviewStatus as OverseasContainerFeeSource['reviewStatus'], sourceStatus: raw.sourceStatus as OverseasContainerFeeSource['sourceStatus'], reviewReason: text(raw.reviewReason), reviewedAt: text(raw.reviewedAt), } } export async function listOverseasContainerFees(containerBookingId: string) { const response = await overseasHttp.get, ApiEnvelope>(basePath, { params: { containerBookingId } }) return unwrapApiResponse(response).map(normalizeFee) } export async function listOverseasContainerCustomers(containerBookingId: string) { const response = await overseasHttp.get>, ApiEnvelope>>(`${basePath}/container-customers`, { params: { containerBookingId } }) return unwrapApiResponse(response).map((item) => ({ customerId: requiredText(item.customerId), customerName: text(item.customerName) })) } export async function createOverseasContainerFee(payload: OverseasContainerFeeSaveRequest, idempotencyKey: string) { return normalizeFee(unwrapApiResponse(await overseasHttp.post, ApiEnvelope>(basePath, payload, { headers: { 'Idempotency-Key': idempotencyKey } }))) } export async function submitOverseasContainerFee(sourceFeeId: string, idempotencyKey: string) { return normalizeFee(unwrapApiResponse(await overseasHttp.post, ApiEnvelope>(`${basePath}/${encodeURIComponent(sourceFeeId)}/submit`, { idempotencyKey }))) } export async function reviewOverseasContainerFee(sourceFeeId: string, decision: 'APPROVE' | 'REJECT', reason: string | null, idempotencyKey: string) { return normalizeFee(unwrapApiResponse(await overseasHttp.post, ApiEnvelope>(`${basePath}/${encodeURIComponent(sourceFeeId)}/review`, { decision, reason, idempotencyKey }))) } export async function adjustOverseasContainerFee(sourceFeeId: string, expectedVersion: number, fee: OverseasContainerFeeSaveRequest, idempotencyKey: string) { return normalizeFee(unwrapApiResponse(await overseasHttp.post, ApiEnvelope>(`${basePath}/${encodeURIComponent(sourceFeeId)}/adjust`, { expectedVersion, fee, idempotencyKey }))) } export async function voidOverseasContainerFee(sourceFeeId: string, expectedVersion: number, reason: string, idempotencyKey: string) { return normalizeFee(unwrapApiResponse(await overseasHttp.post, ApiEnvelope>(`${basePath}/${encodeURIComponent(sourceFeeId)}/void`, { expectedVersion, reason, idempotencyKey }))) }