From 141db46356047c5ec2eb81bd0486168bc9743a3f Mon Sep 17 00:00:00 2001 From: hailin Date: Wed, 14 Jan 2026 18:01:30 -0800 Subject: [PATCH] fix(contribution-service): use real contributionPerTree from rate service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, adoptions were synced with hardcoded contributionPerTree=1, resulting in contribution values like 0.7 instead of the expected 15831.9. Now the handler fetches the actual contribution rate from ContributionRateService based on the adoption date, storing values like: - Personal (70%): 22617 × 70% = 15831.9 - Team Level (0.5%): 22617 × 0.5% = 113.085 - Team Bonus (2.5%): 22617 × 2.5% = 565.425 Note: Historical data may need migration to apply the correct multiplier. Co-Authored-By: Claude Opus 4.5 --- .../event-handlers/adoption-synced.handler.ts | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/backend/services/contribution-service/src/application/event-handlers/adoption-synced.handler.ts b/backend/services/contribution-service/src/application/event-handlers/adoption-synced.handler.ts index fa2378fe..6db467f2 100644 --- a/backend/services/contribution-service/src/application/event-handlers/adoption-synced.handler.ts +++ b/backend/services/contribution-service/src/application/event-handlers/adoption-synced.handler.ts @@ -2,6 +2,7 @@ import { Injectable, Logger } from '@nestjs/common'; import Decimal from 'decimal.js'; import { CDCEvent, TransactionClient } from '../../infrastructure/kafka/cdc-consumer.service'; import { ContributionCalculationService } from '../services/contribution-calculation.service'; +import { ContributionRateService } from '../services/contribution-rate.service'; /** * 认种同步结果,用于事务提交后的算力计算 @@ -27,6 +28,7 @@ export class AdoptionSyncedHandler { constructor( private readonly contributionCalculationService: ContributionCalculationService, + private readonly contributionRateService: ContributionRateService, ) {} /** @@ -40,13 +42,28 @@ export class AdoptionSyncedHandler { this.logger.log(`[CDC] Adoption event received: op=${op}, seq=${event.sequenceNum}`); this.logger.debug(`[CDC] Adoption event payload: ${JSON.stringify(after || before)}`); + // 获取认种日期,用于查询当日贡献值 + const data = after || before; + const adoptionDate = data?.created_at || data?.createdAt || data?.paid_at || data?.paidAt; + + // 在事务外获取当日每棵树的贡献值 + let contributionPerTree = new Decimal('22617'); // 默认值 + if (adoptionDate) { + try { + contributionPerTree = await this.contributionRateService.getContributionPerTree(new Date(adoptionDate)); + this.logger.log(`[CDC] Got contributionPerTree for ${adoptionDate}: ${contributionPerTree.toString()}`); + } catch (error) { + this.logger.warn(`[CDC] Failed to get contributionPerTree, using default 22617`, error); + } + } + try { switch (op) { case 'c': // create case 'r': // read (snapshot) - return await this.handleCreate(after, event.sequenceNum, tx); + return await this.handleCreate(after, event.sequenceNum, tx, contributionPerTree); case 'u': // update - return await this.handleUpdate(after, before, event.sequenceNum, tx); + return await this.handleUpdate(after, before, event.sequenceNum, tx, contributionPerTree); case 'd': // delete await this.handleDelete(before); return null; @@ -78,7 +95,7 @@ export class AdoptionSyncedHandler { } } - private async handleCreate(data: any, sequenceNum: bigint, tx: TransactionClient): Promise { + private async handleCreate(data: any, sequenceNum: bigint, tx: TransactionClient, contributionPerTree: Decimal): Promise { if (!data) { this.logger.warn(`[CDC] Adoption create: empty data received`); return null; @@ -92,7 +109,7 @@ export class AdoptionSyncedHandler { const selectedCity = data.selected_city || data.selectedCity || null; const status = data.status ?? null; - this.logger.log(`[CDC] Adoption create: orderId=${orderId}, account=${accountSequence}, trees=${treeCount}, status=${status}`); + this.logger.log(`[CDC] Adoption create: orderId=${orderId}, account=${accountSequence}, trees=${treeCount}, status=${status}, contributionPerTree=${contributionPerTree.toString()}`); if (!orderId || !accountSequence) { this.logger.warn(`[CDC] Invalid adoption data: missing order_id or account_sequence`, { data }); @@ -101,7 +118,7 @@ export class AdoptionSyncedHandler { const originalAdoptionId = BigInt(orderId); - // 100%同步数据 + // 100%同步数据,使用真实的每棵树贡献值 await tx.syncedAdoption.upsert({ where: { originalAdoptionId }, create: { @@ -112,7 +129,7 @@ export class AdoptionSyncedHandler { status, selectedProvince, selectedCity, - contributionPerTree: new Decimal('1'), + contributionPerTree, sourceSequenceNum: sequenceNum, syncedAt: new Date(), }, @@ -123,7 +140,7 @@ export class AdoptionSyncedHandler { status, selectedProvince, selectedCity, - contributionPerTree: new Decimal('1'), + contributionPerTree, sourceSequenceNum: sequenceNum, syncedAt: new Date(), }, @@ -139,7 +156,7 @@ export class AdoptionSyncedHandler { }; } - private async handleUpdate(after: any, before: any, sequenceNum: bigint, tx: TransactionClient): Promise { + private async handleUpdate(after: any, before: any, sequenceNum: bigint, tx: TransactionClient, contributionPerTree: Decimal): Promise { if (!after) { this.logger.warn(`[CDC] Adoption update: empty after data received`); return null; @@ -155,14 +172,14 @@ export class AdoptionSyncedHandler { const newStatus = after.status ?? null; const oldStatus = before?.status ?? null; - this.logger.log(`[CDC] Adoption update: orderId=${orderId}, status=${oldStatus} -> ${newStatus}`); + this.logger.log(`[CDC] Adoption update: orderId=${orderId}, status=${oldStatus} -> ${newStatus}, contributionPerTree=${contributionPerTree.toString()}`); // 查询现有记录 const existingAdoption = await tx.syncedAdoption.findUnique({ where: { originalAdoptionId }, }); - // 100%同步数据,不跳过任何更新 + // 100%同步数据,使用真实的每棵树贡献值 await tx.syncedAdoption.upsert({ where: { originalAdoptionId }, create: { @@ -173,7 +190,7 @@ export class AdoptionSyncedHandler { status: newStatus, selectedProvince, selectedCity, - contributionPerTree: new Decimal('1'), + contributionPerTree, sourceSequenceNum: sequenceNum, syncedAt: new Date(), }, @@ -184,7 +201,7 @@ export class AdoptionSyncedHandler { status: newStatus, selectedProvince, selectedCity, - contributionPerTree: new Decimal('1'), + contributionPerTree, sourceSequenceNum: sequenceNum, syncedAt: new Date(), },