diff --git a/src/dto/logistics.dto.ts b/src/dto/logistics.dto.ts index 206884c..fa57e60 100644 --- a/src/dto/logistics.dto.ts +++ b/src/dto/logistics.dto.ts @@ -19,9 +19,16 @@ export class ShipmentBookDTO { @ApiProperty({ type: 'number', isArray: true }) @Rule(RuleType.array().default([])) orderIds?: number[]; + + @ApiProperty() + @Rule(RuleType.string()) + shipmentPlatform: string; } export class ShipmentFeeBookDTO { + + @ApiProperty() + shipmentPlatform: string; @ApiProperty() stockPointId: number; @ApiProperty() @@ -63,6 +70,8 @@ export class ShipmentFeeBookDTO { weight: number; @ApiProperty() weightUom: string; + @ApiProperty() + address_id: number; } export class PaymentMethodDTO { diff --git a/src/entity/shipment.entity.ts b/src/entity/shipment.entity.ts index 947db07..26237d8 100644 --- a/src/entity/shipment.entity.ts +++ b/src/entity/shipment.entity.ts @@ -54,9 +54,9 @@ export class Shipment { tracking_provider?: string; @ApiProperty() - @Column() + @Column({ nullable: true }) @Expose() - unique_id: string; + unique_id?: string; @Column({ nullable: true }) @Expose() diff --git a/src/job/sync_tms.job.ts b/src/job/sync_tms.job.ts new file mode 100644 index 0000000..ece6af6 --- /dev/null +++ b/src/job/sync_tms.job.ts @@ -0,0 +1,40 @@ +import { ILogger, Inject, Logger } from '@midwayjs/core'; +import { IJob, Job } from '@midwayjs/cron'; +import { LogisticsService } from '../service/logistics.service'; +import { Repository } from 'typeorm'; +import { Shipment } from '../entity/shipment.entity'; +import { InjectEntityModel } from '@midwayjs/typeorm'; + + +@Job({ + cronTime: '0 0 12 * * *', // 每天12点执行 + start: true +}) +export class SyncTmsJob implements IJob { + @Logger() + logger: ILogger; + + @Inject() + logisticsService: LogisticsService; + + @InjectEntityModel(Shipment) + shipmentModel: Repository + + async onTick() { + const shipments:Shipment[] = await this.shipmentModel.findBy({ tracking_provider: 'freightwaves',finished: false }); + const results = await Promise.all( + shipments.map(async shipment => { + return await this.logisticsService.updateFreightwavesShipmentState(shipment); + }) + ) + this.logger.info(`更新运单状态完毕 ${JSON.stringify(results)}`); + return results + } + + onComplete(result: any) { + this.logger.info(`更新运单状态完成 ${result}`); + } + onError(error: any) { + this.logger.error(`更新运单状态失败 ${error.message}`); + } +} \ No newline at end of file diff --git a/src/service/freightwaves.service.ts b/src/service/freightwaves.service.ts index dfb0ef6..be7deee 100644 --- a/src/service/freightwaves.service.ts +++ b/src/service/freightwaves.service.ts @@ -67,7 +67,7 @@ interface Declaration { } // 费用试算请求接口 -interface RateTryRequest { +export interface RateTryRequest { shipCompany: string; partnerOrderNumber: string; warehouseId?: string; @@ -118,8 +118,8 @@ interface RateTryResponseData { // 创建订单响应数据接口 interface CreateOrderResponseData { - partnerOrderNumber: string; - shipOrderId: string; + msg: string; + data: any; } // 查询订单响应数据接口 @@ -140,10 +140,10 @@ interface QueryOrderResponseData { } // 修改订单响应数据接口 -interface ModifyOrderResponseData extends CreateOrderResponseData {} +interface ModifyOrderResponseData extends CreateOrderResponseData { } // 订单退款响应数据接口 -interface RefundOrderResponseData {} +interface RefundOrderResponseData { } @Provide() export class FreightwavesService { @@ -152,8 +152,8 @@ export class FreightwavesService { // 默认配置 private config: FreightwavesConfig = { appSecret: 'gELCHguGmdTLo!zfihfM91hae8G@9Sz23Mh6pHrt', - apiBaseUrl: 'https://tms.freightwaves.ca', - partner: '25072621035200000060', + apiBaseUrl: 'http://tms.freightwaves.ca:8901/', + partner: '25072621035200000060' }; // 初始化配置 @@ -180,19 +180,19 @@ export class FreightwavesService { }; // 记录请求前的详细信息 - console.log(`Sending request to: ${this.config.apiBaseUrl}${url}`,JSON.stringify({ + console.log(`Sending request to: ${this.config.apiBaseUrl}${url}`, JSON.stringify({ headers, data })) - console.log('Request data:', `${this.config.apiBaseUrl}${url}`, data,headers); + console.log('Request data:', `${this.config.apiBaseUrl}${url}`, data, headers); // 发送请求 - 临时禁用SSL证书验证以解决UNABLE_TO_VERIFY_LEAF_SIGNATURE错误 const response = await axios.post>( `${this.config.apiBaseUrl}${url}`, data, - { + { headers, - httpsAgent: new (require('https').Agent)({ - rejectUnauthorized: false + httpsAgent: new (require('https').Agent)({ + rejectUnauthorized: false }) } ); @@ -267,8 +267,8 @@ export class FreightwavesService { partner: this.config.partner, }; - const response = await this.sendRequest('shipService/order/rateTry', requestData); - return response.data; + const response = await this.sendRequest('shipService/order/createOrder', requestData); + return response; } /** @@ -283,6 +283,9 @@ export class FreightwavesService { }; const response = await this.sendRequest('/shipService/order/queryOrder', requestData); + if (response.code !== '00000200') { + throw new Error(response.msg); + } return response.data; } @@ -331,9 +334,9 @@ export class FreightwavesService { // 准备测试数据 const testParams: Omit = { - shipCompany: '', + shipCompany: 'UPSYYZ7000NEW', partnerOrderNumber: `test-order-${Date.now()}`, - warehouseId: '25072621035200000060', + warehouseId: '25072621030107400060', shipper: { name: 'John Doe', phone: '123-456-7890', @@ -397,12 +400,12 @@ export class FreightwavesService { // 调用创建订单方法 this.log('开始测试创建订单...'); this.log('测试参数:', testParams); - + // 注意:在实际环境中取消注释以下行来执行真实请求 const result = await this.createOrder(testParams); - this.log('创建订单成功:', result); - - + this.log('创建订单成功:', result); + + // 返回模拟结果 return { partnerOrderNumber: testParams.partnerOrderNumber, @@ -414,6 +417,95 @@ export class FreightwavesService { } } + /** + * 测试费用试算方法 + * @returns 费用试算结果 + */ + async testRateTry() { + try { + // 设置必要的配置 + this.setConfig({ + appSecret: 'gELCHguGmdTLo!zfihfM91hae8G@9Sz23Mh6pHrt', + apiBaseUrl: 'http://tms.freightwaves.ca:8901', + partner: '25072621035200000060' + }); + + // 准备测试数据 - 符合RateTryRequest接口要求 + const testParams: Omit = { + shipCompany: 'UPSYYZ7000NEW', + partnerOrderNumber: `test-rate-try-${Date.now()}`, + warehouseId: '25072621030107400060', + shipper: { + name: 'John Doe', + phone: '123-456-7890', + company: 'Test Company', + countryCode: 'CA', + city: 'Toronto', + state: 'ON', + address1: '123 Main St', + address2: 'Suite 400', + postCode: 'M5V 2T6', + countryName: 'Canada', + cityName: 'Toronto', + stateName: 'Ontario', + companyName: 'Test Company Inc.' + }, + reciver: { + name: 'Jane Smith', + phone: '987-654-3210', + company: 'Receiver Company', + countryCode: 'CA', + city: 'Vancouver', + state: 'BC', + address1: '456 Oak St', + address2: '', + postCode: 'V6J 2A9', + countryName: 'Canada', + cityName: 'Vancouver', + stateName: 'British Columbia', + companyName: 'Receiver Company Ltd.' + }, + packages: [ + { + dimensions: { + length: 10, + width: 8, + height: 6, + lengthUnit: 'IN', + weight: 5, + weightUnit: 'LB' + }, + currency: 'CAD', + description: 'Test Package' + } + ], + signService: 0 + }; + + // 调用费用试算方法 + this.log('开始测试费用试算...'); + this.log('测试参数:', testParams); + + // 注意:在实际环境中取消注释以下行来执行真实请求 + const result = await this.rateTry(testParams); + this.log('费用试算成功:', result); + + this.log('测试完成:费用试算方法调用成功(模拟)'); + this.log('提示:在实际环境中,取消注释代码中的rateTry调用行来执行真实请求'); + + // 返回模拟结果 + return { + shipCompany: 'DHL', + channelCode: 'DHL-EXPRESS', + totalAmount: 125.50, + currency: 'CAD' + }; + } catch (error) { + this.log('测试费用试算失败:', error); + throw error; + } + } + /** * 测试查询订单方法 * @returns 查询订单结果 @@ -423,7 +515,7 @@ export class FreightwavesService { // 设置必要的配置 this.setConfig({ appSecret: 'gELCHguGmdTLo!zfihfM91hae8G@9Sz23Mh6pHrt', - apiBaseUrl: 'http://freightwaves.ca:8901/shipService/order/rateTry', + apiBaseUrl: 'http://freightwaves.ca:8901', partner: '25072621035200000060' }); @@ -437,13 +529,13 @@ export class FreightwavesService { // 调用查询订单方法 this.log('开始测试查询订单...'); this.log('测试参数:', testParams); - + // 注意:在实际环境中取消注释以下行来执行真实请求 const result = await this.queryOrder(testParams); this.log('查询订单成功:', result); - + this.log('测试完成:查询订单方法调用成功(模拟)'); - + // 返回模拟结果 return { thirdOrderId: 'thirdOrder-123456789', diff --git a/src/service/logistics.service.ts b/src/service/logistics.service.ts index b37c781..787e03e 100644 --- a/src/service/logistics.service.ts +++ b/src/service/logistics.service.ts @@ -27,6 +27,7 @@ import { CanadaPostService } from './canadaPost.service'; import { OrderItem } from '../entity/order_item.entity'; import { OrderSale } from '../entity/order_sale.entity'; import { UniExpressService } from './uni_express.service'; +import { FreightwavesService, RateTryRequest } from './freightwaves.service'; import { StockPoint } from '../entity/stock_point.entity'; import { OrderService } from './order.service'; import { convertKeysFromCamelToSnake } from '../utils/object-transform.util'; @@ -73,6 +74,9 @@ export class LogisticsService { @Inject() uniExpressService: UniExpressService; + @Inject() + freightwavesService: FreightwavesService; + @Inject() wpService: WPService; @@ -126,8 +130,8 @@ export class LogisticsService { const data = await this.uniExpressService.getOrderStatus(shipment.return_tracking_number); console.log('updateShipmentState data:', data); // huo - if(data.status === 'FAIL'){ - throw new Error('获取运单状态失败,原因为'+ data.ret_msg) + if (data.status === 'FAIL') { + throw new Error('获取运单状态失败,原因为' + data.ret_msg) } shipment.state = data.data[0].state; if (shipment.state in [203, 215, 216, 230]) { // todo,写常数 @@ -141,6 +145,30 @@ export class LogisticsService { } } + //"expressFinish": 0, //是否快递创建完成(1:完成 0:未完成,需要轮询 2:失败) + async updateFreightwavesShipmentState(shipment: Shipment) { + try { + const data = await this.freightwavesService.queryOrder({ shipOrderId: shipment.order_id.toString() }); + console.log('updateFreightwavesShipmentState data:', data); + // huo + if (data.expressFinish === 2) { + throw new Error('获取运单状态失败,原因为' + data.expressFailMsg) + } + + if (data.expressFinish === 0) { + shipment.state = '203'; + shipment.finished = true; + } + + this.shipmentModel.save(shipment); + return shipment.state; + } catch (error) { + throw error; + // throw new Error(`更新运单状态失败 ${error.message}`); + } + } + + async updateShipmentStateById(id: number) { const shipment: Shipment = await this.shipmentModel.findOneBy({ id: id }); return this.updateShipmentState(shipment); @@ -294,7 +322,18 @@ export class LogisticsService { currency: 'CAD', // item_description: data.sales, // todo: 货品信息 } - const resShipmentFee = await this.uniExpressService.getRates(reqBody); + let resShipmentFee: any; + if (data.shipmentPlatform === 'uniuni') { + resShipmentFee = await this.uniExpressService.getRates(reqBody); + } else if (data.shipmentPlatform === 'freightwaves') { + + + // resShipmentFee = await this.freightwavesService.rateTry(reqBody); + } else { + throw new Error('不支持的运单平台'); + } + + if (resShipmentFee.status !== 'SUCCESS') { throw new Error(resShipmentFee.ret_msg); } @@ -319,40 +358,49 @@ export class LogisticsService { let resShipmentOrder; try { - const stock_point = await this.stockPointModel.findOneBy({ id: data.stockPointId }); - const reqBody = { - sender: data.details.origin.contact_name, - start_phone: data.details.origin.phone_number, - start_postal_code: data.details.origin.address.postal_code.replace(/\s/g, ''), - pickup_address: data.details.origin.address.address_line_1, - pickup_warehouse: stock_point.upStreamStockPointId, - shipper_country_code: data.details.origin.address.country, - receiver: data.details.destination.contact_name, - city: data.details.destination.address.city, - province: data.details.destination.address.region, - country: data.details.destination.address.country, - postal_code: data.details.destination.address.postal_code.replace(/\s/g, ''), - delivery_address: data.details.destination.address.address_line_1, - receiver_phone: data.details.destination.phone_number.number, - receiver_email: data.details.destination.email_addresses, - // item_description: data.sales, // todo: 货品信息 - length: data.details.packaging_properties.packages[0].measurements.cuboid.l, - width: data.details.packaging_properties.packages[0].measurements.cuboid.w, - height: data.details.packaging_properties.packages[0].measurements.cuboid.h, - dimension_uom: data.details.packaging_properties.packages[0].measurements.cuboid.unit, - weight: data.details.packaging_properties.packages[0].measurements.weight.value, - weight_uom: data.details.packaging_properties.packages[0].measurements.weight.unit, - currency: 'CAD', - custom_field: { - 'order_id': order.externalOrderId - } - } + //const stock_point = await this.stockPointModel.findOneBy({ id: data.stockPointId }); + // const reqBody = { + // sender: data.details.origin.contact_name, + // start_phone: data.details.origin.phone_number, + // start_postal_code: data.details.origin.address.postal_code.replace(/\s/g, ''), + // pickup_address: data.details.origin.address.address_line_1, + // pickup_warehouse: stock_point.upStreamStockPointId, + // shipper_country_code: data.details.origin.address.country, + // receiver: data.details.destination.contact_name, + // city: data.details.destination.address.city, + // province: data.details.destination.address.region, + // country: data.details.destination.address.country, + // postal_code: data.details.destination.address.postal_code.replace(/\s/g, ''), + // delivery_address: data.details.destination.address.address_line_1, + // receiver_phone: data.details.destination.phone_number.number, + // receiver_email: data.details.destination.email_addresses, + // // item_description: data.sales, // todo: 货品信息 + // length: data.details.packaging_properties.packages[0].measurements.cuboid.l, + // width: data.details.packaging_properties.packages[0].measurements.cuboid.w, + // height: data.details.packaging_properties.packages[0].measurements.cuboid.h, + // dimension_uom: data.details.packaging_properties.packages[0].measurements.cuboid.unit, + // weight: data.details.packaging_properties.packages[0].measurements.weight.value, + // weight_uom: data.details.packaging_properties.packages[0].measurements.weight.unit, + // currency: 'CAD', + // custom_field: { + // 'order_id': order.externalOrderId + // } + // } - // 添加运单 - resShipmentOrder = await this.uniExpressService.createShipment(reqBody); + resShipmentOrder = await this.mepShipment(data, order); + + // if (data.shipmentPlatform === 'uniuni') { + // // 添加运单 + // resShipmentOrder = await this.uniExpressService.createShipment(reqBody); + // } + + // if (data.shipmentPlatform === 'freightwaves') { + // // 添加运单 + // resShipmentOrder = await this.freightcomService.createShipment(reqBody); + // } // 记录物流信息,并将订单状态转到完成 - if (resShipmentOrder.status === 'SUCCESS') { + if (resShipmentOrder.status === 'SUCCESS' || resShipmentOrder.code === '00000200') { order.orderStatus = ErpOrderStatus.COMPLETED; } else { throw new Error('运单生成失败'); @@ -363,12 +411,24 @@ export class LogisticsService { await dataSource.transaction(async manager => { const orderRepo = manager.getRepository(Order); const shipmentRepo = manager.getRepository(Shipment); - const tracking_provider = 'UniUni'; // todo: id未确定,后写进常数 + const tracking_provider = data.shipmentPlatform; // todo: id未确定,后写进常数 // 同步物流信息到woocommerce const site = await this.siteService.get(Number(order.siteId), true); + let co: any; + let unique_id: any; + let state: any; + if (data.shipmentPlatform === 'uniuni') { + co = resShipmentOrder.data.tno; + unique_id = resShipmentOrder.data.uni_order_sn; + state = resShipmentOrder.data.uni_status_code; + } else { + co = resShipmentOrder.data?.shipOrderId; + unique_id = resShipmentOrder.data?.shipOrderId; + state = ErpOrderStatus.COMPLETED; + } const res = await this.wpService.createFulfillment(site, order.externalOrderId, { - tracking_number: resShipmentOrder.data.tno, + tracking_number: co, tracking_provider: tracking_provider, }); @@ -376,10 +436,10 @@ export class LogisticsService { const shipment = await shipmentRepo.save({ tracking_provider: tracking_provider, tracking_id: res.data.tracking_id, - unique_id: resShipmentOrder.data.uni_order_sn, + unique_id: unique_id, stockPointId: String(data.stockPointId), // todo - state: resShipmentOrder.data.uni_status_code, - return_tracking_number: resShipmentOrder.data.tno, + state: state, + return_tracking_number: co, fee: data.details.shipmentFee, order: order }); @@ -388,12 +448,15 @@ export class LogisticsService { } // 同步订单状态到woocommerce - if (order.status !== OrderStatus.COMPLETED) { - await this.wpService.updateOrder(site, order.externalOrderId, { - status: OrderStatus.COMPLETED, - }); - order.status = OrderStatus.COMPLETED; + 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); @@ -642,4 +705,208 @@ export class LogisticsService { return { items, total, current, pageSize }; } + + + async mepShipment(data: ShipmentBookDTO, order: Order) { + try { + const stock_point = await this.stockPointModel.findOneBy({ id: data.stockPointId }); + let resShipmentOrder; + + if (data.shipmentPlatform === 'uniuni') { + const reqBody = { + sender: data.details.origin.contact_name, + start_phone: data.details.origin.phone_number, + start_postal_code: data.details.origin.address.postal_code.replace(/\s/g, ''), + pickup_address: data.details.origin.address.address_line_1, + pickup_warehouse: stock_point.upStreamStockPointId, + shipper_country_code: data.details.origin.address.country, + receiver: data.details.destination.contact_name, + city: data.details.destination.address.city, + province: data.details.destination.address.region, + country: data.details.destination.address.country, + postal_code: data.details.destination.address.postal_code.replace(/\s/g, ''), + delivery_address: data.details.destination.address.address_line_1, + receiver_phone: data.details.destination.phone_number.number, + receiver_email: data.details.destination.email_addresses, + // item_description: data.sales, // todo: 货品信息 + length: data.details.packaging_properties.packages[0].measurements.cuboid.l, + width: data.details.packaging_properties.packages[0].measurements.cuboid.w, + height: data.details.packaging_properties.packages[0].measurements.cuboid.h, + dimension_uom: data.details.packaging_properties.packages[0].measurements.cuboid.unit, + weight: data.details.packaging_properties.packages[0].measurements.weight.value, + weight_uom: data.details.packaging_properties.packages[0].measurements.weight.unit, + currency: 'CAD', + custom_field: { + 'order_id': order.externalOrderId // todo: 需要获取订单的externalOrderId + } + }; + + // 添加运单 + resShipmentOrder = await this.uniExpressService.createShipment(reqBody); + } + + if (data.shipmentPlatform === 'freightwaves') { + // 根据TMS系统对接说明文档格式化参数 + const reqBody: any = { + shipCompany: 'UPSYYZ7000NEW', + partnerOrderNumber: order.siteId + '-1-' + order.externalOrderId, + warehouseId: '25072621030107400060', + shipper: { + name: data.details.origin.contact_name, // 姓名 + phone: data.details.origin.phone_number.number, // 电话(提取number属性转换为字符串) + company: '', // 公司 + countryCode: data.details.origin.address.country, // 国家Code + city: data.details.origin.address.city, // 城市 + state: data.details.origin.address.region, // 州/省Code,两个字母缩写 + address1: data.details.origin.address.address_line_1, // 详细地址 + address2: '', // 详细地址2(Address类型中没有address_line_2属性) + postCode: data.details.origin.address.postal_code.replace(/\s/g, ''), // 邮编 + countryName: data.details.origin.address.country, // 国家名称(Address类型中没有country_name属性,使用country代替) + cityName: data.details.origin.address.city, // 城市名称 + stateName: data.details.origin.address.region, // 州/省名称 + companyName: '' // 公司名称 + }, + reciver: { + name: data.details.destination.contact_name, // 姓名 + phone: data.details.destination.phone_number.number, // 电话 + company: '', // 公司 + countryCode: data.details.destination.address.country, // 国家Code + city: data.details.destination.address.city, // 城市 + state: data.details.destination.address.region, // 州/省Code,两个字母的缩写 + address1: data.details.destination.address.address_line_1, // 详细地址 + address2: '', // 详细地址2(Address类型中没有address_line_2属性) + postCode: data.details.destination.address.postal_code.replace(/\s/g, ''), // 邮编 + countryName: data.details.destination.address.country, // 国家名称(Address类型中没有country_name属性,使用country代替) + cityName: data.details.destination.address.city, // 城市名称 + stateName: data.details.destination.address.region, // 州/省名称 + companyName: '' // 公司名称 + }, + packages: [ + { + dimensions: { + length: data.details.packaging_properties.packages[0].measurements.cuboid.l, // 长 + width: data.details.packaging_properties.packages[0].measurements.cuboid.w, // 宽 + height: data.details.packaging_properties.packages[0].measurements.cuboid.h, // 高 + lengthUnit: (data.details.packaging_properties.packages[0].measurements.cuboid.unit === 'cm' ? 'CM' : 'IN') as 'CM' | 'IN', // 长度单位(IN,CM) + weight: data.details.packaging_properties.packages[0].measurements.weight.value, // 重量 + weightUnit: (data.details.packaging_properties.packages[0].measurements.weight.unit === 'kg' ? 'KG' : 'LB') as 'KG' | 'LB' // 重量单位(LB,KG) + }, + currency: 'CAD', // 币种(默认CAD) + description: 'site:' + order.siteId + ' orderId:' + order.externalOrderId // 包裹描述(确保是字符串类型) + } + ], + signService: 0 + // signService: 0, // 签名服务 0不使用, 1使用 + // declaration: { + // "boxNo": "", //箱子编号 + // "sku": "", //SKU + // "cnname": "", //中文名称 + // "enname": "", //英文名称 + // "declaredPrice": 1, //申报单价 + // "declaredQty": 1, //申报数量 + // "material": "", //材质 + // "intendedUse": "", //用途 + // "cweight": 1, //产品单重 + // "hsCode": "", //海关编码 + // "battery": "" //电池描述 + // } + }; + + // 调用freightwaves费用试算或创建订单API + // 注意:根据实际需要调用对应的方法 + // resShipmentOrder = await this.freightwavesService.rateTry(reqBody); // 费用试算 + resShipmentOrder = await this.freightwavesService.createOrder(reqBody); // 创建订单 + } + + return resShipmentOrder; + } catch (error) { + console.log('物流订单处理失败:', error); // 使用console.log代替this.log + throw error; + } + } + + /** + * 将ShipmentFeeBookDTO转换为freightwaves的RateTryRequest格式 + * @param data ShipmentFeeBookDTO数据 + * @returns RateTryRequest格式的数据 + */ + convertToFreightwavesRateTry(data: ShipmentFeeBookDTO): Omit { + // 转换为RateTryRequest格式 + return { + shipCompany: 'UPSYYZ7000NEW', // 必填,但ShipmentFeeBookDTO中缺少 + partnerOrderNumber: `order-${Date.now()}`, // 必填,使用时间戳生成 + warehouseId: '25072621030107400060', // 可选,使用stockPointId转换 + shipper: { + name: data.sender, // 必填 + phone: data.startPhone, // 必填 + company: '', // 必填,但ShipmentFeeBookDTO中缺少 + countryCode: data.shipperCountryCode, // 必填 + city: '', // 必填,但ShipmentFeeBookDTO中缺少 + state: '', // 必填,但ShipmentFeeBookDTO中缺少 + address1: data.pickupAddress, // 必填 + address2: '', // 必填,但ShipmentFeeBookDTO中缺少 + postCode: data.startPostalCode, // 必填 + countryName: '', // 必填,但ShipmentFeeBookDTO中缺少 + cityName: '', // 必填,但ShipmentFeeBookDTO中缺少 + stateName: '', // 必填,但ShipmentFeeBookDTO中缺少 + companyName: '', // 必填,但ShipmentFeeBookDTO中缺少 + }, + reciver: { + name: data.receiver, // 必填 + phone: data.receiverPhone, // 必填 + company: '', // 必填,但ShipmentFeeBookDTO中缺少 + countryCode: data.country, // 必填,使用country代替countryCode + city: data.city, // 必填 + state: data.province, // 必填,使用province代替state + address1: data.deliveryAddress, // 必填 + address2: '', // 必填,但ShipmentFeeBookDTO中缺少 + postCode: data.postalCode, // 必填 + countryName: '', // 必填,但ShipmentFeeBookDTO中缺少 + cityName: data.city, // 必填,使用city代替cityName + stateName: data.province, // 必填,使用province代替stateName + companyName: '', // 必填,但ShipmentFeeBookDTO中缺少 + }, + packages: [ + { + dimensions: { + length: data.length, // 必填 + width: data.width, // 必填 + height: data.height, // 必填 + lengthUnit: (data.dimensionUom.toUpperCase() === 'CM' ? 'CM' : 'IN') as 'CM' | 'IN', // 必填,转换为有效的单位 + weight: data.weight, // 必填 + weightUnit: (data.weightUom.toUpperCase() === 'KG' ? 'KG' : 'LB') as 'KG' | 'LB', // 必填,转换为有效的单位 + }, + currency: 'CAD', // 必填,但ShipmentFeeBookDTO中缺少,使用默认值 + description: 'Package', // 必填,但ShipmentFeeBookDTO中缺少,使用默认值 + }, + ], + signService: 0, // 可选,默认不使用签名服务 + }; + } + + /** + * 获取ShipmentFeeBookDTO缺少的freightwaves必填字段 + * @returns 缺少的必填字段列表 + */ + getMissingFreightwavesFields(): string[] { + return [ + 'shipCompany', // 渠道 + 'partnerOrderNumber', // 第三方客户订单编号 + 'shipper.company', // 发货人公司 + 'shipper.city', // 发货人城市 + 'shipper.state', // 发货人州/省Code + 'shipper.address2', // 发货人详细地址2 + 'shipper.countryName', // 发货人国家名称 + 'shipper.cityName', // 发货人城市名称 + 'shipper.stateName', // 发货人州/省名称 + 'shipper.companyName', // 发货人公司名称 + 'reciver.company', // 收货人公司 + 'reciver.address2', // 收货人详细地址2 + 'reciver.countryName', // 收货人国家名称 + 'reciver.companyName', // 收货人公司名称 + 'packages[0].currency', // 包裹币种 + 'packages[0].description', // 包裹描述 + 'partner', // 商户ID + ]; + } } diff --git a/src/service/order.service.ts b/src/service/order.service.ts index dc363da..2b9e527 100644 --- a/src/service/order.service.ts +++ b/src/service/order.service.ts @@ -732,10 +732,12 @@ export class OrderService { } if (!orderItem.sku) return; // 从数据库查询产品,关联查询组件 - const productDetail = await this.productService.getComponentDetailFromSiteSku({ sku: orderItem.sku, name: orderItem.name }); - - if (!productDetail || !productDetail.quantity) return; - const {product, quantity} = productDetail + const product = await this.productModel.findOne({ + where: { siteSkus: Like(`%${orderItem.sku}%`) }, + relations: ['components','attributes','attributes.dict'], + }); + + if (!product) return; const componentDetails: { product: Product, quantity: number }[] = product.components?.length > 0 ? await Promise.all(product.components.map(async comp => { return { product: await this.productModel.findOne({ diff --git a/src/service/shopyy.service.ts b/src/service/shopyy.service.ts index 28029bb..b42e7c7 100644 --- a/src/service/shopyy.service.ts +++ b/src/service/shopyy.service.ts @@ -481,7 +481,7 @@ export class ShopyyService { shipping_method: data.shipping_method }; - const response = await this.request(site, `orders/${orderId}/shipments`, 'POST', fulfillmentData); + const response = await this.request(site, `orders/${orderId}/fulfillments`, 'POST', fulfillmentData); return response.data; } diff --git a/test-freightwaves.js b/test-freightwaves.js index 9236bcf..c41c661 100644 --- a/test-freightwaves.js +++ b/test-freightwaves.js @@ -9,7 +9,7 @@ async function testFreightwavesService() { // Call the test method console.log('Starting test for createOrder method...'); - const result = await service.testCreateOrder(); + const result = await service.testQueryOrder(); console.log('Test completed successfully!'); console.log('Result:', result);