200 lines
6.1 KiB
TypeScript
200 lines
6.1 KiB
TypeScript
import { 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';
|
||
|
||
@Provide()
|
||
export class SiteApiService {
|
||
@Inject()
|
||
siteService: SiteService;
|
||
|
||
@Inject()
|
||
wpService: WPService;
|
||
|
||
@Inject()
|
||
shopyyService: ShopyyService;
|
||
|
||
@Inject()
|
||
productService: ProductService;
|
||
|
||
async getAdapter(siteId: number): Promise<ISiteAdapter> {
|
||
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: any): Promise<any> {
|
||
if (!siteProduct || !siteProduct.sku) {
|
||
return siteProduct;
|
||
}
|
||
|
||
try {
|
||
// 使用站点SKU查询对应的ERP产品
|
||
const erpProduct = await this.productService.findProductBySiteSku(siteProduct.sku);
|
||
|
||
// 将ERP产品信息合并到站点商品中
|
||
return {
|
||
...siteProduct,
|
||
erpProduct: {
|
||
id: erpProduct.id,
|
||
sku: erpProduct.sku,
|
||
name: erpProduct.name,
|
||
nameCn: erpProduct.nameCn,
|
||
category: erpProduct.category,
|
||
attributes: erpProduct.attributes,
|
||
components: erpProduct.components,
|
||
price: erpProduct.price,
|
||
promotionPrice: erpProduct.promotionPrice,
|
||
// 可以根据需要添加更多ERP产品字段
|
||
}
|
||
};
|
||
} 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: any[]): Promise<any[]> {
|
||
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<UnifiedProductDTO>): Promise<any> {
|
||
const adapter = await this.getAdapter(siteId);
|
||
|
||
// 首先尝试查找产品
|
||
if (product.sku) {
|
||
// 如果没有提供ID但提供了SKU,尝试通过SKU查找产品
|
||
try {
|
||
// 尝试搜索具有相同SKU的产品
|
||
const existingProduct = await adapter.getProduct( { sku: product.sku });
|
||
if (existingProduct) {
|
||
// 找到现有产品,更新它
|
||
return await adapter.updateProduct({ id: existingProduct.id }, product);
|
||
}
|
||
// 产品不存在,执行创建
|
||
return await adapter.createProduct(product);
|
||
} catch (error) {
|
||
// 搜索失败,继续执行创建逻辑
|
||
console.log(`通过SKU搜索产品失败:`, error.message);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 批量更新或创建产品
|
||
* @param siteId 站点ID
|
||
* @param products 产品数据数组
|
||
* @returns 批量操作结果
|
||
*/
|
||
async batchUpsertProduct(siteId: number, products: Partial<UnifiedProductDTO>[]): 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<any> {
|
||
const adapter = await this.getAdapter(siteId);
|
||
return await adapter.getProducts(params);
|
||
}
|
||
|
||
/**
|
||
* 从站点获取单个产品
|
||
* @param siteId 站点ID
|
||
* @param productId 产品ID
|
||
* @returns 站点产品
|
||
*/
|
||
async getProductFromSite(siteId: number, productId: string | number): Promise<any> {
|
||
const adapter = await this.getAdapter(siteId);
|
||
return await adapter.getProduct({ id: productId });
|
||
}
|
||
|
||
/**
|
||
* 从站点获取所有产品
|
||
* @param siteId 站点ID
|
||
* @param params 查询参数
|
||
* @returns 站点产品列表
|
||
*/
|
||
async getAllProductsFromSite(siteId: number, params?: any): Promise<any[]> {
|
||
const adapter = await this.getAdapter(siteId);
|
||
return await adapter.getAllProducts(params);
|
||
}
|
||
}
|