fix: simplify balance billing and govern operation logs

This commit is contained in:
hectorzhao
2026-07-14 17:40:32 +08:00
parent f35691f185
commit 28dad93e3e
40 changed files with 740 additions and 395 deletions
+5 -60
View File
@@ -2,20 +2,9 @@ import { Injectable } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';
export interface CreateBillingPlanDto {
name: string;
priceCents: number;
smsUnits: number;
validDays: number;
status?: string;
description?: string;
}
export interface CreateTenantAccountDto {
tenantId: string;
balanceCents?: number;
smsUnits?: number;
creditCents?: number;
status?: string;
}
@@ -23,7 +12,6 @@ export interface CreateAccountTransactionDto {
tenantId: string;
transactionType: string;
amountCents?: number;
smsUnits?: number;
balanceAfter?: number;
relatedType?: string;
relatedId?: string;
@@ -40,9 +28,7 @@ export interface CreateBillingRuleDto {
export interface CreateRechargeOrderDto {
tenantId: string;
planId?: string;
amountCents?: number;
smsUnits?: number;
amountCents: number;
payMethod?: string;
operatorId?: string;
remark?: string;
@@ -51,7 +37,6 @@ export interface CreateRechargeOrderDto {
export interface CreateManualRechargeDto {
tenantId: string;
amountCents: number;
smsUnits?: number;
operatorId?: string;
remark?: string;
}
@@ -68,7 +53,6 @@ export interface EstimateSmsCostDto {
export interface BillingActionDto {
tenantId: string;
amountCents?: number;
smsUnits?: number;
relatedType?: string;
relatedId?: string;
remark?: string;
@@ -88,23 +72,6 @@ export interface CreateSmsBillingRecordDto {
export class BillingService {
constructor(private readonly prisma: PrismaService) {}
listPlans() {
return this.prisma.billingPlan.findMany({ orderBy: { createdAt: 'desc' } });
}
createPlan(data: CreateBillingPlanDto) {
return this.prisma.billingPlan.create({
data: {
name: data.name,
priceCents: data.priceCents,
smsUnits: data.smsUnits,
validDays: data.validDays,
status: data.status ?? 'active',
description: data.description,
},
});
}
listAccounts() {
return this.prisma.tenantAccount.findMany({
include: { tenant: true },
@@ -116,8 +83,6 @@ export class BillingService {
const createData: Prisma.TenantAccountUncheckedCreateInput = {
tenantId: data.tenantId,
balanceCents: data.balanceCents ?? 0,
smsUnits: data.smsUnits ?? 0,
creditCents: data.creditCents ?? 0,
status: data.status ?? 'active',
};
return this.prisma.tenantAccount.create({ data: createData });
@@ -126,7 +91,6 @@ export class BillingService {
listRechargeOrders(tenantId?: string) {
return this.prisma.rechargeOrder.findMany({
where: tenantId ? { tenantId } : undefined,
include: { plan: true },
orderBy: { createdAt: 'desc' },
});
}
@@ -137,7 +101,6 @@ export class BillingService {
tenantId,
payMethod: 'manual_topup',
},
include: { plan: true },
orderBy: { createdAt: 'desc' },
});
const orderIds = orders.map((order) => order.id);
@@ -161,16 +124,12 @@ export class BillingService {
}
async createRechargeOrder(data: CreateRechargeOrderDto) {
const plan = data.planId ? await this.prisma.billingPlan.findUnique({ where: { id: data.planId } }) : null;
const amountCents = data.amountCents ?? plan?.priceCents ?? 0;
const smsUnits = data.smsUnits ?? plan?.smsUnits ?? 0;
const amountCents = data.amountCents;
const order = await this.prisma.rechargeOrder.create({
data: {
tenantId: data.tenantId,
planId: data.planId,
orderNo: `R${Date.now()}${Math.floor(Math.random() * 10000).toString().padStart(4, '0')}`,
amountCents,
smsUnits,
status: 'paid',
payMethod: data.payMethod ?? 'manual',
paidAt: new Date(),
@@ -183,7 +142,6 @@ export class BillingService {
tenantId: data.tenantId,
transactionType: 'recharge',
amountCents,
smsUnits,
relatedType: 'recharge_order',
relatedId: order.id,
remark: data.remark,
@@ -196,7 +154,6 @@ export class BillingService {
const order = await this.createRechargeOrder({
tenantId: data.tenantId,
amountCents: data.amountCents,
smsUnits: data.smsUnits ?? 0,
payMethod: 'manual_topup',
operatorId: data.operatorId,
remark: data.remark,
@@ -210,7 +167,6 @@ export class BillingService {
resourceId: order.id,
detail: {
amountCents: data.amountCents,
smsUnits: data.smsUnits ?? 0,
orderNo: order.orderNo,
remark: data.remark,
} as Prisma.InputJsonValue,
@@ -239,15 +195,12 @@ export class BillingService {
async checkAccount(data: BillingActionDto) {
const account = await this.getAccountOrCreate(data.tenantId);
const requiredAmount = data.amountCents ?? 0;
const requiredUnits = data.smsUnits ?? 0;
const availableAmount = account.balanceCents + account.creditCents;
const availableAmount = account.balanceCents;
return {
tenantId: data.tenantId,
requiredAmount,
requiredUnits,
availableAmount,
availableSmsUnits: account.smsUnits,
canSend: availableAmount >= requiredAmount && account.smsUnits >= requiredUnits,
canSend: availableAmount >= requiredAmount,
};
}
@@ -256,7 +209,6 @@ export class BillingService {
...data,
transactionType: 'frozen',
amountCents: -(data.amountCents ?? 0),
smsUnits: -(data.smsUnits ?? 0),
});
}
@@ -265,7 +217,6 @@ export class BillingService {
...data,
transactionType: 'charged',
amountCents: -(data.amountCents ?? 0),
smsUnits: -(data.smsUnits ?? 0),
});
}
@@ -274,7 +225,6 @@ export class BillingService {
...data,
transactionType: 'released',
amountCents: data.amountCents ?? 0,
smsUnits: data.smsUnits ?? 0,
});
}
@@ -283,7 +233,6 @@ export class BillingService {
...data,
transactionType: 'refunded',
amountCents: data.amountCents ?? 0,
smsUnits: data.smsUnits ?? 0,
});
}
@@ -292,7 +241,6 @@ export class BillingService {
...data,
transactionType: 'adjusted',
amountCents: data.amountCents ?? 0,
smsUnits: data.smsUnits ?? 0,
});
}
@@ -348,19 +296,17 @@ export class BillingService {
return this.prisma.tenantAccount.upsert({
where: { tenantId },
update: {},
create: { tenantId, balanceCents: 0, smsUnits: 0, creditCents: 0, status: 'active' },
create: { tenantId, balanceCents: 0, status: 'active' },
});
}
private async applyAccountDelta(data: CreateAccountTransactionDto) {
const account = await this.getAccountOrCreate(data.tenantId);
const nextBalance = account.balanceCents + (data.amountCents ?? 0);
const nextUnits = account.smsUnits + (data.smsUnits ?? 0);
await this.prisma.tenantAccount.update({
where: { tenantId: data.tenantId },
data: {
balanceCents: nextBalance,
smsUnits: nextUnits,
},
});
@@ -369,7 +315,6 @@ export class BillingService {
tenantId: data.tenantId,
transactionType: data.transactionType,
amountCents: data.amountCents ?? 0,
smsUnits: data.smsUnits ?? 0,
balanceAfter: nextBalance,
relatedType: data.relatedType,
relatedId: data.relatedId,