import { Inject, Provide } from '@midwayjs/core'; import axios, { AxiosRequestConfig } from 'axios'; import * as fs from 'fs'; import * as FormData from 'form-data'; import { SiteService } from './site.service'; import { Site } from '../entity/site.entity'; import { UnifiedReviewDTO } from '../dto/site-api.dto'; import { ShopyyReview } from '../dto/shopyy.dto'; import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto'; import { UnifiedSearchParamsDTO } from '../dto/api.dto'; /** * ShopYY平台服务实现 */ @Provide() export class ShopyyService { /** * 获取ShopYY评论列表 * @param site 站点配置 * @param params 查询参数 * @returns 分页评论列表 */ async getReviews(site: any, params: any): Promise { // ShopYY API: GET /reviews/list const { items, total, totalPages, page, per_page } = await this.fetchResourcePaged(site, 'comments/list', params); return { items: items.map(this.mapReview), total, totalPages, page, per_page }; } mapReview(review: ShopyyReview): UnifiedReviewDTO { return { id: review.id, product_id: review.product_id, // countryId: mapReview.country_id, // ip: mapReview.ip, rating: review.star, author: review.customer_name, email: review.customer_email, // reply_content: mapReview.reply_content, content: review.content, status: review.status.toString(), // is_image: mapReview.is_image, // images: mapReview.images, date_modified: review.updated_at ? new Date(review.updated_at * 1000).toISOString() : undefined, date_created: review.created_at ? new Date(review.created_at * 1000).toISOString() : undefined, raw: review } } /** * 获取单个ShopYY评论 * @param site 站点配置 * @param reviewId 评论ID * @returns 评论详情 */ async getReview(site: any, reviewId: string | number): Promise { // ShopYY API: GET /reviews/{id} const response = await this.request(site, `comments/${reviewId}`, 'GET'); return response.data; } /** * 创建ShopYY评论 * @param site 站点配置 * @param data 评论数据 * @returns 创建结果 */ async createReview(site: any, data: any): Promise { // ShopYY API: POST /reviews/create const response = await this.request(site, 'comments/create', 'POST', data); return response.data; } /** * 更新ShopYY评论 * @param site 站点配置 * @param reviewId 评论ID * @param data 更新数据 * @returns 更新结果 */ async updateReview(site: any, reviewId: string | number, data: any): Promise { // ShopYY API: POST /reviews/update/{id} const response = await this.request(site, `comments/update/${reviewId}`, 'POST', data); return response.data; } /** * 删除ShopYY评论 * @param site 站点配置 * @param reviewId 评论ID * @returns 删除结果 */ async deleteReview(site: any, reviewId: string | number): Promise { try { // ShopYY API: DELETE /reviews/delete/{id} await this.request(site, `comments/delete/${reviewId}`, 'DELETE'); return true; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '删除ShopYY评论失败'; throw new Error(`删除ShopYY评论失败: ${errorMessage}`); } } fetchMediaPaged(site: any, params: Record): Promise<{ items: any[]; total: number; totalPages: number; page: number; per_page: number; }> { throw new Error('Method not implemented.'); } convertMediaToWebp(siteId: number, mediaIds: Array): Promise<{ converted: any[]; failed: Array<{ id: number | string; error: string; }>; }> { throw new Error('Method not implemented.'); } getSubscriptions?(siteId: number): Promise { throw new Error('Method not implemented.'); } getCustomers(site: any): Promise { throw new Error('Method not implemented.'); } @Inject() private readonly siteService: SiteService; /** * 构建ShopYY API请求URL * @param baseUrl 基础URL * @param endpoint API端点 * @returns 完整URL */ private buildURL(baseUrl: string, endpoint: string): string { // ShopYY API URL格式:https://{shop}.shopyy.com/openapi/{version}/{endpoint} const base = baseUrl.replace(/\/$/, ''); const end = endpoint.replace(/^\//, ''); return `${base}/${end}`; } /** * 构建ShopYY API请求头 * @param site 站点配置 * @returns 请求头 */ private buildHeaders(site: Site): Record { if (!site?.token) { throw new Error(`获取站点${site?.name}数据,但失败,因为未设置站点令牌配置`) } return { 'Content-Type': 'application/json', token: site.token || '' }; } /** * 发送ShopYY API请求 * @param site 站点配置 * @param endpoint API端点 * @param method 请求方法 * @param data 请求数据 * @param params 请求参数 * @returns 响应数据 */ private async request(site: any, endpoint: string, method: string = 'GET', data: any = null, params: any = null): Promise { const url = this.buildURL(site.apiUrl, endpoint); const headers = this.buildHeaders(site); const config: AxiosRequestConfig = { url, method, headers, params, data }; try { const response = await axios(config); return response.data; } catch (error) { console.error('ShopYY API请求失败:', error.response?.data || error.message); throw error; } } /** * 通用分页获取资源 */ public async fetchResourcePaged(site: any, endpoint: string, params: Record = {}) { const page = Number(params.page || 1); const limit = Number(params.per_page ?? 20); const where = params.where && typeof params.where === 'object' ? params.where : {}; let orderby: string | undefined = params.orderby; let order: 'asc' | 'desc' | undefined = params.orderDir as any; if (!orderby && params.order && typeof params.order === 'object') { const entries = Object.entries(params.order as Record); if (entries.length > 0) { const [field, dir] = entries[0]; orderby = field; order = String(dir).toLowerCase() === 'desc' ? 'desc' : 'asc'; } } // 映射统一入参到平台入参 const requestParams = { ...where, ...(params.search ? { search: params.search } : {}), ...(params.status ? { status: params.status } : {}), ...(orderby ? { orderby } : {}), ...(order ? { order } : {}), page, limit }; const response = await this.request(site, endpoint, 'GET', null, requestParams); if (response?.code !== 0) { throw new Error(response?.msg) } return { items: (response.data.list || []) as T[], total: response.data?.paginate?.total || 0, totalPages: response.data?.paginate?.pageTotal || 0, page: response.data?.paginate?.current || requestParams.page, per_page: response.data?.paginate?.pagesize || requestParams.limit, }; } /** * 获取ShopYY产品列表 * @param site 站点配置 * @param page 页码 * @param pageSize 每页数量 * @returns 分页产品列表 */ async getProducts(site: any, page: number = 1, pageSize: number = 100): Promise { // ShopYY API: GET /products // 通过 fields 参数指定需要返回的字段,确保 handle 等关键信息被包含 const response = await this.request(site, 'products', 'GET', null, { page, page_size: pageSize, fields: 'id,name,sku,handle,status,type,stock_status,stock_quantity,images,regular_price,sale_price,tags,variations' }); return { items: response.data || [], total: response.meta?.pagination?.total || 0, totalPages: response.meta?.pagination?.total_pages || 0, page: response.meta?.pagination?.current_page || page, per_page: response.meta?.pagination?.per_page || pageSize }; } /** * 获取单个ShopYY产品 * @param site 站点配置 * @param productId 产品ID * @returns 产品详情 */ async getProduct(site: any, productId: string | number): Promise { // ShopYY API: GET /products/{id} const response = await this.request(site, `products/${productId}`, 'GET'); return response.data; } /** * 获取ShopYY产品变体列表 * @param site 站点配置 * @param productId 产品ID * @param page 页码 * @param pageSize 每页数量 * @returns 分页变体列表 */ async getVariations(site: any, productId: number, page: number = 1, pageSize: number = 100): Promise { // ShopYY API: GET /products/{id}/variations const response = await this.request(site, `products/${productId}/variations`, 'GET', null, { page, page_size: pageSize }); return { items: response.data || [], total: response.meta?.pagination?.total || 0, totalPages: response.meta?.pagination?.total_pages || 0, page: response.meta?.pagination?.current_page || page, per_page: response.meta?.pagination?.per_page || pageSize }; } /** * 获取ShopYY产品变体详情 * @param site 站点配置 * @param productId 产品ID * @param variationId 变体ID * @returns 变体详情 */ async getVariation(site: any, productId: number, variationId: number): Promise { // ShopYY API: GET /products/{product_id}/variations/{variation_id} const response = await this.request(site, `products/${productId}/variations/${variationId}`, 'GET'); return response.data; } mapOrderSearchParams(params: UnifiedSearchParamsDTO){ const { after, before, ...restParams } = params; return { ...restParams, ...(after ? { created_at_min: after } : {}), ...(before ? { created_at_max: before } : {}), } } /** * 获取ShopYY订单列表 * @param site 站点配置或站点ID * @param page 页码 * @param pageSize 每页数量 * @returns 分页订单列表 */ async getOrders(site: any | number, page: number = 1, pageSize: number = 100, params: UnifiedSearchParamsDTO = {}): Promise { // 如果传入的是站点ID,则获取站点配置 const siteConfig = typeof site === 'number' ? await this.siteService.get(site) : site; // ShopYY API: GET /orders const response = await this.request(siteConfig, 'orders', 'GET', null, { page, limit: pageSize, ...params }); return { items: response.data?.list || [], total: response?.data?.paginate?.total || 0, totalPages: response?.data?.paginate?.pageTotal || 0, page: response?.data?.paginate?.current || page, per_page: response?.data?.paginate?.pagesize || pageSize }; } async getAllOrders(site: any | number, params: Record = {}, maxPages: number = 10, concurrencyLimit: number = 100): Promise { const firstPage = await this.getOrders(site, 1, 100); const { items: firstPageItems, totalPages} = firstPage; // const { page = 1, per_page = 100 } = params; // 如果只有一页数据,直接返回 if (totalPages <= 1) { return firstPageItems; } // 限制最大页数,避免过多的并发请求 const actualMaxPages = Math.min(totalPages, maxPages); // 收集所有页面数据,从第二页开始 const allItems = [...firstPageItems]; let currentPage = 2; // 使用并发限制,避免一次性发起过多请求 while (currentPage <= actualMaxPages) { const batchPromises: Promise[] = []; const batchSize = Math.min(concurrencyLimit, actualMaxPages - currentPage + 1); // 创建当前批次的并发请求 for (let i = 0; i < batchSize; i++) { const page = currentPage + i; const pagePromise = this.getOrders(site, page, 100) .then(pageResult => pageResult.items) .catch(error => { console.error(`获取第 ${page} 页数据失败:`, error); return []; // 如果某页获取失败,返回空数组,不影响整体结果 }); batchPromises.push(pagePromise); } // 等待当前批次完成 const batchResults = await Promise.all(batchPromises); // 合并当前批次的数据 for (const pageItems of batchResults) { allItems.push(...pageItems); } // 移动到下一批次 currentPage += batchSize; } return allItems; } /** * 获取ShopYY订单详情 * @param siteId 站点ID * @param orderId 订单ID * @returns 订单详情 */ async getOrder(siteId: string, orderId: string): Promise { const site = await this.siteService.get(Number(siteId)); // ShopYY API: GET /orders/{id} const response = await this.request(site, `orders/${orderId}`, 'GET'); return response.data; } /** * 创建ShopYY产品 * @param site 站点配置 * @param data 产品数据 * @returns 创建结果 */ async createProduct(site: any, data: any): Promise { // ShopYY API: POST /products const response = await this.request(site, 'products', 'POST', data); return response.data; } /** * 更新ShopYY产品 * @param site 站点配置 * @param productId 产品ID * @param data 更新数据 * @returns 更新结果 */ async updateProduct(site: any, productId: string, data: any): Promise { try { // ShopYY API: PUT /products/{id} await this.request(site, `products/${productId}`, 'PUT', data); return true; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '更新ShopYY产品失败'; throw new Error(`更新ShopYY产品失败: ${errorMessage}`); } } /** * 更新ShopYY产品状态 * @param site 站点配置 * @param productId 产品ID * @param status 产品状态 * @param stockStatus 库存状态 * @returns 更新结果 */ async updateProductStatus(site: any, productId: string, status: string, stockStatus: string): Promise { // ShopYY产品状态映射 const shopyyStatus = status === 'publish' ? 1 : 0; const shopyyStockStatus = stockStatus === 'instock' ? 1 : 0; try { await this.request(site, `products/${productId}`, 'PUT', { status: shopyyStatus, stock_status: shopyyStockStatus }); return true; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '更新ShopYY产品状态失败'; throw new Error(`更新ShopYY产品状态失败: ${errorMessage}`); } } /** * 更新ShopYY产品变体 * @param site 站点配置 * @param productId 产品ID * @param variationId 变体ID * @param data 更新数据 * @returns 更新结果 */ async updateVariation(site: any, productId: string, variationId: string, data: any): Promise { try { // ShopYY API: PUT /products/{product_id}/variations/{variation_id} await this.request(site, `products/${productId}/variations/${variationId}`, 'PUT', data); return true; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '更新ShopYY产品变体失败'; throw new Error(`更新ShopYY产品变体失败: ${errorMessage}`); } } /** * 更新ShopYY订单 * @param site 站点配置 * @param orderId 订单ID * @param data 更新数据 * @returns 更新结果 */ async updateOrder(site: any, orderId: string, data: Record): Promise { try { // ShopYY API: PUT /orders/{id} await this.request(site, `orders/${orderId}`, 'PUT', data); return true; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '更新ShopYY订单失败'; throw new Error(`更新ShopYY订单失败: ${errorMessage}`); } } /** * 创建ShopYY履约信息 * @param site 站点配置 * @param orderId 订单ID * @param data 履约数据 * @returns 创建结果 */ async createFulfillment(site: Site, orderId: string, data: any): Promise { // ShopYY API: POST /orders/{id}/shipments const fulfillmentData = { tracking_number: data.tracking_number, carrier_code: data.carrier_code, carrier_name: data.carrier_name, shipping_method: data.shipping_method }; const response = await this.request(site, `orders/${orderId}/shipments`, 'POST', fulfillmentData); return response.data; } /** * 删除ShopYY履约信息 * @param site 站点配置 * @param orderId 订单ID * @param fulfillmentId 履约跟踪ID * @returns 删除结果 */ async deleteFulfillment(site: any, orderId: string, fulfillmentId: string): Promise { try { // ShopYY API: DELETE /orders/{order_id}/shipments/{fulfillment_id} await this.request(site, `orders/${orderId}/fulfillments/${fulfillmentId}`, 'DELETE'); return true; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '删除ShopYY履约信息失败'; throw new Error(`删除ShopYY履约信息失败: ${errorMessage}`); } } /** * 获取ShopYY订单履约跟踪信息 * @param site 站点配置 * @param orderId 订单ID * @returns 履约跟踪信息列表 */ async getFulfillments(site: any, orderId: string): Promise { try { // ShopYY API: GET /orders/{id}/shipments const response = await this.request(site, `orders/${orderId}/fulfillments`, 'GET'); // 返回履约跟踪信息列表 return response.data || []; } catch (error) { // 如果订单没有履约跟踪信息,返回空数组 if (error.response?.status === 404) { return []; } const errorMessage = error.response?.data?.msg || error.message || '获取履约跟踪信息失败'; throw new Error(`获取履约跟踪信息失败: ${errorMessage}`); } } /** * 更新ShopYY订单履约跟踪信息 * @param site 站点配置 * @param orderId 订单ID * @param trackingId 履约跟踪ID * @param data 更新数据 * @returns 更新结果 */ async updateFulfillment(site: any, orderId: string, trackingId: string, data: { tracking_number?: string; tracking_provider?: string; date_shipped?: string; status_shipped?: string; }): Promise { try { // ShopYY API: PUT /orders/{order_id}/shipments/{tracking_id} const fulfillmentData: any = {}; // 只传递有值的字段 if (data.tracking_number !== undefined) { fulfillmentData.tracking_number = data.tracking_number; } if (data.tracking_provider !== undefined) { fulfillmentData.carrier_name = data.tracking_provider; } if (data.date_shipped !== undefined) { fulfillmentData.shipped_at = data.date_shipped; } if (data.status_shipped !== undefined) { fulfillmentData.status = data.status_shipped; } const response = await this.request(site, `orders/${orderId}/fulfillments/${trackingId}`, 'PUT', fulfillmentData); return response.data; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '更新履约跟踪信息失败'; throw new Error(`更新履约跟踪信息失败: ${errorMessage}`); } } /** * 获取ShopYY订单备注 * @param site 站点配置 * @param orderId 订单ID * @param page 页码 * @param pageSize 每页数量 * @returns 分页订单备注列表 */ async getOrderNotes(site: any, orderId: string | number, page: number = 1, pageSize: number = 100): Promise { // ShopYY API: GET /orders/{id}/notes const response = await this.request(site, `orders/${orderId}/notes`, 'GET', null, { page, page_size: pageSize }); return { items: response.data || [], total: response.meta?.pagination?.total || 0, totalPages: response.meta?.pagination?.total_pages || 0, page: response.meta?.pagination?.current_page || page, per_page: response.meta?.pagination?.per_page || pageSize }; } /** * 创建ShopYY订单备注 * @param site 站点配置 * @param orderId 订单ID * @param data 备注数据 * @returns 创建结果 */ async createOrderNote(site: any, orderId: string | number, data: any): Promise { // ShopYY API: POST /orders/{id}/notes const noteData = { note: data.note, is_customer_note: data.is_customer_note || false }; const response = await this.request(site, `orders/${orderId}/notes`, 'POST', noteData); return response.data; } /** * 创建ShopYY订单 * @param site 站点配置 * @param data 订单数据 * @returns 创建结果 */ async createOrder(site: any, data: any): Promise { // ShopYY API: POST /orders const response = await this.request(site, 'orders', 'POST', data); return response.data; } /** * 删除ShopYY订单 * @param site 站点配置 * @param orderId 订单ID * @returns 删除结果 */ async deleteOrder(site: any, orderId: string | number): Promise { try { // ShopYY API: DELETE /orders/{id} await this.request(site, `orders/${orderId}`, 'DELETE'); return true; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '删除ShopYY订单失败'; throw new Error(`删除ShopYY订单失败: ${errorMessage}`); } } /** * 批量处理ShopYY产品 * @param site 站点配置 * @param data 批量操作数据 * @returns 处理结果 */ async batchProcessProducts(site: any, data: BatchOperationDTO): Promise { // ShopYY API: POST /products/batch const response = await this.request(site, 'products/batch', 'POST', data); const result = response.data; // 转换 ShopYY 批量操作结果为统一格式 const errors: Array<{identifier: string, error: string}> = []; // 假设 ShopYY 返回格式与 WooCommerce 类似: { create: [...], update: [...], delete: [...] } // 错误信息可能在每个项目的 error 字段中 const checkForErrors = (items: any[]) => { items.forEach(item => { if (item.error) { errors.push({ identifier: String(item.id || item.sku || 'unknown'), error: typeof item.error === 'string' ? item.error : JSON.stringify(item.error) }); } }); }; // 检查每个操作类型的结果中的错误 if (result.create) checkForErrors(result.create); if (result.update) checkForErrors(result.update); if (result.delete) checkForErrors(result.delete); return { total: (data.create?.length || 0) + (data.update?.length || 0) + (data.delete?.length || 0), processed: (result.create?.length || 0) + (result.update?.length || 0) + (result.delete?.length || 0), created: result.create?.length || 0, updated: result.update?.length || 0, deleted: result.delete?.length || 0, errors: errors }; } /** * 获取ShopYY客户列表 * @param site 站点配置 * @param params 查询参数 * @returns 分页客户列表 */ async fetchCustomersPaged(site: any, params: any): Promise { // ShopYY API: GET /customers const { items, total, totalPages, page, per_page } = await this.fetchResourcePaged(site, 'customers/list', params); return { items, total, totalPages, page, per_page }; } /** * 获取单个ShopYY客户 * @param site 站点配置 * @param customerId 客户ID * @returns 客户详情 */ async getCustomer(site: any, customerId: string | number): Promise { // ShopYY API: GET /customers/{id} const response = await this.request(site, `customers/${customerId}`, 'GET'); return response.data; } /** * 创建ShopYY客户 * @param site 站点配置 * @param data 客户数据 * @returns 创建结果 */ async createCustomer(site: any, data: any): Promise { // ShopYY API: POST /customers const customerData = { firstname: data.first_name || '', lastname: data.last_name || '', email: data.email || '', phone: data.phone || '', password: data.password || '' }; const response = await this.request(site, 'customers', 'POST', customerData); return response.data; } /** * 更新ShopYY客户 * @param site 站点配置 * @param customerId 客户ID * @param data 更新数据 * @returns 更新结果 */ async updateCustomer(site: any, customerId: string | number, data: any): Promise { // ShopYY API: PUT /customers/{id} const customerData = { firstname: data.first_name || '', lastname: data.last_name || '', email: data.email || '', phone: data.phone || '' }; const response = await this.request(site, `customers/${customerId}`, 'PUT', customerData); return response.data; } /** * 删除ShopYY客户 * @param site 站点配置 * @param customerId 客户ID * @returns 删除结果 */ async deleteCustomer(site: any, customerId: string | number): Promise { try { // ShopYY API: DELETE /customers/{id} await this.request(site, `customers/${customerId}`, 'DELETE'); return true; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '删除ShopYY客户失败'; throw new Error(`删除ShopYY客户失败: ${errorMessage}`); } } /** * 创建ShopYY媒体 * @param site 站点配置 * @param file 文件 * @returns 创建结果 */ async createMedia(site: any, file: any): Promise { // ShopYY API: POST /media/create const response = await this.requestWithFormData(site, 'media/create', { file: fs.createReadStream(file.filepath), }); return response.data; } /** * 更新ShopYY媒体 * @param site 站点配置 * @param mediaId 媒体ID * @param data 更新数据 * @returns 更新结果 */ async updateMedia(site: any, mediaId: string | number, data: any): Promise { // ShopYY API: POST /media/update/{id} const response = await this.requestWithFormData(site, `media/update/${mediaId}`, data); return response.data; } /** * 删除ShopYY媒体 * @param site 站点配置 * @param mediaId 媒体ID * @returns 删除结果 */ async deleteMedia(site: any, mediaId: string | number): Promise { try { // ShopYY API: DELETE /media/delete/{id} await this.request(site, `media/delete/${mediaId}`, 'DELETE'); return true; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '删除ShopYY媒体失败'; throw new Error(`删除ShopYY媒体失败: ${errorMessage}`); } } /** * 使用multipart/form-data发送ShopYY API请求 * @param site 站点配置 * @param endpoint API端点 * @param formData 表单数据 * @returns 响应数据 */ private async requestWithFormData(site: any, endpoint: string, formData: Record): Promise { const url = this.buildURL(site.apiUrl, endpoint); const headers = this.buildHeaders(site); const form = new FormData(); for (const key in formData) { form.append(key, formData[key]); } const config: AxiosRequestConfig = { url, method: 'POST', headers: { ...headers, ...form.getHeaders(), }, data: form, }; try { const response = await axios(config); return response.data; } catch (error) { console.error('ShopYY API (form-data)请求失败:', error.response?.data || error.message); throw error; } } /** * 构建产品链接 * @param site 站点信息 * @param product 产品信息 * @param preview 是否是预览链接 * @returns */ buildProductPermalink(site: Site, product: any, preview = false): string { // 确保 product 和 product.handle 存在 if (!product || !product.handle) { // 如果 product 或 product.handle 不存在, 返回空字符串 return ''; } // 移除 websiteUrl 末尾的斜杠 (如果有) const websiteUrl = site.websiteUrl.endsWith('/') ? site.websiteUrl.slice(0, -1) : site.websiteUrl; // 拼接 URL let permalink = `${websiteUrl}/products/${product.handle}`; // 如果是预览, 添加预览参数 if (preview) { permalink += '?preview=1'; } // 返回拼接后的产品 URL return permalink; } getApiClient(site: any): any { throw new Error('Method not implemented.'); } /** * 获取ShopYY webhook列表 * @param site 站点配置 * @param params 查询参数 * @returns 分页webhook列表 */ async getWebhooks(site: any, params: any): Promise { // ShopYY API: GET /webhooks const { items, total, totalPages, page, per_page } = await this.fetchResourcePaged(site, 'webhooks', params); return { items, total, totalPages, page, per_page }; } /** * 获取单个ShopYY webhook * @param site 站点配置 * @param webhookId webhook ID * @returns webhook详情 */ async getWebhook(site: any, webhookId: string | number): Promise { // ShopYY API: GET /webhooks/{id} const response = await this.request(site, `webhooks/${webhookId}`, 'GET'); return response.data; } /** * 创建ShopYY webhook * @param site 站点配置 * @param data webhook数据 * @returns 创建结果 */ async createWebhook(site: any, data: any): Promise { // ShopYY API: POST /webhooks const response = await this.request(site, 'webhooks', 'POST', data); return response.data; } /** * 更新ShopYY webhook * @param site 站点配置 * @param webhookId webhook ID * @param data 更新数据 * @returns 更新结果 */ async updateWebhook(site: any, webhookId: string | number, data: any): Promise { // ShopYY API: PUT /webhooks/{id} const response = await this.request(site, `webhooks/${webhookId}`, 'PUT', data); return response.data; } /** * 删除ShopYY webhook * @param site 站点配置 * @param webhookId webhook ID * @returns 删除结果 */ async deleteWebhook(site: any, webhookId: string | number): Promise { try { // ShopYY API: DELETE /webhooks/{id} await this.request(site, `webhooks/${webhookId}`, 'DELETE'); return true; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '删除ShopYY webhook失败'; throw new Error(`删除ShopYY webhook失败: ${errorMessage}`); } } /** * 批量履约订单 * @param site 站点配置 * @param data 履约数据 * @returns 履约结果 */ async batchFulfillOrders(site: any, data: { order_number: string; tracking_company: string; tracking_number: string; courier_code: number; note: string; mode: "replace" | 'cover' | null; }): Promise { try { // ShopYY API: POST /orders/fulfillment/batch const response = await this.request(site, 'orders/fulfillment/batch', 'POST', data); return response.data; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '批量履约订单失败'; throw new Error(`批量履约订单失败: ${errorMessage}`); } } /** * 部分履约订单 * @param site 站点配置 * @param data 部分履约数据 * @returns 履约结果 */ async partFulfillOrder(site: any, data: { order_number: string; note: string; tracking_company: string; tracking_number: string; courier_code: string; products: Array<{ quantity: number; order_product_id: string; }>; }): Promise { try { // ShopYY API: POST /orders/fulfillment/part const response = await this.request(site, 'orders/fulfillment/part', 'POST', data); return response.data; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '部分履约订单失败'; throw new Error(`部分履约订单失败: ${errorMessage}`); } } /** * 取消履约订单 * @param site 站点配置 * @param data 取消履约数据 * @returns 取消结果 */ async cancelFulfillment(site: any, data: { order_id: string; fullfillment_id: string; }): Promise { try { // ShopYY API: POST /orders/fulfillment/cancel const response = await this.request(site, 'orders/fulfillment/cancel', 'POST', data); return response.code === 0; } catch (error) { const errorMessage = error.response?.data?.msg || error.message || '取消履约订单失败'; throw new Error(`取消履约订单失败: ${errorMessage}`); } } }