diff --git a/backend/services/mining-wallet-service/package.json b/backend/services/mining-wallet-service/package.json index c20d51b3..fef71cdb 100644 --- a/backend/services/mining-wallet-service/package.json +++ b/backend/services/mining-wallet-service/package.json @@ -16,7 +16,8 @@ "prisma:generate": "prisma generate", "prisma:migrate": "prisma migrate dev", "prisma:migrate:prod": "prisma migrate deploy", - "prisma:studio": "prisma studio" + "prisma:studio": "prisma studio", + "prisma:seed": "ts-node prisma/seed.ts" }, "dependencies": { "@nestjs/common": "^10.3.0", diff --git a/backend/services/mining-wallet-service/prisma/seed.ts b/backend/services/mining-wallet-service/prisma/seed.ts new file mode 100644 index 00000000..d160e008 --- /dev/null +++ b/backend/services/mining-wallet-service/prisma/seed.ts @@ -0,0 +1,92 @@ +import { PrismaClient } from '@prisma/client'; +import Decimal from 'decimal.js'; + +const prisma = new PrismaClient(); + +async function main() { + console.log('Seeding mining-wallet-service database...'); + + // 1. 初始化核心系统账户(总部、运营、手续费) + const systemAccounts = [ + { accountType: 'HEADQUARTERS', name: '总部账户', code: 'HQ' }, + { accountType: 'OPERATION', name: '运营账户', code: 'OP' }, + { accountType: 'FEE', name: '手续费账户', code: 'FEE' }, + ]; + + for (const account of systemAccounts) { + const existing = await prisma.systemAccount.findFirst({ + where: { code: account.code }, + }); + + if (!existing) { + await prisma.systemAccount.create({ + data: { + accountType: account.accountType as any, + name: account.name, + code: account.code, + isActive: true, + }, + }); + console.log(`Created system account: ${account.code}`); + } else { + console.log(`System account already exists: ${account.code}`); + } + } + + // 2. 初始化池账户(积分股池、黑洞池、流通池) + const poolAccounts = [ + { + poolType: 'SHARE_POOL', + name: '积分股池', + balance: new Decimal('100000000'), // 1亿初始发行量 + description: '挖矿奖励的来源池,总发行量', + }, + { + poolType: 'BLACK_HOLE_POOL', + name: '黑洞池', + balance: new Decimal('0'), + targetBurn: new Decimal('50000000'), // 目标销毁5000万 + description: '销毁的积分股,用于减少流通量', + }, + { + poolType: 'CIRCULATION_POOL', + name: '流通池', + balance: new Decimal('0'), + description: '市场流通的积分股', + }, + ]; + + for (const pool of poolAccounts) { + const existing = await prisma.poolAccount.findFirst({ + where: { poolType: pool.poolType as any }, + }); + + if (!existing) { + await prisma.poolAccount.create({ + data: { + poolType: pool.poolType as any, + name: pool.name, + balance: pool.balance, + targetBurn: pool.targetBurn, + remainingBurn: pool.targetBurn, + description: pool.description, + isActive: true, + }, + }); + console.log(`Created pool account: ${pool.poolType}`); + } else { + console.log(`Pool account already exists: ${pool.poolType}`); + } + } + + console.log('Seeding completed!'); +} + +main() + .catch((e) => { + console.error('Seeding failed:', e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/backend/services/mining-wallet-service/src/application/services/contribution-wallet.service.ts b/backend/services/mining-wallet-service/src/application/services/contribution-wallet.service.ts index 2f4394a5..427e17bb 100644 --- a/backend/services/mining-wallet-service/src/application/services/contribution-wallet.service.ts +++ b/backend/services/mining-wallet-service/src/application/services/contribution-wallet.service.ts @@ -151,15 +151,25 @@ export class ContributionWalletService { }; } - const systemAccount = await tx.systemAccount.findFirst({ + let systemAccount = await tx.systemAccount.findFirst({ where: whereClause, }); + // 如果找不到,尝试自动创建省/市级系统账户 if (!systemAccount) { - this.logger.warn( - `System account not found: ${input.accountType}, province: ${input.provinceCode}, city: ${input.cityCode}`, + systemAccount = await this.createSystemAccountIfNeeded( + tx, + input.accountType, + input.provinceCode, + input.cityCode, ); - return; + + if (!systemAccount) { + this.logger.warn( + `Failed to create system account: ${input.accountType}, province: ${input.provinceCode}, city: ${input.cityCode}`, + ); + return; + } } const balanceBefore = new Decimal( @@ -281,4 +291,110 @@ export class ContributionWalletService { }; return `${typeMap[input.contributionType]}, 来源认种: ${input.sourceAdoptionId}, 认种人: ${input.sourceAccountSequence}`; } + + /** + * 自动创建省/市级系统账户(如果不存在) + * 同时会创建对应的省/市区域记录 + */ + private async createSystemAccountIfNeeded( + tx: any, + accountType: string, + provinceCode?: string, + cityCode?: string, + ): Promise { + // 只处理省/市级账户的自动创建 + if (accountType === 'PROVINCE' && provinceCode) { + // 先找或创建省份 + let province = await tx.province.findUnique({ + where: { code: provinceCode }, + }); + + if (!province) { + province = await tx.province.create({ + data: { + code: provinceCode, + name: `${provinceCode}省`, // 默认名称,后续可更新 + status: 'ACTIVE', + }, + }); + this.logger.log(`Auto-created province: ${provinceCode}`); + } + + // 创建省级系统账户 + const account = await tx.systemAccount.create({ + data: { + accountType: 'PROVINCE', + name: `${province.name}账户`, + code: `PROV-${provinceCode}`, + provinceId: province.id, + isActive: true, + }, + }); + this.logger.log(`Auto-created province system account: ${account.code}`); + return account; + } + + if (accountType === 'CITY' && cityCode) { + // 先找城市 + let city = await tx.city.findUnique({ + where: { code: cityCode }, + }); + + if (!city) { + // 城市不存在,需要先有省份 + // 尝试从 cityCode 推断省份(如 GD-SZ 中的 GD) + const parts = cityCode.split('-'); + const inferredProvinceCode = parts.length > 1 ? parts[0] : null; + + if (!inferredProvinceCode) { + this.logger.warn(`Cannot infer province from city code: ${cityCode}`); + return null; + } + + // 找或创建省份 + let province = await tx.province.findUnique({ + where: { code: inferredProvinceCode }, + }); + + if (!province) { + province = await tx.province.create({ + data: { + code: inferredProvinceCode, + name: `${inferredProvinceCode}省`, + status: 'ACTIVE', + }, + }); + this.logger.log(`Auto-created province: ${inferredProvinceCode}`); + } + + // 创建城市 + city = await tx.city.create({ + data: { + code: cityCode, + name: `${cityCode}市`, // 默认名称 + provinceId: province.id, + status: 'ACTIVE', + }, + }); + this.logger.log(`Auto-created city: ${cityCode}`); + } + + // 创建市级系统账户 + const account = await tx.systemAccount.create({ + data: { + accountType: 'CITY', + name: `${city.name}账户`, + code: `CITY-${cityCode}`, + provinceId: city.provinceId, + cityId: city.id, + isActive: true, + }, + }); + this.logger.log(`Auto-created city system account: ${account.code}`); + return account; + } + + // 其他类型(HEADQUARTERS, OPERATION, FEE)不自动创建,需要在 seed 中初始化 + return null; + } }