Compare commits

..

3 Commits

Author SHA1 Message Date
tikkhun 75056db42c refactor(woocommerce): 优化参数处理逻辑并提取工具函数
将参数转换逻辑提取到独立的工具模块中
合并重复的include参数处理逻辑
添加对parent_exclude参数的支持
2026-01-22 15:05:41 +08:00
tikkhun d5384944a4 feat(woocommerce): 添加物流追踪创建和更新接口
添加 WooFulfillmentCreateParams 接口定义并重构物流追踪创建和更新方法
使用统一的 FulfillmentDTO 类型简化参数处理
2026-01-22 14:44:42 +08:00
tikkhun cb876e8c0f refactor(物流): 更新物流相关接口和DTO以支持可选字段
重构物流追踪相关接口和DTO,将order_item_id和quantity改为可选字段
添加tracking_id字段到FulfillmentDTO
优化woocommerce物流数据结构映射
更新package-lock.json添加faker依赖
2026-01-22 11:38:44 +08:00
5 changed files with 74 additions and 76 deletions

17
package-lock.json generated
View File

@ -523,6 +523,23 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@faker-js/faker": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.2.0.tgz",
"integrity": "sha512-rTXwAsIxpCqzUnZvrxVh3L0QA0NzToqWBLAhV+zDV3MIIwiQhAZHMdPCIaj5n/yADu/tyk12wIPgL6YHGXJP+g==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/fakerjs"
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0",
"npm": ">=10"
}
},
"node_modules/@hapi/bourne": { "node_modules/@hapi/bourne": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmmirror.com/@hapi/bourne/-/bourne-3.0.0.tgz", "resolved": "https://registry.npmmirror.com/@hapi/bourne/-/bourne-3.0.0.tgz",

View File

@ -17,6 +17,7 @@ import {
UnifiedVariationPaginationDTO, UnifiedVariationPaginationDTO,
CreateReviewDTO, CreateReviewDTO,
UpdateReviewDTO, UpdateReviewDTO,
FulfillmentDTO,
} from '../dto/site-api.dto'; } from '../dto/site-api.dto';
import { UnifiedPaginationDTO, UnifiedSearchParamsDTO } from '../dto/api.dto'; import { UnifiedPaginationDTO, UnifiedSearchParamsDTO } from '../dto/api.dto';
import { import {
@ -29,10 +30,12 @@ import {
WooOrderSearchParams, WooOrderSearchParams,
WooProductSearchParams, WooProductSearchParams,
WpMediaGetListParams, WpMediaGetListParams,
WooFulfillment,
} from '../dto/woocommerce.dto'; } from '../dto/woocommerce.dto';
import { Site } from '../entity/site.entity'; import { Site } from '../entity/site.entity';
import { WPService } from '../service/wp.service'; import { WPService } from '../service/wp.service';
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto'; import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
import { toArray, toNumber } from '../utils/trans.util';
export class WooCommerceAdapter implements ISiteAdapter { export class WooCommerceAdapter implements ISiteAdapter {
// 构造函数接收站点配置与服务实例 // 构造函数接收站点配置与服务实例
@ -330,22 +333,11 @@ export class WooCommerceAdapter implements ISiteAdapter {
// } // }
const mapped: any = { const mapped: any = {
...(params.search ? { search: params.search } : {}), ...(params.search ? { search: params.search } : {}),
// ...(orderBy ? { orderBy } : {}),
page, page,
per_page, per_page,
}; };
const toArray = (value: any): any[] => {
if (Array.isArray(value)) return value;
if (value === undefined || value === null) return [];
return String(value).split(',').map(v => v.trim()).filter(Boolean);
};
const toNumber = (value: any): number | undefined => {
if (value === undefined || value === null || value === '') return undefined;
const n = Number(value);
return Number.isFinite(n) ? n : undefined;
};
// 时间过滤参数 // 时间过滤参数
if (where.after ?? where.date_created_after ?? where.created_after) mapped.after = String(where.after ?? where.date_created_after ?? where.created_after); if (where.after ?? where.date_created_after ?? where.created_after) mapped.after = String(where.after ?? where.date_created_after ?? where.created_after);
@ -356,8 +348,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
// 集合过滤参数 // 集合过滤参数
if (where.exclude) mapped.exclude = toArray(where.exclude); if (where.exclude) mapped.exclude = toArray(where.exclude);
if (where.include) mapped.include = toArray(where.include); 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) mapped.include = toArray(where.ids);
if (toNumber(where.offset) !== undefined) mapped.offset = Number(where.offset); 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 ?? where.parentId) mapped.parent = toArray(where.parent ?? where.parentId);
if (where.parent_exclude ?? where.parentExclude) mapped.parent_exclude = toArray(where.parent_exclude ?? where.parentExclude); if (where.parent_exclude ?? where.parentExclude) mapped.parent_exclude = toArray(where.parent_exclude ?? where.parentExclude);
@ -408,13 +399,11 @@ export class WooCommerceAdapter implements ISiteAdapter {
// 包含账单地址与收货地址以及创建与更新时间 // 包含账单地址与收货地址以及创建与更新时间
// 映射物流追踪信息,将后端格式转换为前端期望的格式 // 映射物流追踪信息,将后端格式转换为前端期望的格式
const fulfillments = (item.fulfillments || []).map((track: any) => ({ const fulfillments = (item.fulfillments || []).map((track) => ({
tracking_number: track.tracking_number || '', tracking_id: track.tracking_id,
shipping_provider: track.shipping_provider || '', tracking_number: track.tracking_number,
shipping_method: track.shipping_method || '', shipping_provider: track.tracking_provider,
status: track.status || '', date_created: track.data_sipped,
date_created: track.date_created || '',
items: track.items || [],
})); }));
return { return {
@ -541,54 +530,25 @@ export class WooCommerceAdapter implements ISiteAdapter {
return await this.wpService.getFulfillments(this.site, String(orderId)); return await this.wpService.getFulfillments(this.site, String(orderId));
} }
async createOrderFulfillment(orderId: string | number, data: { async createOrderFulfillment(orderId: string | number, data: FulfillmentDTO): Promise<any> {
tracking_number: string; const shipmentData: Partial<WooFulfillment> = {
shipping_provider: string; tracking_provider: data.shipping_provider,
shipping_method?: string;
status?: string;
date_created?: string;
items?: Array<{
order_item_id: number;
quantity: number;
}>;
}): Promise<any> {
const shipmentData: any = {
shipping_provider: data.shipping_provider,
tracking_number: data.tracking_number, tracking_number: data.tracking_number,
}; data_sipped: data.date_created,
// items: data.items,
if (data.shipping_method) {
shipmentData.shipping_method = data.shipping_method;
} }
if (data.status) {
shipmentData.status = data.status;
}
if (data.date_created) {
shipmentData.date_created = data.date_created;
}
if (data.items) {
shipmentData.items = data.items;
}
const response = await this.wpService.createFulfillment(this.site, String(orderId), shipmentData); const response = await this.wpService.createFulfillment(this.site, String(orderId), shipmentData);
return response.data; return response.data;
} }
async updateOrderFulfillment(orderId: string | number, fulfillmentId: string, data: { async updateOrderFulfillment(orderId: string | number, fulfillmentId: string, data: FulfillmentDTO): Promise<any> {
tracking_number?: string; const shipmentData: Partial<WooFulfillment> = {
shipping_provider?: string; tracking_provider: data.shipping_provider,
shipping_method?: string; tracking_number: data.tracking_number,
status?: string; data_sipped: data.date_created,
date_created?: string; // items: data.items,
items?: Array<{ }
order_item_id: number; return await this.wpService.updateFulfillment(this.site, String(orderId), fulfillmentId, shipmentData);
quantity: number;
}>;
}): Promise<any> {
return await this.wpService.updateFulfillment(this.site, String(orderId), fulfillmentId, data);
} }
async deleteOrderFulfillment(orderId: string | number, fulfillmentId: string): Promise<boolean> { async deleteOrderFulfillment(orderId: string | number, fulfillmentId: string): Promise<boolean> {

View File

@ -799,14 +799,16 @@ export class UpdateWebhookDTO {
export class FulfillmentItemDTO { export class FulfillmentItemDTO {
@ApiProperty({ description: '订单项ID' }) @ApiProperty({ description: '订单项ID' ,required: false})
order_item_id: number; order_item_id: number;
@ApiProperty({ description: '数量' }) @ApiProperty({ description: '数量' ,required:false})
quantity: number; quantity: number;
} }
export class FulfillmentDTO { export class FulfillmentDTO {
@ApiProperty({ description: '物流id', required: false })
tracking_id?: string;
@ApiProperty({ description: '物流单号', required: false }) @ApiProperty({ description: '物流单号', required: false })
tracking_number?: string; tracking_number?: string;

View File

@ -370,17 +370,24 @@ export interface WooOrder {
date_modified?: string; date_modified?: string;
date_modified_gmt?: string; date_modified_gmt?: string;
// 物流追踪信息 // 物流追踪信息
fulfillments?: Array<{ fulfillments?: WooFulfillment[];
tracking_number?: string; }
shipping_provider?: string; // 这个是一个插件的物流追踪信息
shipping_method?: string; // 接口:
status?: string; export interface WooFulfillment {
date_created?: string; data_sipped: string;
items?: Array<{ tracking_id: string;
order_item_id?: number; tracking_link: string;
quantity?: number; tracking_number: string;
}>; tracking_provider: string;
}>; }
// https://docs.zorem.com/docs/ast-free/developers/adding-tracking-info-to-orders/
export interface WooFulfillmentCreateParams {
order_id: string;
tracking_provider: string;
tracking_number: string;
date_shipped?: string;
status_shipped?: string;
} }
export interface WooOrderRefund { export interface WooOrderRefund {
id?: number; id?: number;
@ -552,7 +559,8 @@ export interface WooOrderSearchParams {
order: string; order: string;
orderby: string; orderby: string;
parant: string[]; parant: string[];
status: (WooOrderStatusSearchParams)[]; parent_exclude: string[];
status: WooOrderStatusSearchParams[];
customer: number; customer: number;
product: number; product: number;
dp: number; dp: number;

11
src/utils/trans.util.ts Normal file
View File

@ -0,0 +1,11 @@
export const toArray = (value: any): any[] => {
if (Array.isArray(value)) return value;
if (value === undefined || value === null) return [];
return String(value).split(',').map(v => v.trim()).filter(Boolean);
};
export const toNumber = (value: any): number | undefined => {
if (value === undefined || value === null || value === '') return undefined;
const n = Number(value);
return Number.isFinite(n) ? n : undefined;
};