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

797 lines
30 KiB
TypeScript

import { ISiteAdapter } from '../interface/site-adapter.interface';
import { IPlatformService } from '../interface/platform.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';
export class WooCommerceAdapter implements ISiteAdapter {
// 构造函数接收站点配置与服务实例
constructor(private site: Site, private wpService: IPlatformService) {
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)}`);
}
}
// 获取单个 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,
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 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 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 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,
};
}
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 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 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;
}
}