import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { HttpService } from '@nestjs/axios'; import { firstValueFrom } from 'rxjs'; import { SYSTEM_ACCOUNTS } from '../../domain/value-objects/pre-planting-right-amounts'; export interface RewardDistributionResult { recipientAccountSequence: string; isFallback: boolean; } /** * authorization-service 省/市区域 API 返回的 distributions 数组项 */ interface AreaDistributionItem { accountSequence: string; treeCount: number; reason: string; isSystemAccount: boolean; } /** * authorization-service 全局 TransformInterceptor 包装格式 * 所有响应都被包装为 { success: boolean, data: T, timestamp: string } */ interface WrappedResponse { success: boolean; data: T; timestamp: string; } @Injectable() export class PrePlantingAuthorizationClient { private readonly logger = new Logger(PrePlantingAuthorizationClient.name); private readonly baseUrl: string; constructor( private readonly configService: ConfigService, private readonly httpService: HttpService, ) { this.baseUrl = this.configService.get('AUTHORIZATION_SERVICE_URL') || 'http://localhost:3006'; } /** * 社区权益分配对象 */ async getCommunityDistribution( accountSequence: string, ): Promise { try { const response = await firstValueFrom( this.httpService.get>( `${this.baseUrl}/api/v1/authorization/community-reward-distribution`, { params: { accountSequence } }, ), ); return { recipientAccountSequence: response.data.data.accountSequence, isFallback: false, }; } catch (error) { this.logger.warn( `Failed to get community distribution for ${accountSequence}, fallback to HQ`, ); return { recipientAccountSequence: SYSTEM_ACCOUNTS.HEADQUARTERS, isFallback: true, }; } } /** * 省区域权益分配对象 * * [2026-02-28] 修复: * 1. 传 treeCount=0(预种阶段不计入省公司月度考核,等合成1棵树后再累计) * 2. 正确解析 { success, data: { distributions: [...] } } 包装格式 * 3. fallback 路径使用 padEnd(6,'0') 右补零,确保生成 7 位标准格式(如 9440000) */ async getProvinceAreaDistribution( provinceCode: string, ): Promise { try { const response = await firstValueFrom( this.httpService.get>( `${this.baseUrl}/api/v1/authorization/province-area-reward-distribution`, { params: { provinceCode, treeCount: 0 } }, ), ); const distributions = response.data.data.distributions; if (!distributions || distributions.length === 0) { throw new Error('Empty distributions returned'); } // 预种不拆分金额,取第一个分配对象的 accountSequence // 如果跨考核达标点有多个 distribution,优先取非系统账户(即省公司) const target = distributions.find(d => !d.isSystemAccount) || distributions[0]; this.logger.debug( `Province area distribution for ${provinceCode}: ${target.accountSequence} (${target.reason})`, ); return { recipientAccountSequence: target.accountSequence, isFallback: false, }; } catch (error) { this.logger.warn( `Failed to get province area distribution for ${provinceCode}, fallback to system province account`, ); return { recipientAccountSequence: `9${provinceCode.padEnd(6, '0')}`, isFallback: true, }; } } /** * 省团队权益分配对象 */ async getProvinceTeamDistribution( accountSequence: string, ): Promise { try { const response = await firstValueFrom( this.httpService.get>( `${this.baseUrl}/api/v1/authorization/province-team-reward-distribution`, { params: { accountSequence } }, ), ); return { recipientAccountSequence: response.data.data.accountSequence, isFallback: false, }; } catch (error) { this.logger.warn( `Failed to get province team distribution, fallback to HQ`, ); return { recipientAccountSequence: SYSTEM_ACCOUNTS.HEADQUARTERS, isFallback: true, }; } } /** * 市区域权益分配对象 * * [2026-02-28] 修复:与省区域同样的处理 * 1. 传 treeCount=0(预种阶段不计入市公司月度考核,等合成1棵树后再累计) * 2. 正确解析 { success, data: { distributions: [...] } } 包装格式 * 3. fallback 路径使用 padEnd(6,'0') 右补零,确保生成 7 位标准格式(如 8440100) */ async getCityAreaDistribution( cityCode: string, ): Promise { try { const response = await firstValueFrom( this.httpService.get>( `${this.baseUrl}/api/v1/authorization/city-area-reward-distribution`, { params: { cityCode, treeCount: 0 } }, ), ); const distributions = response.data.data.distributions; if (!distributions || distributions.length === 0) { throw new Error('Empty distributions returned'); } // 预种不拆分金额,取第一个分配对象的 accountSequence const target = distributions.find(d => !d.isSystemAccount) || distributions[0]; this.logger.debug( `City area distribution for ${cityCode}: ${target.accountSequence} (${target.reason})`, ); return { recipientAccountSequence: target.accountSequence, isFallback: false, }; } catch (error) { this.logger.warn( `Failed to get city area distribution for ${cityCode}, fallback to system city account`, ); return { recipientAccountSequence: `8${cityCode.padEnd(6, '0')}`, isFallback: true, }; } } /** * 市团队权益分配对象 */ async getCityTeamDistribution( accountSequence: string, ): Promise { try { const response = await firstValueFrom( this.httpService.get>( `${this.baseUrl}/api/v1/authorization/city-team-reward-distribution`, { params: { accountSequence } }, ), ); return { recipientAccountSequence: response.data.data.accountSequence, isFallback: false, }; } catch (error) { this.logger.warn( `Failed to get city team distribution, fallback to HQ`, ); return { recipientAccountSequence: SYSTEM_ACCOUNTS.HEADQUARTERS, isFallback: true, }; } } }