main #61
|
|
@ -244,7 +244,7 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
fullname: billing.name || `${item.firstname} ${item.lastname}`.trim(),
|
fullname: billing.name || `${item.firstname} ${item.lastname}`.trim(),
|
||||||
company: billing.company || '',
|
company: billing.company || '',
|
||||||
email: item.customer_email || item.email || '',
|
email: item.customer_email || item.email || '',
|
||||||
phone: billing.phone || (item as any).telephone || '',
|
phone: billing.phone || item.telephone || '',
|
||||||
address_1: billing.address1 || item.payment_address || '',
|
address_1: billing.address1 || item.payment_address || '',
|
||||||
address_2: billing.address2 || '',
|
address_2: billing.address2 || '',
|
||||||
city: billing.city || item.payment_city || '',
|
city: billing.city || item.payment_city || '',
|
||||||
|
|
@ -275,7 +275,7 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
state: shipping.province || item.shipping_zone || '',
|
state: shipping.province || item.shipping_zone || '',
|
||||||
postcode: shipping.zip || item.shipping_postcode || '',
|
postcode: shipping.zip || item.shipping_postcode || '',
|
||||||
method_title: item.payment_method || '',
|
method_title: item.payment_method || '',
|
||||||
phone: shipping.phone || (item as any).telephone || '',
|
phone: shipping.phone || item.telephone || '',
|
||||||
country:
|
country:
|
||||||
shipping.country_name ||
|
shipping.country_name ||
|
||||||
shipping.country_code ||
|
shipping.country_code ||
|
||||||
|
|
@ -393,6 +393,7 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
tracking_number: f.tracking_number || '',
|
tracking_number: f.tracking_number || '',
|
||||||
shipping_provider: f.tracking_company || '',
|
shipping_provider: f.tracking_company || '',
|
||||||
shipping_method: f.tracking_company || '',
|
shipping_method: f.tracking_company || '',
|
||||||
|
|
||||||
date_created: typeof f.created_at === 'number'
|
date_created: typeof f.created_at === 'number'
|
||||||
? new Date(f.created_at * 1000).toISOString()
|
? new Date(f.created_at * 1000).toISOString()
|
||||||
: f.created_at || '',
|
: f.created_at || '',
|
||||||
|
|
|
||||||
|
|
@ -19,15 +19,22 @@ export class ShipmentBookDTO {
|
||||||
@ApiProperty({ type: 'number', isArray: true })
|
@ApiProperty({ type: 'number', isArray: true })
|
||||||
@Rule(RuleType.array<number>().default([]))
|
@Rule(RuleType.array<number>().default([]))
|
||||||
orderIds?: number[];
|
orderIds?: number[];
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
shipmentPlatform: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ShipmentFeeBookDTO {
|
export class ShipmentFeeBookDTO {
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
shipmentPlatform: string;
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
stockPointId: number;
|
stockPointId: number;
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
sender: string;
|
sender: string;
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
startPhone: string;
|
startPhone: string|any;
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
startPostalCode: string;
|
startPostalCode: string;
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
|
|
@ -63,6 +70,8 @@ export class ShipmentFeeBookDTO {
|
||||||
weight: number;
|
weight: number;
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
weightUom: string;
|
weightUom: string;
|
||||||
|
@ApiProperty()
|
||||||
|
address_id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PaymentMethodDTO {
|
export class PaymentMethodDTO {
|
||||||
|
|
|
||||||
|
|
@ -967,8 +967,6 @@ export interface ShopyyOrder {
|
||||||
}>;
|
}>;
|
||||||
// 支付时间
|
// 支付时间
|
||||||
pay_at?: number | null;
|
pay_at?: number | null;
|
||||||
// 支付时间(备用)
|
|
||||||
date_paid?: number | string;
|
|
||||||
// 系统支付ID
|
// 系统支付ID
|
||||||
sys_payment_id?: number;
|
sys_payment_id?: number;
|
||||||
|
|
||||||
|
|
@ -1211,6 +1209,7 @@ export interface ShopyyOrder {
|
||||||
// 时间戳信息
|
// 时间戳信息
|
||||||
// ========================================
|
// ========================================
|
||||||
// 订单创建时间
|
// 订单创建时间
|
||||||
|
date_paid?: number | string;
|
||||||
created_at?: number | string;
|
created_at?: number | string;
|
||||||
// 订单添加时间
|
// 订单添加时间
|
||||||
date_added?: string;
|
date_added?: string;
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,9 @@ export class Shipment {
|
||||||
tracking_provider?: string;
|
tracking_provider?: string;
|
||||||
|
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@Column()
|
@Column({ nullable: true })
|
||||||
@Expose()
|
@Expose()
|
||||||
unique_id: string;
|
unique_id?: string;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
@Expose()
|
@Expose()
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,11 @@ export class ShippingAddress {
|
||||||
@Expose()
|
@Expose()
|
||||||
phone_number_country: string;
|
phone_number_country: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
email: string;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
example: '2022-12-12 11:11:11',
|
example: '2022-12-12 11:11:11',
|
||||||
description: '创建时间',
|
description: '创建时间',
|
||||||
|
|
|
||||||
|
|
@ -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<Shipment>
|
||||||
|
|
||||||
|
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}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -67,7 +67,7 @@ interface Declaration {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 费用试算请求接口
|
// 费用试算请求接口
|
||||||
interface RateTryRequest {
|
export interface RateTryRequest {
|
||||||
shipCompany: string;
|
shipCompany: string;
|
||||||
partnerOrderNumber: string;
|
partnerOrderNumber: string;
|
||||||
warehouseId?: string;
|
warehouseId?: string;
|
||||||
|
|
@ -118,8 +118,8 @@ interface RateTryResponseData {
|
||||||
|
|
||||||
// 创建订单响应数据接口
|
// 创建订单响应数据接口
|
||||||
interface CreateOrderResponseData {
|
interface CreateOrderResponseData {
|
||||||
partnerOrderNumber: string;
|
msg: string;
|
||||||
shipOrderId: string;
|
data: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询订单响应数据接口
|
// 查询订单响应数据接口
|
||||||
|
|
@ -140,10 +140,10 @@ interface QueryOrderResponseData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改订单响应数据接口
|
// 修改订单响应数据接口
|
||||||
interface ModifyOrderResponseData extends CreateOrderResponseData {}
|
interface ModifyOrderResponseData extends CreateOrderResponseData { }
|
||||||
|
|
||||||
// 订单退款响应数据接口
|
// 订单退款响应数据接口
|
||||||
interface RefundOrderResponseData {}
|
interface RefundOrderResponseData { }
|
||||||
|
|
||||||
@Provide()
|
@Provide()
|
||||||
export class FreightwavesService {
|
export class FreightwavesService {
|
||||||
|
|
@ -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'
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化配置
|
// 初始化配置
|
||||||
|
|
@ -172,27 +172,21 @@ export class FreightwavesService {
|
||||||
private async sendRequest<T>(url: string, data: any): Promise<FreightwavesResponse<T>> {
|
private async sendRequest<T>(url: string, data: any): Promise<FreightwavesResponse<T>> {
|
||||||
try {
|
try {
|
||||||
// 设置请求头 - 使用太平洋时间 (America/Los_Angeles)
|
// 设置请求头 - 使用太平洋时间 (America/Los_Angeles)
|
||||||
const date = dayjs().tz('America/Los_Angeles').format('YYYY-mm-dd HH:mm:ss');
|
const date = dayjs().tz('America/Los_Angeles').format('YYYY-MM-DD HH:mm:ss');
|
||||||
const headers = {
|
const headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'requestDate': date,
|
'requestDate': date,
|
||||||
'signature': this.generateSignature(data, date),
|
'signature': this.generateSignature(data, date),
|
||||||
};
|
};
|
||||||
|
|
||||||
// 记录请求前的详细信息
|
|
||||||
this.log(`Sending request to: ${this.config.apiBaseUrl}${url}`, {
|
|
||||||
headers,
|
|
||||||
data
|
|
||||||
});
|
|
||||||
|
|
||||||
// 发送请求 - 临时禁用SSL证书验证以解决UNABLE_TO_VERIFY_LEAF_SIGNATURE错误
|
// 发送请求 - 临时禁用SSL证书验证以解决UNABLE_TO_VERIFY_LEAF_SIGNATURE错误
|
||||||
const response = await axios.post<FreightwavesResponse<T>>(
|
const response = await axios.post<FreightwavesResponse<T>>(
|
||||||
`${this.config.apiBaseUrl}${url}`,
|
`${this.config.apiBaseUrl}${url}`,
|
||||||
data,
|
data,
|
||||||
{
|
{
|
||||||
headers,
|
headers,
|
||||||
|
zhuotianyuan marked this conversation as resolved
Outdated
|
|||||||
httpsAgent: new (require('https').Agent)({
|
httpsAgent: new (require('https').Agent)({
|
||||||
rejectUnauthorized: false
|
rejectUnauthorized: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -267,8 +261,8 @@ export class FreightwavesService {
|
||||||
partner: this.config.partner,
|
partner: this.config.partner,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await this.sendRequest<CreateOrderResponseData>('/shipService/order/createOrder?apipost_id=0422aa', requestData);
|
const response = await this.sendRequest<CreateOrderResponseData>('/shipService/order/createOrder', requestData);
|
||||||
return response.data;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -283,6 +277,9 @@ export class FreightwavesService {
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await this.sendRequest<QueryOrderResponseData>('/shipService/order/queryOrder', requestData);
|
const response = await this.sendRequest<QueryOrderResponseData>('/shipService/order/queryOrder', requestData);
|
||||||
|
if (response.code !== '00000200') {
|
||||||
|
throw new Error(response.msg);
|
||||||
|
}
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -311,161 +308,10 @@ export class FreightwavesService {
|
||||||
...params,
|
...params,
|
||||||
partner: this.config.partner,
|
partner: this.config.partner,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await this.sendRequest<RefundOrderResponseData>('/shipService/order/refundOrder', requestData);
|
const response = await this.sendRequest<RefundOrderResponseData>('/shipService/order/refundOrder', requestData);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试创建订单方法
|
|
||||||
* 用于演示如何使用createOrder方法
|
|
||||||
*/
|
|
||||||
async testCreateOrder() {
|
|
||||||
try {
|
|
||||||
// 设置必要的配置
|
|
||||||
this.setConfig({
|
|
||||||
appSecret: 'gELCHguGmdTLo!zfihfM91hae8G@9Sz23Mh6pHrt',
|
|
||||||
apiBaseUrl: 'https://tms.freightwaves.ca',
|
|
||||||
partner: '25072621035200000060'
|
|
||||||
});
|
|
||||||
|
|
||||||
// 准备测试数据
|
|
||||||
const testParams: Omit<CreateOrderRequest, 'partner'> = {
|
|
||||||
shipCompany: 'DHL',
|
|
||||||
partnerOrderNumber: `test-order-${Date.now()}`,
|
|
||||||
warehouseId: '25072621035200000060',
|
|
||||||
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'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
declaration: {
|
|
||||||
boxNo: 'BOX-001',
|
|
||||||
sku: 'TEST-SKU-001',
|
|
||||||
cnname: '测试产品',
|
|
||||||
enname: 'Test Product',
|
|
||||||
declaredPrice: 100,
|
|
||||||
declaredQty: 1,
|
|
||||||
material: 'Plastic',
|
|
||||||
intendedUse: 'General use',
|
|
||||||
cweight: 5,
|
|
||||||
hsCode: '39269090',
|
|
||||||
battery: 'No'
|
|
||||||
},
|
|
||||||
signService: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
// 调用创建订单方法
|
|
||||||
this.log('开始测试创建订单...');
|
|
||||||
this.log('测试参数:', testParams);
|
|
||||||
|
|
||||||
// 注意:在实际环境中取消注释以下行来执行真实请求
|
|
||||||
const result = await this.createOrder(testParams);
|
|
||||||
this.log('创建订单成功:', result);
|
|
||||||
|
|
||||||
|
|
||||||
// 返回模拟结果
|
|
||||||
return {
|
|
||||||
partnerOrderNumber: testParams.partnerOrderNumber,
|
|
||||||
shipOrderId: `simulated-shipOrderId-${Date.now()}`
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
this.log('测试创建订单失败:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试查询订单方法
|
|
||||||
* @returns 查询订单结果
|
|
||||||
*/
|
|
||||||
async testQueryOrder() {
|
|
||||||
try {
|
|
||||||
// 设置必要的配置
|
|
||||||
this.setConfig({
|
|
||||||
appSecret: 'gELCHguGmdTLo!zfihfM91hae8G@9Sz23Mh6pHrt',
|
|
||||||
apiBaseUrl: 'https://tms.freightwaves.ca',
|
|
||||||
partner: '25072621035200000060'
|
|
||||||
});
|
|
||||||
|
|
||||||
// 准备测试数据 - 可以通过partnerOrderNumber或shipOrderId查询
|
|
||||||
const testParams: Omit<QueryOrderRequest, 'partner'> = {
|
|
||||||
// 选择其中一个参数进行测试
|
|
||||||
partnerOrderNumber: 'test-order-123456789', // 示例订单号
|
|
||||||
// shipOrderId: 'simulated-shipOrderId-123456789' // 或者使用运单号
|
|
||||||
};
|
|
||||||
|
|
||||||
// 调用查询订单方法
|
|
||||||
this.log('开始测试查询订单...');
|
|
||||||
this.log('测试参数:', testParams);
|
|
||||||
|
|
||||||
// 注意:在实际环境中取消注释以下行来执行真实请求
|
|
||||||
const result = await this.queryOrder(testParams);
|
|
||||||
this.log('查询订单成功:', result);
|
|
||||||
|
|
||||||
this.log('测试完成:查询订单方法调用成功(模拟)');
|
|
||||||
|
|
||||||
// 返回模拟结果
|
|
||||||
return {
|
|
||||||
thirdOrderId: 'thirdOrder-123456789',
|
|
||||||
shipCompany: 'DHL',
|
|
||||||
expressFinish: 0,
|
|
||||||
expressFailMsg: '',
|
|
||||||
expressOrder: {
|
|
||||||
mainTrackingNumber: '1234567890',
|
|
||||||
labelPath: ['https://example.com/label.pdf'],
|
|
||||||
totalAmount: 100,
|
|
||||||
currency: 'CAD',
|
|
||||||
balance: 50
|
|
||||||
},
|
|
||||||
partnerOrderNumber: testParams.partnerOrderNumber,
|
|
||||||
shipOrderId: 'simulated-shipOrderId-123456789'
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
this.log('测试查询订单失败:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 辅助日志方法,处理logger可能未定义的情况
|
* 辅助日志方法,处理logger可能未定义的情况
|
||||||
* @param message 日志消息
|
* @param message 日志消息
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,12 @@ import { CanadaPostService } from './canadaPost.service';
|
||||||
import { OrderItem } from '../entity/order_item.entity';
|
import { OrderItem } from '../entity/order_item.entity';
|
||||||
import { OrderSale } from '../entity/order_sale.entity';
|
import { OrderSale } from '../entity/order_sale.entity';
|
||||||
import { UniExpressService } from './uni_express.service';
|
import { UniExpressService } from './uni_express.service';
|
||||||
|
import { FreightwavesService, RateTryRequest } from './freightwaves.service';
|
||||||
import { StockPoint } from '../entity/stock_point.entity';
|
import { StockPoint } from '../entity/stock_point.entity';
|
||||||
import { OrderService } from './order.service';
|
import { OrderService } from './order.service';
|
||||||
import { convertKeysFromCamelToSnake } from '../utils/object-transform.util';
|
import { convertKeysFromCamelToSnake } from '../utils/object-transform.util';
|
||||||
import { SiteService } from './site.service';
|
import { SiteService } from './site.service';
|
||||||
|
import { ShopyyService } from './shopyy.service';
|
||||||
|
|
||||||
@Provide()
|
@Provide()
|
||||||
export class LogisticsService {
|
export class LogisticsService {
|
||||||
|
|
@ -73,9 +75,15 @@ export class LogisticsService {
|
||||||
@Inject()
|
@Inject()
|
||||||
uniExpressService: UniExpressService;
|
uniExpressService: UniExpressService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
freightwavesService: FreightwavesService;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
wpService: WPService;
|
wpService: WPService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
shopyyService: ShopyyService;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
orderService: OrderService;
|
orderService: OrderService;
|
||||||
|
|
||||||
|
|
@ -126,8 +134,8 @@ export class LogisticsService {
|
||||||
const data = await this.uniExpressService.getOrderStatus(shipment.return_tracking_number);
|
const data = await this.uniExpressService.getOrderStatus(shipment.return_tracking_number);
|
||||||
console.log('updateShipmentState data:', data);
|
console.log('updateShipmentState data:', data);
|
||||||
// huo
|
// huo
|
||||||
if(data.status === 'FAIL'){
|
if (data.status === 'FAIL') {
|
||||||
throw new Error('获取运单状态失败,原因为'+ data.ret_msg)
|
throw new Error('获取运单状态失败,原因为' + data.ret_msg)
|
||||||
}
|
}
|
||||||
shipment.state = data.data[0].state;
|
shipment.state = data.data[0].state;
|
||||||
if (shipment.state in [203, 215, 216, 230]) { // todo,写常数
|
if (shipment.state in [203, 215, 216, 230]) { // todo,写常数
|
||||||
|
|
@ -141,6 +149,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) {
|
async updateShipmentStateById(id: number) {
|
||||||
const shipment: Shipment = await this.shipmentModel.findOneBy({ id: id });
|
const shipment: Shipment = await this.shipmentModel.findOneBy({ id: id });
|
||||||
return this.updateShipmentState(shipment);
|
return this.updateShipmentState(shipment);
|
||||||
|
|
@ -247,8 +279,7 @@ export class LogisticsService {
|
||||||
|
|
||||||
shipmentRepo.remove(shipment);
|
shipmentRepo.remove(shipment);
|
||||||
|
|
||||||
const res = await this.uniExpressService.deleteShipment(shipment.return_tracking_number);
|
await this.uniExpressService.deleteShipment(shipment.return_tracking_number);
|
||||||
console.log('res', res.data); // todo
|
|
||||||
|
|
||||||
await orderRepo.save(order);
|
await orderRepo.save(order);
|
||||||
|
|
||||||
|
|
@ -278,7 +309,6 @@ export class LogisticsService {
|
||||||
console.log('同步到woocommerce失败', error);
|
console.log('同步到woocommerce失败', error);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch {
|
} catch {
|
||||||
throw new Error('删除运单失败');
|
throw new Error('删除运单失败');
|
||||||
|
|
@ -294,7 +324,16 @@ export class LogisticsService {
|
||||||
currency: 'CAD',
|
currency: 'CAD',
|
||||||
// item_description: data.sales, // todo: 货品信息
|
// 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') {
|
||||||
|
const fre_reqBody = await this.convertToFreightwavesRateTry(data);
|
||||||
|
resShipmentFee = await this.freightwavesService.rateTry(fre_reqBody);
|
||||||
|
} else {
|
||||||
|
throw new Error('不支持的运单平台');
|
||||||
|
}
|
||||||
|
|
||||||
if (resShipmentFee.status !== 'SUCCESS') {
|
if (resShipmentFee.status !== 'SUCCESS') {
|
||||||
throw new Error(resShipmentFee.ret_msg);
|
throw new Error(resShipmentFee.ret_msg);
|
||||||
}
|
}
|
||||||
|
|
@ -319,40 +358,10 @@ export class LogisticsService {
|
||||||
|
|
||||||
let resShipmentOrder;
|
let resShipmentOrder;
|
||||||
try {
|
try {
|
||||||
const stock_point = await this.stockPointModel.findOneBy({ id: data.stockPointId });
|
resShipmentOrder = await this.mepShipment(data, order);
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加运单
|
// 记录物流信息,并将订单状态转到完成,uniuni状态为SUCCESS,tms.freightwaves状态为00000200
|
||||||
resShipmentOrder = await this.uniExpressService.createShipment(reqBody);
|
if (resShipmentOrder.status === 'SUCCESS' || resShipmentOrder.code === '00000200') {
|
||||||
|
|
||||||
// 记录物流信息,并将订单状态转到完成
|
|
||||||
if (resShipmentOrder.status === 'SUCCESS') {
|
|
||||||
order.orderStatus = ErpOrderStatus.COMPLETED;
|
order.orderStatus = ErpOrderStatus.COMPLETED;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('运单生成失败');
|
throw new Error('运单生成失败');
|
||||||
|
|
@ -363,49 +372,89 @@ export class LogisticsService {
|
||||||
await dataSource.transaction(async manager => {
|
await dataSource.transaction(async manager => {
|
||||||
const orderRepo = manager.getRepository(Order);
|
const orderRepo = manager.getRepository(Order);
|
||||||
const shipmentRepo = manager.getRepository(Shipment);
|
const shipmentRepo = manager.getRepository(Shipment);
|
||||||
const tracking_provider = 'UniUni'; // todo: id未确定,后写进常数
|
const tracking_provider = data.shipmentPlatform; // todo: id未确定,后写进常数
|
||||||
|
|
||||||
// 同步物流信息到woocommerce
|
// 同步物流信息到woocommerce
|
||||||
const site = await this.siteService.get(Number(order.siteId), true);
|
const site = await this.siteService.get(Number(order.siteId), true);
|
||||||
const res = await this.wpService.createFulfillment(site, order.externalOrderId, {
|
let co: any;
|
||||||
tracking_number: resShipmentOrder.data.tno,
|
let unique_id: any;
|
||||||
tracking_provider: tracking_provider,
|
let state: any;
|
||||||
});
|
if (data.shipmentPlatform === 'uniuni') {
|
||||||
|
co = resShipmentOrder.data.tno;
|
||||||
if (order.orderStatus === ErpOrderStatus.COMPLETED) {
|
unique_id = resShipmentOrder.data.uni_order_sn;
|
||||||
const shipment = await shipmentRepo.save({
|
state = resShipmentOrder.data.uni_status_code;
|
||||||
tracking_provider: tracking_provider,
|
} else {
|
||||||
tracking_id: res.data.tracking_id,
|
co = resShipmentOrder.data?.shipOrderId;
|
||||||
unique_id: resShipmentOrder.data.uni_order_sn,
|
unique_id = resShipmentOrder.data?.shipOrderId;
|
||||||
stockPointId: String(data.stockPointId), // todo
|
state = ErpOrderStatus.COMPLETED;
|
||||||
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
|
// 同步订单状态到woocommerce
|
||||||
if (order.status !== OrderStatus.COMPLETED) {
|
if (order.source_type != "shopyy") {
|
||||||
await this.wpService.updateOrder(site, order.externalOrderId, {
|
const res = await this.wpService.createFulfillment(site, order.externalOrderId, {
|
||||||
status: OrderStatus.COMPLETED,
|
tracking_number: co,
|
||||||
|
tracking_provider: tracking_provider,
|
||||||
});
|
});
|
||||||
order.status = OrderStatus.COMPLETED;
|
|
||||||
|
if (order.orderStatus === ErpOrderStatus.COMPLETED) {
|
||||||
|
const shipment = await shipmentRepo.save({
|
||||||
|
tracking_provider: tracking_provider,
|
||||||
|
tracking_id: res.data.tracking_id,
|
||||||
|
unique_id: unique_id,
|
||||||
|
stockPointId: String(data.stockPointId), // todo
|
||||||
|
state: state,
|
||||||
|
return_tracking_number: co,
|
||||||
|
fee: data.details.shipmentFee,
|
||||||
|
order: order
|
||||||
|
});
|
||||||
|
order.shipmentId = shipment.id;
|
||||||
|
shipmentId = shipment.id;
|
||||||
|
}
|
||||||
|
if (order.status !== OrderStatus.COMPLETED) {
|
||||||
|
await this.wpService.updateOrder(site, order.externalOrderId, {
|
||||||
|
status: OrderStatus.COMPLETED,
|
||||||
|
});
|
||||||
|
order.status = OrderStatus.COMPLETED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (order.source_type === "shopyy") {
|
||||||
|
const res = await this.shopyyService.createFulfillment(site, order.externalOrderId, {
|
||||||
|
tracking_number: co,
|
||||||
|
tracking_company: resShipmentOrder.shipCompany,
|
||||||
|
carrier_code: resShipmentOrder.shipperOrderId,
|
||||||
|
});
|
||||||
|
if (order.orderStatus === ErpOrderStatus.COMPLETED) {
|
||||||
|
const shipment = await shipmentRepo.save({
|
||||||
|
tracking_provider: tracking_provider,
|
||||||
|
tracking_id: res.data.tracking_id,
|
||||||
|
unique_id: unique_id,
|
||||||
|
stockPointId: String(data.stockPointId), // todo
|
||||||
|
state: state,
|
||||||
|
return_tracking_number: co,
|
||||||
|
fee: data.details.shipmentFee,
|
||||||
|
order: order
|
||||||
|
});
|
||||||
|
order.shipmentId = shipment.id;
|
||||||
|
shipmentId = shipment.id;
|
||||||
|
}
|
||||||
|
if (order.status !== OrderStatus.COMPLETED) {
|
||||||
|
// shopyy未提供更新订单接口,暂不更新订单状态
|
||||||
|
// await this.shopyyService.updateOrder(site, order.externalOrderId, {
|
||||||
|
// status: OrderStatus.COMPLETED,
|
||||||
|
// });
|
||||||
|
order.status = OrderStatus.COMPLETED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
order.orderStatus = ErpOrderStatus.COMPLETED;
|
order.orderStatus = ErpOrderStatus.COMPLETED;
|
||||||
|
|
||||||
await orderRepo.save(order);
|
await orderRepo.save(order);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
transactionError = error
|
transactionError = error
|
||||||
|
throw new Error(`请求错误:${error}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (transactionError !== undefined) {
|
if (transactionError !== undefined) {
|
||||||
console.log('err', transactionError);
|
|
||||||
throw transactionError;
|
throw transactionError;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新产品发货信息
|
// 更新产品发货信息
|
||||||
this.orderService.updateOrderSales(order.id, sales);
|
this.orderService.updateOrderSales(order.id, sales);
|
||||||
|
|
||||||
|
|
@ -642,4 +691,190 @@ export class LogisticsService {
|
||||||
|
|
||||||
return { items, total, current, pageSize };
|
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 + '-' + 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
|
||||||
|
// 非跨境订单不需要declaration
|
||||||
|
// declaration: {
|
||||||
|
// "boxNo": "", //箱子编号
|
||||||
|
// "sku": "", //SKU
|
||||||
|
// "cnname": "", //中文名称
|
||||||
|
// "enname": "", //英文名称
|
||||||
|
// "declaredPrice": 1, //申报单价
|
||||||
|
// "declaredQty": 1, //申报数量
|
||||||
|
// "material": "", //材质
|
||||||
|
// "intendedUse": "", //用途
|
||||||
|
// "cweight": 1, //产品单重
|
||||||
|
// "hsCode": "", //海关编码
|
||||||
|
// "battery": "" //电池描述
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
resShipmentOrder = await this.freightwavesService.createOrder(reqBody); // 创建订单
|
||||||
|
//tms只返回了物流订单号,需要查询一次来获取完整的物流信息
|
||||||
|
const queryRes = await this.freightwavesService.queryOrder({ shipOrderId: resShipmentOrder.shipOrderId }); // 查询订单
|
||||||
|
resShipmentOrder.push(queryRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resShipmentOrder;
|
||||||
|
} catch (error) {
|
||||||
|
console.log('物流订单处理失败:', error); // 使用console.log代替this.log
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将ShipmentFeeBookDTO转换为freightwaves的RateTryRequest格式
|
||||||
|
* @param data ShipmentFeeBookDTO数据
|
||||||
|
* @returns RateTryRequest格式的数据
|
||||||
|
*/
|
||||||
|
async convertToFreightwavesRateTry(data: ShipmentFeeBookDTO): Promise<Omit<RateTryRequest, 'partner'>> {
|
||||||
|
|
||||||
|
const shipments = await this.shippingAddressModel.findOne({
|
||||||
|
where: {
|
||||||
|
id: data.address_id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const address = shipments?.address;
|
||||||
|
// 转换为RateTryRequest格式
|
||||||
|
const r = {
|
||||||
|
shipCompany: 'UPSYYZ7000NEW', // 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
partnerOrderNumber: `order-${Date.now()}`, // 必填,使用时间戳生成
|
||||||
|
warehouseId: '25072621030107400060', // 可选,使用stockPointId转换
|
||||||
|
shipper: {
|
||||||
|
name: data.sender, // 必填
|
||||||
|
phone: data.startPhone.phone, // 必填
|
||||||
|
company: address.country, // 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
countryCode: data.shipperCountryCode, // 必填
|
||||||
|
city: address.city || '', // 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
state: address.region || '', // 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
address1: address.address_line_1, // 必填
|
||||||
|
address2: address.address_line_1 || '', // 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
postCode: data.startPostalCode, // 必填
|
||||||
|
countryName: address.country || '', // 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
cityName: address.city || '', // 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
stateName: address.region || '', // 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
companyName: address.country || '', // 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
},
|
||||||
|
reciver: {
|
||||||
|
name: data.receiver, // 必填
|
||||||
|
phone: data.receiverPhone, // 必填
|
||||||
|
company: address.country,// 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
countryCode: data.country, // 必填,使用country代替countryCode
|
||||||
|
city: data.city, // 必填
|
||||||
|
state: data.province, // 必填,使用province代替state
|
||||||
|
address1: data.deliveryAddress, // 必填
|
||||||
|
address2: data.deliveryAddress, // 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
postCode: data.postalCode, // 必填
|
||||||
|
countryName: address.country, // 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
cityName: data.city || '', // 必填,使用city代替cityName
|
||||||
|
stateName: data.province || '', // 必填,使用province代替stateName
|
||||||
|
companyName: address.country || '', // 必填,但ShipmentFeeBookDTO中缺少
|
||||||
|
},
|
||||||
|
packages: [
|
||||||
|
{
|
||||||
|
dimensions: {
|
||||||
|
length: data.length, // 必填
|
||||||
|
width: data.width, // 必填
|
||||||
|
height: data.height, // 必填
|
||||||
|
lengthUnit: (data.dimensionUom === 'IN' ? 'IN' : 'CM') as 'IN' | 'CM', // 必填,转换为有效的单位
|
||||||
|
weight: data.weight, // 必填
|
||||||
|
weightUnit: (data.weightUom === 'LBS' ? 'LB' : 'KG') as 'LB' | 'KG', // 必填,转换为有效的单位
|
||||||
|
},
|
||||||
|
currency: 'CAD', // 必填,但ShipmentFeeBookDTO中缺少,使用默认值
|
||||||
|
description: 'Package', // 必填,但ShipmentFeeBookDTO中缺少,使用默认值
|
||||||
|
},
|
||||||
|
],
|
||||||
|
signService: 0, // 可选,默认不使用签名服务
|
||||||
|
};
|
||||||
|
return r as any;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ export class OrderService {
|
||||||
updated: 0,
|
updated: 0,
|
||||||
errors: []
|
errors: []
|
||||||
};
|
};
|
||||||
console.log('开始进入循环同步订单', result.length, '个订单')
|
this.logger.info('开始进入循环同步订单', result.length, '个订单')
|
||||||
// 遍历每个订单进行同步
|
// 遍历每个订单进行同步
|
||||||
for (const order of result) {
|
for (const order of result) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -150,7 +150,7 @@ export class OrderService {
|
||||||
where: { externalOrderId: String(order.id), siteId: siteId },
|
where: { externalOrderId: String(order.id), siteId: siteId },
|
||||||
});
|
});
|
||||||
if (!existingOrder) {
|
if (!existingOrder) {
|
||||||
console.log("数据库中不存在", order.id, '订单状态:', order.status)
|
this.logger.debug("数据库中不存在", order.id, '订单状态:', order.status)
|
||||||
}
|
}
|
||||||
// 同步单个订单
|
// 同步单个订单
|
||||||
await this.syncSingleOrder(siteId, order);
|
await this.syncSingleOrder(siteId, order);
|
||||||
|
|
@ -165,7 +165,7 @@ export class OrderService {
|
||||||
} else {
|
} else {
|
||||||
syncResult.created++;
|
syncResult.created++;
|
||||||
}
|
}
|
||||||
// console.log('updated', syncResult.updated, 'created:', syncResult.created)
|
// console.log('updated', syncResult.updated, 'created:', syncResult.created)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 记录错误但不中断整个同步过程
|
// 记录错误但不中断整个同步过程
|
||||||
syncResult.errors.push({
|
syncResult.errors.push({
|
||||||
|
|
@ -175,9 +175,7 @@ export class OrderService {
|
||||||
syncResult.processed++;
|
syncResult.processed++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('同步完成', syncResult.updated, 'created:', syncResult.created)
|
this.logger.info('同步完成', syncResult.updated, 'created:', syncResult.created)
|
||||||
|
|
||||||
this.logger.debug('syncOrders result', syncResult)
|
|
||||||
return syncResult;
|
return syncResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,7 +213,7 @@ export class OrderService {
|
||||||
where: { externalOrderId: String(order.id), siteId: siteId },
|
where: { externalOrderId: String(order.id), siteId: siteId },
|
||||||
});
|
});
|
||||||
if (!existingOrder) {
|
if (!existingOrder) {
|
||||||
console.log("数据库不存在", siteId, "订单:", order.id, '订单状态:' + order.status)
|
this.logger.debug("数据库不存在", siteId, "订单:", order.id, '订单状态:' + order.status)
|
||||||
}
|
}
|
||||||
// 同步单个订单
|
// 同步单个订单
|
||||||
await this.syncSingleOrder(siteId, order, true);
|
await this.syncSingleOrder(siteId, order, true);
|
||||||
|
|
@ -329,13 +327,30 @@ export class OrderService {
|
||||||
this.logger.debug('订单状态为 AUTO_DRAFT,跳过处理', siteId, order.id)
|
this.logger.debug('订单状态为 AUTO_DRAFT,跳过处理', siteId, order.id)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 这里其实不用过滤不可编辑的行为,而是应在 save 中做判断
|
// 检查数据库中是否已存在该订单
|
||||||
// if(!order.is_editable && !forceUpdate){
|
const existingOrder = await this.orderModel.findOne({
|
||||||
// this.logger.debug('订单不可编辑,跳过处理', siteId, order.id)
|
where: { externalOrderId: String(order.id), siteId: siteId },
|
||||||
// return;
|
});
|
||||||
// }
|
// 自动更新订单状态(如果需要)
|
||||||
// 自动转换远程订单的状态(如果需要)
|
|
||||||
await this.autoUpdateOrderStatus(siteId, order);
|
await this.autoUpdateOrderStatus(siteId, order);
|
||||||
|
|
||||||
|
if (existingOrder) {
|
||||||
|
// 矫正数据库中的订单数据
|
||||||
|
const updateData: any = { status: order.status };
|
||||||
|
if (this.canUpdateErpStatus(existingOrder.orderStatus)) {
|
||||||
|
updateData.orderStatus = this.mapOrderStatus(order.status as any);
|
||||||
|
}
|
||||||
|
// 更新订单主数据
|
||||||
|
await this.orderModel.update({ externalOrderId: String(order.id), siteId: siteId }, updateData);
|
||||||
|
// 更新 fulfillments 数据
|
||||||
|
await this.saveOrderFulfillments({
|
||||||
|
siteId,
|
||||||
|
orderId: existingOrder.id,
|
||||||
|
externalOrderId: order.id,
|
||||||
|
fulfillments: fulfillments,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const externalOrderId = String(order.id);
|
||||||
// 这里的 saveOrder 已经包括了创建订单和更新订单
|
// 这里的 saveOrder 已经包括了创建订单和更新订单
|
||||||
let orderRecord: Order = await this.saveOrder(siteId, orderData);
|
let orderRecord: Order = await this.saveOrder(siteId, orderData);
|
||||||
// 如果订单从未完成变为完成状态,则更新库存
|
// 如果订单从未完成变为完成状态,则更新库存
|
||||||
|
|
@ -347,7 +362,6 @@ export class OrderService {
|
||||||
await this.updateStock(orderRecord);
|
await this.updateStock(orderRecord);
|
||||||
// 不再直接返回,继续执行后续的更新操作
|
// 不再直接返回,继续执行后续的更新操作
|
||||||
}
|
}
|
||||||
const externalOrderId = String(order.id);
|
|
||||||
const orderId = orderRecord.id;
|
const orderId = orderRecord.id;
|
||||||
// 保存订单项
|
// 保存订单项
|
||||||
await this.saveOrderItems({
|
await this.saveOrderItems({
|
||||||
|
|
@ -360,7 +374,7 @@ export class OrderService {
|
||||||
await this.saveOrderRefunds({
|
await this.saveOrderRefunds({
|
||||||
siteId,
|
siteId,
|
||||||
orderId,
|
orderId,
|
||||||
externalOrderId ,
|
externalOrderId,
|
||||||
refunds,
|
refunds,
|
||||||
});
|
});
|
||||||
// 保存费用信息
|
// 保存费用信息
|
||||||
|
|
@ -714,11 +728,12 @@ export class OrderService {
|
||||||
await this.orderSaleModel.delete(currentOrderSale.map(v => v.id));
|
await this.orderSaleModel.delete(currentOrderSale.map(v => v.id));
|
||||||
}
|
}
|
||||||
if (!orderItem.sku) return;
|
if (!orderItem.sku) return;
|
||||||
|
|
||||||
// 从数据库查询产品,关联查询组件
|
// 从数据库查询产品,关联查询组件
|
||||||
const productDetail = await this.productService.getComponentDetailFromSiteSku({ sku: orderItem.sku, name: orderItem.name });
|
const productDetail = await this.productService.getComponentDetailFromSiteSku({ sku: orderItem.sku, name: orderItem.name });
|
||||||
|
|
||||||
if (!productDetail || !productDetail.quantity) return;
|
if (!productDetail || !productDetail.quantity) return;
|
||||||
const {product, quantity} = productDetail
|
const { product, quantity } = productDetail
|
||||||
const componentDetails: { product: Product, quantity: number }[] = product.components?.length > 0 ? await Promise.all(product.components.map(async comp => {
|
const componentDetails: { product: Product, quantity: number }[] = product.components?.length > 0 ? await Promise.all(product.components.map(async comp => {
|
||||||
return {
|
return {
|
||||||
|
zhuotianyuan marked this conversation as resolved
Outdated
longbot
commented
缩进! 缩进!
|
|||||||
product: await this.productModel.findOne({
|
product: await this.productModel.findOne({
|
||||||
|
|
@ -752,7 +767,6 @@ export class OrderService {
|
||||||
});
|
});
|
||||||
return orderSale
|
return orderSale
|
||||||
}).filter(v => v !== null)
|
}).filter(v => v !== null)
|
||||||
console.log("orderSales",orderSales)
|
|
||||||
if (orderSales.length > 0) {
|
if (orderSales.length > 0) {
|
||||||
await this.orderSaleModel.save(orderSales);
|
await this.orderSaleModel.save(orderSales);
|
||||||
}
|
}
|
||||||
|
|
@ -1544,7 +1558,6 @@ export class OrderService {
|
||||||
GROUP BY os.productId
|
GROUP BY os.productId
|
||||||
`;
|
`;
|
||||||
|
|
||||||
console.log('------3.5-----', pcSql, pcParams, exceptPackage);
|
|
||||||
const pcResults = await this.orderSaleModel.query(pcSql, pcParams);
|
const pcResults = await this.orderSaleModel.query(pcSql, pcParams);
|
||||||
|
|
||||||
const pcMap = new Map<number, any>();
|
const pcMap = new Map<number, any>();
|
||||||
|
|
@ -2512,7 +2525,7 @@ export class OrderService {
|
||||||
const boxCount = items.reduce((total, item) => total + item.quantity, 0);
|
const boxCount = items.reduce((total, item) => total + item.quantity, 0);
|
||||||
|
|
||||||
// 构建订单内容
|
// 构建订单内容
|
||||||
const orderContent = items.map(item => `${item.name} (${item.sku || ''}) x ${item.quantity}`).join('; ');
|
const orderContent = items.map(item => `${item.name} x ${item.quantity}`).join('; ');
|
||||||
|
|
||||||
// 构建姓名地址
|
// 构建姓名地址
|
||||||
const shipping = order.shipping;
|
const shipping = order.shipping;
|
||||||
|
|
@ -2544,7 +2557,7 @@ export class OrderService {
|
||||||
'姓名地址': nameAddress,
|
'姓名地址': nameAddress,
|
||||||
'邮箱': order.customer_email || '',
|
'邮箱': order.customer_email || '',
|
||||||
'号码': phone,
|
'号码': phone,
|
||||||
'订单内容': this.removeLastParenthesesContent(orderContent),
|
'订单内容': orderContent,
|
||||||
'盒数': boxCount,
|
'盒数': boxCount,
|
||||||
'换盒数': exchangeBoxCount,
|
'换盒数': exchangeBoxCount,
|
||||||
'换货内容': exchangeContent,
|
'换货内容': exchangeContent,
|
||||||
|
|
@ -2623,13 +2636,9 @@ export class OrderService {
|
||||||
if (!fs.existsSync(downloadsDir)) {
|
if (!fs.existsSync(downloadsDir)) {
|
||||||
fs.mkdirSync(downloadsDir, { recursive: true });
|
fs.mkdirSync(downloadsDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const filePath = path.join(downloadsDir, fileName);
|
const filePath = path.join(downloadsDir, fileName);
|
||||||
|
|
||||||
// 写入文件
|
// 写入文件
|
||||||
fs.writeFileSync(filePath, csvContent, 'utf8');
|
fs.writeFileSync(filePath, csvContent, 'utf8');
|
||||||
|
|
||||||
console.log(`数据已成功导出至 ${filePath}`);
|
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2640,7 +2649,6 @@ export class OrderService {
|
||||||
|
|
||||||
return csvContent;
|
return csvContent;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('导出CSV时出错:', error);
|
|
||||||
throw new Error(`导出CSV文件失败: ${error.message}`);
|
throw new Error(`导出CSV文件失败: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2658,10 +2666,10 @@ export class OrderService {
|
||||||
// 辅助函数:删除指定位置的括号对及其内容
|
// 辅助函数:删除指定位置的括号对及其内容
|
||||||
const removeParenthesesAt = (s: string, leftIndex: number): string => {
|
const removeParenthesesAt = (s: string, leftIndex: number): string => {
|
||||||
if (leftIndex === -1) return s;
|
if (leftIndex === -1) return s;
|
||||||
|
|
||||||
let rightIndex = -1;
|
let rightIndex = -1;
|
||||||
let parenCount = 0;
|
let parenCount = 0;
|
||||||
|
|
||||||
for (let i = leftIndex; i < s.length; i++) {
|
for (let i = leftIndex; i < s.length; i++) {
|
||||||
const char = s[i];
|
const char = s[i];
|
||||||
if (char === '(') {
|
if (char === '(') {
|
||||||
|
|
@ -2674,17 +2682,17 @@ export class OrderService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rightIndex !== -1) {
|
if (rightIndex !== -1) {
|
||||||
return s.substring(0, leftIndex) + s.substring(rightIndex + 1);
|
return s.substring(0, leftIndex) + s.substring(rightIndex + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 1. 处理每个分号前面的括号对
|
// 1. 处理每个分号前面的括号对
|
||||||
let result = str;
|
let result = str;
|
||||||
|
|
||||||
// 找出所有分号的位置
|
// 找出所有分号的位置
|
||||||
const semicolonIndices: number[] = [];
|
const semicolonIndices: number[] = [];
|
||||||
for (let i = 0; i < result.length; i++) {
|
for (let i = 0; i < result.length; i++) {
|
||||||
|
|
@ -2692,11 +2700,11 @@ export class OrderService {
|
||||||
semicolonIndices.push(i);
|
semicolonIndices.push(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从后向前处理每个分号,避免位置变化影响后续处理
|
// 从后向前处理每个分号,避免位置变化影响后续处理
|
||||||
for (let i = semicolonIndices.length - 1; i >= 0; i--) {
|
for (let i = semicolonIndices.length - 1; i >= 0; i--) {
|
||||||
const semicolonIndex = semicolonIndices[i];
|
const semicolonIndex = semicolonIndices[i];
|
||||||
|
|
||||||
// 从分号位置向前查找最近的左括号
|
// 从分号位置向前查找最近的左括号
|
||||||
let lastLeftParenIndex = -1;
|
let lastLeftParenIndex = -1;
|
||||||
for (let j = semicolonIndex - 1; j >= 0; j--) {
|
for (let j = semicolonIndex - 1; j >= 0; j--) {
|
||||||
|
|
@ -2705,7 +2713,7 @@ export class OrderService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果找到左括号,删除该括号对及其内容
|
// 如果找到左括号,删除该括号对及其内容
|
||||||
if (lastLeftParenIndex !== -1) {
|
if (lastLeftParenIndex !== -1) {
|
||||||
result = removeParenthesesAt(result, lastLeftParenIndex);
|
result = removeParenthesesAt(result, lastLeftParenIndex);
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@ import { Site } from '../entity/site.entity';
|
||||||
import { UnifiedReviewDTO } from '../dto/site-api.dto';
|
import { UnifiedReviewDTO } from '../dto/site-api.dto';
|
||||||
import { ShopyyGetOneOrderResult, ShopyyReview } from '../dto/shopyy.dto';
|
import { ShopyyGetOneOrderResult, ShopyyReview } from '../dto/shopyy.dto';
|
||||||
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
|
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
|
||||||
import { UnifiedSearchParamsDTO,ShopyyGetAllOrdersParams } from '../dto/api.dto';
|
import { UnifiedSearchParamsDTO, ShopyyGetAllOrdersParams } from '../dto/api.dto';
|
||||||
/**
|
/**
|
||||||
* ShopYY平台服务实现
|
* ShopYY平台服务实现
|
||||||
*/
|
*/
|
||||||
@Provide()
|
@Provide()
|
||||||
export class ShopyyService {
|
export class ShopyyService {
|
||||||
@Inject()
|
@Inject()
|
||||||
logger:ILogger;
|
logger: ILogger;
|
||||||
/**
|
/**
|
||||||
* 获取ShopYY评论列表
|
* 获取ShopYY评论列表
|
||||||
* @param site 站点配置
|
* @param site 站点配置
|
||||||
|
|
@ -184,9 +184,9 @@ export class ShopyyService {
|
||||||
*/
|
*/
|
||||||
public async fetchResourcePaged<T>(site: any, endpoint: string, params: Record<string, any> = {}) {
|
public async fetchResourcePaged<T>(site: any, endpoint: string, params: Record<string, any> = {}) {
|
||||||
const response = await this.request(site, endpoint, 'GET', null, params);
|
const response = await this.request(site, endpoint, 'GET', null, params);
|
||||||
return this.mapPageResponse<T>(response,params);
|
return this.mapPageResponse<T>(response, params);
|
||||||
}
|
}
|
||||||
mapPageResponse<T>(response:any,query: Record<string, any>){
|
mapPageResponse<T>(response: any, query: Record<string, any>) {
|
||||||
if (response?.code !== 0) {
|
if (response?.code !== 0) {
|
||||||
throw new Error(response?.msg)
|
throw new Error(response?.msg)
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +272,7 @@ export class ShopyyService {
|
||||||
const response = await this.request(site, `products/${productId}/variations/${variationId}`, 'GET');
|
const response = await this.request(site, `products/${productId}/variations/${variationId}`, 'GET');
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
mapOrderSearchParams(params: UnifiedSearchParamsDTO){
|
mapOrderSearchParams(params: UnifiedSearchParamsDTO) {
|
||||||
const { after, before, ...restParams } = params;
|
const { after, before, ...restParams } = params;
|
||||||
return {
|
return {
|
||||||
...restParams,
|
...restParams,
|
||||||
|
|
@ -310,9 +310,9 @@ export class ShopyyService {
|
||||||
|
|
||||||
async getAllOrders(site: any | number, params: ShopyyGetAllOrdersParams = {}, maxPages: number = 10, concurrencyLimit: number = 100): Promise<any> {
|
async getAllOrders(site: any | number, params: ShopyyGetAllOrdersParams = {}, maxPages: number = 10, concurrencyLimit: number = 100): Promise<any> {
|
||||||
const firstPage = await this.getOrders(site, 1, 100, params);
|
const firstPage = await this.getOrders(site, 1, 100, params);
|
||||||
|
|
||||||
const { items: firstPageItems, totalPages} = firstPage;
|
const { items: firstPageItems, totalPages } = firstPage;
|
||||||
|
|
||||||
// 如果只有一页数据,直接返回
|
// 如果只有一页数据,直接返回
|
||||||
if (totalPages <= 1) {
|
if (totalPages <= 1) {
|
||||||
return firstPageItems;
|
return firstPageItems;
|
||||||
|
|
@ -320,7 +320,7 @@ export class ShopyyService {
|
||||||
|
|
||||||
// 限制最大页数,避免过多的并发请求
|
// 限制最大页数,避免过多的并发请求
|
||||||
const actualMaxPages = Math.min(totalPages, maxPages);
|
const actualMaxPages = Math.min(totalPages, maxPages);
|
||||||
|
|
||||||
// 收集所有页面数据,从第二页开始
|
// 收集所有页面数据,从第二页开始
|
||||||
const allItems = [...firstPageItems];
|
const allItems = [...firstPageItems];
|
||||||
let currentPage = 2;
|
let currentPage = 2;
|
||||||
|
|
@ -329,7 +329,7 @@ export class ShopyyService {
|
||||||
while (currentPage <= actualMaxPages) {
|
while (currentPage <= actualMaxPages) {
|
||||||
const batchPromises: Promise<any[]>[] = [];
|
const batchPromises: Promise<any[]>[] = [];
|
||||||
const batchSize = Math.min(concurrencyLimit, actualMaxPages - currentPage + 1);
|
const batchSize = Math.min(concurrencyLimit, actualMaxPages - currentPage + 1);
|
||||||
|
|
||||||
// 创建当前批次的并发请求
|
// 创建当前批次的并发请求
|
||||||
for (let i = 0; i < batchSize; i++) {
|
for (let i = 0; i < batchSize; i++) {
|
||||||
const page = currentPage + i;
|
const page = currentPage + i;
|
||||||
|
|
@ -339,25 +339,25 @@ export class ShopyyService {
|
||||||
console.error(`获取第 ${page} 页数据失败:`, error);
|
console.error(`获取第 ${page} 页数据失败:`, error);
|
||||||
return []; // 如果某页获取失败,返回空数组,不影响整体结果
|
return []; // 如果某页获取失败,返回空数组,不影响整体结果
|
||||||
});
|
});
|
||||||
|
|
||||||
batchPromises.push(pagePromise);
|
batchPromises.push(pagePromise);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 等待当前批次完成
|
// 等待当前批次完成
|
||||||
const batchResults = await Promise.all(batchPromises);
|
const batchResults = await Promise.all(batchPromises);
|
||||||
|
|
||||||
// 合并当前批次的数据
|
// 合并当前批次的数据
|
||||||
for (const pageItems of batchResults) {
|
for (const pageItems of batchResults) {
|
||||||
allItems.push(...pageItems);
|
allItems.push(...pageItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移动到下一批次
|
// 移动到下一批次
|
||||||
currentPage += batchSize;
|
currentPage += batchSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return allItems;
|
return allItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取ShopYY订单详情
|
* 获取ShopYY订单详情
|
||||||
|
|
@ -475,13 +475,16 @@ export class ShopyyService {
|
||||||
async createFulfillment(site: Site, orderId: string, data: any): Promise<any> {
|
async createFulfillment(site: Site, orderId: string, data: any): Promise<any> {
|
||||||
// ShopYY API: POST /orders/{id}/shipments
|
// ShopYY API: POST /orders/{id}/shipments
|
||||||
const fulfillmentData = {
|
const fulfillmentData = {
|
||||||
tracking_number: data.tracking_number,
|
data: [{
|
||||||
carrier_code: data.carrier_code,
|
order_number: orderId,
|
||||||
carrier_name: data.carrier_name,
|
tracking_company: data.tracking_company,
|
||||||
shipping_method: data.shipping_method
|
tracking_number: data.tracking_number,
|
||||||
|
carrier_code: data.carrier_code,
|
||||||
|
note: "note",
|
||||||
|
mode: ""
|
||||||
|
}]
|
||||||
};
|
};
|
||||||
|
const response = await this.request(site, `orders/fulfillments`, 'POST', fulfillmentData);
|
||||||
const response = await this.request(site, `orders/${orderId}/shipments`, 'POST', fulfillmentData);
|
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -494,7 +497,7 @@ export class ShopyyService {
|
||||||
*/
|
*/
|
||||||
async deleteFulfillment(site: any, orderId: string, fulfillmentId: string): Promise<boolean> {
|
async deleteFulfillment(site: any, orderId: string, fulfillmentId: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
// ShopYY API: DELETE /orders/{order_id}/shipments/{fulfillment_id}
|
// ShopYY API: DELETE /orders/fulfillments/{fulfillment_id}
|
||||||
await this.request(site, `orders/${orderId}/fulfillments/${fulfillmentId}`, 'DELETE');
|
await this.request(site, `orders/${orderId}/fulfillments/${fulfillmentId}`, 'DELETE');
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -542,7 +545,7 @@ export class ShopyyService {
|
||||||
try {
|
try {
|
||||||
// ShopYY API: PUT /orders/{order_id}/shipments/{tracking_id}
|
// ShopYY API: PUT /orders/{order_id}/shipments/{tracking_id}
|
||||||
const fulfillmentData: any = {};
|
const fulfillmentData: any = {};
|
||||||
|
|
||||||
// 只传递有值的字段
|
// 只传递有值的字段
|
||||||
if (data.tracking_number !== undefined) {
|
if (data.tracking_number !== undefined) {
|
||||||
fulfillmentData.tracking_number = data.tracking_number;
|
fulfillmentData.tracking_number = data.tracking_number;
|
||||||
|
|
@ -645,10 +648,10 @@ export class ShopyyService {
|
||||||
// ShopYY API: POST /products/batch
|
// ShopYY API: POST /products/batch
|
||||||
const response = await this.request(site, 'products/batch', 'POST', data);
|
const response = await this.request(site, 'products/batch', 'POST', data);
|
||||||
const result = response.data;
|
const result = response.data;
|
||||||
|
|
||||||
// 转换 ShopYY 批量操作结果为统一格式
|
// 转换 ShopYY 批量操作结果为统一格式
|
||||||
const errors: Array<{identifier: string, error: string}> = [];
|
const errors: Array<{ identifier: string, error: string }> = [];
|
||||||
|
|
||||||
// 假设 ShopYY 返回格式与 WooCommerce 类似: { create: [...], update: [...], delete: [...] }
|
// 假设 ShopYY 返回格式与 WooCommerce 类似: { create: [...], update: [...], delete: [...] }
|
||||||
// 错误信息可能在每个项目的 error 字段中
|
// 错误信息可能在每个项目的 error 字段中
|
||||||
const checkForErrors = (items: any[]) => {
|
const checkForErrors = (items: any[]) => {
|
||||||
|
|
@ -661,12 +664,12 @@ export class ShopyyService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 检查每个操作类型的结果中的错误
|
// 检查每个操作类型的结果中的错误
|
||||||
if (result.create) checkForErrors(result.create);
|
if (result.create) checkForErrors(result.create);
|
||||||
if (result.update) checkForErrors(result.update);
|
if (result.update) checkForErrors(result.update);
|
||||||
if (result.delete) checkForErrors(result.delete);
|
if (result.delete) checkForErrors(result.delete);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
total: (data.create?.length || 0) + (data.update?.length || 0) + (data.delete?.length || 0),
|
total: (data.create?.length || 0) + (data.update?.length || 0) + (data.delete?.length || 0),
|
||||||
processed: (result.create?.length || 0) + (result.update?.length || 0) + (result.delete?.length || 0),
|
processed: (result.create?.length || 0) + (result.update?.length || 0) + (result.delete?.length || 0),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
删除这些调试时候的日志