import type { Order, Quote, CheckoutValidateRequest, CheckoutAddress, CheckoutShipmentItem, CheckoutParcel, CheckoutParcelContent, PluginSettings, } from '../../../types'; import { isQuoteDropoff, isQuoteDDP } from './quoteHelpers'; import { isEUCountry, mapDestination, parseNum, splitName, truncateText, } from '../../../shared/utils'; export interface OrderToCheckoutValidatePayloadOptions { /** Discount code to apply when validating (e.g. from ConfirmBookingModal). */ discountCode?: string | null; /** Override collection date (for collection services). When not provided, uses first quote date. */ collectionDate?: string | null; /** Override DDP (Delivery Duty Paid). When not provided, uses quote tags. */ ddp?: boolean; /** Override IOSS (Import One-Stop Shop). */ ioss?: string | null; } /** * Build CheckoutValidateRequest from WooCommerce order, store, selected quote and extras. */ export function orderToCheckoutValidatePayload( order: Order, settings: PluginSettings, quote: Quote, extras: string[], options?: OrderToCheckoutValidatePayloadOptions ): CheckoutValidateRequest | null { const store = settings.shipping; if (!store?.country || !order?.shipping?.country) return null; const origin: CheckoutAddress = { useAddress: { ...store, companyStatus: settings.tax.vatStatus ?? null, companyTaxNumber: settings.tax.vatNumber ?? null, eori: settings.tax.eori ?? null, taxId: null, }, }; const defaultDimension = settings.packages.find( (pkg) => pkg.id === settings.defaultPackageId ); const orderRef = String(order.id); const ddp = options?.ddp ?? null; const ioss = options?.ioss ?? null; const collectionDate = options?.collectionDate ?? null; let totalWeight = 0; let totalValue = 0; let max_length = 0; let max_width = 0; let max_height = 0; const contents: CheckoutParcelContent[] = []; const defaultTariff = settings.overrides.defaultTariffCode; const defaultCountryOfManufacture = settings.overrides.defaultCountryOfManufacture; for (const orderItem of order.items ?? []) { const weightPerUnit = parseNum(orderItem.dimensions?.weight) ?? 0; const quantity = Math.max(0, orderItem.quantity); totalWeight += weightPerUnit * quantity; totalValue += (parseNum(orderItem.total) ?? 0); max_length = Math.max(max_length, parseNum(orderItem.dimensions?.length) ?? 0); max_width = Math.max(max_width, parseNum(orderItem.dimensions?.width) ?? 0); max_height = Math.max(max_height, parseNum(orderItem.dimensions?.height) ?? 0); const tariffCode = orderItem.tariff_code?.trim() || defaultTariff || ''; const countryOfManufacture = orderItem.country_of_manufacture?.trim() || defaultCountryOfManufacture || 'CN'; contents.push({ quantity, description: truncateText(orderItem.name, 256), value: Math.round((parseNum(orderItem.total) ?? 0) * 100), weight: weightPerUnit, countryOfManufacture: countryOfManufacture, tariffCode: tariffCode, }); } const contentSummary = contents.length > 0 ? contents .map((c) => `${c.quantity}x ${c.description || 'Item'}`) .join(', ') : 'Order contents #' + orderRef; // IOSS only applies for shipments to EU with total value up to 150 EUR // (exchange was not considered in this calculation for simplicity, as it would require fetching historical rates) const isIOSS_Eligible = isEUCountry(order?.shipping?.country) && totalValue <= 150; const parcels: CheckoutParcel[] = [ { ref: orderRef, weight: totalWeight, length: max_length || defaultDimension?.length || 10, width: max_width || defaultDimension?.width || 10, height: max_height || defaultDimension?.height || 10, value: Math.round(totalValue * 100), contentSummary, contents: contents.length > 0 ? contents : undefined, }, ]; const shipmentItem: CheckoutShipmentItem = { $type: 'shipment', serviceSlug: quote.service.slug, origin, destination: mapDestination(order), parcels, extras: extras?.map((e) => ({ key: e })) ?? [], collectionDate, ref: orderRef, customs: { exportReason: 'Sale', dutyTerms: ddp ? "ddp" : null, ioss: isIOSS_Eligible ? ioss : null, }, }; const orderPayload = { ref: orderRef, items: [shipmentItem], billingAddress: origin, customer: { ...splitName(store.contactName ?? 'Woo Shop'), email: store.email || null, }, discountCode: options?.discountCode ?? null, }; return orderPayload; }