feat: link deposits to bill payment
This commit is contained in:
@@ -34,7 +34,7 @@ export class BillsExportService {
|
||||
if (query.status) qb.andWhere('b.status = :status', { status: query.status });
|
||||
const bills = await qb.getMany();
|
||||
|
||||
// 查询涉及学生的"已缴未退"押金,用于导出押金抵扣字段
|
||||
// 查询涉及学生当前押金余额。账单生成时不冻结押金,导出只展示实时余额和已实际扣款。
|
||||
const studentIds = Array.from(new Set(bills.map((b) => b.studentId)));
|
||||
const depMap = new Map<number, number>();
|
||||
if (studentIds.length > 0) {
|
||||
@@ -61,8 +61,7 @@ export class BillsExportService {
|
||||
{ header: '个人费用', key: 'personal', width: 12 },
|
||||
{ header: '总金额', key: 'total', width: 12 },
|
||||
{ header: '可用押金', key: 'deposit', width: 12 },
|
||||
{ header: '押金抵扣', key: 'depositApplied', width: 12 },
|
||||
{ header: '抵扣后应付', key: 'afterDeposit', width: 14 },
|
||||
{ header: '已扣押金', key: 'depositDeducted', width: 12 },
|
||||
{ header: '状态', key: 'status', width: 10 },
|
||||
{ header: '生成时间', key: 'generatedAt', width: 20 },
|
||||
];
|
||||
@@ -72,14 +71,11 @@ export class BillsExportService {
|
||||
|
||||
const statusMap: Record<string, string> = {
|
||||
draft: '草稿',
|
||||
confirmed: '已确认',
|
||||
paid: '已结清',
|
||||
};
|
||||
for (const bill of bills) {
|
||||
const total = Number(bill.totalAmount || 0);
|
||||
const dep = Number((depMap.get(bill.studentId) || 0).toFixed(2));
|
||||
const applied = Number(Math.min(dep, total).toFixed(2));
|
||||
const after = Number(Math.max(0, total - applied).toFixed(2));
|
||||
ws.addRow({
|
||||
id: bill.id,
|
||||
studentName: (bill as any).student?.name || '-',
|
||||
@@ -88,8 +84,7 @@ export class BillsExportService {
|
||||
personal: Number(bill.personalAmount),
|
||||
total,
|
||||
deposit: dep,
|
||||
depositApplied: applied,
|
||||
afterDeposit: after,
|
||||
depositDeducted: Number(bill.depositDeductedAmount || 0),
|
||||
status: statusMap[bill.status] || bill.status,
|
||||
generatedAt: bill.generatedAt ? new Date(bill.generatedAt).toLocaleString('zh-CN') : '',
|
||||
});
|
||||
@@ -147,7 +142,7 @@ export class BillsExportService {
|
||||
return;
|
||||
}
|
||||
|
||||
// 查询该学生的可用押金(已缴未退)
|
||||
// 查询该学生的当前可用押金。草稿账单只展示余额,不预生成抵扣金额。
|
||||
const deposits = await this.depositRepo
|
||||
.createQueryBuilder('d')
|
||||
.where('d.studentId = :sid', { sid: bill.studentId })
|
||||
@@ -155,8 +150,7 @@ export class BillsExportService {
|
||||
.getMany();
|
||||
const availableDeposit = deposits.reduce((s, d) => s + Number(d.amount || 0), 0);
|
||||
const totalAmount = Number(bill.totalAmount || 0);
|
||||
const depositApplied = Math.min(availableDeposit, totalAmount);
|
||||
const amountAfterDeposit = Math.max(0, totalAmount - depositApplied);
|
||||
const depositDeducted = Number(bill.depositDeductedAmount || 0);
|
||||
|
||||
const doc = new PDFDocument({ size: 'A4', margin: 50 });
|
||||
res.setHeader('Content-Type', 'application/pdf');
|
||||
@@ -192,7 +186,6 @@ export class BillsExportService {
|
||||
|
||||
const statusMap: Record<string, string> = {
|
||||
draft: '草稿',
|
||||
confirmed: '已确认',
|
||||
paid: '已结清',
|
||||
};
|
||||
|
||||
@@ -223,19 +216,17 @@ export class BillsExportService {
|
||||
.fillColor('#007AFF')
|
||||
.text(`应付总额: ¥${totalAmount.toFixed(2)}`);
|
||||
doc.moveDown(0.3);
|
||||
if (availableDeposit > 0) {
|
||||
if (availableDeposit > 0 || depositDeducted > 0) {
|
||||
doc
|
||||
.fontSize(11)
|
||||
.fillColor('#52C41A')
|
||||
.text(`可用押金: ¥${availableDeposit.toFixed(2)}`);
|
||||
doc
|
||||
.fontSize(11)
|
||||
.fillColor('#FA8C16')
|
||||
.text(`押金抵扣: -¥${depositApplied.toFixed(2)}`);
|
||||
doc
|
||||
.fontSize(14)
|
||||
.fillColor('#FF3B30')
|
||||
.text(`抵扣后应付: ¥${amountAfterDeposit.toFixed(2)}`);
|
||||
if (depositDeducted > 0) {
|
||||
doc
|
||||
.fontSize(11)
|
||||
.fillColor('#FA8C16')
|
||||
.text(`已扣押金: -¥${depositDeducted.toFixed(2)}`);
|
||||
}
|
||||
}
|
||||
doc.moveDown(1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user