feat(logistics): 完善物流服务接口并添加fulfillment功能

重构物流服务接口,调整订单创建流程以支持多平台发货
添加wp服务的createFulfillment方法用于同步物流信息
优化mepShipment方法参数传递和请求体构造
This commit is contained in:
zhuotianyuan 2026-01-21 20:02:45 +08:00
parent fe5d4bf2f0
commit 5deedc2f45
3 changed files with 131 additions and 91 deletions

View File

@ -118,8 +118,8 @@ interface RateTryResponseData {
// 创建订单响应数据接口 // 创建订单响应数据接口
interface CreateOrderResponseData { interface CreateOrderResponseData {
partnerOrderNumber: string; msg: string;
shipOrderId: string; data: any;
} }
// 查询订单响应数据接口 // 查询订单响应数据接口
@ -152,8 +152,8 @@ export class FreightwavesService {
// 默认配置 // 默认配置
private config: FreightwavesConfig = { private config: FreightwavesConfig = {
appSecret: 'gELCHguGmdTLo!zfihfM91hae8G@9Sz23Mh6pHrt', appSecret: 'gELCHguGmdTLo!zfihfM91hae8G@9Sz23Mh6pHrt',
apiBaseUrl: 'https://tms.freightwaves.ca', apiBaseUrl: 'http://tms.freightwaves.ca:8901/',
partner: '25072621035200000060', partner: '25072621035200000060'
}; };
// 初始化配置 // 初始化配置

View File

@ -343,7 +343,6 @@ export class LogisticsService {
let resShipmentOrder; let resShipmentOrder;
try { try {
resShipmentOrder = this.mepShipment(data);
//const stock_point = await this.stockPointModel.findOneBy({ id: data.stockPointId }); //const stock_point = await this.stockPointModel.findOneBy({ id: data.stockPointId });
// const reqBody = { // const reqBody = {
// sender: data.details.origin.contact_name, // sender: data.details.origin.contact_name,
@ -373,77 +372,89 @@ export class LogisticsService {
// } // }
// } // }
resShipmentOrder =await this.mepShipment(data,order);
// if (data.shipmentPlatform === 'uniuni') {
// // 添加运单 // // 添加运单
// resShipmentOrder = await this.uniExpressService.createShipment(reqBody); // resShipmentOrder = await this.uniExpressService.createShipment(reqBody);
// // 记录物流信息,并将订单状态转到完成
// if (resShipmentOrder.status === 'SUCCESS') {
// order.orderStatus = ErpOrderStatus.COMPLETED;
// } else {
// throw new Error('运单生成失败');
// }
// const dataSource = this.dataSourceManager.getDataSource('default');
// let transactionError = undefined;
// let shipmentId = undefined;
// await dataSource.transaction(async manager => {
// const orderRepo = manager.getRepository(Order);
// const shipmentRepo = manager.getRepository(Shipment);
// const tracking_provider = 'UniUni'; // todo: id未确定后写进常数
// // 同步物流信息到woocommerce
// const site = await this.siteService.get(Number(order.siteId), true);
// const res = await this.wpService.createShipment(site, order.externalOrderId, {
// tracking_number: resShipmentOrder.data.tno,
// tracking_provider: tracking_provider,
// });
// if (order.orderStatus === ErpOrderStatus.COMPLETED) {
// const shipment = await shipmentRepo.save({
// tracking_provider: tracking_provider,
// tracking_id: res.data.tracking_id,
// unique_id: resShipmentOrder.data.uni_order_sn,
// stockPointId: String(data.stockPointId), // todo
// state: resShipmentOrder.data.uni_status_code,
// return_tracking_number: resShipmentOrder.data.tno,
// fee: data.details.shipmentFee,
// order: order
// });
// order.shipmentId = shipment.id;
// shipmentId = shipment.id;
// } // }
// // 同步订单状态到woocommerce // if (data.shipmentPlatform === 'freightwaves') {
// if (order.status !== OrderStatus.COMPLETED) { // // 添加运单
// await this.wpService.updateOrder(site, order.externalOrderId, { // resShipmentOrder = await this.freightcomService.createShipment(reqBody);
// status: OrderStatus.COMPLETED,
// });
// order.status = OrderStatus.COMPLETED;
// }
// order.orderStatus = ErpOrderStatus.COMPLETED;
// await orderRepo.save(order);
// }).catch(error => {
// transactionError = error
// });
// if (transactionError !== undefined) {
// console.log('err', transactionError);
// throw transactionError;
// } // }
// // 更新产品发货信息 // 记录物流信息,并将订单状态转到完成
// this.orderService.updateOrderSales(order.id, sales); if (resShipmentOrder.status === 'SUCCESS'||resShipmentOrder.code === '00000200') {
order.orderStatus = ErpOrderStatus.COMPLETED;
} else {
throw new Error('运单生成失败');
}
const dataSource = this.dataSourceManager.getDataSource('default');
let transactionError = undefined;
let shipmentId = undefined;
await dataSource.transaction(async manager => {
const orderRepo = manager.getRepository(Order);
const shipmentRepo = manager.getRepository(Shipment);
const tracking_provider = data.shipmentPlatform; // todo: id未确定,后写进常数
// return { // 同步物流信息到woocommerce
// data: { const site = await this.siteService.get(Number(order.siteId), true);
// shipmentId const res = await this.wpService.createFulfillment(site, order.externalOrderId, {
// } tracking_number: resShipmentOrder.data.tno,
// }; tracking_provider: tracking_provider,
});
if (order.orderStatus === ErpOrderStatus.COMPLETED) {
const shipment = await shipmentRepo.save({
tracking_provider: tracking_provider,
tracking_id: res.data.tracking_id,
unique_id: resShipmentOrder.data.uni_order_sn,
stockPointId: String(data.stockPointId), // todo
state: resShipmentOrder.data.uni_status_code,
return_tracking_number: resShipmentOrder.data.tno,
fee: data.details.shipmentFee,
order: order
});
order.shipmentId = shipment.id;
shipmentId = shipment.id;
}
// 同步订单状态到woocommerce
if(order.source_type!="shopyy"){
if (order.status !== OrderStatus.COMPLETED) {
await this.wpService.updateOrder(site, order.externalOrderId, {
status: OrderStatus.COMPLETED,
});
order.status = OrderStatus.COMPLETED;
}
}
order.orderStatus = ErpOrderStatus.COMPLETED;
await orderRepo.save(order);
}).catch(error => {
transactionError = error
});
if (transactionError !== undefined) {
console.log('err', transactionError);
throw transactionError;
}
// 更新产品发货信息
this.orderService.updateOrderSales(order.id, sales);
return {
data: {
shipmentId
}
};
} catch (error) { } catch (error) {
if (resShipmentOrder.status === 'SUCCESS') { if (resShipmentOrder.status === 'SUCCESS') {
await this.uniExpressService.deleteShipment(resShipmentOrder.data.tno); await this.uniExpressService.deleteShipment(resShipmentOrder.data.tno);
} }
throw new Error(`上游请求错误:${error}`); throw new Error(`上游请求错误:${error}`);
} }
} }
@ -670,8 +681,7 @@ export class LogisticsService {
async mepShipment(data: ShipmentBookDTO,order:Order) {
async mepShipment(data: ShipmentBookDTO) {
try { try {
const stock_point = await this.stockPointModel.findOneBy({ id: data.stockPointId }); const stock_point = await this.stockPointModel.findOneBy({ id: data.stockPointId });
let resShipmentOrder; let resShipmentOrder;
@ -701,7 +711,7 @@ export class LogisticsService {
weight_uom: data.details.packaging_properties.packages[0].measurements.weight.unit, weight_uom: data.details.packaging_properties.packages[0].measurements.weight.unit,
currency: 'CAD', currency: 'CAD',
custom_field: { custom_field: {
'order_id': '' // todo: 需要获取订单的externalOrderId 'order_id': order.externalOrderId // todo: 需要获取订单的externalOrderId
} }
}; };
@ -711,10 +721,10 @@ export class LogisticsService {
if (data.shipmentPlatform === 'freightwaves') { if (data.shipmentPlatform === 'freightwaves') {
// 根据TMS系统对接说明文档格式化参数 // 根据TMS系统对接说明文档格式化参数
const reqBody = { const reqBody: any = {
shipCompany: '', // 渠道(可以不指定) shipCompany: 'UPSYYZ7000NEW',
partnerOrderNumber: `order-${Date.now()}`, // 第三方客户订单编号(唯一) partnerOrderNumber: order.externalOrderId ,
warehouseId: String(stock_point.upStreamStockPointId), // 发货仓库编号(转换为字符串类型) warehouseId: '25072621030107400060',
shipper: { shipper: {
name: data.details.origin.contact_name, // 姓名 name: data.details.origin.contact_name, // 姓名
phone: data.details.origin.phone_number.number, // 电话提取number属性转换为字符串 phone: data.details.origin.phone_number.number, // 电话提取number属性转换为字符串
@ -756,22 +766,22 @@ export class LogisticsService {
weightUnit: (data.details.packaging_properties.packages[0].measurements.weight.unit === 'kg' ? 'KG' : 'LB') as 'KG' | 'LB' // 重量单位LB,KG weightUnit: (data.details.packaging_properties.packages[0].measurements.weight.unit === 'kg' ? 'KG' : 'LB') as 'KG' | 'LB' // 重量单位LB,KG
}, },
currency: 'CAD', // 币种默认CAD currency: 'CAD', // 币种默认CAD
description: 'Package' // 包裹描述(确保是字符串类型) description: '订单编号:'+order.externalOrderId // 包裹描述(确保是字符串类型)
} }
], ],
signService: 0 as 0 | 1, // 签名服务 0不使用, 1使用 signService: 0, // 签名服务 0不使用, 1使用
declaration: { declaration: {
boxNo: 'BOX-001', // 箱 "boxNo": "", //箱子编
sku: 'DEFAULT-SKU', // SKU "sku": "", //SKU
cnname: '默认商品', // 中文名称 "cnname": "", //中文名称
enname: 'Default Product', // 英文名称 "enname": "", //英文名称
declaredPrice: 0, // 申报价格 "declaredPrice": 1, //申报单价
declaredQty: 1, // 申报数量 "declaredQty": 1, //申报数量
material: 'General', // 材质 "material": "", //材质
intendedUse: 'General use', // 用途 "intendedUse": "", //用途
cweight: data.details.packaging_properties.packages[0].measurements.weight.value, // 重量 "cweight": 1, //产品单重
hsCode: '39269090', // 海关编码 "hsCode": "", //海关编码
battery: 'No' // 是否含电池 "battery": "" //电池描述
} }
}; };

View File

@ -403,4 +403,34 @@ export class WPService {
}; };
return await axios.request(config); return await axios.request(config);
} }
async createFulfillment(
site: any,
orderId: string,
data: Record<string, any>
) {
const apiUrl = site.apiUrl;
const { consumerKey, consumerSecret } = site;
const auth = Buffer.from(`${consumerKey}:${consumerSecret}`).toString(
'base64'
);
const config: AxiosRequestConfig = {
method: 'POST',
// 构建 URL,规避多/或少/问题
url: this.buildURL(
apiUrl,
'/wp-json',
'wc-ast/v3/orders',
orderId,
'shipment-trackings'
),
headers: {
Authorization: `Basic ${auth}`,
},
data,
};
return await axios.request(config);
}
} }