fix(reward): change sourceOrderId to sourceOrderNo string type
Fixes BigInt conversion error when consuming planting.order.paid events. The orderId from planting-service is a string format like PLT1765391584505Q0Q6QD, not a numeric value. Changes: - reward-source.vo.ts: sourceOrderId (bigint) → sourceOrderNo (string) - reward-calculation.service.ts: updated all method signatures - reward-application.service.ts: updated distributeRewards params - event-consumer.controller.ts: removed BigInt() conversion - prisma schema: changed column type to VarChar(50) - mapper/repository: updated field names accordingly - Removed incompatible prisma.config.ts (Prisma 7.x format) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
6b10b15492
commit
8cea0e7998
|
|
@ -1,14 +0,0 @@
|
|||
// This file was generated by Prisma and assumes you have installed the following:
|
||||
// npm install --save-dev prisma dotenv
|
||||
import "dotenv/config";
|
||||
import { defineConfig, env } from "prisma/config";
|
||||
|
||||
export default defineConfig({
|
||||
schema: "prisma/schema.prisma",
|
||||
migrations: {
|
||||
path: "prisma/migrations",
|
||||
},
|
||||
datasource: {
|
||||
url: env("DATABASE_URL"),
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
-- AlterColumn: Change source_order_id from BIGINT to VARCHAR(50)
|
||||
-- This is needed because planting-service sends orderNo as string (e.g., PLT1765391584505Q0Q6QD)
|
||||
|
||||
-- Step 1: Drop the existing index
|
||||
DROP INDEX IF EXISTS "idx_source_order";
|
||||
|
||||
-- Step 2: Rename the old column
|
||||
ALTER TABLE "reward_ledger_entries" RENAME COLUMN "source_order_id" TO "source_order_no";
|
||||
|
||||
-- Step 3: Change the column type from BIGINT to VARCHAR(50)
|
||||
ALTER TABLE "reward_ledger_entries"
|
||||
ALTER COLUMN "source_order_no" TYPE VARCHAR(50) USING "source_order_no"::VARCHAR(50);
|
||||
|
||||
-- Step 4: Recreate the index on the new column
|
||||
CREATE INDEX "idx_source_order" ON "reward_ledger_entries"("source_order_no");
|
||||
|
|
@ -16,7 +16,7 @@ model RewardLedgerEntry {
|
|||
userId BigInt @map("user_id") // 接收奖励的用户ID
|
||||
|
||||
// === 奖励来源 ===
|
||||
sourceOrderId BigInt @map("source_order_id") // 来源认种订单ID
|
||||
sourceOrderNo String @map("source_order_no") @db.VarChar(50) // 来源认种订单号(字符串格式如PLT1765391584505Q0Q6QD)
|
||||
sourceUserId BigInt @map("source_user_id") // 触发奖励的用户ID(认种者)
|
||||
rightType String @map("right_type") @db.VarChar(50) // 权益类型
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ model RewardLedgerEntry {
|
|||
@@map("reward_ledger_entries")
|
||||
@@index([userId, rewardStatus], name: "idx_user_status")
|
||||
@@index([userId, createdAt(sort: Desc)], name: "idx_user_created")
|
||||
@@index([sourceOrderId], name: "idx_source_order")
|
||||
@@index([sourceOrderNo], name: "idx_source_order")
|
||||
@@index([sourceUserId], name: "idx_source_user")
|
||||
@@index([rightType], name: "idx_right_type")
|
||||
@@index([rewardStatus], name: "idx_status")
|
||||
|
|
|
|||
|
|
@ -35,13 +35,13 @@ export class RewardApplicationService {
|
|||
* 分配奖励 (响应认种订单支付成功事件)
|
||||
*/
|
||||
async distributeRewards(params: {
|
||||
sourceOrderId: bigint;
|
||||
sourceOrderNo: string; // 订单号是字符串格式如 PLT1765391584505Q0Q6QD
|
||||
sourceUserId: bigint;
|
||||
treeCount: number;
|
||||
provinceCode: string;
|
||||
cityCode: string;
|
||||
}): Promise<void> {
|
||||
this.logger.log(`Distributing rewards for order ${params.sourceOrderId}`);
|
||||
this.logger.log(`Distributing rewards for order ${params.sourceOrderNo}`);
|
||||
|
||||
// 1. 计算所有奖励
|
||||
const rewards = await this.rewardCalculationService.calculateRewards(params);
|
||||
|
|
@ -76,7 +76,7 @@ export class RewardApplicationService {
|
|||
reward.clearDomainEvents();
|
||||
}
|
||||
|
||||
this.logger.log(`Distributed ${rewards.length} rewards for order ${params.sourceOrderId}`);
|
||||
this.logger.log(`Distributed ${rewards.length} rewards for order ${params.sourceOrderNo}`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ export class RewardLedgerEntry {
|
|||
entry._domainEvents.push(new RewardCreatedEvent({
|
||||
entryId: entry._id?.toString() || 'temp',
|
||||
userId: entry._userId.toString(),
|
||||
sourceOrderId: entry._rewardSource.sourceOrderId.toString(),
|
||||
sourceOrderNo: entry._rewardSource.sourceOrderNo,
|
||||
sourceUserId: entry._rewardSource.sourceUserId.toString(),
|
||||
rightType: entry._rewardSource.rightType,
|
||||
usdtAmount: entry._usdtAmount.amount,
|
||||
|
|
@ -143,7 +143,7 @@ export class RewardLedgerEntry {
|
|||
entry._domainEvents.push(new RewardCreatedEvent({
|
||||
entryId: entry._id?.toString() || 'temp',
|
||||
userId: entry._userId.toString(),
|
||||
sourceOrderId: entry._rewardSource.sourceOrderId.toString(),
|
||||
sourceOrderNo: entry._rewardSource.sourceOrderNo,
|
||||
sourceUserId: entry._rewardSource.sourceUserId.toString(),
|
||||
rightType: entry._rewardSource.rightType,
|
||||
usdtAmount: entry._usdtAmount.amount,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { RewardStatus } from '../value-objects/reward-status.enum';
|
|||
export interface RewardCreatedPayload {
|
||||
entryId: string;
|
||||
userId: string;
|
||||
sourceOrderId: string;
|
||||
sourceOrderNo: string;
|
||||
sourceUserId: string;
|
||||
rightType: RightType;
|
||||
usdtAmount: number;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export interface IRewardLedgerEntryRepository {
|
|||
findPendingByUserId(userId: bigint): Promise<RewardLedgerEntry[]>;
|
||||
findSettleableByUserId(userId: bigint): Promise<RewardLedgerEntry[]>;
|
||||
findExpiredPending(beforeDate: Date): Promise<RewardLedgerEntry[]>;
|
||||
findBySourceOrderId(sourceOrderId: bigint): Promise<RewardLedgerEntry[]>;
|
||||
findBySourceOrderNo(sourceOrderNo: string): Promise<RewardLedgerEntry[]>;
|
||||
countByUserId(userId: bigint, status?: RewardStatus): Promise<number>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export class RewardCalculationService {
|
|||
* 总计 2199 USDT = 400 + 300 + 9 + 800 + 500 + 15 + 20 + 35 + 40 + 80
|
||||
*/
|
||||
async calculateRewards(params: {
|
||||
sourceOrderId: bigint;
|
||||
sourceOrderNo: string; // 订单号是字符串格式
|
||||
sourceUserId: bigint;
|
||||
treeCount: number;
|
||||
provinceCode: string;
|
||||
|
|
@ -65,7 +65,7 @@ export class RewardCalculationService {
|
|||
|
||||
// 1. 成本费 (400 USDT)
|
||||
const costFeeReward = this.calculateCostFee(
|
||||
params.sourceOrderId,
|
||||
params.sourceOrderNo,
|
||||
params.sourceUserId,
|
||||
params.treeCount,
|
||||
);
|
||||
|
|
@ -73,7 +73,7 @@ export class RewardCalculationService {
|
|||
|
||||
// 2. 运营费 (300 USDT)
|
||||
const operationFeeReward = this.calculateOperationFee(
|
||||
params.sourceOrderId,
|
||||
params.sourceOrderNo,
|
||||
params.sourceUserId,
|
||||
params.treeCount,
|
||||
);
|
||||
|
|
@ -81,7 +81,7 @@ export class RewardCalculationService {
|
|||
|
||||
// 3. 总部社区基础费 (9 USDT)
|
||||
const headquartersBaseFeeReward = this.calculateHeadquartersBaseFee(
|
||||
params.sourceOrderId,
|
||||
params.sourceOrderNo,
|
||||
params.sourceUserId,
|
||||
params.treeCount,
|
||||
);
|
||||
|
|
@ -89,7 +89,7 @@ export class RewardCalculationService {
|
|||
|
||||
// 4. RWAD底池注入 (800 USDT)
|
||||
const rwadPoolReward = this.calculateRwadPoolInjection(
|
||||
params.sourceOrderId,
|
||||
params.sourceOrderNo,
|
||||
params.sourceUserId,
|
||||
params.treeCount,
|
||||
);
|
||||
|
|
@ -101,7 +101,7 @@ export class RewardCalculationService {
|
|||
|
||||
// 5. 分享权益 (500 USDT)
|
||||
const shareRewards = await this.calculateShareRights(
|
||||
params.sourceOrderId,
|
||||
params.sourceOrderNo,
|
||||
params.sourceUserId,
|
||||
params.treeCount,
|
||||
);
|
||||
|
|
@ -109,7 +109,7 @@ export class RewardCalculationService {
|
|||
|
||||
// 6. 省团队权益 (20 USDT)
|
||||
const provinceTeamReward = await this.calculateProvinceTeamRight(
|
||||
params.sourceOrderId,
|
||||
params.sourceOrderNo,
|
||||
params.sourceUserId,
|
||||
params.provinceCode,
|
||||
params.treeCount,
|
||||
|
|
@ -118,7 +118,7 @@ export class RewardCalculationService {
|
|||
|
||||
// 7. 省区域权益 (15 USDT + 1%算力)
|
||||
const provinceAreaReward = this.calculateProvinceAreaRight(
|
||||
params.sourceOrderId,
|
||||
params.sourceOrderNo,
|
||||
params.sourceUserId,
|
||||
params.provinceCode,
|
||||
params.treeCount,
|
||||
|
|
@ -127,7 +127,7 @@ export class RewardCalculationService {
|
|||
|
||||
// 8. 市团队权益 (40 USDT)
|
||||
const cityTeamReward = await this.calculateCityTeamRight(
|
||||
params.sourceOrderId,
|
||||
params.sourceOrderNo,
|
||||
params.sourceUserId,
|
||||
params.cityCode,
|
||||
params.treeCount,
|
||||
|
|
@ -136,7 +136,7 @@ export class RewardCalculationService {
|
|||
|
||||
// 9. 市区域权益 (35 USDT + 2%算力)
|
||||
const cityAreaReward = this.calculateCityAreaRight(
|
||||
params.sourceOrderId,
|
||||
params.sourceOrderNo,
|
||||
params.sourceUserId,
|
||||
params.cityCode,
|
||||
params.treeCount,
|
||||
|
|
@ -145,7 +145,7 @@ export class RewardCalculationService {
|
|||
|
||||
// 10. 社区权益 (80 USDT)
|
||||
const communityReward = await this.calculateCommunityRight(
|
||||
params.sourceOrderId,
|
||||
params.sourceOrderNo,
|
||||
params.sourceUserId,
|
||||
params.treeCount,
|
||||
);
|
||||
|
|
@ -163,7 +163,7 @@ export class RewardCalculationService {
|
|||
* 分配至指定成本账户
|
||||
*/
|
||||
private calculateCostFee(
|
||||
sourceOrderId: bigint,
|
||||
sourceOrderNo: string,
|
||||
sourceUserId: bigint,
|
||||
treeCount: number,
|
||||
): RewardLedgerEntry {
|
||||
|
|
@ -173,7 +173,7 @@ export class RewardCalculationService {
|
|||
|
||||
const rewardSource = RewardSource.create(
|
||||
RightType.COST_FEE,
|
||||
sourceOrderId,
|
||||
sourceOrderNo,
|
||||
sourceUserId,
|
||||
);
|
||||
|
||||
|
|
@ -191,7 +191,7 @@ export class RewardCalculationService {
|
|||
* 分配至指定运营账户
|
||||
*/
|
||||
private calculateOperationFee(
|
||||
sourceOrderId: bigint,
|
||||
sourceOrderNo: string,
|
||||
sourceUserId: bigint,
|
||||
treeCount: number,
|
||||
): RewardLedgerEntry {
|
||||
|
|
@ -201,7 +201,7 @@ export class RewardCalculationService {
|
|||
|
||||
const rewardSource = RewardSource.create(
|
||||
RightType.OPERATION_FEE,
|
||||
sourceOrderId,
|
||||
sourceOrderNo,
|
||||
sourceUserId,
|
||||
);
|
||||
|
||||
|
|
@ -219,7 +219,7 @@ export class RewardCalculationService {
|
|||
* 分配至总部社区账户
|
||||
*/
|
||||
private calculateHeadquartersBaseFee(
|
||||
sourceOrderId: bigint,
|
||||
sourceOrderNo: string,
|
||||
sourceUserId: bigint,
|
||||
treeCount: number,
|
||||
): RewardLedgerEntry {
|
||||
|
|
@ -229,7 +229,7 @@ export class RewardCalculationService {
|
|||
|
||||
const rewardSource = RewardSource.create(
|
||||
RightType.HEADQUARTERS_BASE_FEE,
|
||||
sourceOrderId,
|
||||
sourceOrderNo,
|
||||
sourceUserId,
|
||||
);
|
||||
|
||||
|
|
@ -247,7 +247,7 @@ export class RewardCalculationService {
|
|||
* 注入RWAD 1号底池
|
||||
*/
|
||||
private calculateRwadPoolInjection(
|
||||
sourceOrderId: bigint,
|
||||
sourceOrderNo: string,
|
||||
sourceUserId: bigint,
|
||||
treeCount: number,
|
||||
): RewardLedgerEntry {
|
||||
|
|
@ -257,7 +257,7 @@ export class RewardCalculationService {
|
|||
|
||||
const rewardSource = RewardSource.create(
|
||||
RightType.RWAD_POOL_INJECTION,
|
||||
sourceOrderId,
|
||||
sourceOrderNo,
|
||||
sourceUserId,
|
||||
);
|
||||
|
||||
|
|
@ -278,7 +278,7 @@ export class RewardCalculationService {
|
|||
* 计算分享权益 (500 USDT)
|
||||
*/
|
||||
private async calculateShareRights(
|
||||
sourceOrderId: bigint,
|
||||
sourceOrderNo: string,
|
||||
sourceUserId: bigint,
|
||||
treeCount: number,
|
||||
): Promise<RewardLedgerEntry[]> {
|
||||
|
|
@ -288,7 +288,7 @@ export class RewardCalculationService {
|
|||
|
||||
const rewardSource = RewardSource.create(
|
||||
RightType.SHARE_RIGHT,
|
||||
sourceOrderId,
|
||||
sourceOrderNo,
|
||||
sourceUserId,
|
||||
);
|
||||
|
||||
|
|
@ -333,7 +333,7 @@ export class RewardCalculationService {
|
|||
* 计算省团队权益 (20 USDT)
|
||||
*/
|
||||
private async calculateProvinceTeamRight(
|
||||
sourceOrderId: bigint,
|
||||
sourceOrderNo: string,
|
||||
sourceUserId: bigint,
|
||||
provinceCode: string,
|
||||
treeCount: number,
|
||||
|
|
@ -344,7 +344,7 @@ export class RewardCalculationService {
|
|||
|
||||
const rewardSource = RewardSource.create(
|
||||
RightType.PROVINCE_TEAM_RIGHT,
|
||||
sourceOrderId,
|
||||
sourceOrderNo,
|
||||
sourceUserId,
|
||||
);
|
||||
|
||||
|
|
@ -377,7 +377,7 @@ export class RewardCalculationService {
|
|||
* 计算省区域权益 (15 USDT + 1%算力)
|
||||
*/
|
||||
private calculateProvinceAreaRight(
|
||||
sourceOrderId: bigint,
|
||||
sourceOrderNo: string,
|
||||
sourceUserId: bigint,
|
||||
provinceCode: string,
|
||||
treeCount: number,
|
||||
|
|
@ -388,7 +388,7 @@ export class RewardCalculationService {
|
|||
|
||||
const rewardSource = RewardSource.create(
|
||||
RightType.PROVINCE_AREA_RIGHT,
|
||||
sourceOrderId,
|
||||
sourceOrderNo,
|
||||
sourceUserId,
|
||||
);
|
||||
|
||||
|
|
@ -408,7 +408,7 @@ export class RewardCalculationService {
|
|||
* 计算市团队权益 (40 USDT)
|
||||
*/
|
||||
private async calculateCityTeamRight(
|
||||
sourceOrderId: bigint,
|
||||
sourceOrderNo: string,
|
||||
sourceUserId: bigint,
|
||||
cityCode: string,
|
||||
treeCount: number,
|
||||
|
|
@ -419,7 +419,7 @@ export class RewardCalculationService {
|
|||
|
||||
const rewardSource = RewardSource.create(
|
||||
RightType.CITY_TEAM_RIGHT,
|
||||
sourceOrderId,
|
||||
sourceOrderNo,
|
||||
sourceUserId,
|
||||
);
|
||||
|
||||
|
|
@ -452,7 +452,7 @@ export class RewardCalculationService {
|
|||
* 计算市区域权益 (35 USDT + 2%算力)
|
||||
*/
|
||||
private calculateCityAreaRight(
|
||||
sourceOrderId: bigint,
|
||||
sourceOrderNo: string,
|
||||
sourceUserId: bigint,
|
||||
cityCode: string,
|
||||
treeCount: number,
|
||||
|
|
@ -463,7 +463,7 @@ export class RewardCalculationService {
|
|||
|
||||
const rewardSource = RewardSource.create(
|
||||
RightType.CITY_AREA_RIGHT,
|
||||
sourceOrderId,
|
||||
sourceOrderNo,
|
||||
sourceUserId,
|
||||
);
|
||||
|
||||
|
|
@ -483,7 +483,7 @@ export class RewardCalculationService {
|
|||
* 计算社区权益 (80 USDT)
|
||||
*/
|
||||
private async calculateCommunityRight(
|
||||
sourceOrderId: bigint,
|
||||
sourceOrderNo: string,
|
||||
sourceUserId: bigint,
|
||||
treeCount: number,
|
||||
): Promise<RewardLedgerEntry> {
|
||||
|
|
@ -493,7 +493,7 @@ export class RewardCalculationService {
|
|||
|
||||
const rewardSource = RewardSource.create(
|
||||
RightType.COMMUNITY_RIGHT,
|
||||
sourceOrderId,
|
||||
sourceOrderNo,
|
||||
sourceUserId,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,22 +3,22 @@ import { RightType } from './right-type.enum';
|
|||
export class RewardSource {
|
||||
private constructor(
|
||||
public readonly rightType: RightType,
|
||||
public readonly sourceOrderId: bigint,
|
||||
public readonly sourceOrderNo: string, // 订单号是字符串格式如 PLT1765391584505Q0Q6QD
|
||||
public readonly sourceUserId: bigint,
|
||||
) {}
|
||||
|
||||
static create(
|
||||
rightType: RightType,
|
||||
sourceOrderId: bigint,
|
||||
sourceOrderNo: string,
|
||||
sourceUserId: bigint,
|
||||
): RewardSource {
|
||||
return new RewardSource(rightType, sourceOrderId, sourceUserId);
|
||||
return new RewardSource(rightType, sourceOrderNo, sourceUserId);
|
||||
}
|
||||
|
||||
equals(other: RewardSource): boolean {
|
||||
return (
|
||||
this.rightType === other.rightType &&
|
||||
this.sourceOrderId === other.sourceOrderId &&
|
||||
this.sourceOrderNo === other.sourceOrderNo &&
|
||||
this.sourceUserId === other.sourceUserId
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export class EventConsumerController {
|
|||
try {
|
||||
// 1. 计算并分配奖励
|
||||
await this.rewardService.distributeRewards({
|
||||
sourceOrderId: BigInt(eventData.orderId),
|
||||
sourceOrderNo: eventData.orderId, // orderId 实际是 orderNo 字符串格式
|
||||
sourceUserId: BigInt(eventData.userId),
|
||||
treeCount: eventData.treeCount,
|
||||
provinceCode: eventData.provinceCode,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export class RewardLedgerEntryMapper {
|
|||
userId: raw.userId,
|
||||
rewardSource: RewardSource.create(
|
||||
raw.rightType as RightType,
|
||||
raw.sourceOrderId,
|
||||
raw.sourceOrderNo,
|
||||
raw.sourceUserId,
|
||||
),
|
||||
usdtAmount: Number(raw.usdtAmount),
|
||||
|
|
@ -30,7 +30,7 @@ export class RewardLedgerEntryMapper {
|
|||
return {
|
||||
id: entry.id || undefined,
|
||||
userId: entry.userId,
|
||||
sourceOrderId: entry.rewardSource.sourceOrderId,
|
||||
sourceOrderNo: entry.rewardSource.sourceOrderNo,
|
||||
sourceUserId: entry.rewardSource.sourceUserId,
|
||||
rightType: entry.rewardSource.rightType,
|
||||
usdtAmount: new Prisma.Decimal(entry.usdtAmount.amount),
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export class RewardLedgerEntryRepositoryImpl implements IRewardLedgerEntryReposi
|
|||
const created = await this.prisma.rewardLedgerEntry.create({
|
||||
data: {
|
||||
userId: data.userId,
|
||||
sourceOrderId: data.sourceOrderId,
|
||||
sourceOrderNo: data.sourceOrderNo,
|
||||
sourceUserId: data.sourceUserId,
|
||||
rightType: data.rightType,
|
||||
usdtAmount: data.usdtAmount,
|
||||
|
|
@ -137,9 +137,9 @@ export class RewardLedgerEntryRepositoryImpl implements IRewardLedgerEntryReposi
|
|||
return rawList.map(RewardLedgerEntryMapper.toDomain);
|
||||
}
|
||||
|
||||
async findBySourceOrderId(sourceOrderId: bigint): Promise<RewardLedgerEntry[]> {
|
||||
async findBySourceOrderNo(sourceOrderNo: string): Promise<RewardLedgerEntry[]> {
|
||||
const rawList = await this.prisma.rewardLedgerEntry.findMany({
|
||||
where: { sourceOrderId },
|
||||
where: { sourceOrderNo },
|
||||
});
|
||||
|
||||
return rawList.map(RewardLedgerEntryMapper.toDomain);
|
||||
|
|
|
|||
Loading…
Reference in New Issue