API/src/adapter/woocommerce.adapter.ts

1465 lines
57 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ISiteAdapter } from '../interface/site-adapter.interface';
import {
UnifiedMediaDTO,
UnifiedOrderDTO,
UnifiedProductDTO,
UnifiedSubscriptionDTO,
UnifiedCustomerDTO,
UnifiedReviewPaginationDTO,
UnifiedReviewDTO,
UnifiedWebhookDTO,
UnifiedWebhookPaginationDTO,
CreateWebhookDTO,
UpdateWebhookDTO,
CreateVariationDTO,
UpdateVariationDTO,
UnifiedProductVariationDTO,
UnifiedVariationPaginationDTO,
CreateReviewDTO,
UpdateReviewDTO,
CreateReviewDTO,
UpdateReviewDTO,
} from '../dto/site-api.dto';
import { UnifiedPaginationDTO, UnifiedSearchParamsDTO } from '../dto/api.dto';
import {
WooProduct,
WooOrder,
WooSubscription,
WpMedia,
WooCustomer,
WooWebhook,
WooOrderSearchParams,
WooProductSearchParams,
} from '../dto/woocommerce.dto';
import { Site } from '../entity/site.entity';
import { WPService } from '../service/wp.service';
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
export class WooCommerceAdapter implements ISiteAdapter {
// 构造函数接收站点配置与服务实例
constructor(private site: Site, private wpService: WPService) {
this.mapPlatformToUnifiedProduct = this.mapPlatformToUnifiedProduct.bind(this);
this.mapPlatformToUnifiedReview = this.mapPlatformToUnifiedReview.bind(this);
this.mapPlatformToUnifiedCustomer = this.mapPlatformToUnifiedCustomer.bind(this);
this.mapPlatformToUnifiedMedia = this.mapPlatformToUnifiedMedia.bind(this);
this.mapPlatformToUnifiedOrder = this.mapPlatformToUnifiedOrder.bind(this);
this.mapPlatformToUnifiedWebhook = this.mapPlatformToUnifiedWebhook.bind(this);
}
batchProcessProducts?(data: BatchOperationDTO): Promise<BatchOperationResultDTO> {
throw new Error('Method not implemented.');
}
mapCreateVariationParams(data: CreateVariationDTO) {
throw new Error('Method not implemented.');
}
mapUpdateVariationParams(data: UpdateVariationDTO) {
throw new Error('Method not implemented.');
}
// ========== 客户映射方法 ==========
mapPlatformToUnifiedCustomer(data: any): UnifiedCustomerDTO {
return data;
}
mapUnifiedToPlatformCustomer(data: Partial<UnifiedCustomerDTO>) {
return data;
}
mapCustomer(item: WooCustomer): UnifiedCustomerDTO {
// 将 WooCommerce 客户数据映射为统一客户DTO
// 包含基础信息地址信息与时间信息
return {
id: item.id,
avatar: item.avatar_url,
email: item.email,
orders: Number(item.orders ?? 0),
total_spend: Number(item.total_spent ?? 0),
first_name: item.first_name,
last_name: item.last_name,
username: item.username,
phone: item.billing?.phone || item.shipping?.phone,
billing: item.billing,
shipping: item.shipping,
date_created: item.date_created,
date_modified: item.date_modified,
raw: item,
id: item.id,
avatar: item.avatar_url,
email: item.email,
orders: Number(item.orders ?? 0),
total_spend: Number(item.total_spent ?? 0),
first_name: item.first_name,
last_name: item.last_name,
username: item.username,
phone: item.billing?.phone || item.shipping?.phone,
billing: item.billing,
shipping: item.shipping,
date_created: item.date_created,
date_modified: item.date_modified,
raw: item,
};
}
mapCustomerSearchParams(params: UnifiedSearchParamsDTO): Record<string, any> {
const page = Number(params.page ?? 1);
const per_page = Number(params.per_page ?? 20);
const where = params.where && typeof params.where === 'object' ? params.where : {};
const mapped: any = {
...(params.search ? { search: params.search } : {}),
page,
per_page,
};
// 处理orderBy参数转换为WooCommerce API的order和orderby格式
if (params.orderBy) {
// 支持字符串格式 "field:desc" 或对象格式 { "field": "desc" }
if (typeof params.orderBy === 'string') {
const [field, direction = 'desc'] = params.orderBy.split(':');
mapped.orderby = field;
mapped.order = direction.toLowerCase() === 'asc' ? 'asc' : 'desc';
} else if (typeof params.orderBy === 'object') {
const entries = Object.entries(params.orderBy);
if (entries.length > 0) {
const [field, direction] = entries[0];
mapped.orderby = field;
mapped.order = direction === 'asc' ? 'asc' : 'desc';
}
}
}
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.exclude) mapped.exclude = toArray(where.exclude);
if (where.include) mapped.include = toArray(where.include);
if (where.ids) mapped.include = toArray(where.ids);
if (toNumber(where.offset) !== undefined) mapped.offset = Number(where.offset);
if (where.email) mapped.email = String(where.email);
const roleSource = where.role;
if (roleSource !== undefined) mapped.role = String(roleSource);
return mapped;
}
// 客户操作方法
async getCustomer(id: string | number): Promise<UnifiedCustomerDTO> {
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const res = await api.get(`customers/${id}`);
return this.mapCustomer(res.data);
}
async getCustomers(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedCustomerDTO>> {
const requestParams = this.mapCustomerSearchParams(params);
const { items, total, totalPages, page, per_page } = await this.wpService.fetchResourcePaged<any>(
this.site,
'customers',
requestParams
);
return {
items: items.map((i: any) => this.mapCustomer(i)),
total,
totalPages,
page,
per_page,
};
}
async getAllCustomers(params?: UnifiedSearchParamsDTO): Promise<UnifiedCustomerDTO[]> {
// 使用sdkGetAll获取所有客户数据不受分页限制
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
// 处理orderBy参数转换为WooCommerce API需要的格式
const requestParams = this.mapCustomerSearchParams(params || {});
const customers = await this.wpService.sdkGetAll(api, 'customers', requestParams);
return customers.map((customer: any) => this.mapCustomer(customer));
}
async createCustomer(data: Partial<UnifiedCustomerDTO>): Promise<UnifiedCustomerDTO> {
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const res = await api.post('customers', data);
return this.mapCustomer(res.data);
}
async updateCustomer(id: string | number, data: Partial<UnifiedCustomerDTO>): Promise<UnifiedCustomerDTO> {
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const res = await api.put(`customers/${id}`, data);
return this.mapCustomer(res.data);
}
async deleteCustomer(id: string | number): Promise<boolean> {
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
await api.delete(`customers/${id}`, { force: true });
return true;
}
// ========== 媒体映射方法 ==========
mapPlatformToUnifiedMedia(data: any): UnifiedMediaDTO {
return data;
}
mapUnifiedToPlatformMedia(data: Partial<UnifiedMediaDTO>) {
return data;
}
mapMedia(item: WpMedia): UnifiedMediaDTO {
// 将 WordPress 媒体数据映射为统一媒体DTO
// 兼容不同字段命名的时间信息
return {
id: item.id,
title:
typeof item.title === 'string'
? item.title
: item.title?.rendered || '',
media_type: item.media_type,
mime_type: item.mime_type,
source_url: item.source_url,
date_created: item.date_created ?? item.date,
date_modified: item.date_modified ?? item.modified,
};
}
// 媒体操作方法
async getMedia(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedMediaDTO>> {
// 获取媒体列表并映射为统一媒体DTO集合
const { items, total, totalPages, page, per_page } = await this.wpService.fetchMediaPaged(
this.site,
params
);
return {
items: items.map(this.mapMedia.bind(this)),
total,
totalPages,
page,
per_page,
};
}
async getAllMedia(params?: UnifiedSearchParamsDTO): Promise<UnifiedMediaDTO[]> {
// 使用sdkGetAll获取所有媒体数据不受分页限制
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const media = await this.wpService.sdkGetAll(api, 'media', params);
return media.map((mediaItem: any) => this.mapMedia(mediaItem));
}
createMedia(file: any): Promise<UnifiedMediaDTO> {
throw new Error('Method not implemented.');
}
async updateMedia(id: string | number, data: any): Promise<any> {
// 更新媒体信息
return await this.wpService.updateMedia(Number(this.site.id), Number(id), data);
}
async deleteMedia(id: string | number): Promise<boolean> {
// 删除媒体资源
await this.wpService.deleteMedia(Number(this.site.id), Number(id), true);
return true;
}
async convertMediaToWebp(ids: Array<string | number>): Promise<{ converted: any[]; failed: any[] }> {
// 函数说明 调用服务层将站点的指定媒体批量转换为 webp 并上传
const result = await this.wpService.convertMediaToWebp(Number(this.site.id), ids);
return result as any;
}
// ========== 订单映射方法 ==========
mapPlatformToUnifiedOrder(data: any): UnifiedOrderDTO {
return data;
}
mapUnifiedToPlatformOrder(data: Partial<UnifiedOrderDTO>) {
return data;
}
mapCreateOrderParams(data: Partial<UnifiedOrderDTO>) {
return data;
}
mapUpdateOrderParams(data: Partial<UnifiedOrderDTO>) {
return data;
}
mapOrderSearchParams(params: UnifiedSearchParamsDTO): Partial<WooOrderSearchParams> {
// 计算分页参数
const page = Number(params.page ?? 1);
const per_page = Number(params.per_page ?? 20);
// 解析排序参数 支持从 order 对象推导
const where = params.where && typeof params.where === 'object' ? params.where : {};
// if (params.orderBy && typeof params.orderBy === 'object') {
// }
const mapped: any = {
...(params.search ? { search: params.search } : {}),
// ...(orderBy ? { orderBy } : {}),
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.before ?? where.date_created_before ?? where.created_before) mapped.before = String(where.before ?? where.date_created_before ?? where.created_before);
if (where.modified_after ?? where.date_modified_after) mapped.modified_after = String(where.modified_after ?? where.date_modified_after);
if (where.modified_before ?? where.date_modified_before) mapped.modified_before = String(where.modified_before ?? where.date_modified_before);
if (where.dates_are_gmt ?? where.datesAreGmt) mapped.dates_are_gmt = Boolean(where.dates_are_gmt ?? where.datesAreGmt);
// 集合过滤参数
if (where.exclude) mapped.exclude = toArray(where.exclude);
if (where.include) mapped.include = toArray(where.include);
if (where.ids) mapped.include = toArray(where.ids);
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);
// 状态过滤 参数支持数组或逗号分隔字符串
const statusSource = where.status;
if (statusSource !== undefined) {
mapped.status = Array.isArray(statusSource)
? statusSource.map(s => String(s))
: String(statusSource).split(',').map(s => s.trim()).filter(Boolean);
}
// 客户与产品过滤
const customerVal = where.customer ?? where.customer_id;
const productVal = where.product ?? where.product_id;
const dpVal = where.dp;
if (toNumber(customerVal) !== undefined) mapped.customer = Number(customerVal);
if (toNumber(productVal) !== undefined) mapped.product = Number(productVal);
if (toNumber(dpVal) !== undefined) mapped.dp = Number(dpVal);
// 创建来源过滤 支持逗号分隔
const createdViaVal = where.created_via;
if (createdViaVal !== undefined) mapped.created_via = Array.isArray(createdViaVal)
? createdViaVal.join(',')
: String(createdViaVal);
return mapped;
}
private buildFullAddress(addr: any): string {
if (!addr) return '';
const name = addr.fullname || `${addr.first_name || ''} ${addr.last_name || ''}`.trim();
return [
name,
addr.company,
addr.address_1,
addr.address_2,
addr.city,
addr.state,
addr.postcode,
addr.country,
addr.phone
].filter(Boolean).join(', ');
}
mapOrder(item: WooOrder): UnifiedOrderDTO {
// 将 WooCommerce 订单数据映射为统一订单DTO
// 包含账单地址与收货地址以及创建与更新时间
// 映射物流追踪信息,将后端格式转换为前端期望的格式
const fulfillments = (item.fulfillments || []).map((track: any) => ({
tracking_number: track.tracking_number || '',
shipping_provider: track.shipping_provider || '',
shipping_method: track.shipping_method || '',
status: track.status || '',
date_created: track.date_created || '',
items: track.items || [],
}));
return {
id: item.id,
number: item.number,
status: item.status,
currency: item.currency,
total: item.total,
customer_id: item.customer_id,
customer_email: item.billing?.email || '', // TODO 与 email 重复 保留一个即可
email: item.billing?.email || '',
customer_name: `${item.billing?.first_name || ''} ${item.billing?.last_name || ''}`.trim(),
refunds: item.refunds?.map?.(refund => ({
id: refund.id,
reason: refund.reason,
total: refund.total,
})),
line_items: (item.line_items as any[]).map(li => ({
...li,
productId: li.product_id,
})),
customer_ip_address: item.customer_ip_address ?? '',
date_paid: item.date_paid ?? '',
utm_source: item?.meta_data?.find(el => el.key === '_wc_order_attribution_utm_source')?.value || '',
device_type: item?.meta_data?.find(el => el.key === '_wc_order_attribution_device_type')?.value || '',
source_type: item?.meta_data?.find(el => el.key === '_wc_order_attribution_source_type')?.value || '',
billing: item.billing,
shipping: item.shipping,
billing_full_address: this.buildFullAddress(item.billing),
shipping_full_address: this.buildFullAddress(item.shipping),
payment_method: item.payment_method_title,
date_created: item.date_created,
date_modified: item.date_modified,
shipping_lines: item.shipping_lines,
fee_lines: item.fee_lines,
coupon_lines: item.coupon_lines,
fulfillments,
raw: item,
};
}
// 订单操作方法
async getOrder(id: string | number): Promise<UnifiedOrderDTO> {
// 获取单个订单详情
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const res = await api.get(`orders/${id}`);
return this.mapOrder(res.data);
}
async getOrders(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedOrderDTO>> {
const requestParams = this.mapOrderSearchParams(params);
const { items, total, totalPages, page, per_page } = await this.wpService.fetchResourcePaged<any>(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.mapOrder),
total,
totalPages,
page,
per_page,
};
}
async getAllOrders(params?: UnifiedSearchParamsDTO): Promise<UnifiedOrderDTO[]> {
// 使用sdkGetAll获取所有订单数据不受分页限制
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const orders = await this.wpService.sdkGetAll(api, 'orders', params);
return orders.map((order: any) => this.mapOrder(order));
}
async countOrders(where: Record<string, any>): Promise<number> {
// 使用最小分页只获取总数
const searchParams: UnifiedSearchParamsDTO = {
where,
page: 1,
per_page: 1,
};
const requestParams = this.mapOrderSearchParams(searchParams);
const { total } = await this.wpService.fetchResourcePaged<any>(this.site, 'orders', requestParams);
return total || 0;
}
async createOrder(data: Partial<UnifiedOrderDTO>): Promise<UnifiedOrderDTO> {
// 创建订单并返回统一订单DTO
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const res = await api.post('orders', data);
return this.mapOrder(res.data);
}
async updateOrder(id: string | number, data: Partial<UnifiedOrderDTO>): Promise<boolean> {
// 更新订单并返回布尔结果
return await this.wpService.updateOrder(this.site, String(id), data as any);
}
async deleteOrder(id: string | number): Promise<boolean> {
// 删除订单
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
await api.delete(`orders/${id}`, { force: true });
return true;
}
async getOrderFulfillments(orderId: string | number): Promise<any[]> {
return await this.wpService.getFulfillments(this.site, String(orderId));
}
async createOrderFulfillment(orderId: string | number, data: {
tracking_number: string;
shipping_provider: string;
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,
};
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);
return response.data;
}
async updateOrderFulfillment(orderId: string | number, fulfillmentId: string, data: {
tracking_number?: string;
shipping_provider?: string;
shipping_method?: string;
status?: string;
date_created?: string;
items?: Array<{
order_item_id: number;
quantity: number;
}>;
}): Promise<any> {
return await this.wpService.updateFulfillment(this.site, String(orderId), fulfillmentId, data);
}
async deleteOrderFulfillment(orderId: string | number, fulfillmentId: string): Promise<boolean> {
return await this.wpService.deleteFulfillment(this.site, String(orderId), fulfillmentId);
}
async getOrderNotes(orderId: string | number): Promise<any[]> {
// 获取订单备注列表
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const res = await api.get(`orders/${orderId}/notes`);
return res.data;
}
async createOrderNote(orderId: string | number, data: any): Promise<any> {
// 创建订单备注
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const res = await api.post(`orders/${orderId}/notes`, data);
return res.data;
}
async cancelFulfillment(orderId: string | number, data: {
reason?: string;
shipment_id?: string;
}): Promise<any> {
throw new Error('暂未实现');
// 取消订单履行
// const api = (this.wpService as any).createApi(this.site, 'wc/v3');
// try {
// // 将订单状态改回处理中
// await api.put(`orders/${orderId}`, { status: 'processing' });
// // 添加取消履行的备注
// const note = `订单履行已取消${data.reason ? `,原因:${data.reason}` : ''}`;
// await api.post(`orders/${orderId}/notes`, { note, customer_note: true });
// return {
// success: true,
// order_id: orderId,
// shipment_id: data.shipment_id,
// reason: data.reason,
// cancelled_at: new Date().toISOString()
// };
// } catch (error) {
// throw new Error(`取消履行失败: ${error.message}`);
// }
}
// ========== 产品映射方法 ==========
mapPlatformToUnifiedProduct(data: any): UnifiedProductDTO {
return data;
}
mapUnifiedToPlatformProduct(data: Partial<UnifiedProductDTO>) {
return data;
}
mapCreateProductParams(data: Partial<UnifiedProductDTO>) {
return data;
}
mapUpdateProductParams(data: Partial<UnifiedProductDTO>) {
return data;
}
mapProductSearchParams(params: UnifiedSearchParamsDTO): Partial<WooProductSearchParams> {
const page = Number(params.page ?? 1);
const per_page = Number(params.per_page ?? 20);
const where = params.where && typeof params.where === 'object' ? params.where : {};
const mapped: any = {
...(params.search ? { search: params.search } : {}),
...(where.status ? { status: where.status } : {}),
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);
};
if (where.search_fields ?? where.searchFields) mapped.search_fields = toArray(where.search_fields ?? where.searchFields);
if (where.after ?? where.date_created_after ?? where.created_after) mapped.after = String(where.after ?? where.date_created_after ?? where.created_after);
if (where.before ?? where.date_created_before ?? where.created_before) mapped.before = String(where.before ?? where.date_created_before ?? where.created_before);
if (where.modified_after ?? where.date_modified_after) mapped.modified_after = String(where.modified_after ?? where.date_modified_after);
if (where.modified_before ?? where.date_modified_before) mapped.modified_before = String(where.modified_before ?? where.date_modified_before);
if (where.dates_are_gmt ?? where.datesAreGmt) mapped.dates_are_gmt = Boolean(where.dates_are_gmt ?? where.datesAreGmt);
if (where.exclude ?? where.exclude_ids ?? where.excludedIds) mapped.exclude = toArray(where.exclude ?? where.exclude_ids ?? where.excludedIds);
if (where.include ?? where.ids) mapped.include = toArray(where.include ?? where.ids);
if (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);
if (where.slug) mapped.slug = String(where.slug);
if (!mapped.status && (where.status || where.include_status || where.exclude_status || where.includeStatus || where.excludeStatus)) {
if (where.include_status ?? where.includeStatus) mapped.include_status = String(where.include_status ?? where.includeStatus);
if (where.exclude_status ?? where.excludeStatus) mapped.exclude_status = String(where.exclude_status ?? where.excludeStatus);
if (where.status) mapped.status = String(where.status);
}
if (where.type) mapped.type = String(where.type);
if (where.include_types ?? where.includeTypes) mapped.include_types = String(where.include_types ?? where.includeTypes);
if (where.exclude_types ?? where.excludeTypes) mapped.exclude_types = String(where.exclude_types ?? where.excludeTypes);
if (where.sku) mapped.sku = String(where.sku);
if (where.featured ?? where.isFeatured) mapped.featured = Boolean(where.featured ?? where.isFeatured);
if (where.category ?? where.categoryId) mapped.category = String(where.category ?? where.categoryId);
if (where.tag ?? where.tagId) mapped.tag = String(where.tag ?? where.tagId);
if (where.shipping_class ?? where.shippingClass) mapped.shipping_class = String(where.shipping_class ?? where.shippingClass);
if (where.attribute ?? where.attributeName) mapped.attribute = String(where.attribute ?? where.attributeName);
if (where.attribute_term ?? where.attributeTermId ?? where.attributeTerm) mapped.attribute_term = String(where.attribute_term ?? where.attributeTermId ?? where.attributeTerm);
if (where.tax_class ?? where.taxClass) mapped.tax_class = String(where.tax_class ?? where.taxClass);
if (where.on_sale ?? where.onSale) mapped.on_sale = Boolean(where.on_sale ?? where.onSale);
if (where.min_price ?? where.minPrice) mapped.min_price = String(where.min_price ?? where.minPrice);
if (where.max_price ?? where.maxPrice) mapped.max_price = String(where.max_price ?? where.maxPrice);
if (where.stock_status ?? where.stockStatus) mapped.stock_status = String(where.stock_status ?? where.stockStatus);
if (where.virtual !== undefined) mapped.virtual = Boolean(where.virtual);
if (where.downloadable !== undefined) mapped.downloadable = Boolean(where.downloadable);
if (where.search_fields ?? where.searchFields) mapped.search_fields = toArray(where.search_fields ?? where.searchFields);
if (where.after ?? where.date_created_after ?? where.created_after) mapped.after = String(where.after ?? where.date_created_after ?? where.created_after);
if (where.before ?? where.date_created_before ?? where.created_before) mapped.before = String(where.before ?? where.date_created_before ?? where.created_before);
if (where.modified_after ?? where.date_modified_after) mapped.modified_after = String(where.modified_after ?? where.date_modified_after);
if (where.modified_before ?? where.date_modified_before) mapped.modified_before = String(where.modified_before ?? where.date_modified_before);
if (where.dates_are_gmt ?? where.datesAreGmt) mapped.dates_are_gmt = Boolean(where.dates_are_gmt ?? where.datesAreGmt);
if (where.exclude ?? where.exclude_ids ?? where.excludedIds) mapped.exclude = toArray(where.exclude ?? where.exclude_ids ?? where.excludedIds);
if (where.include ?? where.ids) mapped.include = toArray(where.include ?? where.ids);
if (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);
if (where.slug) mapped.slug = String(where.slug);
if (!mapped.status && (where.status || where.include_status || where.exclude_status || where.includeStatus || where.excludeStatus)) {
if (where.include_status ?? where.includeStatus) mapped.include_status = String(where.include_status ?? where.includeStatus);
if (where.exclude_status ?? where.excludeStatus) mapped.exclude_status = String(where.exclude_status ?? where.excludeStatus);
if (where.status) mapped.status = String(where.status);
}
if (where.type) mapped.type = String(where.type);
if (where.include_types ?? where.includeTypes) mapped.include_types = String(where.include_types ?? where.includeTypes);
if (where.exclude_types ?? where.excludeTypes) mapped.exclude_types = String(where.exclude_types ?? where.excludeTypes);
if (where.sku) mapped.sku = String(where.sku);
if (where.featured ?? where.isFeatured) mapped.featured = Boolean(where.featured ?? where.isFeatured);
if (where.category ?? where.categoryId) mapped.category = String(where.category ?? where.categoryId);
if (where.tag ?? where.tagId) mapped.tag = String(where.tag ?? where.tagId);
if (where.shipping_class ?? where.shippingClass) mapped.shipping_class = String(where.shipping_class ?? where.shippingClass);
if (where.attribute ?? where.attributeName) mapped.attribute = String(where.attribute ?? where.attributeName);
if (where.attribute_term ?? where.attributeTermId ?? where.attributeTerm) mapped.attribute_term = String(where.attribute_term ?? where.attributeTermId ?? where.attributeTerm);
if (where.tax_class ?? where.taxClass) mapped.tax_class = String(where.tax_class ?? where.taxClass);
if (where.on_sale ?? where.onSale) mapped.on_sale = Boolean(where.on_sale ?? where.onSale);
if (where.min_price ?? where.minPrice) mapped.min_price = String(where.min_price ?? where.minPrice);
if (where.max_price ?? where.maxPrice) mapped.max_price = String(where.max_price ?? where.maxPrice);
if (where.stock_status ?? where.stockStatus) mapped.stock_status = String(where.stock_status ?? where.stockStatus);
if (where.virtual !== undefined) mapped.virtual = Boolean(where.virtual);
if (where.downloadable !== undefined) mapped.downloadable = Boolean(where.downloadable);
return mapped;
}
mapProduct(item: WooProduct): UnifiedProductDTO {
// 将 WooCommerce 产品数据映射为统一产品DTO
// 保留常用字段与时间信息以便前端统一展示
// https://woocommerce.github.io/woocommerce-rest-api-docs/?javascript#product-properties
// 映射变体数据
const mappedVariations = item.variations && Array.isArray(item.variations)
? item.variations
.filter((variation: any) => typeof variation !== 'number') // 过滤掉数字类型的变体ID
.map((variation: any) => {
// 将变体属性转换为统一格式
const mappedAttributes = variation.attributes && Array.isArray(variation.attributes)
? variation.attributes.map((attr: any) => ({
id: attr.id,
name: attr.name || '',
position: attr.position,
visible: attr.visible,
variation: attr.variation,
option: attr.option || '' // 变体属性使用 option 而不是 options
}))
: [];
// 映射变体图片
const mappedImage = variation.image
? {
id: variation.image.id,
src: variation.image.src,
name: variation.image.name,
alt: variation.image.alt,
}
: undefined;
return {
id: variation.id,
name: variation.name || item.name, // 如果变体没有名称,使用父产品名称
sku: variation.sku || '',
regular_price: String(variation.regular_price || ''),
sale_price: String(variation.sale_price || ''),
price: String(variation.price || ''),
stock_status: variation.stock_status || 'outofstock',
stock_quantity: variation.stock_quantity || 0,
attributes: mappedAttributes,
image: mappedImage
};
})
: [];
return {
id: item.id,
date_created: item.date_created,
date_modified: item.date_modified,
type: item.type, // simple grouped external variable
status: item.status, // draft pending private publish
sku: item.sku,
name: item.name,
//价格
regular_price: item.regular_price,
sale_price: item.sale_price,
price: item.price,
stock_status: item.stock_status,
stock_quantity: item.stock_quantity,
images: (item.images || []).map((img: any) => ({
id: img.id,
src: img.src,
name: img.name,
alt: img.alt,
})),
categories: (item.categories || []).map((c: any) => ({
id: c.id,
name: c.name,
})),
tags: (item.tags || []).map((t: any) => ({
id: t.id,
name: t.name,
})),
attributes: (item.attributes || []).map(attr => ({
id: attr.id,
name: attr.name || '',
position: attr.position,
visible: attr.visible,
variation: attr.variation,
options: attr.options || []
})),
variations: mappedVariations,
permalink: item.permalink,
raw: item,
};
}
// 产品操作方法
async getProduct(id: string | number): Promise<UnifiedProductDTO> {
// 获取单个产品详情并映射为统一产品DTO
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const res = await api.get(`products/${id}`);
const product = res.data;
// 如果产品类型是 variable 且有变体 ID 列表,则加载完整的变体数据
if (product.type === 'variable' && product.variations && Array.isArray(product.variations) && product.variations.length > 0) {
try {
// 批量获取该产品的所有变体数据
const variations = await this.wpService.sdkGetAll(
api,
`products/${product.id}/variations`
);
// 将完整的变体数据添加到产品对象中
product.variations = variations;
} catch (error) {
// 如果获取变体失败,保持原有的 ID 数组
console.error(`获取产品 ${product.id} 的变体数据失败:`, error);
}
}
return this.mapProduct(product);
}
async getProducts(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedProductDTO>> {
async getProducts(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedProductDTO>> {
// 获取产品列表并使用统一分页结构返回
const requestParams = this.mapProductSearchParams(params);
const { items, total, totalPages, page, per_page } = await this.wpService.fetchResourcePaged<any>(
this.site,
'products',
requestParams
);
const { items, total, totalPages, page, per_page } = await this.wpService.fetchResourcePaged<any>(
this.site,
'products',
requestParams
);
// 对于类型为 variable 的产品,需要加载完整的变体数据
const productsWithVariations = await Promise.all(
items.map(async (item: any) => {
// 如果产品类型是 variable 且有变体 ID 列表,则加载完整的变体数据
if (item.type === 'variable' && item.variations && Array.isArray(item.variations) && item.variations.length > 0) {
try {
// 批量获取该产品的所有变体数据
const variations = await this.wpService.sdkGetAll(
(this.wpService as any).createApi(this.site, 'wc/v3'),
`products/${item.id}/variations`
);
// 将完整的变体数据添加到产品对象中
item.variations = variations;
} catch (error) {
// 如果获取变体失败,保持原有的 ID 数组
console.error(`获取产品 ${item.id} 的变体数据失败:`, error);
}
}
return item;
})
);
return {
items: productsWithVariations.map(this.mapPlatformToUnifiedProduct),
total,
totalPages,
page,
per_page,
};
}
async getAllProducts(params?: UnifiedSearchParamsDTO): Promise<UnifiedProductDTO[]> {
// 使用sdkGetAll获取所有产品数据不受分页限制
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const products = await this.wpService.sdkGetAll(api, 'products', params);
// 对于类型为 variable 的产品,需要加载完整的变体数据
const productsWithVariations = await Promise.all(
products.map(async (product: any) => {
// 如果产品类型是 variable 且有变体 ID 列表,则加载完整的变体数据
if (product.type === 'variable' && product.variations && Array.isArray(product.variations) && product.variations.length > 0) {
try {
// 批量获取该产品的所有变体数据
const variations = await this.wpService.sdkGetAll(
api,
`products/${product.id}/variations`
);
// 将完整的变体数据添加到产品对象中
product.variations = variations;
} catch (error) {
// 如果获取变体失败,保持原有的 ID 数组
console.error(`获取产品 ${product.id} 的变体数据失败:`, error);
}
}
return product;
})
);
return productsWithVariations.map((product: any) => this.mapProduct(product));
}
async createProduct(data: Partial<UnifiedProductDTO>): Promise<UnifiedProductDTO> {
// 创建产品并返回统一产品DTO
const res = await this.wpService.createProduct(this.site, data);
return this.mapPlatformToUnifiedProduct(res);
}
async updateProduct(where: {id?: string | number, sku?: string}, data: Partial<UnifiedProductDTO>): Promise<boolean> {
// 更新产品并返回统一产品DTO
const res = await this.wpService.updateProduct(this.site, String(id), data as any);
return res;
}
async deleteProduct(where: {id?: string | number, sku?: string}): Promise<boolean> {
// 删除产品
let productId: string;
if (where.id) {
productId = String(where.id);
} else if (where.sku) {
// 通过sku获取产品ID
const product = await this.getProductBySku(where.sku);
productId = String(product.id);
} else {
throw new Error('必须提供id或sku参数');
}
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
try {
await api.delete(`products/${productId}`, { force: true });
return true;
} catch (e) {
return false;
}
}
// ========== 评论映射方法 ==========
mapPlatformToUnifiedReview(data: any): UnifiedReviewDTO {
return data;
}
mapUnifiedToPlatformReview(data: Partial<UnifiedReviewDTO>) {
return data;
}
mapCreateReviewParams(data: CreateReviewDTO) {
return data;
}
mapUpdateReviewParams(data: UpdateReviewDTO) {
return data;
}
mapReview(item: any): UnifiedReviewDTO & { raw: any } {
// 将 WooCommerce 评论数据映射为统一评论DTO
return {
id: item.id,
product_id: item.product_id,
author: item.reviewer,
email: item.reviewer_email,
content: item.review,
rating: item.rating,
status: item.status,
date_created: item.date_created,
raw: item
};
}
// 评论操作方法
async getReviews(params: UnifiedSearchParamsDTO): Promise<UnifiedReviewPaginationDTO> {
// 评论操作方法
async getReviews(params: UnifiedSearchParamsDTO): Promise<UnifiedReviewPaginationDTO> {
// 获取评论列表并使用统一分页结构返回
const requestParams = this.mapProductSearchParams(params);
const { items, total, totalPages, page, per_page } = await this.wpService.fetchResourcePaged<any>(
this.site,
'products/reviews',
requestParams
);
const { items, total, totalPages, page, per_page } = await this.wpService.fetchResourcePaged<any>(
this.site,
'products/reviews',
requestParams
);
return {
items: items.map(this.mapPlatformToUnifiedReview.bind(this)),
total,
totalPages,
page,
per_page,
};
}
async getAllReviews(params?: UnifiedSearchParamsDTO): Promise<UnifiedReviewDTO[]> {
// 使用sdkGetAll获取所有评论数据不受分页限制
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const reviews = await this.wpService.sdkGetAll(api, 'products/reviews', params);
return reviews.map((review: any) => this.mapPlatformToUnifiedReview(review));
}
async createReview(data: any): Promise<UnifiedReviewDTO> {
const res = await this.wpService.createReview(this.site, data);
return this.mapPlatformToUnifiedReview(res);
}
async updateReview(where: {id: number}, data: any): Promise<UnifiedReviewDTO> {
const res = await this.wpService.updateReview(this.site, where.id, data);
return this.mapPlatformToUnifiedReview(res);
}
async deleteReview(id: number): Promise<boolean> {
return await this.wpService.deleteReview(this.site, id);
}
// ========== 订阅映射方法 ==========
mapPlatformToUnifiedSubscription(data: any): UnifiedSubscriptionDTO {
return data;
}
mapUnifiedToPlatformSubscription(data: Partial<UnifiedSubscriptionDTO>) {
return data;
}
mapSubscription(item: WooSubscription): UnifiedSubscriptionDTO {
// 将 WooCommerce 订阅数据映射为统一订阅DTO
// 若缺少创建时间则回退为开始时间
return {
id: item.id,
status: item.status,
customer_id: item.customer_id,
billing_period: item.billing_period,
billing_interval: item.billing_interval,
date_created: item.date_created ?? item.start_date,
status: item.status,
customer_id: item.customer_id,
billing_period: item.billing_period,
billing_interval: item.billing_interval,
date_created: item.date_created ?? item.start_date,
date_modified: item.date_modified,
start_date: item.start_date,
next_payment_date: item.next_payment_date,
line_items: item.line_items,
start_date: item.start_date,
next_payment_date: item.next_payment_date,
line_items: item.line_items,
raw: item,
};
}
// 订阅操作方法
async getSubscriptions(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedSubscriptionDTO>> {
// 获取订阅列表并映射为统一订阅DTO集合
// 订阅操作方法
async getSubscriptions(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedSubscriptionDTO>> {
// 获取订阅列表并映射为统一订阅DTO集合
const { items, total, totalPages, page, per_page } = await this.wpService.fetchResourcePaged<any>(
this.site,
'subscriptions',
params
'subscriptions',
params
);
return {
items: items.map(this.mapSubscription),
total,
totalPages,
page,
per_page,
};
}
async getAllSubscriptions(params?: UnifiedSearchParamsDTO): Promise<UnifiedSubscriptionDTO[]> {
// 使用sdkGetAll获取所有订阅数据不受分页限制
async getAllSubscriptions(params?: UnifiedSearchParamsDTO): Promise<UnifiedSubscriptionDTO[]> {
// 使用sdkGetAll获取所有订阅数据不受分页限制
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const subscriptions = await this.wpService.sdkGetAll(api, 'subscriptions', params);
return subscriptions.map((subscription: any) => this.mapSubscription(subscription));
}
// ========== 变体映射方法 ==========
mapPlatformToUnifiedVariation(data: any): UnifiedProductVariationDTO {
return data;
}
mapUnifiedToPlatformVariation(data: Partial<UnifiedProductVariationDTO>) {
return data;
// ========== 变体映射方法 ==========
mapPlatformToUnifiedVariation(data: any): UnifiedProductVariationDTO {
return data;
}
mapUnifiedToPlatformVariation(data: Partial<UnifiedProductVariationDTO>) {
return data;
}
// 映射 WooCommerce 变体到统一格式
mapVariation(variation: any, productName?: string): UnifiedProductVariationDTO {
// 将变体属性转换为统一格式
const mappedAttributes = variation.attributes && Array.isArray(variation.attributes)
? variation.attributes.map((attr: any) => ({
id: attr.id,
name: attr.name || '',
position: attr.position,
visible: attr.visible,
variation: attr.variation,
option: attr.option || ''
}))
: [];
// 映射变体图片
const mappedImage = variation.image
? {
id: variation.image.id,
src: variation.image.src,
name: variation.image.name,
alt: variation.image.alt,
}
: undefined;
return {
id: variation.id,
name: variation.name || productName || '',
sku: variation.sku || '',
regular_price: String(variation.regular_price || ''),
sale_price: String(variation.sale_price || ''),
price: String(variation.price || ''),
stock_status: variation.stock_status || 'outofstock',
stock_quantity: variation.stock_quantity || 0,
attributes: mappedAttributes,
image: mappedImage,
description: variation.description || '',
enabled: variation.status === 'publish',
downloadable: variation.downloadable || false,
virtual: variation.virtual || false,
manage_stock: variation.manage_stock || false,
weight: variation.weight || '',
length: variation.dimensions?.length || '',
width: variation.dimensions?.width || '',
height: variation.dimensions?.height || '',
shipping_class: variation.shipping_class || '',
tax_class: variation.tax_class || '',
menu_order: variation.menu_order || 0,
};
}
// 变体操作方法
// 变体操作方法
// 获取产品变体列表
async getVariations(productId: string | number, params: UnifiedSearchParamsDTO): Promise<UnifiedVariationPaginationDTO> {
try {
const page = Number(params.page ?? 1);
const per_page = Number(params.per_page ?? 20);
const result = await this.wpService.getVariations(this.site, Number(productId), page, per_page);
// 获取产品名称用于变体显示
const product = await this.wpService.getProduct(this.site, Number(productId));
const productName = product?.name || '';
return {
items: (result.items as any[]).map((variation: any) => this.mapVariation(variation, productName)),
total: result.total,
page: result.page,
per_page: result.per_page,
totalPages: result.totalPages,
};
} catch (error) {
throw new Error(`获取产品变体列表失败: ${error instanceof Error ? error.message : String(error)}`);
}
}
// 获取所有产品变体
async getAllVariations(productId: string | number, params?: UnifiedSearchParamsDTO): Promise<UnifiedProductVariationDTO[]> {
try {
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const variations = await this.wpService.sdkGetAll(api, `products/${productId}/variations`, params);
// 获取产品名称用于变体显示
const product = await this.wpService.getProduct(this.site, Number(productId));
const productName = product?.name || '';
return variations.map((variation: any) => this.mapVariation(variation, productName));
} catch (error) {
throw new Error(`获取所有产品变体失败: ${error instanceof Error ? error.message : String(error)}`);
}
}
// 获取单个产品变体
async getVariation(productId: string | number, variationId: string | number): Promise<UnifiedProductVariationDTO> {
try {
const variation = await this.wpService.getVariation(this.site, Number(productId), Number(variationId));
// 获取产品名称用于变体显示
const product = await this.wpService.getProduct(this.site, Number(productId));
const productName = product?.name || '';
return this.mapVariation(variation, productName);
} catch (error) {
throw new Error(`获取产品变体失败: ${error instanceof Error ? error.message : String(error)}`);
}
}
// 创建产品变体
async createVariation(productId: string | number, data: CreateVariationDTO): Promise<UnifiedProductVariationDTO> {
try {
// 将统一DTO转换为WooCommerce API格式
const createData: any = {
sku: data.sku,
regular_price: data.regular_price,
sale_price: data.sale_price,
stock_status: data.stock_status,
stock_quantity: data.stock_quantity,
description: data.description,
status: data.enabled ? 'publish' : 'draft',
downloadable: data.downloadable,
virtual: data.virtual,
manage_stock: data.manage_stock,
weight: data.weight,
dimensions: {
length: data.length,
width: data.width,
height: data.height,
},
shipping_class: data.shipping_class,
tax_class: data.tax_class,
menu_order: data.menu_order,
};
// 映射属性
if (data.attributes && Array.isArray(data.attributes)) {
createData.attributes = data.attributes.map(attr => ({
id: attr.id,
name: attr.name,
option: attr.option || attr.options?.[0] || '',
}));
}
// 映射图片
if (data.image) {
createData.image = {
id: data.image.id,
};
}
const variation = await this.wpService.createVariation(this.site, String(productId), createData);
// 获取产品名称用于变体显示
const product = await this.wpService.getProduct(this.site, Number(productId));
const productName = product?.name || '';
return this.mapVariation(variation, productName);
} catch (error) {
throw new Error(`创建产品变体失败: ${error instanceof Error ? error.message : String(error)}`);
}
}
// 更新产品变体
async updateVariation(productId: string | number, variationId: string | number, data: UpdateVariationDTO): Promise<UnifiedProductVariationDTO> {
try {
// 将统一DTO转换为WooCommerce API格式
const updateData: any = {
sku: data.sku,
regular_price: data.regular_price,
sale_price: data.sale_price,
stock_status: data.stock_status,
stock_quantity: data.stock_quantity,
description: data.description,
status: data.enabled !== undefined ? (data.enabled ? 'publish' : 'draft') : undefined,
downloadable: data.downloadable,
virtual: data.virtual,
manage_stock: data.manage_stock,
weight: data.weight,
shipping_class: data.shipping_class,
tax_class: data.tax_class,
menu_order: data.menu_order,
};
// 映射尺寸
if (data.length || data.width || data.height) {
updateData.dimensions = {};
if (data.length) updateData.dimensions.length = data.length;
if (data.width) updateData.dimensions.width = data.width;
if (data.height) updateData.dimensions.height = data.height;
}
// 映射属性
if (data.attributes && Array.isArray(data.attributes)) {
updateData.attributes = data.attributes.map(attr => ({
id: attr.id,
name: attr.name,
option: attr.option || attr.options?.[0] || '',
}));
}
// 映射图片
if (data.image) {
updateData.image = {
id: data.image.id,
};
}
const variation = await this.wpService.updateVariation(this.site, String(productId), String(variationId), updateData);
// 获取产品名称用于变体显示
const product = await this.wpService.getProduct(this.site, Number(productId));
const productName = product?.name || '';
return this.mapVariation(variation, productName);
} catch (error) {
throw new Error(`更新产品变体失败: ${error instanceof Error ? error.message : String(error)}`);
}
}
// 删除产品变体
async deleteVariation(productId: string | number, variationId: string | number): Promise<boolean> {
try {
await this.wpService.deleteVariation(this.site, String(productId), String(variationId));
return true;
} catch (error) {
throw new Error(`删除产品变体失败: ${error instanceof Error ? error.message : String(error)}`);
}
}
// ========== 网络钩子映射方法 ==========
mapPlatformToUnifiedWebhook(data: any): UnifiedWebhookDTO {
return data;
}
mapUnifiedToPlatformWebhook(data: Partial<UnifiedWebhookDTO>) {
return data;
}
mapCreateWebhookParams(data: CreateWebhookDTO) {
return data;
}
mapUpdateWebhookParams(data: UpdateWebhookDTO) {
return data;
}
// 映射 WooCommerce webhook 到统一格式
mapWebhook(webhook: WooWebhook): UnifiedWebhookDTO {
return {
id: webhook.id.toString(),
name: webhook.name,
status: webhook.status,
topic: webhook.topic,
delivery_url: webhook.delivery_url,
secret: webhook.secret,
api_version: webhook.api_version,
date_created: webhook.date_created,
date_modified: webhook.date_modified,
// metadata: webhook.meta_data || [],
};
}
// 网络钩子操作方法
// 获取站点的 webhooks 列表
async getWebhooks(params: UnifiedSearchParamsDTO): Promise<UnifiedWebhookPaginationDTO> {
try {
const result = await this.wpService.getWebhooks(this.site, params);
return {
items: (result.items as WooWebhook[]).map(this.mapWebhook),
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)}`);
}
}
// 获取所有webhooks
async getAllWebhooks(params?: UnifiedSearchParamsDTO): Promise<UnifiedWebhookDTO[]> {
try {
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const webhooks = await this.wpService.sdkGetAll(api, 'webhooks', params);
return webhooks.map((webhook: any) => this.mapWebhook(webhook));
} catch (error) {
throw new Error(`Failed to get all webhooks: ${error instanceof Error ? error.message : String(error)}`);
}
}
// 获取单个 webhook 详情
async getWebhook(id: string | number): Promise<UnifiedWebhookDTO> {
try {
const result = await this.wpService.getWebhook(this.site, id);
return this.mapWebhook(result as WooWebhook);
} catch (error) {
throw new Error(`Failed to get webhook: ${error instanceof Error ? error.message : String(error)}`);
}
}
// 创建新的 webhook
async createWebhook(data: CreateWebhookDTO): Promise<UnifiedWebhookDTO> {
try {
const params = {
name: data.name,
status: 'active', // 默认状态为活跃
topic: data.topic,
delivery_url: data.delivery_url,
secret: data.secret,
api_version: data.api_version || 'wp/v2',
};
const result = await this.wpService.createWebhook(this.site, params);
return this.mapWebhook(result as WooWebhook);
} catch (error) {
throw new Error(`Failed to create webhook: ${error instanceof Error ? error.message : String(error)}`);
}
}
// 更新现有的 webhook
async updateWebhook(id: string | number, data: UpdateWebhookDTO): Promise<UnifiedWebhookDTO> {
try {
const params = {
...(data.name ? { name: data.name } : {}),
...(data.status ? { status: data.status } : {}),
...(data.topic ? { topic: data.topic } : {}),
...(data.delivery_url ? { delivery_url: data.delivery_url } : {}),
...(data.secret ? { secret: data.secret } : {}),
...(data.api_version ? { api_version: data.api_version } : {}),
};
const result = await this.wpService.updateWebhook(this.site, id, params);
return this.mapWebhook(result as WooWebhook);
} catch (error) {
throw new Error(`Failed to update webhook: ${error instanceof Error ? error.message : String(error)}`);
}
}
// 删除指定的 webhook
async deleteWebhook(id: string | number): Promise<boolean> {
try {
await this.wpService.deleteWebhook(this.site, id);
return true;
} catch (error) {
throw new Error(`Failed to delete webhook: ${error instanceof Error ? error.message : String(error)}`);
}
}
// ========== 其他方法 ==========
async getLinks(): Promise<Array<{ title: string, url: string }>> {
const baseUrl = this.site.apiUrl;
const links = [
{ title: '访问网站', url: baseUrl },
{ title: '管理后台', url: `${baseUrl}/wp-admin/` },
{ title: '订单管理', url: `${baseUrl}/wp-admin/edit.php?post_type=shop_order` },
{ title: '产品管理', url: `${baseUrl}/wp-admin/edit.php?post_type=product` },
{ title: '客户管理', url: `${baseUrl}/wp-admin/users.php` },
{ title: '插件管理', url: `${baseUrl}/wp-admin/plugins.php` },
{ title: '主题管理', url: `${baseUrl}/wp-admin/themes.php` },
{ title: 'WooCommerce设置', url: `${baseUrl}/wp-admin/admin.php?page=wc-settings` },
{ title: 'WooCommerce报告', url: `${baseUrl}/wp-admin/admin.php?page=wc-reports` },
];
return links;
}
batchProcessOrders?(data: { create?: any[]; update?: any[]; delete?: Array<string | number>; }): Promise<any> {
throw new Error('Method not implemented.');
}
batchProcessCustomers?(data: { create?: any[]; update?: any[]; delete?: Array<string | number>; }): Promise<any> {
throw new Error('Method not implemented.');
}
}