Files
makemd/server/src/api/controllers/OrderController.ts
wurenzhi 0dac26d781 feat: 添加MSW模拟服务和数据源集成
refactor: 重构页面组件移除冗余Layout组件

feat: 实现WebSocket和事件总线系统

feat: 添加队列和调度系统

docs: 更新架构文档和服务映射

style: 清理重复接口定义使用数据源

chore: 更新依赖项配置

feat: 添加运行时系统和领域引导

ci: 配置ESLint边界检查规则

build: 添加Redis和WebSocket依赖

test: 添加MSW浏览器环境入口

perf: 优化数据获取逻辑使用统一数据源

fix: 修复类型定义和状态管理问题
2026-03-19 01:39:34 +08:00

368 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Request, Response } from 'express';
import { logger } from '../../utils/logger';
import { ConsumerOrderService, ConsumerOrder } from '../../domains/Trade/ConsumerOrderService';
import { OrderService } from '../../services/OrderService';
/**
* [BIZ_OPS_01] 多平台订单 Webhook 接收器 (Order Webhook Receiver)
* @description 接收来自不同平台 (Amazon, AliExpress, Shopify, TikTok) 的订单 Webhook 推送,
* 并将其映射为系统统一的 cf_order 模型进行入库处理。
*/
export class OrderController {
/**
* 平台 Webhook 入口
* POST /api/v1/orders/webhook/:platform
*/
static async handlePlatformWebhook(req: Request, res: Response) {
const { platform } = req.params;
const payload = req.body;
const tenantId = req.headers['x-tenant-id'] as string || 'default-tenant';
const shopId = req.headers['x-shop-id'] as string || 'default-shop';
logger.info(`[OrderWebhook] Received webhook from platform: ${platform} for Tenant: ${tenantId}`);
try {
// 1. 根据不同平台解析 Payload (Mapping)
const normalizedOrder = OrderService.mapPlatformPayloadToOrder(platform as string, payload, tenantId, shopId);
if (!normalizedOrder) {
return res.status(400).json({ success: false, error: `Unsupported or invalid payload for platform: ${platform}` });
}
// 2. 调用 ConsumerOrderService 进行同步
const orderId = await ConsumerOrderService.syncPlatformOrder(normalizedOrder);
logger.info(`[OrderWebhook] Successfully synced order ${normalizedOrder.platform_order_id} to internal ID: ${orderId}`);
// 3. 返回平台要求的 200 OK
return res.json({ success: true, orderId });
} catch (err: any) {
logger.error(`[OrderWebhook] Webhook handling failed for ${platform}: ${err.message}`);
return res.status(500).json({ success: false, error: 'Internal server error' });
}
}
/**
* 手动触发同步 (API 入口)
* POST /api/v1/orders/sync
*/
static async triggerManualSync(req: Request, res: Response) {
try {
const { platform, shopId } = req.body;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
logger.info(`[OrderSync] Manual sync triggered for Platform: ${platform}, Shop: ${shopId}`);
// 此处应调用各平台 Connector 的 supportsOrderPull 能力
// 示例Mock 拉取成功
res.json({ success: true, message: `Manual sync triggered for ${platform}` });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 获取订单统计
* GET /api/v1/orders/stats
*/
static async getStats(req: Request, res: Response) {
try {
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const stats = await ConsumerOrderService.getOrderStats(tenantId);
res.json({ success: true, data: stats });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 创建订单
* POST /api/v1/orders
*/
static async createOrder(req: Request, res: Response) {
try {
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const orderData = { ...req.body, tenant_id: tenantId };
const orderId = await OrderService.createOrder(orderData);
res.json({ success: true, orderId });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 获取订单详情
* GET /api/v1/orders/:id
*/
static async getOrderById(req: Request, res: Response) {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const order = await OrderService.getOrderById(id as string, tenantId);
if (order) {
res.json({ success: true, data: order });
} else {
res.status(404).json({ success: false, error: 'Order not found' });
}
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 更新订单
* PUT /api/v1/orders/:id
*/
static async updateOrder(req: Request, res: Response) {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
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 });
}
}
/**
* 删除订单
* DELETE /api/v1/orders/:id
*/
static async deleteOrder(req: Request, res: Response) {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
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 });
}
}
/**
* 获取订单列表
* GET /api/v1/orders
*/
static async getOrders(req: Request, res: Response) {
try {
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const params = {
page: parseInt(req.query.page as string) || 1,
pageSize: parseInt(req.query.pageSize as string) || 20,
status: req.query.status as string,
platform: req.query.platform as string,
startDate: req.query.startDate as string,
endDate: req.query.endDate as string,
};
const result = await OrderService.getOrders(tenantId, params);
res.json({ success: true, data: result });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 批量更新订单
* PUT /api/v1/orders/batch
*/
static async batchUpdateOrders(req: Request, res: Response) {
try {
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { orderIds, updates } = req.body;
const result = await OrderService.batchUpdateOrders(tenantId, orderIds, updates);
res.json({ success: true, data: result });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 订单状态流转
* POST /api/v1/orders/:id/status
*/
static async transitionOrderStatus(req: Request, res: Response) {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { status, reason } = req.body;
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 });
}
}
/**
* 批量审核订单
* POST /api/v1/orders/batch/audit
*/
static async batchAuditOrders(req: Request, res: Response) {
try {
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { orderIds } = req.body;
const result = await OrderService.batchAuditOrders(tenantId, orderIds);
res.json({ success: true, data: result });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 批量发货
* POST /api/v1/orders/batch/ship
*/
static async batchShipOrders(req: Request, res: Response) {
try {
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { orderIds } = req.body;
const result = await OrderService.batchShipOrders(tenantId, orderIds);
res.json({ success: true, data: result });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 标记订单为异常
* POST /api/v1/orders/:id/exception
*/
static async markOrderAsException(req: Request, res: Response) {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { reason } = req.body;
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 });
}
}
/**
* 自动改派订单
* POST /api/v1/orders/:id/reroute
*/
static async autoRerouteOrder(req: Request, res: Response) {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
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 });
}
}
/**
* 重试异常订单
* POST /api/v1/orders/:id/retry
*/
static async retryExceptionOrder(req: Request, res: Response) {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
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 });
}
}
/**
* 取消订单
* POST /api/v1/orders/:id/cancel
*/
static async cancelOrder(req: Request, res: Response) {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { reason } = req.body;
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 });
}
}
/**
* 申请退款
* POST /api/v1/orders/:id/refund
*/
static async requestRefund(req: Request, res: Response) {
try {
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 as string, reason, amount);
res.json({ success: true, refundId });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 审批退款
* POST /api/v1/orders/refund/:id/approve
*/
static async approveRefund(req: Request, res: Response) {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { approved, note } = req.body;
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 });
}
}
/**
* 申请售后
* POST /api/v1/orders/:id/after-sales
*/
static async requestAfterSales(req: Request, res: Response) {
try {
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 as string, type, reason, items);
res.json({ success: true, serviceId });
} catch (err: any) {
res.status(500).json({ success: false, error: err.message });
}
}
/**
* 处理售后申请
* POST /api/v1/orders/after-sales/:id/process
*/
static async processAfterSales(req: Request, res: Response) {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
const { action, note } = req.body;
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 });
}
}
/**
* 完成订单
* POST /api/v1/orders/:id/complete
*/
static async completeOrder(req: Request, res: Response) {
try {
const { id } = req.params;
const { tenantId } = (req as any).traceContext || { tenantId: 'default-tenant' };
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 });
}
}
}