import { apiBlobRequest, apiRequest } from '@/api/http' export type ApiFirstLegStatus = 'DRAFT' | 'SUBMITTED' | 'APPROVED' | 'ACCEPTED' | 'REJECTED' | 'CANCELLED' | 'PROCESSING' | 'COMPLETED' export type ApiTransportMode = 'SEA' | 'AIR' | 'RAIL' | 'TRUCK' export type ApiPickupMethod = 'SELF_EXPRESS' | 'PICKUP' | 'SELF_TRUCK' export type ApiTaxMode = 'BUY_DECLARATION' | 'TAX_REFUND' export type ApiContainerMode = 'FULL_CONTAINER' | 'LCL' export type ApiDestinationType = 'FBA' | 'OVERSEAS' | 'PRIVATE' export type ApiPricingTaxMode = 'TAX_INCLUDED' | 'TAX_EXCLUDED' export type ApiPriceModel = 'FBA_WAREHOUSE_RATE' | 'REGION_WEIGHT_TIER' export interface PageResult { records: T[] page: number size: number total: number pages: number } export type MerchantWarehouseType = 'DOMESTIC' | 'FBA' | 'OVERSEAS' export interface MerchantWarehouseQuery { page?: number size?: number status?: 'ACTIVE' | 'INACTIVE' warehouseType?: MerchantWarehouseType } export interface MerchantWarehouse { id: number | string warehouseCode: string warehouseName: string warehouseType: string countryCode: string timezone: string | null contactName: string | null contactPhone: string | null contactEmail: string | null status: 'ACTIVE' | 'INACTIVE' remark: string | null updatedAt: string | null } export interface MerchantWarehouseAddress { countryCode: string stateProvince: string | null city: string | null district: string | null postalCode: string | null addressLine1: string addressLine2: string | null } export interface MerchantWarehouseCapability { capabilityCode: string capabilityName: string enabled: boolean cutoffTime: string | null description: string | null } export interface MerchantWarehouseDetail { warehouse: MerchantWarehouse addresses: MerchantWarehouseAddress[] capabilities: MerchantWarehouseCapability[] } export interface FirstLegOrderPartyPayload { companyName: string contactName: string phone: string email?: string countryCode: string province?: string city: string district?: string addressLine: string postalCode?: string } export interface FirstLegOrderCargoPayload { cargoName: string hsCode?: string packageType: string packageCount: number grossWeightKg: number volumeCbm: number lengthCm?: number widthCm?: number heightCm?: number declaredValue?: number currency?: string dangerousGoods?: boolean cargoRemark?: string skuNo?: string upcNo?: string cargoNameEn?: string customsHsCode?: string unitsPerPackage?: number totalQuantity?: number netWeightKg?: number unitDeclaredValue?: number material?: string usage?: string model?: string brand?: string productLengthCm?: number productWidthCm?: number productHeightCm?: number shipmentId?: string referenceId?: string productImageFileId?: number | string } export interface ProductImageUploadResult { fileId: number | string fileName: string contentType: string sizeBytes: number } export interface FirstLegOrderSaveRequest { customerId?: number | string customerName: string transportMode: ApiTransportMode tradeTerm?: string destinationCountryCode: string destinationWarehouseId?: number | string destinationWarehouseName: string expectedShipDate?: string customerRemark?: string sender?: FirstLegOrderPartyPayload receiver?: FirstLegOrderPartyPayload cargoes: FirstLegOrderCargoPayload[] pickupMethod: ApiPickupMethod receivingWarehouseId: number | string receivingWarehouseName: string receivingWarehouseAddress?: string | null receivingTime?: string | null channelCode: string channelName: string pricingTaxMode: ApiPricingTaxMode taxMode: ApiTaxMode containerMode?: ApiContainerMode customsInspection: boolean destinationType: ApiDestinationType amazonWarehouseCode?: string shipmentId?: string referenceId?: string } export interface MerchantBatchDraftItem { clientRowId: string draft: FirstLegOrderSaveRequest } export interface MerchantBatchDraftResult { index: number clientRowId: string success: boolean orderId: number | string | null orderNo: string | null inboundCode: string | null errorCode: string | null errorMessage: string | null } export interface MerchantBatchDraftResponse { total: number succeeded: number failed: number items: MerchantBatchDraftResult[] } export interface MerchantFirstLegOrder { id?: number | string orderId?: number | string orderNo: string | null customerId: number | string | null customerName: string status: ApiFirstLegStatus transportMode?: ApiTransportMode tradeTerm: string | null destinationCountryCode: string destinationWarehouseId: number | string | null destinationWarehouseName: string expectedShipDate: string | null customerRemark: string | null pickupMethod: ApiPickupMethod receivingWarehouseId: number | string receivingWarehouseName: string receivingWarehouseAddress?: string | null receivingTime?: string | null channelCode: string channelName: string pricingTaxMode?: ApiPricingTaxMode | null carrierId?: number | string | null carrierName?: string | null taxMode: ApiTaxMode containerMode: ApiContainerMode | null customsInspection: boolean destinationType: ApiDestinationType amazonWarehouseCode: string | null shipmentId: string | null referenceId: string | null expressCompany?: string | null expressTrackingNo?: string | null submittedAt?: string | null completedAt?: string | null version: number createdAt: string updatedAt: string } export interface MerchantFirstLegOrderCargo extends FirstLegOrderCargoPayload { id: number | string itemNo: number productUsage?: string } export interface MerchantFirstLegOrderParty extends FirstLegOrderPartyPayload { id: number | string partyType: 'SENDER' | 'RECEIVER' | string } export interface MerchantOrderStatusHistory { id: number | string fromStatus: ApiFirstLegStatus | null toStatus: ApiFirstLegStatus action: string reason: string | null operatorName: string | null occurredAt: string } export interface MerchantFirstLegOrderDetail { order: MerchantFirstLegOrder cargoes: MerchantFirstLegOrderCargo[] parties: MerchantFirstLegOrderParty[] internalNotes: [] statusHistory: MerchantOrderStatusHistory[] } export function uploadMerchantProductImage(file: File) { const data = new FormData() data.append('file', file) return apiRequest({ method: 'POST', url: '/merchant/v1/files/product-images', data }) } export function downloadMerchantProductImage(fileId: number | string) { return apiBlobRequest({ method: 'GET', url: `/merchant/v1/files/product-images/${fileId}` }) } export interface FirstLegOrderQuery { keyword?: string status?: ApiFirstLegStatus customerId?: number | string destinationWarehouseId?: number | string createdFrom?: string createdTo?: string page?: number size?: number } export interface MerchantPricingChannel { priceBookVersionId: number | string channelCode: string channelName: string priceModel: ApiPriceModel pricingTaxModes: ApiPricingTaxMode[] estimatedDepartureDate: string | null estimatedDepartureText: string | null latestWarehouseEntry: string | null referenceTransit: string | null surchargeDescription: string | null remark: string | null } export interface MerchantPriceEstimateRequest { originWarehouseId: number | string channelCode: string destinationCode?: string destinationType: Exclude destinationWarehouseId?: number | string destinationName?: string pricingTaxMode: ApiPricingTaxMode actualWeightKg: number actualVolumeCbm: number } export interface MerchantPriceEstimate { priceBookVersionId: number | string channelCode: string priceModel: ApiPriceModel pricingTaxMode: ApiPricingTaxMode chargeableQuantity: number chargeUnit: string unitPrice: number estimatedAmount: number currency: string disclaimer: string } export function getMerchantWarehouses(params: MerchantWarehouseQuery = {}) { return apiRequest>({ method: 'GET', url: '/merchant/v1/warehouses', params: { page: 1, size: 200, status: 'ACTIVE', ...params }, }) } export function getMerchantWarehouseDetail(id: number | string) { return apiRequest({ method: 'GET', url: `/merchant/v1/warehouses/${id}` }) } export function getMerchantPricingChannels(originWarehouseId: number | string) { return apiRequest({ method: 'GET', url: '/merchant/v1/first-leg/pricing/channels', params: { originWarehouseId }, }) } export function estimateMerchantFirstLegPrice(payload: MerchantPriceEstimateRequest) { return apiRequest({ method: 'POST', url: '/merchant/v1/first-leg/pricing/estimate', data: payload, }) } export function getMerchantFirstLegOrders(params: FirstLegOrderQuery = {}) { return apiRequest>({ method: 'GET', url: '/merchant/v1/orders/first-leg', params: { page: 1, size: 200, ...params } }) } export function getMerchantFirstLegOrder(id: number | string) { return apiRequest({ method: 'GET', url: `/merchant/v1/orders/first-leg/${id}` }) } export function createMerchantFirstLegOrder(payload: FirstLegOrderSaveRequest) { return apiRequest({ method: 'POST', url: '/merchant/v1/orders/first-leg', data: payload, headers: { 'Idempotency-Key': createIdempotencyKey('first-leg-create') }, }) } export function createMerchantFirstLegOrderBatch(items: MerchantBatchDraftItem[], idempotencyKey: string) { return apiRequest({ method: 'POST', url: '/merchant/v1/orders/first-leg/batch', data: items, headers: { 'Idempotency-Key': idempotencyKey }, }) } export function updateMerchantFirstLegOrder(id: number | string, payload: FirstLegOrderSaveRequest) { return apiRequest({ method: 'PUT', url: `/merchant/v1/orders/first-leg/${id}`, data: payload }) } export function submitMerchantFirstLegOrder(id: number | string) { return apiRequest({ method: 'POST', url: `/merchant/v1/orders/first-leg/${id}/submit`, headers: { 'Idempotency-Key': createIdempotencyKey(`first-leg-submit-${id}`) }, }) } function createIdempotencyKey(scope: string) { const randomPart = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}` return `${scope}-${randomPart}` }