feat(pricing): 预种每份价格从 3171 调整为 3566 绿积分

分配规则:按 reward-service RIGHT_AMOUNTS(15831 整棵树)各项 /5 取整,
余额全归总部社区(HQ_BASE_FEE)。5 份合成一棵树 = 17830。

10 类分配金额变更:
- COST_FEE:       576 (不变, floor(2880/5))
- OPERATION_FEE:  420 (不变, floor(2100/5))
- HQ_BASE_FEE:    29.4 → 427 (3566 - 3139, 吸收全部余额)
- RWAD_POOL:      1152 (不变, floor(5760/5))
- SHARE_RIGHT:    720 (不变, floor(3600/5))
- PROVINCE_AREA:  21.6 → 21 (floor(108/5))
- PROVINCE_TEAM:  28.8 → 28 (floor(144/5))
- CITY_AREA:      50.4 → 50 (floor(252/5))
- CITY_TEAM:      57.6 → 57 (floor(288/5))
- COMMUNITY:      115.2 → 115 (floor(576/5))
- 合计: 3171 → 3566 ✓

涉及服务:planting-service, admin-service, contribution-service
涉及前端:admin-web, mobile-app (Flutter)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-02-26 08:02:17 -08:00
parent 5adcd023e6
commit acf55b26a7
18 changed files with 51 additions and 51 deletions

View File

