P2-14: Deposit installment tracking + refund approval flow
- Add DepositInstallment entity (id, depositId, amount, dueDate, paidDate, status, createdAt) - Add installments OneToMany relation to Deposit entity with cascade+eager - Add refund approval fields: refundStatus, refundRequestedAt, refundApprovedBy, refundApprovedAt - Add installment DTOs (CreateInstallmentDto, UpdateInstallmentDto) - Add refund approval DTOs (ApproveRefundDto, CreateDepositWithInstallmentsDto) - Service: add/create/update/delete installments, requestRefund, approveRefund, findPendingRefunds - Controller: GET deposits/:id, GET pending-refunds, POST :id/installments, PUT installments/:id, DELETE installments/:id, POST :id/request-refund, PUT :id/approve-refund - Frontend: detail modal with installment list, refund request button, pending refunds tab with approve actions
This commit is contained in:
37
apps/server/src/entities/deposit-installment.entity.ts
Normal file
37
apps/server/src/entities/deposit-installment.entity.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { Deposit } from './deposit.entity';
|
||||
|
||||
@Entity('deposit_installments')
|
||||
export class DepositInstallment {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'deposit_id' })
|
||||
depositId: number;
|
||||
|
||||
@Column({ type: 'decimal', precision: 10, scale: 2 })
|
||||
amount: number;
|
||||
|
||||
@Column({ name: 'due_date', type: 'date' })
|
||||
dueDate: string;
|
||||
|
||||
@Column({ name: 'paid_date', type: 'date', nullable: true })
|
||||
paidDate: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 20, default: 'pending' })
|
||||
status: string; // pending | paid
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt: Date;
|
||||
|
||||
@ManyToOne(() => Deposit, (d) => d.installments, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'deposit_id' })
|
||||
deposit: Deposit;
|
||||
}
|
||||
@@ -4,9 +4,11 @@ import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { Student } from './student.entity';
|
||||
import { DepositInstallment } from './deposit-installment.entity';
|
||||
|
||||
@Entity('deposits')
|
||||
export class Deposit {
|
||||
@@ -44,10 +46,26 @@ export class Deposit {
|
||||
@Column({ name: 'recorded_by', nullable: true })
|
||||
recordedBy: number;
|
||||
|
||||
@Column({ name: 'refund_status', length: 30, nullable: true })
|
||||
refundStatus: string | null; // pending | head_teacher_approved | finance_approved | refunded
|
||||
|
||||
@Column({ name: 'refund_requested_at', nullable: true })
|
||||
refundRequestedAt: Date | null;
|
||||
|
||||
@Column({ name: 'refund_approved_by', type: 'integer', nullable: true })
|
||||
refundApprovedBy: number | null;
|
||||
|
||||
@Column({ name: 'refund_approved_at', nullable: true })
|
||||
refundApprovedAt: Date | null;
|
||||
|
||||
@OneToMany(() => DepositInstallment, (i) => i.deposit, { cascade: true, eager: true })
|
||||
installments: DepositInstallment[];
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt: Date;
|
||||
|
||||
@ManyToOne(() => Student, { eager: true })
|
||||
@JoinColumn({ name: 'student_id' })
|
||||
student: Student;
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export { BillItem } from './bill-item.entity';
|
||||
export { User } from './user.entity';
|
||||
export { OperationLog } from './operation-log.entity';
|
||||
export { Deposit } from './deposit.entity';
|
||||
export { DepositInstallment } from './deposit-installment.entity';
|
||||
export { Classroom } from './classroom.entity';
|
||||
export { Tenant } from './tenant.entity';
|
||||
export { ClassroomRental } from './classroom-rental.entity';
|
||||
|
||||
Reference in New Issue
Block a user