import type { CheckoutValidateRequest, CheckoutShipmentItem, CheckoutParcel, CheckoutParcelContent, } from '../../../types'; import { mapDestination, parseNum, splitName, truncateText, } from '../../../shared/utils'; import type { Order } from '../../../types/order'; import type { PluginSettings } from '../../../types/settings'; interface OrdersToCheckoutValidatePayloadOptions { orders: Order[]; settings: PluginSettings; discountCode?: string | null; collectionDate?: string | null; ddp?: boolean | null; } /** * Build a bulk CheckoutValidateRequest from multiple WooCommerce orders. * Each order must have a `cheapestQuote` already attached (from bulk quotes). * Orders without a cheapestQuote are skipped. */ const ordersToCheckoutValidatePayload = ({ orders, settings, discountCode = null, }: OrdersToCheckoutValidatePayloadOptions): CheckoutValidateRequest | null => { if (!settings.shipping?.country) return null; const shopAddress = settings.shipping; const defaultPackage = settings.packages.find( (pkg) => pkg.id === settings.defaultPackageId ); const originAddress = { contactName: shopAddress.contactName, country: shopAddress.country, town: shopAddress.town, property: shopAddress.property, postcode: shopAddress.postcode, street: shopAddress.street, county: shopAddress.county, phone: shopAddress.phone, email: shopAddress.email, companyStatus: settings.tax.vatStatus ?? null, companyTaxNumber: settings.tax.vatNumber ?? null, eori: settings.tax.eori ?? null, taxId: null, }; const items: CheckoutShipmentItem[] = []; for (const order of orders) { const cheapestQuote = order.cheapestQuote; if (!cheapestQuote || !order.shipping?.country) continue; const orderRef = String(order.id); let totalWeight = 0; let totalValue = 0; let max_length = 0; let max_width = 0; let max_height = 0; const contents: CheckoutParcelContent[] = []; for (const orderItem of order.items ?? []) { const weightPerUnit = parseNum(orderItem.dimensions?.weight) ?? 0; const length = parseNum(orderItem.dimensions?.length) ?? 0; const width = parseNum(orderItem.dimensions?.width) ?? 0; const height = parseNum(orderItem.dimensions?.height) ?? 0; max_length = Math.max(max_length, length); max_width = Math.max(max_width, width); max_height = Math.max(max_height, height); const quantity = Math.max(0, orderItem.quantity); totalWeight += weightPerUnit * quantity; totalValue += (parseNum(orderItem.total) ?? 0); contents.push({ quantity, description: truncateText(orderItem.name, 256), value: Math.round((parseNum(orderItem.total) ?? 0) * 100), weight: weightPerUnit, countryOfManufacture: orderItem.country_of_manufacture?.trim() || settings.overrides.defaultCountryOfManufacture || 'CN', tariffCode: orderItem.tariff_code?.trim() || settings.overrides.defaultTariffCode, }); } const contentSummary = contents.length > 0 ? contents .map((c) => `${c.quantity}x ${c.description || 'Item'}`) .join(', ') : 'Order contents #' + orderRef; const hasBaseProtection = cheapestQuote.availableExtras?.some( (x) => x.key === 'protection:base' ); const parcels: CheckoutParcel[] = [ { ref: orderRef, weight: totalWeight, length: max_length || defaultPackage?.length || 10, width: max_width || defaultPackage?.width || 10, height: max_height || defaultPackage?.height || 10, value: Math.round(totalValue * 100), contentSummary, contents: contents.length > 0 ? contents : undefined, }, ]; const shipmentItem: CheckoutShipmentItem = { $type: 'shipment', ref: orderRef, serviceSlug: cheapestQuote.service.slug, origin: { useAddress: originAddress }, destination: mapDestination(order), parcels, extras: hasBaseProtection ? [{ key: 'protection:base' }] : [], collectionDate: cheapestQuote.dates?.[0]?.collection?.date ?? null, customs: { exportReason: 'Sale', }, metadata: {}, }; items.push(shipmentItem); } if (items.length === 0) return null; return { ref: 'bulk', items, billingAddress: { useAddress: originAddress }, customer: { ...splitName(shopAddress.contactName ?? 'Woo Shop'), email: shopAddress.email || null, }, discountCode, }; }; export default ordersToCheckoutValidatePayload;