@ -3,7 +3,7 @@ import { PrismaService } from '../infrastructure/persistence/prisma/prisma.servi
/** 基础价常量 */
const BASE_PRICE = 15831;
const BASE_PORTION_PRICE = 3171; // 预种基础价 = BASE_PRICE 的 1/5 取整
const BASE_PORTION_PRICE = 3566; // 预种基础价9项 floor(整棵树/5) 取整 + 余额归总部
export interface TreePricingConfigResponse {
basePrice: number;

View File

@ -205,8 +205,8 @@ export class PrePlantingOrderSyncedHandler {
userId: BigInt(data.user_id || data.userId || 0),
accountSequence: data.account_sequence || data.accountSequence,
portionCount: data.portion_count || data.portionCount || 1,
pricePerPortion: data.price_per_portion || data.pricePerPortion || 3171,
totalAmount: data.total_amount || data.totalAmount || 3171,
pricePerPortion: data.price_per_portion || data.pricePerPortion || 3566,
totalAmount: data.total_amount || data.totalAmount || 3566,
provinceCode: data.province_code || data.provinceCode || '',
cityCode: data.city_code || data.cityCode || '',
status: data.status || 'CREATED',

View File

@ -396,7 +396,7 @@ model DebeziumHeartbeat {
}
// ============================================
// 预种订单表 (3171 预种计划)
// 预种订单表 (3566 预种计划)
// 每次购买一份预种创建一条记录
// ============================================
model PrePlantingOrder {
@ -407,7 +407,7 @@ model PrePlantingOrder {
// 购买信息
portionCount Int @default(1) @map("portion_count")
pricePerPortion Decimal @default(3171) @map("price_per_portion") @db.Decimal(20, 8)
pricePerPortion Decimal @default(3566) @map("price_per_portion") @db.Decimal(20, 8)
totalAmount Decimal @map("total_amount") @db.Decimal(20, 8)
priceSupplement Int @default(0) @map("price_supplement") // 总部运营成本压力涨价(每份加价金额),归总部 (S0000000001)

View File

@ -5,7 +5,7 @@ import { InfrastructureModule } from './infrastructure/infrastructure.module';
import { DomainModule } from './domain/domain.module';
import { ApplicationModule } from './application/application.module';
import { ApiModule } from './api/api.module';
// [2026-02-17] 新增3171 预种计划模块(纯新增,与现有 PlantingOrder 零耦合)
// [2026-02-17] 新增3566 预种计划模块(纯新增,与现有 PlantingOrder 零耦合)
import { PrePlantingModule } from './pre-planting/pre-planting.module';
import { GlobalExceptionFilter } from './shared/filters/global-exception.filter';
import configs from './config';

View File

@ -45,13 +45,13 @@ export class TreePricingAdminClient {
return response.data;
} catch (error) {
this.logger.error('Failed to get tree pricing config, using default (supplement=0)', error);
// 安全降级:加价为 0等同于原始价格 15831不影响现有业务
// 安全降级:加价为 0不影响现有业务
return {
basePrice: 15831,
basePortionPrice: 3171,
basePortionPrice: 3566,
currentSupplement: 0,
totalPrice: 15831,
totalPortionPrice: 3171,
totalPortionPrice: 3566,
autoIncreaseEnabled: false,
autoIncreaseAmount: 0,
autoIncreaseIntervalDays: 0,

View File

@ -1,25 +1,25 @@
/**
* 1/5
*
* reward-service RIGHT_AMOUNTS
* = / 5 4.8 HQ_BASE_FEE
* reward-service RIGHT_AMOUNTS15831
* 9 = floor( / 5) HQ_BASE_FEE
*/
export const PRE_PLANTING_RIGHT_AMOUNTS = {
COST_FEE: 576, // 2880/5
OPERATION_FEE: 420, // 2100/5
HEADQUARTERS_BASE_FEE: 29.4, // 123/5 + 4.8 差额3171 - 3166.2 = 4.8
RWAD_POOL_INJECTION: 1152, // 5760/5
SHARE_RIGHT: 720, // 3600/5 = 720推荐奖励金额
PROVINCE_AREA_RIGHT: 21.6, // 108/5
PROVINCE_TEAM_RIGHT: 28.8, // 144/5
CITY_AREA_RIGHT: 50.4, // 252/5
CITY_TEAM_RIGHT: 57.6, // 288/5
COMMUNITY_RIGHT: 115.2, // 576/5
COST_FEE: 576, // floor(2880/5)
OPERATION_FEE: 420, // floor(2100/5)
HEADQUARTERS_BASE_FEE: 427, // 3566 - 3139 = 427吸收全部余额
RWAD_POOL_INJECTION: 1152, // floor(5760/5)
SHARE_RIGHT: 720, // floor(3600/5)
PROVINCE_AREA_RIGHT: 21, // floor(108/5)
PROVINCE_TEAM_RIGHT: 28, // floor(144/5)
CITY_AREA_RIGHT: 50, // floor(252/5)
CITY_TEAM_RIGHT: 57, // floor(288/5)
COMMUNITY_RIGHT: 115, // floor(576/5)
} as const;
// 合计 = 576 + 420 + 29.4 + 1152 + 720 + 21.6 + 28.8 + 50.4 + 57.6 + 115.2 = 3171.0
// 合计 = 576 + 420 + 427 + 1152 + 720 + 21 + 28 + 50 + 57 + 115 = 3566
export const PRE_PLANTING_PRICE_PER_PORTION = 3171;
export const PRE_PLANTING_PRICE_PER_PORTION = 3566;
export const PRE_PLANTING_PORTIONS_PER_TREE = 5;
/**

View File

@ -21,10 +21,10 @@ import { PrePlantingReferralClient } from './infrastructure/external/pre-plantin
import { PrePlantingAuthorizationClient } from './infrastructure/external/pre-planting-authorization.client';
/**
* (3171 / )
* (3566 / )
*
* === ===
* 3171 USDT/ 11/551
* 3566 USDT/ 11/551
*
*
* === ===

View File

@ -140,7 +140,7 @@ export default function PrePlantingPage() {
</div>
<div className={styles.prePlanting__switchDesc}>
{config?.isActive
? '用户可正常购买预种份额3171 USDT/份)'
? '用户可正常购买预种份额3566 USDT/份)'
: '新用户不可购买;已有未凑满份额的用户可继续购买至 5 的倍数'}
</div>
</div>

View File

@ -35,7 +35,7 @@ const topMenuItems: MenuItem[] = [
{ key: 'withdrawals', icon: '/images/Container5.svg', label: '提现审核', path: '/withdrawals' },
{ key: 'system-transfer', icon: '/images/Container5.svg', label: '系统划转', path: '/system-transfer' },
{ key: 'statistics', icon: '/images/Container5.svg', label: '数据统计', path: '/statistics' },
// [2026-02-17] 新增预种计划管理3171 USDT/份预种开关 + 订单/持仓/合并查询)
// [2026-02-17] 新增预种计划管理3566 USDT/份预种开关 + 订单/持仓/合并查询)
{ key: 'pre-planting', icon: '/images/Container3.svg', label: '预种管理', path: '/pre-planting' },
// [2026-02-19] 纯新增:树转让管理
{ key: 'transfers', icon: '/images/Container5.svg', label: '转让管理', path: '/transfers' },

View File

@ -289,7 +289,7 @@ export const API_ENDPOINTS = {
BATCH_DOWNLOAD_STATUS: (taskNo: string) => `/v1/admin/contracts/batch-download/${taskNo}`,
},
// [2026-02-17] 新增:预种计划管理 (admin-service / PrePlantingAdminModule)
// 3171 USDT/份预种,累计 5 份合成 1 棵树
// 3566 USDT/份预种,累计 5 份合成 1 棵树
// 开关管理 + 预种订单/持仓/合并记录查询
PRE_PLANTING: {
// 预种开关配置

View File

@ -98,7 +98,7 @@ class ApiEndpoints {
static const String pendingActionsComplete = '/user/pending-actions'; // POST /:id/complete
// [2026-02-17] (-> Planting Service / PrePlantingModule)
// 3171 USDT/ 5 1
// 3566 USDT/ 5 1
// /planting/*
static const String prePlanting = '/pre-planting';
static const String prePlantingConfig = '$prePlanting/config'; //

View File

@ -9,7 +9,7 @@ import '../services/authorization_service.dart';
import '../services/deposit_service.dart';
import '../services/wallet_service.dart';
import '../services/planting_service.dart';
// [2026-02-17] 3171 USDT/
// [2026-02-17] 3566 USDT/
import '../services/pre_planting_service.dart';
// [2026-02-19]
import '../services/transfer_service.dart';
@ -102,7 +102,7 @@ final plantingServiceProvider = Provider<PlantingService>((ref) {
});
// [2026-02-17] Pre-Planting Service Provider ( planting-service / PrePlantingModule)
// 3171 USDT/ 5 1 PlantingService
// 3566 USDT/ 5 1 PlantingService
final prePlantingServiceProvider = Provider<PrePlantingService>((ref) {
final apiClient = ref.watch(apiClientProvider);
return PrePlantingService(apiClient: apiClient);

View File

@ -5,8 +5,8 @@ import '../network/api_client.dart';
// [2026-02-17] API
// ============================================
//
// 3171 / Flutter API
// 3171 USDT/ 5 1
// 3566 / Flutter API
// 3566 USDT/ 5 1
//
// === API ===
// planting-service PrePlantingModule
@ -21,7 +21,7 @@ import '../network/api_client.dart';
//
// === PlantingService ===
// PlantingService 15831 USDT/
// PrePlantingService 3171 USDT/
// PrePlantingService 3566 USDT/
// API
///
@ -112,7 +112,7 @@ class PrePlantingPosition {
class PrePlantingOrder {
final String orderNo;
final int portionCount; // 1
final double pricePerPortion; // 3171 USDT
final double pricePerPortion; // 3566 USDT
final double totalAmount; //
final PrePlantingOrderStatus status;
final String? mergedToMergeId; // MergeId
@ -136,8 +136,8 @@ class PrePlantingOrder {
return PrePlantingOrder(
orderNo: json['orderNo'] ?? '',
portionCount: json['portionCount'] ?? 1,
pricePerPortion: (json['pricePerPortion'] ?? 3171).toDouble(),
totalAmount: (json['totalAmount'] ?? 3171).toDouble(),
pricePerPortion: (json['pricePerPortion'] ?? 3566).toDouble(),
totalAmount: (json['totalAmount'] ?? 3566).toDouble(),
status: _parseStatus(json['status']),
mergedToMergeId: json['mergedToMergeId']?.toString(),
paidAt: json['paidAt'] != null ? DateTime.parse(json['paidAt']) : null,
@ -239,8 +239,8 @@ class CreatePrePlantingOrderResponse {
return CreatePrePlantingOrderResponse(
orderNo: json['orderNo'] ?? '',
portionCount: json['portionCount'] ?? 1,
totalAmount: (json['totalAmount'] ?? 3171).toDouble(),
pricePerPortion: (json['pricePerPortion'] ?? 3171).toDouble(),
totalAmount: (json['totalAmount'] ?? 3566).toDouble(),
pricePerPortion: (json['pricePerPortion'] ?? 3566).toDouble(),
);
}
}

View File

@ -10,7 +10,7 @@ class TreePricingConfig {
/// 15831
final int basePrice;
/// 3171
/// 3566
final int basePortionPrice;
///
@ -49,10 +49,10 @@ class TreePricingConfig {
factory TreePricingConfig.fromJson(Map<String, dynamic> json) {
return TreePricingConfig(
basePrice: json['basePrice'] ?? 15831,
basePortionPrice: json['basePortionPrice'] ?? 3171,
basePortionPrice: json['basePortionPrice'] ?? 3566,
currentSupplement: json['currentSupplement'] ?? 0,
totalPrice: json['totalPrice'] ?? 15831,
totalPortionPrice: json['totalPortionPrice'] ?? 3171,
totalPortionPrice: json['totalPortionPrice'] ?? 3566,
autoIncreaseEnabled: json['autoIncreaseEnabled'] ?? false,
autoIncreaseAmount: json['autoIncreaseAmount'] ?? 0,
autoIncreaseIntervalDays: json['autoIncreaseIntervalDays'] ?? 0,
@ -66,10 +66,10 @@ class TreePricingConfig {
factory TreePricingConfig.defaultConfig() {
return TreePricingConfig(
basePrice: 15831,
basePortionPrice: 3171,
basePortionPrice: 3566,
currentSupplement: 0,
totalPrice: 15831,
totalPortionPrice: 3171,
totalPortionPrice: 3566,
autoIncreaseEnabled: false,
autoIncreaseAmount: 0,
autoIncreaseIntervalDays: 0,

View File

@ -421,7 +421,7 @@ class _PrePlantingMergeDetailPageState
const SizedBox(height: 8),
_buildDetailRow(
'总价值',
'${(merge.sourceOrderNos.length * 3171).toString()} USDT',
'${(merge.sourceOrderNos.length * 3566).toString()} USDT',
),
if (merge.selectedProvince != null) ...[
const SizedBox(height: 8),

View File

@ -11,7 +11,7 @@ import '../../../../core/services/tree_pricing_service.dart';
// ============================================
//
// /
// - 3171 USDT/
// - 3566 USDT/
// - 5 1
// -
// -
@ -24,11 +24,11 @@ import '../../../../core/services/tree_pricing_service.dart';
//
// === ===
// planting_quantity_page.dart 15831 USDT/
// 3171 USDT/
// 3566 USDT/
///
///
/// 3171 USDT/ 5 1
/// 3566 USDT/ 5 1
///
class PrePlantingPurchasePage extends ConsumerStatefulWidget {
const PrePlantingPurchasePage({super.key});
@ -43,7 +43,7 @@ class _PrePlantingPurchasePageState
// === ===
/// USDT- admin-service
double _pricePerPortion = 3171.0;
double _pricePerPortion = 3566.0;
///
static const int _portionsPerTree = 5;

View File

@ -1931,7 +1931,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
/// [2026-02-17] +
///
///
/// - 3171 USDT/
/// - 3566 USDT/
/// -
Widget _buildPrePlantingButtons() {
return Row(

View File

@ -44,7 +44,7 @@ import '../features/kyc/presentation/pages/change_phone_page.dart';
import '../features/contract_signing/presentation/pages/contract_signing_page.dart';
import '../features/contract_signing/presentation/pages/pending_contracts_page.dart';
import '../features/pending_actions/presentation/pages/pending_actions_page.dart';
// [2026-02-17] 3171 USDT/ 5 1
// [2026-02-17] 3566 USDT/ 5 1
import '../features/pre_planting/presentation/pages/pre_planting_purchase_page.dart';
import '../features/pre_planting/presentation/pages/pre_planting_position_page.dart';
import '../features/pre_planting/presentation/pages/pre_planting_merge_detail_page.dart';