feat: 实现服务层核心功能与文档更新

refactor(ProductService): 修复createProduct方法和其他方法错误
fix(InventoryAgingService): 修复AGING_THRESHOLD_DAYS引用问题
fix(InventoryService): 修复predictSKUDemand方法
refactor(ChatBotController): 从tsoa风格改为Express风格
fix(CommandCenterController): 修复类型问题
fix(AdAutoService): 修复stock可能为undefined的问题
docs: 更新SERVICE_MAP、DOMAIN_MODEL等架构文档
chore: 启动前端服务(运行在http://localhost:8000)
This commit is contained in:
2026-03-18 12:35:52 +08:00
parent 2ad40da777
commit 5cfd0c4c89
55 changed files with 6077 additions and 1733 deletions

View File

@@ -0,0 +1,207 @@
import db from '../config/database';
import { logger } from '../utils/logger';
/**
* [BE-I002] 库存同步服务
* @description 实现多商户库存的实时同步和管理
* @taskId BE-I002
* @version 1.0
*/
export class InventorySyncService {
private static generateId(prefix: string): string {
return `${prefix}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
private static generateTraceId(): string {
return `trace_${Date.now()}_${Math.random().toString(36).substr(2, 12)}`;
}
/**
* 同步商户库存
* @param merchantId 商户ID
* @param inventoryData 库存数据
*/
static async syncMerchantInventory(
merchantId: string,
inventoryData: Array<{
skuId: string;
quantity: number;
warehouseId?: string;
platform?: string;
}>
): Promise<{ success: boolean; syncedCount: number; failedCount: number }> {
const traceId = this.generateTraceId();
logger.info('[InventorySyncService] Syncing merchant inventory', {
merchantId,
itemCount: inventoryData.length,
traceId,
});
try {
const merchant = await db('cf_merchant').where({ id: merchantId }).first();
if (!merchant || merchant.status !== 'ACTIVE') {
throw new Error('Merchant not found or not active');
}
let syncedCount = 0;
let failedCount = 0;
for (const item of inventoryData) {
try {
const existingInventory = await db('cf_inventory')
.where({
tenant_id: merchant.tenant_id,
sku_id: item.skuId,
warehouse_id: item.warehouseId || 'default',
})
.first();
if (existingInventory) {
await db('cf_inventory')
.where({ id: existingInventory.id })
.update({
total_qty: item.quantity,
available_qty: item.quantity - (existingInventory.reserved_qty || 0),
updated_at: new Date(),
});
} else {
await db('cf_inventory').insert({
id: this.generateId('inv'),
tenant_id: merchant.tenant_id,
sku_id: item.skuId,
warehouse_id: item.warehouseId || 'default',
total_qty: item.quantity,
available_qty: item.quantity,
reserved_qty: 0,
trace_id: traceId,
business_type: 'TOC',
created_at: new Date(),
updated_at: new Date(),
});
}
// 记录同步日志
await db('cf_inventory_sync_log').insert({
id: this.generateId('sync_log'),
merchant_id: merchantId,
sku_id: item.skuId,
quantity: item.quantity,
platform: item.platform || 'unknown',
status: 'SUCCESS',
trace_id: traceId,
created_at: new Date(),
});
syncedCount++;
} catch (error: any) {
logger.error('[InventorySyncService] Failed to sync inventory item', {
merchantId,
skuId: item.skuId,
error: error.message,
traceId,
});
// 记录失败日志
await db('cf_inventory_sync_log').insert({
id: this.generateId('sync_log'),
merchant_id: merchantId,
sku_id: item.skuId,
quantity: item.quantity,
platform: item.platform || 'unknown',
status: 'FAILED',
error_message: error.message,
trace_id: traceId,
created_at: new Date(),
});
failedCount++;
}
}
logger.info('[InventorySyncService] Inventory sync completed', {
merchantId,
syncedCount,
failedCount,
traceId,
});
return { success: failedCount === 0, syncedCount, failedCount };
} catch (error: any) {
logger.error('[InventorySyncService] Inventory sync failed', {
merchantId,
traceId,
error: error.message,
});
throw error;
}
}
/**
* 获取库存同步历史
* @param merchantId 商户ID
* @param limit 限制数量
*/
static async getSyncHistory(
merchantId: string,
limit: number = 50
): Promise<any[]> {
const traceId = this.generateTraceId();
logger.info('[InventorySyncService] Getting sync history', {
merchantId,
limit,
traceId,
});
try {
const history = await db('cf_inventory_sync_log')
.where({ merchant_id: merchantId })
.orderBy('created_at', 'desc')
.limit(limit)
.select('*');
logger.info('[InventorySyncService] Sync history retrieved', {
merchantId,
recordCount: history.length,
traceId,
});
return history;
} catch (error: any) {
logger.error('[InventorySyncService] Failed to get sync history', {
merchantId,
traceId,
error: error.message,
});
throw error;
}
}
/**
* 初始化库存同步相关数据库表
*/
static async initTables(): Promise<void> {
const syncLogTableExists = await db.schema.hasTable('cf_inventory_sync_log');
if (!syncLogTableExists) {
logger.info('📦 Creating cf_inventory_sync_log table...');
await db.schema.createTable('cf_inventory_sync_log', (table) => {
table.string('id', 64).primary();
table.string('merchant_id', 64).notNullable();
table.string('sku_id', 64).notNullable();
table.integer('quantity').notNullable();
table.string('platform', 50);
table.enum('status', ['SUCCESS', 'FAILED']).notNullable();
table.text('error_message');
table.string('trace_id', 64);
table.timestamp('created_at').defaultTo(db.fn.now());
table.index(['merchant_id']);
table.index(['sku_id']);
table.index(['status']);
table.index(['created_at']);
});
logger.info('✅ Table cf_inventory_sync_log created');
}
}
}