import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http' import type { MasterDataStatus, MonthlyExchangeRate, OverseasTransitPrice, OverseasWarehouseFee, OverseasWarehouseQuote, OverseasWarehouseQuoteDetail, PartnerWarehouseOption, VehicleDetail, VehicleOwnership, VehicleRegion, VehicleStatus, } from '../types' export interface PageResult { records: T[]; page: number; size: number; total: number; pages: number } type PagePayload = Omit, 'page' | 'size' | 'total' | 'pages'> & { page: number | string; size: number | string; total: number | string; pages: number | string } const base = '/platform/v1/last-leg/master-data' type Numeric = number | string type QuoteWire = Omit & { recordVersion: Numeric } type FeeWire = Omit & { unitPrice: Numeric; minimumCharge: Numeric | null } type TransitPriceWire = Omit & { estimatedMiles: Numeric | null; price: Numeric; minimumCharge: Numeric | null } type QuoteDetailWire = Omit & { summary: QuoteWire; warehouseFees: FeeWire[]; transitPrices: TransitPriceWire[] } type ExchangeRateWire = Omit & { usdToCnyAverage: Numeric; recordVersion: Numeric } type ExchangeRateSummary = { latestMonth: string | null; latestUsdToCnyAverage: number | null; updatedBy: string | null; updatedAt: string | null } type ExchangeRateSummaryWire = Omit & { latestUsdToCnyAverage: Numeric | null } type VehicleWire = Omit & { fuelConsumptionPer100Km: Numeric; mileageKm: Numeric; recordVersion: Numeric; maxPalletSpaces: Numeric | null; maxLoadKg: Numeric | null; maxVolumeCbm: Numeric | null } function page(value: PagePayload, normalize: (record: W) => T): PageResult { return { ...value, records: value.records.map(normalize), page: Number(value.page), size: Number(value.size), total: Number(value.total), pages: Number(value.pages) } } async function getPage(path: string, params: object, normalize: (record: W) => T) { return page(unwrapApiResponse(await http.get>, ApiEnvelope>>(path, { params })), normalize) } const numeric = (value: Numeric) => Number(value) const nullableNumeric = (value: Numeric | null) => value == null ? null : Number(value) const normalizeQuote = (value: QuoteWire): OverseasWarehouseQuote => ({ ...value, recordVersion: numeric(value.recordVersion) }) const normalizeFee = (value: FeeWire): OverseasWarehouseFee => ({ ...value, unitPrice: numeric(value.unitPrice), minimumCharge: nullableNumeric(value.minimumCharge) }) const normalizeTransitPrice = (value: TransitPriceWire): OverseasTransitPrice => ({ ...value, estimatedMiles: nullableNumeric(value.estimatedMiles), price: numeric(value.price), minimumCharge: nullableNumeric(value.minimumCharge) }) const normalizeQuoteDetail = (value: QuoteDetailWire): OverseasWarehouseQuoteDetail => ({ ...value, summary: normalizeQuote(value.summary), warehouseFees: value.warehouseFees.map(normalizeFee), transitPrices: value.transitPrices.map(normalizeTransitPrice) }) const normalizeExchangeRate = (value: ExchangeRateWire): MonthlyExchangeRate => ({ ...value, usdToCnyAverage: numeric(value.usdToCnyAverage), recordVersion: numeric(value.recordVersion) }) const normalizeVehicle = (value: VehicleWire): VehicleDetail => ({ ...value, fuelConsumptionPer100Km: numeric(value.fuelConsumptionPer100Km), mileageKm: numeric(value.mileageKm), recordVersion: numeric(value.recordVersion), maxPalletSpaces: nullableNumeric(value.maxPalletSpaces), maxLoadKg: nullableNumeric(value.maxLoadKg), maxVolumeCbm: nullableNumeric(value.maxVolumeCbm) }) export interface QuoteQuery { page: number; size: number; keyword?: string; warehouseId?: string; providerName?: string; currency?: string; status?: MasterDataStatus } type QuoteDetailFields = { warehouseFees: OverseasWarehouseFee[]; transitPrices: OverseasTransitPrice[] } type QuoteEditableFields = Pick & { effectiveEnd: string } & QuoteDetailFields export type QuoteCreate = QuoteEditableFields & Pick export type QuoteUpdate = QuoteEditableFields & Pick export const listQuotes = (query: QuoteQuery) => getPage(`${base}/overseas-quotes`, query, normalizeQuote) export async function getQuote(id: string) { return normalizeQuoteDetail(unwrapApiResponse(await http.get, ApiEnvelope>(`${base}/overseas-quotes/${encodeURIComponent(id)}`))) } export async function listQuoteWarehouseOptions() { return unwrapApiResponse(await http.get, ApiEnvelope>(`${base}/overseas-quotes/warehouse-options`)) } export async function createQuote(payload: QuoteCreate) { return normalizeQuoteDetail(unwrapApiResponse(await http.post, ApiEnvelope>(`${base}/overseas-quotes`, payload))) } export async function updateQuote(id: string, payload: QuoteUpdate) { return normalizeQuoteDetail(unwrapApiResponse(await http.put, ApiEnvelope>(`${base}/overseas-quotes/${encodeURIComponent(id)}`, payload))) } export async function changeQuoteStatus(id: string, status: MasterDataStatus, recordVersion: number) { return normalizeQuoteDetail(unwrapApiResponse(await http.patch, ApiEnvelope>(`${base}/overseas-quotes/${encodeURIComponent(id)}/status`, { status, recordVersion }))) } export interface ExchangeRateQuery { page: number; size: number; monthFrom?: string; monthTo?: string; status?: MasterDataStatus } export const listExchangeRates = (query: ExchangeRateQuery) => getPage(`${base}/exchange-rates`, query, normalizeExchangeRate) export async function getExchangeRate(month: string) { return normalizeExchangeRate(unwrapApiResponse(await http.get, ApiEnvelope>(`${base}/exchange-rates/${encodeURIComponent(month)}`))) } export async function getExchangeRateSummary(): Promise { const value = unwrapApiResponse(await http.get, ApiEnvelope>(`${base}/exchange-rates/summary`)) return { ...value, latestUsdToCnyAverage: nullableNumeric(value.latestUsdToCnyAverage) } } export async function createExchangeRate(payload: { month: string; usdToCnyAverage: number; remark: string | null }) { return normalizeExchangeRate(unwrapApiResponse(await http.post, ApiEnvelope>(`${base}/exchange-rates`, payload))) } export async function updateExchangeRate(month: string, payload: { recordVersion: number; usdToCnyAverage: number; remark: string | null }) { return normalizeExchangeRate(unwrapApiResponse(await http.put, ApiEnvelope>(`${base}/exchange-rates/${encodeURIComponent(month)}`, payload))) } export async function changeExchangeRateStatus(month: string, status: MasterDataStatus, recordVersion: number, remark: string | null) { return normalizeExchangeRate(unwrapApiResponse(await http.patch, ApiEnvelope>(`${base}/exchange-rates/${encodeURIComponent(month)}/status`, { status, recordVersion, remark }))) } export interface VehicleQuery { page: number; size: number; keyword?: string; ownership?: VehicleOwnership; region?: VehicleRegion; status?: VehicleStatus; dispatchNo?: string } type VehicleEditableFields = Omit export type VehicleCreate = VehicleEditableFields & Pick export type VehicleUpdate = VehicleEditableFields & Pick export const listVehicles = (query: VehicleQuery) => getPage(`${base}/vehicles`, query, normalizeVehicle) export async function getVehicle(id: string) { return normalizeVehicle(unwrapApiResponse(await http.get, ApiEnvelope>(`${base}/vehicles/${encodeURIComponent(id)}`))) } export async function createVehicle(payload: VehicleCreate) { return normalizeVehicle(unwrapApiResponse(await http.post, ApiEnvelope>(`${base}/vehicles`, payload))) } export async function updateVehicle(id: string, payload: VehicleUpdate) { return normalizeVehicle(unwrapApiResponse(await http.put, ApiEnvelope>(`${base}/vehicles/${encodeURIComponent(id)}`, payload))) } export async function changeVehicleStatus(id: string, status: VehicleStatus, recordVersion: number) { return normalizeVehicle(unwrapApiResponse(await http.patch, ApiEnvelope>(`${base}/vehicles/${encodeURIComponent(id)}/status`, { status, recordVersion }))) }