fix: harden financial transaction boundaries

This commit is contained in:
2026-07-18 15:33:41 +08:00
parent 4af7acbeaa
commit 5836b421d8
19 changed files with 514 additions and 314 deletions

View File

@@ -9,6 +9,12 @@ export class BillItem {
@Column({ name: 'bill_id' })
billId: number;
@Column({ name: 'room_expense_id', type: 'integer', nullable: true })
roomExpenseId: number | null;
@Column({ name: 'personal_expense_id', type: 'integer', nullable: true })
personalExpenseId: number | null;
@Column({ name: 'room_id', nullable: true })
roomId: number;

View File

@@ -0,0 +1,31 @@
import { Column, CreateDateColumn, Entity, Index, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
export type FinancialOperationStatus = 'running' | 'completed' | 'failed';
@Entity('financial_operations')
@Index(['operationId'], { unique: true })
export class FinancialOperation {
@PrimaryGeneratedColumn()
id: number;
@Column({ name: 'operation_id', type: 'varchar', length: 64, unique: true })
operationId: string;
@Column({ type: 'varchar', length: 64 })
type: string;
@Column({ type: 'varchar', length: 20, default: 'running' })
status: FinancialOperationStatus;
@Column({ name: 'result_json', type: 'text', nullable: true })
resultJson: string | null;
@Column({ name: 'error_message', type: 'varchar', length: 500, nullable: true })
errorMessage: string | null;
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
}

View File

@@ -39,3 +39,4 @@ export { AiConfig } from '../ai-config/ai-config.entity';
export * from './student-wallet.entity';
export * from './wallet-transaction.entity';
export * from './financial-operation.entity';

View File

@@ -5,10 +5,12 @@ import {
CreateDateColumn,
ManyToOne,
JoinColumn,
Index,
} from 'typeorm';
import { Room } from './room.entity';
@Entity('room_expenses')
@Index(['importKey'], { unique: true })
export class RoomExpense {
@PrimaryGeneratedColumn()
id: number;
@@ -34,6 +36,9 @@ export class RoomExpense {
@Column({ name: 'recorded_by', nullable: true })
recordedBy: number;
@Column({ name: 'import_key', type: 'varchar', length: 120, nullable: true, unique: true })
importKey: string | null;
@Column({ type: 'varchar', length: 20, default: 'active' })
status: 'active' | 'archived';

View File

@@ -12,6 +12,9 @@ export class WalletTransaction {
@Column({ name: 'bill_id', type: 'integer', nullable: true })
billId: number | null;
@Column({ name: 'operation_id', type: 'varchar', length: 64, nullable: true })
operationId: string | null;
@Column({ type: 'varchar', length: 30 })
type: 'recharge' | 'adjustment' | 'bill_payment' | 'bill_refund';