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:
2026-07-05 20:46:05 +08:00
parent 5df70a8af0
commit ab4adf1174
8 changed files with 645 additions and 82 deletions

View File

@@ -1,4 +1,5 @@
import { IsInt, IsNumber, IsString, IsOptional } from 'class-validator';
import { IsInt, IsNumber, IsString, IsOptional, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';
export class CreateDepositDto {
@IsInt()
@@ -15,6 +16,25 @@ export class CreateDepositDto {
notes?: string;
}
export class CreateInstallmentDto {
@IsNumber()
amount: number;
@IsString()
dueDate: string;
}
export class UpdateInstallmentDto {
@IsOptional()
@IsString()
paidDate?: string;
@IsOptional()
@IsString()
status?: string;
}
export class RefundDepositDto {
@IsString()
refundDate: string;
@@ -31,3 +51,15 @@ export class RefundDepositDto {
@IsString()
notes?: string;
}
export class CreateDepositWithInstallmentsDto extends CreateDepositDto {
@IsOptional()
@ValidateNested({ each: true })
@Type(() => CreateInstallmentDto)
installments?: CreateInstallmentDto[];
}
export class ApproveRefundDto {
@IsOptional()
@IsString()
notes?: string;
}