diff --git a/src/adapter/woocommerce.adapter.ts b/src/adapter/woocommerce.adapter.ts index f14d7d3..c37ab3c 100644 --- a/src/adapter/woocommerce.adapter.ts +++ b/src/adapter/woocommerce.adapter.ts @@ -31,11 +31,13 @@ import { WooProductSearchParams, WpMediaGetListParams, WooFulfillment, + MetaDataFulfillment, } from '../dto/woocommerce.dto'; import { Site } from '../entity/site.entity'; import { WPService } from '../service/wp.service'; import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto'; import { toArray, toNumber } from '../utils/trans.util'; +import dayjs = require('dayjs'); export class WooCommerceAdapter implements ISiteAdapter { // 构造函数接收站点配置与服务实例 @@ -201,7 +203,7 @@ export class WooCommerceAdapter implements ISiteAdapter { async updateCustomer(where: Partial>, data: Partial): Promise { const api = this.wpService.createApi(this.site, 'wc/v3'); let customerId: string | number; - + // 先根据条件获取客户ID if (where.id) { customerId = where.id; @@ -210,7 +212,7 @@ export class WooCommerceAdapter implements ISiteAdapter { const customer = await this.getCustomer(where); customerId = customer.id; } - + const res = await api.put(`customers/${customerId}`, data); return this.mapPlatformToUnifiedCustomer(res.data); } @@ -218,7 +220,7 @@ export class WooCommerceAdapter implements ISiteAdapter { async deleteCustomer(where: Partial>): Promise { const api = this.wpService.createApi(this.site, 'wc/v3'); let customerId: string | number; - + // 先根据条件获取客户ID if (where.id) { customerId = where.id; @@ -227,7 +229,7 @@ export class WooCommerceAdapter implements ISiteAdapter { const customer = await this.getCustomer(where); customerId = customer.id; } - + await api.delete(`customers/${customerId}`, { force: true }); return true; } @@ -255,7 +257,7 @@ export class WooCommerceAdapter implements ISiteAdapter { } mapMediaSearchParams(params: UnifiedSearchParamsDTO): Partial { const page = params.page - const per_page = Number( params.per_page ?? 20); + const per_page = Number(params.per_page ?? 20); return { ...params.where, @@ -293,12 +295,12 @@ export class WooCommerceAdapter implements ISiteAdapter { throw new Error('Method not implemented.'); } - async updateMedia(where: {id: string | number}, data: any): Promise { + async updateMedia(where: { id: string | number }, data: any): Promise { // 更新媒体信息 return await this.wpService.updateMedia(Number(this.site.id), Number(where.id), data); } - async deleteMedia(where: {id: string | number}): Promise { + async deleteMedia(where: { id: string | number }): Promise { // 删除媒体资源 await this.wpService.deleteMedia(Number(this.site.id), Number(where.id), true); return true; @@ -348,7 +350,7 @@ export class WooCommerceAdapter implements ISiteAdapter { // 集合过滤参数 if (where.exclude) mapped.exclude = toArray(where.exclude); - if (where.ids || where.number || where.id || where.include) mapped.include = [...new Set([where.number,where.id,...toArray(where.ids),...toArray(where.include)])].filter(Boolean); + if (where.ids || where.number || where.id || where.include) mapped.include = [...new Set([where.number, where.id, ...toArray(where.ids), ...toArray(where.include)])].filter(Boolean); if (toNumber(where.offset) !== undefined) mapped.offset = Number(where.offset); if (where.parent ?? where.parentId) mapped.parent = toArray(where.parent ?? where.parentId); if (where.parent_exclude ?? where.parentExclude) mapped.parent_exclude = toArray(where.parent_exclude ?? where.parentExclude); @@ -397,14 +399,17 @@ export class WooCommerceAdapter implements ISiteAdapter { mapPlatformToUnifiedOrder(item: WooOrder): UnifiedOrderDTO { // 将 WooCommerce 订单数据映射为统一订单DTO // 包含账单地址与收货地址以及创建与更新时间 - // 映射物流追踪信息,将后端格式转换为前端期望的格式 - const fulfillments = (item.fulfillments || []).map((track) => ({ - tracking_id: track.tracking_id, - tracking_number: track.tracking_number, - shipping_provider: track.tracking_provider, - date_created: track.data_sipped, - })); + const metaFulfillments: MetaDataFulfillment[] = item.meta_data?.find?.(_meta => _meta.key === "_wc_shipment_tracking_items")?.value || [] + const fulfillments = metaFulfillments.map((track) => { + return ({ + tracking_id: track.tracking_id, + tracking_number: track.tracking_number, + tracking_product_code: track.tracking_product_code, + shipping_provider: track.tracking_provider, + date_created: dayjs(track.date_shipped).toString(), + }) + }); return { id: item.id, @@ -446,7 +451,7 @@ export class WooCommerceAdapter implements ISiteAdapter { } // 订单操作方法 - async getOrder(where: {id: string | number}): Promise { + async getOrder(where: { id: string | number }): Promise { // 获取单个订单详情 const api = this.wpService.createApi(this.site, 'wc/v3'); const res = await api.get(`orders/${where.id}`); @@ -457,30 +462,8 @@ export class WooCommerceAdapter implements ISiteAdapter { const requestParams = this.mapOrderSearchParams(params); const { items, total, totalPages, page, per_page } = await this.wpService.fetchResourcePaged(this.site, 'orders', requestParams); - // 并行获取所有订单的履行信息 - const ordersWithFulfillments = await Promise.all( - items.map(async (order: any) => { - try { - // 获取订单的履行信息 - const fulfillments = await this.getOrderFulfillments(order.id); - // 将履行信息添加到订单对象中 - return { - ...order, - fulfillments: fulfillments || [] - }; - } catch (error) { - // 如果获取履行信息失败,仍然返回订单,只是履行信息为空数组 - console.error(`获取订单 ${order.id} 的履行信息失败:`, error); - return { - ...order, - fulfillments: [] - }; - } - }) - ); - return { - items: ordersWithFulfillments.map(this.mapPlatformToUnifiedOrder), + items: items.map(this.mapPlatformToUnifiedOrder), total, totalPages, page, @@ -514,12 +497,12 @@ export class WooCommerceAdapter implements ISiteAdapter { return this.mapPlatformToUnifiedOrder(res.data); } - async updateOrder(where: {id: string | number}, data: Partial): Promise { + async updateOrder(where: { id: string | number }, data: Partial): Promise { // 更新订单并返回布尔结果 return await this.wpService.updateOrder(this.site, String(where.id), data as any); } - async deleteOrder(where: {id: string | number}): Promise { + async deleteOrder(where: { id: string | number }): Promise { // 删除订单 const api = this.wpService.createApi(this.site, 'wc/v3'); await api.delete(`orders/${where.id}`, { force: true }); @@ -606,7 +589,7 @@ export class WooCommerceAdapter implements ISiteAdapter { name: data.name, type: data.type, status: data.status, - sku: data.sku, + sku: data.sku, regular_price: data.regular_price, sale_price: data.sale_price, price: data.price, @@ -690,10 +673,10 @@ export class WooCommerceAdapter implements ISiteAdapter { return mapped; } - mapCreateProductParams(data: Partial):Partial { - const {id,...mapped}= this.mapUnifiedToPlatformProduct(data); + mapCreateProductParams(data: Partial): Partial { + const { id, ...mapped } = this.mapUnifiedToPlatformProduct(data); // 创建不带 id - return mapped + return mapped } mapUpdateProductParams(data: Partial): Partial { return this.mapUnifiedToPlatformProduct(data); @@ -844,28 +827,28 @@ export class WooCommerceAdapter implements ISiteAdapter { }; } // 判断是否是这个站点的sku - isSiteSkuThisSite(sku: string,){ - return sku.startsWith(this.site.skuPrefix+'-'); + isSiteSkuThisSite(sku: string,) { + return sku.startsWith(this.site.skuPrefix + '-'); } - async getProduct(where: Partial>): Promise{ + async getProduct(where: Partial>): Promise { const { id, sku } = where; - if(id) return this.getProductById(id); - if(sku) return this.getProductBySku(sku); + if (id) return this.getProductById(id); + if (sku) return this.getProductBySku(sku); throw new Error('必须提供id或sku参数'); } - async getProductBySku(sku: string){ + async getProductBySku(sku: string) { // const api = this.wpService.createApi(this.site, 'wc/v3'); // const res = await api.get(`products`,{ // sku // }); // const product = res.data[0]; - const res = await this.wpService.getProducts(this.site,{ + const res = await this.wpService.getProducts(this.site, { sku, - page:1, - per_page:1, + page: 1, + per_page: 1, }); const product = res?.items?.[0]; - if(!product) return null + if (!product) return null return this.mapPlatformToUnifiedProduct(product); } // 产品操作方法 @@ -976,7 +959,7 @@ export class WooCommerceAdapter implements ISiteAdapter { async updateProduct(where: Partial>, data: Partial): Promise { // 更新产品并返回统一产品DTO const product = await this.getProduct(where); - if(!product){ + if (!product) { throw new Error('产品不存在'); } const updateData = this.mapUpdateProductParams(data); @@ -987,7 +970,7 @@ export class WooCommerceAdapter implements ISiteAdapter { async deleteProduct(where: Partial>): Promise { // 删除产品 const product = await this.getProduct(where); - if(!product){ + if (!product) { throw new Error('产品不存在'); } const api = this.wpService.createApi(this.site, 'wc/v3'); @@ -1392,12 +1375,12 @@ export class WooCommerceAdapter implements ISiteAdapter { const result = await this.wpService.getWebhooks(this.site, params); return { - items: (result.items as WooWebhook[]).map(this.mapPlatformToUnifiedWebhook), - total: result.total, - page: Number(params.page || 1), - per_page: Number(params.per_page || 20), - totalPages: result.totalPages, - }; + items: (result.items as WooWebhook[]).map(this.mapPlatformToUnifiedWebhook), + total: result.total, + page: Number(params.page || 1), + per_page: Number(params.per_page || 20), + totalPages: result.totalPages, + }; } catch (error) { throw new Error(`Failed to get webhooks: ${error instanceof Error ? error.message : String(error)}`); } @@ -1415,7 +1398,7 @@ export class WooCommerceAdapter implements ISiteAdapter { } // 获取单个 webhook 详情 - async getWebhook(where: {id: string | number}): Promise { + async getWebhook(where: { id: string | number }): Promise { try { const result = await this.wpService.getWebhook(this.site, where.id); return this.mapPlatformToUnifiedWebhook(result as WooWebhook); diff --git a/src/dto/site-api.dto.ts b/src/dto/site-api.dto.ts index a5b2fc7..6a72809 100644 --- a/src/dto/site-api.dto.ts +++ b/src/dto/site-api.dto.ts @@ -811,7 +811,8 @@ export class FulfillmentDTO { tracking_id?: string; @ApiProperty({ description: '物流单号', required: false }) tracking_number?: string; - + @ApiProperty({ description: "物流产品代码" , required: false}) + tracking_product_code?: string; @ApiProperty({ description: '物流公司', required: false }) shipping_provider?: string; diff --git a/src/dto/woocommerce.dto.ts b/src/dto/woocommerce.dto.ts index c48b85f..8fe99b1 100644 --- a/src/dto/woocommerce.dto.ts +++ b/src/dto/woocommerce.dto.ts @@ -369,9 +369,19 @@ export interface WooOrder { date_created_gmt?: string; date_modified?: string; date_modified_gmt?: string; - // 物流追踪信息 - fulfillments?: WooFulfillment[]; } + export interface MetaDataFulfillment { + custom_tracking_link: string; + custom_tracking_provider: string; + date_shipped: number; + source: string; + status_shipped: string; + tracking_id: string; + tracking_number: string; + tracking_product_code: string; + tracking_provider: string; + user_id: number; + } // 这个是一个插件的物流追踪信息 // 接口: export interface WooFulfillment { diff --git a/src/entity/order.entity.ts b/src/entity/order.entity.ts index d4f1cbb..8fe050c 100644 --- a/src/entity/order.entity.ts +++ b/src/entity/order.entity.ts @@ -106,7 +106,7 @@ export class Order { @Expose() cart_tax: number; - @ApiProperty() + @ApiProperty({ type: "总金额"}) @Column('decimal', { precision: 10, scale: 2, default: 0 }) @Expose() total: number; diff --git a/src/service/order.service.ts b/src/service/order.service.ts index 321221c..5cde38a 100644 --- a/src/service/order.service.ts +++ b/src/service/order.service.ts @@ -1479,7 +1479,7 @@ export class OrderService { } let itemSql = ` - SELECT os.productId, os.name, SUM(os.quantity) AS totalQuantity, COUNT(DISTINCT os.orderId) AS totalOrders + SELECT os.productId, os.name, os.sku, SUM(os.quantity) AS totalQuantity, COUNT(DISTINCT os.orderId) AS totalOrders FROM order_sale os INNER JOIN \`order\` o ON o.id = os.orderId WHERE o.date_paid BETWEEN ? AND ? @@ -1501,7 +1501,7 @@ export class OrderService { } itemSql += nameCondition; itemSql += ` - GROUP BY os.productId, os.name + GROUP BY os.productId, os.name, os.sku ORDER BY totalQuantity DESC LIMIT ? OFFSET ? `;