import { ILogger, Inject, Provide } from '@midwayjs/core'; import { ShopyyAdapter } from '../adapter/shopyy.adapter'; import { WooCommerceAdapter } from '../adapter/woocommerce.adapter'; import { ISiteAdapter } from '../interface/site-adapter.interface'; import { ShopyyService } from './shopyy.service'; import { SiteService } from './site.service'; import { WPService } from './wp.service'; import { ProductService } from './product.service'; import { UnifiedProductDTO } from '../dto/site-api.dto'; import { Product } from '../entity/product.entity'; @Provide() export class SiteApiService { @Inject() siteService: SiteService; @Inject() wpService: WPService; @Inject() shopyyService: ShopyyService; @Inject() productService: ProductService; @Inject() logger: ILogger; async getAdapter(siteId: number): Promise { const site = await this.siteService.get(siteId, true); if (!site) { throw new Error(`Site ${siteId} not found`); } if (site.type === 'woocommerce') { if (!site?.consumerKey || !site.consumerSecret || !site.apiUrl) { throw new Error('站点配置缺少 consumerKey/consumerSecret/apiUrl'); } return new WooCommerceAdapter(site, this.wpService); } else if (site.type === 'shopyy') { if (!site?.token) { throw new Error('站点配置缺少 token'); } return new ShopyyAdapter(site, this.shopyyService); } throw new Error(`Unsupported site type: ${site.type}`); } /** * 获取站点商品并关联ERP产品信息 * @param siteId 站点ID * @param siteProduct 站点商品信息 * @returns 包含ERP产品信息的站点商品 */ async enrichSiteProductWithErpInfo(siteId: number, siteProduct: UnifiedProductDTO): Promise { if (!siteProduct || !siteProduct.sku) { return siteProduct; } try { // 使用站点SKU查询对应的ERP产品 const erpProduct = await this.productService.findProductBySiteSku(siteProduct.sku); // 将ERP产品信息合并到站点商品中 return { ...siteProduct, erpProduct, }; } catch (error) { // 如果找不到对应的ERP产品,返回原始站点商品 console.warn(`未找到站点SKU ${siteProduct.sku} 对应的ERP产品: ${error.message}`); return siteProduct; } } /** * 批量获取站点商品并关联ERP产品信息 * @param siteId 站点ID * @param siteProducts 站点商品列表 * @returns 包含ERP产品信息的站点商品列表 */ async enrichSiteProductsWithErpInfo(siteId: number, siteProducts: UnifiedProductDTO[]): Promise<(UnifiedProductDTO & { erpProduct?: Product })[]> { if (!siteProducts || !siteProducts.length) { return siteProducts; } // 并行处理所有商品 const enrichedProducts = await Promise.all( siteProducts.map(product => this.enrichSiteProductWithErpInfo(siteId, product)) ); return enrichedProducts; } /** * 更新或创建产品 * @param siteId 站点ID * @param product 产品数据 * @returns 更新或创建后的产品 */ async upsertProduct(siteId: number, product: Partial): Promise { const adapter = await this.getAdapter(siteId); // 首先尝试查找产品 if (!product.sku) { throw new Error('产品SKU不能为空'); } // 尝试搜索具有相同SKU的产品 let existingProduct try { existingProduct = await adapter.getProduct({ sku: product.sku }); } catch (error) { this.logger.error(`[Site API] 查找产品失败, siteId: ${siteId}, sku: ${product.sku}, 错误信息: ${error.message}`); existingProduct = null } if (existingProduct) { // 找到现有产品,更新它 return await adapter.updateProduct({ id: existingProduct.id }, product); } // 产品不存在,执行创建 return await adapter.createProduct(product); } /** * 批量更新或创建产品 * @param siteId 站点ID * @param products 产品数据数组 * @returns 批量操作结果 */ async batchUpsertProduct(siteId: number, products: Partial[]): Promise<{ created: any[], updated: any[], errors: any[] }> { const results = { created: [], updated: [], errors: [] }; for (const product of products) { try { const result = await this.upsertProduct(siteId, product); // 判断是创建还是更新 if (result && result.id) { // 简单判断:如果产品原本没有ID而现在有了,说明是创建的 if (!product.id || !product.id.toString().trim()) { results.created.push(result); } else { results.updated.push(result); } } } catch (error) { results.errors.push({ product: product, error: error.message }); } } return results; } /** * 从站点获取产品 * @param siteId 站点ID * @param params 查询参数 * @returns 站点产品列表 */ async getProductsFromSite(siteId: number, params?: any): Promise { const adapter = await this.getAdapter(siteId); return await adapter.getProducts(params); } /** * 从站点获取所有产品 * @param siteId 站点ID * @param params 查询参数 * @returns 站点产品列表 */ async getAllProductsFromSite(siteId: number, params?: any): Promise { const adapter = await this.getAdapter(siteId); return await adapter.getAllProducts(params); } }