diff --git a/src/service/Wintopay.service.ts b/src/service/Wintopay.service.ts new file mode 100644 index 0000000..eaef0c7 --- /dev/null +++ b/src/service/Wintopay.service.ts @@ -0,0 +1,96 @@ +import { Inject, Provide } from '@midwayjs/core'; +import axios from 'axios'; +import dayjs = require('dayjs'); +import utc = require('dayjs/plugin/utc'); +import timezone = require('dayjs/plugin/timezone'); + +// 扩展dayjs功能 +dayjs.extend(utc); +dayjs.extend(timezone); + + +// Wintopay 物流更新请求接口 +interface LogisticsUpdateRequest { + trade_id: string; // 订单的流水号 + track_number: string; // 物流单号 + track_brand: string; // 物流公司编号 +} + +// Wintopay 物流更新响应接口 +interface LogisticsUpdateResponse { + code: string; + message: string; + data: { + trade_id: string; + track_brand: string; + track_number: string; + time: number; + }; + error: any; + request_id: string; +} + +@Provide() +export class WintopayService { + @Inject() logger; + + // 默认配置 + private config = { + //测试环境配置,在生产环境记得换掉 + apiBaseUrl: 'https://stage-merchant-api.wintopay.com', + Authorization: 'Bearer kV8w1er8dFw9p9g2kb0mer398hD8hfWk', + }; + + // 发送请求 + private async sendRequest(url: string, data: any): Promise { + try { + const headers = { + 'Content-Type': 'application/json', + 'Authorization': this.config.Authorization, + }; + + // 发送请求 - 临时禁用SSL证书验证以解决UNABLE_TO_VERIFY_LEAF_SIGNATURE错误 + const response = await axios.post( + `${this.config.apiBaseUrl}${url}`, + data, + { + headers, + httpsAgent: new (require('https').Agent)({ + rejectUnauthorized: false + }) + } + ); + + return response.data; + } catch (error) { + this.logger.error('Wintopay API请求失败:', error); + throw error; + } + } + + + /** + * 更新订单物流信息 + * @param params 物流更新参数 + * @returns 物流更新响应 + */ + async logisticsUpdate(params: LogisticsUpdateRequest): Promise { + try { + this.logger.info('开始更新物流信息:', params); + + const response = await this.sendRequest('/v1/logistics/update', params); + + this.logger.info('物流更新成功:', response); + return response; + } catch (error: any) { + this.logger.error('物流更新失败:', error); + + // 处理API返回的错误 + if (error.response?.data) { + throw new Error(`物流更新失败: ${error.response.data.message || '未知错误'}`); + } + + throw new Error(`物流更新请求失败: ${error.message || '网络错误'}`); + } + } +} \ No newline at end of file diff --git a/src/service/logistics.service.ts b/src/service/logistics.service.ts index 2a58e59..b43f3d0 100644 --- a/src/service/logistics.service.ts +++ b/src/service/logistics.service.ts @@ -327,17 +327,20 @@ export class LogisticsService { let resShipmentFee: any; if (data.shipmentPlatform === 'uniuni') { resShipmentFee = await this.uniExpressService.getRates(reqBody); + if (resShipmentFee.status !== 'SUCCESS') { + throw new Error(resShipmentFee.ret_msg); + } + return resShipmentFee.data.totalAfterTax * 100; } else if (data.shipmentPlatform === 'freightwaves') { const fre_reqBody = await this.convertToFreightwavesRateTry(data); resShipmentFee = await this.freightwavesService.rateTry(fre_reqBody); + return resShipmentFee.totalAmount * 100; } else { throw new Error('不支持的运单平台'); } - if (resShipmentFee.status !== 'SUCCESS') { - throw new Error(resShipmentFee.ret_msg); - } - return resShipmentFee.data.totalAfterTax * 100; + + } catch (e) { throw e; } @@ -360,12 +363,7 @@ export class LogisticsService { try { resShipmentOrder = await this.mepShipment(data, order); - // 记录物流信息,并将订单状态转到完成,uniuni状态为SUCCESS,tms.freightwaves状态为00000200 - if (resShipmentOrder.status === 'SUCCESS' || resShipmentOrder.code === '00000200') { - order.orderStatus = ErpOrderStatus.COMPLETED; - } else { - throw new Error('运单生成失败'); - } + order.orderStatus = ErpOrderStatus.COMPLETED; const dataSource = this.dataSourceManager.getDataSource('default'); let transactionError = undefined; let shipmentId = undefined; @@ -384,8 +382,8 @@ export class LogisticsService { unique_id = resShipmentOrder.data.uni_order_sn; state = resShipmentOrder.data.uni_status_code; } else { - co = resShipmentOrder.data?.shipOrderId; - unique_id = resShipmentOrder.data?.shipOrderId; + co = resShipmentOrder.shipOrderId; + unique_id = resShipmentOrder.shipOrderId; state = ErpOrderStatus.COMPLETED; } @@ -728,6 +726,11 @@ export class LogisticsService { }; // 添加运单 resShipmentOrder = await this.uniExpressService.createShipment(reqBody); + + // 记录物流信息,并将订单状态转到完成,uniuni状态为SUCCESS,tms.freightwaves状态为00000200 + if (resShipmentOrder.status !== 'SUCCESS') { + throw new Error('运单生成失败'); + } } if (data.shipmentPlatform === 'freightwaves') { @@ -735,7 +738,7 @@ export class LogisticsService { const reqBody: any = { // shipCompany: 'UPSYYZ7000NEW', shipCompany: data.courierCompany || "", - partnerOrderNumber: order.siteId + '-1-' + order.externalOrderId, + partnerOrderNumber: order.siteId + '-' + order.externalOrderId, warehouseId: '25072621030107400060', shipper: { name: data.details.origin.contact_name, // 姓名 @@ -811,8 +814,8 @@ export class LogisticsService { return resShipmentOrder; } catch (error) { // 处理错误,例如记录日志或抛出异常 - throw new Error(`物流订单处理失败: ${error}`); - + throw new Error(`物流订单处理失败: ${error}`); + } } diff --git a/src/service/order.service.ts b/src/service/order.service.ts index 8a92c56..cf09271 100644 --- a/src/service/order.service.ts +++ b/src/service/order.service.ts @@ -2454,18 +2454,18 @@ export class OrderService { */ // TODO async exportOrder(ids: number[]) { - // 日期 订单号 姓名地址 邮箱 号码 订单内容 盒数 换盒数 换货内容 快递号 + // 日期 订单号 姓名地址 邮箱 号码 盒数 换盒数 换货内容 快递号 商品1 数量1 商品2 数量2... interface ExportData { '日期': string; '订单号': string; '姓名地址': string; '邮箱': string; '号码': string; - '订单内容': string; '盒数': number; '换盒数': number; '换货内容': string; '快递号': string; + [key: string]: any; // 支持动态添加的商品和数量列 } try { @@ -2512,6 +2512,15 @@ export class OrderService { return acc; }, {} as Record); + // 计算最大商品数量 + let maxItemsCount = 0; + orders.forEach(order => { + const items = orderItemsByOrderId[order.id] || []; + if (items.length > maxItemsCount) { + maxItemsCount = items.length; + } + }); + // 构建导出数据 const exportDataList: ExportData[] = orders.map(order => { // 获取订单的订单项 @@ -2520,9 +2529,6 @@ export class OrderService { // 计算总盒数 const boxCount = items.reduce((total, item) => total + item.quantity, 0); - // 构建订单内容 - const orderContent = items.map(item => `${item.name} x ${item.quantity}`).join('; '); - // 构建姓名地址 const shipping = order.shipping; const billing = order.billing; @@ -2547,18 +2553,32 @@ export class OrderService { const exchangeBoxCount = 0; const exchangeContent = ''; - return { + // 构建基础数据对象 + const baseData: ExportData = { '日期': order.date_created?.toISOString().split('T')[0] || '', '订单号': order.externalOrderId || '', '姓名地址': nameAddress, '邮箱': order.customer_email || '', '号码': phone, - '订单内容': orderContent, '盒数': boxCount, '换盒数': exchangeBoxCount, '换货内容': exchangeContent, '快递号': trackingNumber }; + + // 添加商品和数量列 + items.forEach((item, index) => { + baseData[`商品${index + 1}`] = item.name; + baseData[`数量${index + 1}`] = item.quantity; + }); + + // 填充空值,确保所有行的列数一致 + for (let i = items.length; i < maxItemsCount; i++) { + baseData[`商品${i + 1}`] = ''; + baseData[`数量${i + 1}`] = ''; + } + + return baseData; }); // 返回CSV字符串内容给前端