import { easypostMethods } from './easypost';
import { veeqoMethods } from './veeqo';
import { EasyPostAddress, EasyPostParcel } from '../clients/easypostClient';
import { VeeqoOrder, VeeqoAddress } from '../clients/veeqoClient';
import { RpcBaseError, ValidationError } from '../utils/errors';
import { createLogger } from '../utils/logger';
const logger = createLogger();
// Helper to convert Veeqo address to EasyPost address
function convertVeeqoToEasyPostAddress(address: VeeqoAddress): EasyPostAddress {
return {
name: `${address.first_name} ${address.last_name}`,
company: address.company,
street1: address.address1,
street2: address.address2,
city: address.city,
state: address.state,
zip: address.zip,
country: address.country,
phone: address.phone_number,
email: address.email
};
}
export interface CreateOrderWithLabelParams {
order: VeeqoOrder;
from_address: EasyPostAddress;
parcel?: EasyPostParcel;
rate_id: string;
idempotency_key?: string;
}
export interface SyncTrackingParams {
order_id: string;
shipment_id: string;
}
export interface FulfillOrderParams {
order_id: string;
shipment_id: string;
rate_id: string;
idempotency_key?: string;
}
export const unifiedMethods = {
async createOrderWithLabel(params: CreateOrderWithLabelParams): Promise<any> {
try {
if (!params.order || !params.from_address || !params.rate_id) {
throw new ValidationError('order, from_address, and rate_id are required');
}
// Create Veeqo order
const veeqoResult = await veeqoMethods.createOrder({
order: params.order,
idempotency_key: params.idempotency_key ? `${params.idempotency_key}-veeqo` : undefined
});
// Create EasyPost shipment
const easypostResult = await easypostMethods.createShipment({
to_address: convertVeeqoToEasyPostAddress(params.order.deliver_to!),
from_address: params.from_address,
parcel: params.parcel,
idempotency_key: params.idempotency_key ? `${params.idempotency_key}-easypost` : undefined
});
// Buy label
const labelResult = await easypostMethods.buyLabel({
shipment_id: easypostResult.id,
rate_id: params.rate_id,
idempotency_key: params.idempotency_key ? `${params.idempotency_key}-label` : undefined
});
// Update Veeqo order with tracking info
const updatedOrder = await veeqoMethods.updateOrder({
order_id: veeqoResult.id,
order: {
status: 'shipped',
additional_options: {
shipping_method_override: labelResult.rate.service
}
}
});
return {
order: updatedOrder,
shipment: {
id: easypostResult.id,
tracking_code: labelResult.tracking_code,
label_url: labelResult.label_url
}
};
} catch (error) {
logger.error('Error in unified.createOrderWithLabel', { error });
if (error instanceof RpcBaseError) throw error;
throw new RpcBaseError('UNIFIED_CREATE_ORDER_WITH_LABEL_ERROR', 'Failed to create order with label', error);
}
},
async syncTracking(params: SyncTrackingParams): Promise<any> {
try {
if (!params.order_id || !params.shipment_id) {
throw new ValidationError('order_id and shipment_id are required');
}
// Get tracking info from EasyPost
const shipment = await easypostMethods.getRates({ shipment_id: params.shipment_id });
if (shipment.length === 0) {
throw new ValidationError('No shipment found with the given ID');
}
const trackingCode = shipment[0].tracking_code;
if (!trackingCode) {
throw new ValidationError('Shipment does not have a tracking code');
}
const trackingInfo = await easypostMethods.trackShipment({ tracking_code: trackingCode });
// Update Veeqo order with tracking info
const updatedOrder = await veeqoMethods.updateOrder({
order_id: params.order_id,
order: {
additional_options: {
shipping_method_override: trackingInfo.carrier
}
}
});
return {
order: updatedOrder,
tracking: {
tracking_code: trackingInfo.tracking_code,
status: trackingInfo.status,
carrier: trackingInfo.carrier,
signed_by: trackingInfo.signed_by,
est_delivery_date: trackingInfo.est_delivery_date
}
};
} catch (error) {
logger.error('Error in unified.syncTracking', { error });
if (error instanceof RpcBaseError) throw error;
throw new RpcBaseError('UNIFIED_SYNC_TRACKING_ERROR', 'Failed to sync tracking', error);
}
},
async fulfillOrder(params: FulfillOrderParams): Promise<any> {
try {
if (!params.order_id || !params.shipment_id || !params.rate_id) {
throw new ValidationError('order_id, shipment_id, and rate_id are required');
}
// Buy label
const labelResult = await easypostMethods.buyLabel({
shipment_id: params.shipment_id,
rate_id: params.rate_id,
idempotency_key: params.idempotency_key
});
// Update Veeqo order status to fulfilled
const updatedOrder = await veeqoMethods.updateOrder({
order_id: params.order_id,
order: {
status: 'shipped'
}
});
return {
order: updatedOrder,
label: {
tracking_code: labelResult.tracking_code,
label_url: labelResult.label_url,
carrier: labelResult.rate.carrier,
service: labelResult.rate.service
}
};
} catch (error) {
logger.error('Error in unified.fulfillOrder', { error });
if (error instanceof RpcBaseError) throw error;
throw new RpcBaseError('UNIFIED_FULFILL_ORDER_ERROR', 'Failed to fulfill order', error);
}
}
};