93 lines
2.9 KiB
TypeScript
93 lines
2.9 KiB
TypeScript
import { Controller, Logger } from '@nestjs/common';
|
||
import { MessagePattern, Payload } from '@nestjs/microservices';
|
||
import { RewardApplicationService } from '../../application/services/reward-application.service';
|
||
import { EventAckPublisher } from './event-ack.publisher';
|
||
|
||
interface PlantingOrderPaidEvent {
|
||
eventName?: string;
|
||
data?: {
|
||
orderId: string;
|
||
userId: string;
|
||
treeCount: number;
|
||
provinceCode: string;
|
||
cityCode: string;
|
||
paidAt: string;
|
||
};
|
||
// 兼容旧格式
|
||
orderId?: string;
|
||
userId?: string;
|
||
treeCount?: number;
|
||
provinceCode?: string;
|
||
cityCode?: string;
|
||
paidAt?: string;
|
||
// B方案:outbox 元数据
|
||
_outbox?: {
|
||
id: string;
|
||
aggregateId: string;
|
||
eventType: string;
|
||
};
|
||
}
|
||
|
||
@Controller()
|
||
export class EventConsumerController {
|
||
private readonly logger = new Logger(EventConsumerController.name);
|
||
|
||
constructor(
|
||
private readonly rewardService: RewardApplicationService,
|
||
private readonly eventAckPublisher: EventAckPublisher,
|
||
) {}
|
||
|
||
/**
|
||
* 监听认种订单支付成功事件
|
||
*/
|
||
@MessagePattern('planting.order.paid')
|
||
async handlePlantingOrderPaid(@Payload() message: PlantingOrderPaidEvent) {
|
||
this.logger.log(`Received planting.order.paid event: ${JSON.stringify(message)}`);
|
||
|
||
// 解析消息数据(支持新旧格式)
|
||
const eventData = message.data || {
|
||
orderId: message.orderId!,
|
||
userId: message.userId!,
|
||
treeCount: message.treeCount!,
|
||
provinceCode: message.provinceCode!,
|
||
cityCode: message.cityCode!,
|
||
paidAt: message.paidAt!,
|
||
};
|
||
|
||
// B方案:提取 outbox 信息用于发送确认
|
||
const outboxInfo = message._outbox;
|
||
const eventId = outboxInfo?.aggregateId || eventData.orderId;
|
||
|
||
try {
|
||
// 1. 计算并分配奖励
|
||
await this.rewardService.distributeRewards({
|
||
sourceOrderId: BigInt(eventData.orderId),
|
||
sourceUserId: BigInt(eventData.userId),
|
||
treeCount: eventData.treeCount,
|
||
provinceCode: eventData.provinceCode,
|
||
cityCode: eventData.cityCode,
|
||
});
|
||
|
||
// 2. 检查该用户是否有待领取奖励需要转为可结算
|
||
await this.rewardService.claimPendingRewardsForUser(BigInt(eventData.userId));
|
||
|
||
this.logger.log(`Successfully processed planting.order.paid for order ${eventData.orderId}`);
|
||
|
||
// B方案:发送处理成功确认
|
||
if (outboxInfo) {
|
||
await this.eventAckPublisher.sendSuccess(eventId, outboxInfo.eventType);
|
||
}
|
||
} catch (error) {
|
||
this.logger.error(`Error processing planting.order.paid:`, error);
|
||
|
||
// B方案:发送处理失败确认
|
||
if (outboxInfo) {
|
||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||
await this.eventAckPublisher.sendFailure(eventId, outboxInfo.eventType, errorMessage);
|
||
}
|
||
|
||
throw error;
|
||
}
|
||
}
|
||
}
|