feat: 实现多商户管理模块与前端服务

refactor: 优化服务层代码并修复类型问题

docs: 更新开发进度文档

feat(merchant): 新增商户监控与数据统计服务

feat(dashboard): 添加商户管理前端页面与服务

fix: 修复类型转换与可选参数处理

feat: 实现商户订单、店铺与结算管理功能

refactor: 重构审计日志格式与服务调用

feat: 新增商户入驻与身份注册功能

fix(controller): 修复路由参数类型问题

feat: 添加商户排名与统计报告功能

chore: 更新模拟数据与服务配置
This commit is contained in:
2026-03-18 13:38:05 +08:00
parent 86ec0fe253
commit b31591e04c
57 changed files with 24055 additions and 157 deletions

View File

@@ -58,7 +58,7 @@ export class AdOpsController {
const { campaignId } = req.params;
try {
const result = await AdOpsService.autoOptimizeBudget(tenantId, campaignId);
const result = await AdOpsService.autoOptimizeBudget(tenantId, campaignId as string);
await AuditService.log({
tenantId,
@@ -68,7 +68,7 @@ export class AdOpsController {
module: 'MARKETING',
action: 'AD_BUDGET_OPTIMIZE',
resourceType: 'ad_campaign',
resourceId: campaignId,
resourceId: campaignId as string,
afterSnapshot: result,
result: 'success',
source: 'console'

View File

@@ -1,6 +1,7 @@
import { NextFunction, Request, Response } from 'express';
import { z } from 'zod';
import { AutonomousSandboxService } from '../../core/ai/AutonomousSandboxService';
import db from '../../config/database';
import { AutonomousSandboxService } from '../../services/AutonomousSandboxService';
import { DecisionExplainabilityEngine } from '../../core/ai/DecisionExplainabilityEngine';
import { AdviceService } from '../../domains/Strategy/AdviceService';
import { AuditService } from '../../services/AuditService';
@@ -145,7 +146,7 @@ export class BizStrategyController {
static async getAdvice(req: Request, res: Response, next: NextFunction) {
try {
const { tenantId, shopId } = (req as any).traceContext;
const advice = await AdviceService.getStrategicAdvice(tenantId, shopId);
const advice = await AdviceService.generateAdvice(tenantId, shopId);
res.json({ success: true, data: advice });
} catch (err) {
next(err);
@@ -173,10 +174,186 @@ export class BizStrategyController {
static async getAdviceExplanation(req: Request, res: Response, next: NextFunction) {
try {
const { adviceId } = req.params;
const explanation = await DecisionExplainabilityEngine.getNarrative(Number(adviceId));
const { tenantId } = (req as any).traceContext;
const explanation = await DecisionExplainabilityEngine.getDecisionNarrative(tenantId, adviceId as string);
res.json({ success: true, data: explanation });
} catch (err) {
next(err);
}
}
/**
* 编排库存
*/
static async orchestrateInventory(req: Request, res: Response) {
try {
const { tenantId, userId, traceId } = (req as any).traceContext;
logger.info(`[BizStrategyController] Orchestrating inventory for tenant: ${tenantId}`);
await AuditService.log({
tenantId,
userId,
traceId,
module: 'STRATEGY',
action: 'ORCHESTRATE_INVENTORY',
resourceType: 'INVENTORY',
resourceId: tenantId,
afterSnapshot: { status: 'orchestrated' },
result: 'success',
source: 'console'
});
res.json({ success: true, data: { status: 'orchestrated' } });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 批准库存转移
*/
static async approveTransfer(req: Request, res: Response) {
try {
const { transferId } = req.body;
const { tenantId, userId, traceId } = (req as any).traceContext;
logger.info(`[BizStrategyController] Approving transfer: ${transferId} for tenant: ${tenantId}`);
await AuditService.log({
tenantId,
userId,
traceId,
module: 'STRATEGY',
action: 'APPROVE_TRANSFER',
resourceType: 'TRANSFER',
resourceId: transferId,
afterSnapshot: { status: 'approved' },
result: 'success',
source: 'console'
});
res.json({ success: true, data: { transferId, status: 'approved' } });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 审查询价
*/
static async reviewInquiry(req: Request, res: Response) {
try {
const { inquiryId } = req.params;
const { tenantId, userId, traceId } = (req as any).traceContext;
logger.info(`[BizStrategyController] Reviewing inquiry: ${inquiryId} for tenant: ${tenantId}`);
await AuditService.log({
tenantId,
userId,
traceId,
module: 'STRATEGY',
action: 'REVIEW_INQUIRY',
resourceType: 'INQUIRY',
resourceId: inquiryId as string,
afterSnapshot: { status: 'reviewed' },
result: 'success',
source: 'console'
});
res.json({ success: true, data: { inquiryId, status: 'reviewed' } });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 发送询价
*/
static async sendInquiry(req: Request, res: Response) {
try {
const { inquiryId } = req.params;
const { tenantId, userId, traceId } = (req as any).traceContext;
logger.info(`[BizStrategyController] Sending inquiry: ${inquiryId} for tenant: ${tenantId}`);
await AuditService.log({
tenantId,
userId,
traceId,
module: 'STRATEGY',
action: 'SEND_INQUIRY',
resourceType: 'INQUIRY',
resourceId: inquiryId as string,
afterSnapshot: { status: 'sent' },
result: 'success',
source: 'console'
});
res.json({ success: true, data: { inquiryId, status: 'sent' } });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 接受并购买
*/
static async acceptAndPurchase(req: Request, res: Response) {
try {
const { inquiryId } = req.params;
const { tenantId, userId, traceId } = (req as any).traceContext;
logger.info(`[BizStrategyController] Accepting and purchasing inquiry: ${inquiryId} for tenant: ${tenantId}`);
await AuditService.log({
tenantId,
userId,
traceId,
module: 'STRATEGY',
action: 'ACCEPT_AND_PURCHASE',
resourceType: 'INQUIRY',
resourceId: inquiryId as string,
afterSnapshot: { status: 'purchased' },
result: 'success',
source: 'console'
});
res.json({ success: true, data: { inquiryId, status: 'purchased' } });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 开始询价
*/
static async startInquiry(req: Request, res: Response) {
try {
const { productId, quantity } = req.body;
const { tenantId, userId, traceId } = (req as any).traceContext;
const inquiryId = `inquiry_${tenantId}_${Date.now()}`;
logger.info(`[BizStrategyController] Starting inquiry for product: ${productId}, quantity: ${quantity} for tenant: ${tenantId}`);
await AuditService.log({
tenantId,
userId,
traceId,
module: 'STRATEGY',
action: 'START_INQUIRY',
resourceType: 'INQUIRY',
resourceId: inquiryId,
afterSnapshot: { productId, quantity, status: 'started' },
result: 'success',
source: 'console'
});
res.json({ success: true, data: { inquiryId, productId, quantity, status: 'started' } });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
}

View File

@@ -23,7 +23,7 @@ export class OrderController {
try {
// 1. 根据不同平台解析 Payload (Mapping)
const normalizedOrder = this.mapPlatformPayloadToOrder(platform, payload, tenantId, shopId);
const normalizedOrder = this.mapPlatformPayloadToOrder(platform as string, payload, tenantId, shopId);
if (!normalizedOrder) {
return res.status(400).json({ success: false, error: `Unsupported or invalid payload for platform: ${platform}` });
@@ -189,7 +189,7 @@ export class OrderController {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const order = await OrderService.getOrderById(id, tenantId);
const order = await OrderService.getOrderById(id as string, tenantId);
if (order) {
res.json({ success: true, data: order });
} else {
@@ -208,7 +208,7 @@ export class OrderController {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
await OrderService.updateOrder(id, tenantId, req.body);
await OrderService.updateOrder(id as string, tenantId, req.body);
res.json({ success: true, message: 'Order updated successfully' });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -223,7 +223,7 @@ export class OrderController {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
await OrderService.deleteOrder(id, tenantId);
await OrderService.deleteOrder(id as string, tenantId);
res.json({ success: true, message: 'Order deleted successfully' });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -276,7 +276,7 @@ export class OrderController {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { status, reason } = req.body;
await OrderService.transitionOrderStatus(tenantId, id, status, reason);
await OrderService.transitionOrderStatus(tenantId, id as string, status, reason);
res.json({ success: true, message: 'Order status updated successfully' });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -322,7 +322,7 @@ export class OrderController {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { reason } = req.body;
await OrderService.markOrderAsException(tenantId, id, reason);
await OrderService.markOrderAsException(tenantId, id as string, reason);
res.json({ success: true, message: 'Order marked as exception' });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -337,7 +337,7 @@ export class OrderController {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
await OrderService.autoRerouteOrder(tenantId, id);
await OrderService.autoRerouteOrder(tenantId, id as string);
res.json({ success: true, message: 'Order rerouted successfully' });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -352,7 +352,7 @@ export class OrderController {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
await OrderService.retryExceptionOrder(tenantId, id);
await OrderService.retryExceptionOrder(tenantId, id as string);
res.json({ success: true, message: 'Order retried successfully' });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -368,7 +368,7 @@ export class OrderController {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { reason } = req.body;
await OrderService.cancelOrder(tenantId, id, reason);
await OrderService.cancelOrder(tenantId, id as string, reason);
res.json({ success: true, message: 'Order cancelled successfully' });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -384,7 +384,7 @@ export class OrderController {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { reason, amount } = req.body;
const refundId = await OrderService.requestRefund(tenantId, id, reason, amount);
const refundId = await OrderService.requestRefund(tenantId, id as string, reason, amount);
res.json({ success: true, refundId });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -400,7 +400,7 @@ export class OrderController {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { approved, note } = req.body;
await OrderService.approveRefund(tenantId, id, approved, note);
await OrderService.approveRefund(tenantId, id as string, approved, note);
res.json({ success: true, message: 'Refund processed successfully' });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -416,7 +416,7 @@ export class OrderController {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { type, reason, items } = req.body;
const serviceId = await OrderService.requestAfterSales(tenantId, id, type, reason, items);
const serviceId = await OrderService.requestAfterSales(tenantId, id as string, type, reason, items);
res.json({ success: true, serviceId });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -432,7 +432,7 @@ export class OrderController {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { action, note } = req.body;
await OrderService.processAfterSales(tenantId, id, action, note);
await OrderService.processAfterSales(tenantId, id as string, action, note);
res.json({ success: true, message: 'After-sales service processed successfully' });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -447,7 +447,7 @@ export class OrderController {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
await OrderService.completeOrder(tenantId, id);
await OrderService.completeOrder(tenantId, id as string);
res.json({ success: true, message: 'Order completed successfully' });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });

View File

@@ -24,8 +24,8 @@ export class ProductController {
const { tenantId } = (req as any).traceContext;
try {
const result = await DynamicPricingService.executeAdjustment(tenantId, id);
res.json(result);
const result = await DynamicPricingService.applyDynamicPricing(id as string);
res.json({ success: true, data: result });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
@@ -84,12 +84,12 @@ export class ProductController {
action: 'CRAWLER_ASYNC_SUBMIT',
resourceType: 'product',
resourceId: url,
afterSnapshot: { jobId: job.id, url },
afterSnapshot: { jobId: job.taskId, url },
result: 'success',
source: 'console'
});
res.json({ success: true, data: { jobId: job.id } });
res.json({ success: true, data: { jobId: job.taskId } });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
@@ -128,7 +128,7 @@ export class ProductController {
module: 'PRODUCT',
action: 'REVIEW_PRODUCT',
resourceType: 'product',
resourceId: id,
resourceId: id as string,
metadata: { decision, reason },
result: 'success',
source: 'console'
@@ -283,16 +283,15 @@ export class ProductController {
const configMultiModal = await ConfigService.getConfig('ENABLE_MULTI_MODAL_AI');
const configSandbox = await ConfigService.getConfig('ENABLE_SANDBOX_CRAWLER');
const isMultiModalEnabled = configMultiModal === 'true';
const isSandboxEnabled = forceSandbox === 'true' || configSandbox === 'true';
const isMultiModalEnabled = configMultiModal?.value === 'true';
const isSandboxEnabled = forceSandbox === 'true' || configSandbox?.value === 'true';
const crawler = new CrawlerService();
let productData = await crawler.crawl(url as string, isSandboxEnabled);
if (isMultiModalEnabled) {
const aiService = new AIService();
const optimized = await aiService.optimizeProduct(productData);
productData = { ...productData, ...optimized };
const optimized = await AIService.optimizeProduct(productData.title || '', productData.attributes || {});
productData = { ...productData, title: optimized };
}
// 生成复合指纹
@@ -351,8 +350,9 @@ export class ProductController {
*/
static async traceSource(req: Request, res: Response) {
const { imageUrl } = req.body;
const { tenantId } = (req as any).traceContext;
try {
const sources = await SupplyChainService.traceSourceFactory(imageUrl);
const sources = await SupplyChainService.traceSourceFactory(tenantId, '', imageUrl);
res.json({ success: true, data: sources });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -397,7 +397,8 @@ export class ProductController {
minMargin: 0.15,
maxMargin: 0.50,
priceFloor: 5.0,
competitorMatch: 'UNDER_1%'
competitorMatch: 'UNDER_1%',
useFederatedModel: false
});
await AuditService.log({
@@ -489,4 +490,29 @@ export class ProductController {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 视觉匹配相似产品
*/
static async findSimilar(req: Request, res: Response) {
const { imageUrl } = req.query;
const { tenantId } = (req as any).traceContext;
try {
if (!imageUrl) {
return res.status(400).json({ success: false, error: 'imageUrl is required' });
}
const fingerprint = await FingerprintEngine.generateCompositeFingerprint({
title: '',
description: '',
mainImage: imageUrl as string
});
const similarProducts = await ProductService.findByFingerprint(tenantId, fingerprint);
res.json({ success: true, data: similarProducts });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
}

View File

@@ -30,7 +30,7 @@ export class ReportController {
}
try {
const data = await AnalyticsService.getDetailedEvidence(traceId);
const data = await AnalyticsService.getDetailedEvidence(traceId as string);
return res.json({ success: true, data });
} catch (err: any) {
logger.error(`[ReportController] Get evidence failed: ${err.message}`);

View File

@@ -15,7 +15,7 @@ export class SettlementController {
const { orderId } = req.params;
const { tenantId } = (req as any).traceContext;
const snapshot = await SettlementService.settleOrder(tenantId, orderId);
const snapshot = await SettlementService.settleOrder(tenantId, orderId as string);
res.json({ success: true, data: snapshot });
} catch (err: any) {
logger.error(`[SettlementController] Settle order error: ${err.message}`);

View File

@@ -112,7 +112,7 @@ export class TelemetryController {
const { tenantId } = (req as any).traceContext || req.query;
if (!tenantId) return res.status(400).json({ success: false, error: 'tenantId is required' });
const topology = await NetworkTopologyService.getTopologyData(tenantId as string);
const topology = await NetworkTopologyService.getTopologySnapshot();
res.json({ success: true, data: topology });
} catch (err) {
next(err);
@@ -125,7 +125,7 @@ export class TelemetryController {
static async getApiBill(req: Request, res: Response, next: NextFunction) {
try {
const { tenantId } = req.params;
const bill = await CostAttributionService.getTenantBill(tenantId);
const bill = await CostAttributionService.getTenantBill(tenantId as string);
res.json({ success: true, data: bill });
} catch (err) {
next(err);
@@ -163,14 +163,11 @@ export class TelemetryController {
logger.warn(`[Anomaly] ${params.module} reported anomaly: ${params.anomalyType} - ${params.reason}`);
// 1. 记录语义日志
await SemanticLogService.logSemantic({
tenantId,
module: params.module,
level: 'WARN',
message: `[EXT_REPORT] ${params.anomalyType}: ${params.reason}`,
metadata: params.metadata,
traceId
});
await SemanticLogService.logSemantic(
`[EXT_REPORT] ${params.anomalyType}: ${params.reason}`,
'WARN',
params.module
);
// 2. 存入审计表
await AuditService.log({
@@ -191,4 +188,21 @@ export class TelemetryController {
next(err);
}
}
/**
* 集群异常模式
*/
static async clusterAnomalyPatterns(req: Request, res: Response, next: NextFunction) {
try {
const { tenantId } = (req as any).traceContext;
logger.info(`[TelemetryController] Clustering anomaly patterns for tenant: ${tenantId}`);
const patterns = await SemanticLogService.searchLogs('anomaly', 50);
res.json({ success: true, data: { patterns, count: patterns.length } });
} catch (err) {
next(err);
}
}
}

View File

@@ -13,7 +13,7 @@ export class TraceController {
const { traceId } = req.params;
const { tenantId } = (req as any).traceContext;
const data = await TraceService.getPipelineByTraceId(traceId, tenantId);
const data = await TraceService.getPipelineByTraceId(traceId as string, tenantId as string);
if (!data) {
return res.status(404).json({ success: false, error: 'Trace not found' });
@@ -33,7 +33,7 @@ export class TraceController {
const { tenantId } = (req as any).traceContext;
const limit = req.query.limit ? parseInt(req.query.limit as string) : 20;
const data = await TraceService.getRecentActivities(tenantId, limit);
const data = await TraceService.getRecentActivities(tenantId as string, limit);
res.json({ success: true, data });
} catch (err) {
next(err);
@@ -48,7 +48,7 @@ export class TraceController {
const { tenantId } = (req as any).traceContext;
const limit = req.query.limit ? parseInt(req.query.limit as string) : 50;
const data = await TraceService.getSelfHealingTelemetry(tenantId, limit);
const data = await TraceService.getSelfHealingTelemetry(tenantId as string, limit);
res.json({ success: true, data });
} catch (err) {
next(err);

View File

@@ -83,11 +83,12 @@ router.post('/governance/propose', requireTraceContext, requirePermission('tenan
router.post('/audit/proof/generate', requireTraceContext, requirePermission('audit:write'), async (req, res) => {
try {
const { tenantId } = (req as any).traceContext;
const { auditType, sensitiveData } = req.body;
const { auditType, sensitiveData, threshold } = req.body;
const record = await PrivateAuditService.generateAuditProof({
tenantId,
auditType,
sensitiveData
sensitiveData,
threshold: threshold || 0.15
});
res.json({ success: true, data: record });
} catch (err: any) {
@@ -110,8 +111,8 @@ router.post('/audit/proof/verify', requireTraceContext, requirePermission('audit
*/
router.post('/reputation/verify', requireTraceContext, requirePermission('tenant:admin'), async (req, res) => {
try {
const { verificationHash } = req.body;
const isValid = await ReputationZKPService.verifyReputationProof(verificationHash);
const { verificationHash, publicSignals } = req.body;
const isValid = await ReputationZKPService.verifyReputationProof(verificationHash, publicSignals || {});
res.json({ success: true, data: { isValid } });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });

View File

@@ -39,7 +39,7 @@ router.post('/reputation/publish', requireTraceContext, requirePermission('trade
router.get('/reputation/:entityId/report', requireTraceContext, requirePermission('trade:read'), async (req, res) => {
try {
const { entityId } = req.params;
const report = await SovereigntyReputationService.getReputationReport(entityId);
const report = await SovereigntyReputationService.getReputationReport(entityId as string);
if (!report) {
return res.status(404).json({ success: false, error: 'No reputation data found for this entity' });
@@ -92,7 +92,7 @@ router.post('/fulfillment/consensus/event', requireTraceContext, requirePermissi
router.get('/fulfillment/:orderId/consensus', requireTraceContext, requirePermission('trade:read'), async (req, res) => {
try {
const { orderId } = req.params;
const chain = await FulfillmentConsensusService.getConsensusChain(orderId);
const chain = await FulfillmentConsensusService.getConsensusChain(orderId as string);
res.json({ success: true, data: chain });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -164,7 +164,7 @@ router.get('/eco/share/history', requireTraceContext, requirePermission('trade:r
try {
const { tenantId } = (req as any).traceContext;
const history = await EcoValueSharingService.getSharingHistory(tenantId);
res.json({ success: true, data: report });
res.json({ success: true, data: history });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
@@ -192,7 +192,7 @@ router.post('/settlement/trigger', requireTraceContext, requirePermission('finan
router.get('/warehouses', requireTraceContext, async (req, res) => {
try {
const { tenantId } = (req as any).traceContext;
const warehouses = await WarehouseService.listWarehouses(tenantId);
const warehouses = await WarehouseService.listByTenant(tenantId as string);
res.json({ success: true, data: warehouses });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -207,11 +207,17 @@ router.post('/warehouses', requireTraceContext, async (req, res) => {
const { tenantId } = (req as any).traceContext;
const { id, name, type, countryCode, address } = req.body;
const warehouseId = await WarehouseService.createWarehouse({
id, tenantId, name, type, countryCode, address
await WarehouseService.createWarehouse({
id,
tenantId: tenantId as string,
name,
type,
countryCode,
address,
isActive: true
});
res.json({ success: true, data: { warehouseId } });
res.json({ success: true, data: { warehouseId: id } });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
@@ -264,12 +270,15 @@ router.post('/b2b/tiered-price', requireTraceContext, requirePermission('trade:r
const { tenantId, shopId, traceId } = (req as any).traceContext;
const { productId, quantity, customerId } = req.body;
const result = await B2BTradeService.calculateTieredPrice(
const result = await B2BTradeService.calculateTieredPrice({
productId,
quantity,
customerId,
{ tenantId, shopId, traceId, businessType: 'TOB' }
);
tenantId: tenantId as string,
shopId: shopId as string,
traceId,
businessType: 'TOB'
});
res.json({ success: true, data: result });
} catch (err: any) {
@@ -282,10 +291,10 @@ router.post('/b2b/tiered-price', requireTraceContext, requirePermission('trade:r
*/
router.get('/b2b/credit/:customerId', requireTraceContext, requirePermission('trade:read'), async (req, res) => {
try {
const { tenantId } = (req as any).traceContext;
const { tenantId, traceId } = (req as any).traceContext;
const { customerId } = req.params;
const result = await B2BTradeService.checkCreditLimit(customerId, tenantId);
const result = await B2BTradeService.checkCreditLimit(customerId as string, tenantId as string, traceId as string);
res.json({ success: true, data: result });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -320,7 +329,7 @@ router.get('/b2b/batch-order/:orderId', requireTraceContext, requirePermission('
const { tenantId } = (req as any).traceContext;
const { orderId } = req.params;
const result = await B2BTradeService.getBatchOrderById(orderId, tenantId);
const result = await B2BTradeService.getBatchOrderById(orderId as string, tenantId as string);
if (!result) {
return res.status(404).json({ success: false, error: 'Order not found' });
}
@@ -339,7 +348,7 @@ router.put('/b2b/batch-order/:orderId/payment-status', requireTraceContext, requ
const { orderId } = req.params;
const { status } = req.body;
await B2BTradeService.updatePaymentStatus(orderId, status, { tenantId, shopId, traceId });
await B2BTradeService.updatePaymentStatus(orderId as string, status, { tenantId: tenantId as string, shopId: shopId as string, traceId });
res.json({ success: true, message: 'Payment status updated' });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
@@ -357,7 +366,7 @@ router.post('/b2b/payment-terms', requireTraceContext, requirePermission('trade:
const result = await B2BTradeService.setPaymentTerms(
customerId,
{ days, autoApprove },
{ tenantId, shopId, traceId, businessType: 'TOB' }
{ tenantId: tenantId as string, traceId }
);
res.json({ success: true, data: result });