zksu
/
API
forked from yoone/API
1
0
Fork 0
API/src/adapter/woocommerce.adapter.ts

860 lines
33 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,
UnifiedPaginationDTO,
UnifiedProductDTO,
UnifiedSearchParamsDTO,
UnifiedSubscriptionDTO,
UnifiedCustomerDTO,
UnifiedReviewPaginationDTO,
UnifiedReviewDTO,
UnifiedWebhookDTO,
UnifiedWebhookPaginationDTO,
CreateWebhookDTO,
UpdateWebhookDTO,
} from '../dto/site-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';
export class WooCommerceAdapter implements ISiteAdapter {
// 构造函数接收站点配置与服务实例
constructor(private site: Site, private wpService: WPService) {
this.mapProduct = this.mapProduct.bind(this);
this.mapReview = this.mapReview.bind(this);
this.mapCustomer = this.mapCustomer.bind(this);
this.mapMedia = this.mapMedia.bind(this);
this.mapOrder = this.mapOrder.bind(this);
this.mapWebhook = this.mapWebhook.bind(this);
}
// 映射 WooCommerce webhook 到统一格式
private 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;
}
createMedia(file: any): Promise<UnifiedMediaDTO> {
throw new Error('Method not implemented.');
}
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.');
}
private 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);
return mapped;
}
private 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 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,
};
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;
}
private mapProduct(item: WooProduct): UnifiedProductDTO {
// 将 WooCommerce 产品数据映射为统一产品DTO
// 保留常用字段与时间信息以便前端统一展示
// https://woocommerce.github.io/woocommerce-rest-api-docs/?javascript#product-properties
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: item.variations as any,
permalink: item.permalink,
raw: item,
};
}
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(', ');
}
private mapOrder(item: WooOrder): UnifiedOrderDTO {
// 将 WooCommerce 订单数据映射为统一订单DTO
// 包含账单地址与收货地址以及创建与更新时间
return {
id: item.id,
number: item.number,
status: item.status,
currency: item.currency,
total: item.total,
customer_id: item.customer_id,
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,
})),
email: item.billing?.email || '',
line_items: (item.line_items as any[]).map(li => ({
...li,
productId: li.product_id,
})),
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,
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 || '',
customer_email: item?.billing?.email || '',
source_type: item?.meta_data?.find(el => el.key === '_wc_order_attribution_source_type')?.value || '',
raw: item,
};
}
private 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,
date_modified: item.date_modified,
start_date: item.start_date,
next_payment_date: item.next_payment_date,
line_items: item.line_items,
raw: item,
};
}
private 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 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
);
return {
items: items.map(this.mapProduct),
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);
return products.map((product: any) => this.mapProduct(product));
}
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}`);
return this.mapProduct(res.data);
}
async createProduct(data: Partial<UnifiedProductDTO>): Promise<UnifiedProductDTO> {
// 创建产品并返回统一产品DTO
const res = await this.wpService.createProduct(this.site, data);
return this.mapProduct(res);
}
async updateProduct(id: string | number, data: Partial<UnifiedProductDTO>): Promise<boolean> {
// 更新产品并返回统一产品DTO
const res = await this.wpService.updateProduct(this.site, String(id), data as any);
return res
}
async updateVariation(productId: string | number, variationId: string | number, data: any): Promise<any> {
// 更新变体信息并返回结果
const res = await this.wpService.updateVariation(this.site, String(productId), String(variationId), data);
return res;
}
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 deleteProduct(id: string | number): Promise<boolean> {
// 删除产品
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
try {
await api.delete(`products/${id}`, { force: true });
return true;
} catch (e) {
return false;
}
}
async batchProcessProducts(
data: { create?: any[]; update?: any[]; delete?: Array<string | number> }
): Promise<any> {
// 批量处理产品增删改
return await this.wpService.batchProcessProducts(this.site, 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);
return {
items: items.map(this.mapOrder),
total,
totalPages,
page,
per_page,
};
}
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 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 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 shipOrder(orderId: string | number, data: {
tracking_number?: string;
shipping_provider?: string;
shipping_method?: string;
items?: Array<{
order_item_id: number;
quantity: number;
}>;
}): Promise<any> {
throw new Error('暂无实现')
// 订单发货
// const api = (this.wpService as any).createApi(this.site, 'wc/v3');
// try {
// // 更新订单状态为已完成
// await api.put(`orders/${orderId}`, { status: 'completed' });
// // 如果提供了物流信息,添加到订单备注
// if (data.tracking_number || data.shipping_provider) {
// const note = `订单已发货${data.tracking_number ? `,物流单号:${data.tracking_number}` : ''}${data.shipping_provider ? `,物流公司:${data.shipping_provider}` : ''}`;
// await api.post(`orders/${orderId}/notes`, { note, customer_note: true });
// }
// return {
// success: true,
// order_id: orderId,
// shipment_id: `shipment_${orderId}_${Date.now()}`,
// tracking_number: data.tracking_number,
// shipping_provider: data.shipping_provider,
// shipped_at: new Date().toISOString()
// };
// } catch (error) {
// throw new Error(`发货失败: ${error.message}`);
// }
}
async cancelShipOrder(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}`);
// }
}
async getSubscriptions(
params: UnifiedSearchParamsDTO
): Promise<UnifiedPaginationDTO<UnifiedSubscriptionDTO>> {
// 获取订阅列表并映射为统一订阅DTO集合
const { items, total, totalPages, page, per_page } =
await this.wpService.fetchResourcePaged<any>(
this.site,
'subscriptions',
params
);
return {
items: items.map(this.mapSubscription),
total,
totalPages,
page,
per_page,
};
}
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));
}
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));
}
private 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> {
// 获取评论列表并使用统一分页结构返回
const requestParams = this.mapProductSearchParams(params);
const { items, total, totalPages, page, per_page } =
await this.wpService.fetchResourcePaged<any>(
this.site,
'products/reviews',
requestParams
);
return {
items: items.map(this.mapReview.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.mapReview(review));
}
async createReview(data: any): Promise<UnifiedReviewDTO> {
const res = await this.wpService.createReview(this.site, data);
return this.mapReview(res);
}
async updateReview(id: number, data: any): Promise<UnifiedReviewDTO> {
const res = await this.wpService.updateReview(this.site, id, data);
return this.mapReview(res);
}
async deleteReview(id: number): Promise<boolean> {
return await this.wpService.deleteReview(this.site, id);
}
async deleteMedia(id: string | number): Promise<boolean> {
// 删除媒体资源
await this.wpService.deleteMedia(Number(this.site.id), Number(id), true);
return true;
}
async updateMedia(id: string | number, data: any): Promise<any> {
// 更新媒体信息
return await this.wpService.updateMedia(Number(this.site.id), Number(id), data);
}
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;
}
private 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,
};
}
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');
const customers = await this.wpService.sdkGetAll(api, 'customers', params);
return customers.map((customer: any) => this.mapCustomer(customer));
}
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 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;
}
}