rentease-backend-new/controllers/billPaymentController.js

230 lines
5.8 KiB
JavaScript
Raw Normal View History

2026-04-20 06:43:09 +00:00
const { BillPayment, Bill } = require('../models');
const { Op } = require('sequelize');
// 获取账单的所有支付流水
const getPaymentsByBillId = async (req, res) => {
try {
const { billId } = req.params;
const tenantId = req.user.tenantId;
const payments = await BillPayment.findAll({
where: {
billId,
tenantId,
isDeleted: 0
},
order: [['paymentTime', 'DESC']]
});
res.status(200).json({
code: 200,
data: payments,
message: 'success'
});
} catch (error) {
console.error('获取支付流水失败:', error);
res.status(500).json({ code: 500, error: error.message });
}
};
// 创建支付流水(收款)
const createPayment = async (req, res) => {
try {
const { billId } = req.params;
const { amount, paymentMethod, paymentTime, transactionNo, remark } = req.body;
const tenantId = req.user.tenantId;
const createBy = req.user.id;
// 查找账单
const bill = await Bill.findOne({
where: { id: billId, tenantId, isDeleted: 0 }
});
if (!bill) {
return res.status(404).json({ code: 404, error: '账单不存在' });
}
if (bill.status === 'paid') {
return res.status(400).json({ code: 400, error: '该账单已收清,无法继续收款' });
}
if (bill.status === 'cancelled') {
return res.status(400).json({ code: 400, error: '该账单已取消,无法收款' });
}
// 计算剩余应收金额
const receivableAmount = parseFloat(bill.receivableAmount);
const currentReceived = parseFloat(bill.receivedAmount || 0);
const remainingAmount = receivableAmount - currentReceived;
// 验证支付金额
const paymentAmount = parseFloat(amount);
if (paymentAmount <= 0) {
return res.status(400).json({ code: 400, error: '支付金额必须大于0' });
}
if (paymentAmount > remainingAmount) {
return res.status(400).json({
code: 400,
error: `支付金额不能超过剩余应收金额 ¥${remainingAmount.toFixed(2)}`
});
}
// 创建支付流水
const payment = await BillPayment.create({
billId,
amount: paymentAmount,
paymentMethod,
paymentTime: paymentTime || new Date(),
transactionNo: transactionNo || null,
remark: remark || null,
tenantId,
createBy,
isDeleted: 0
});
// 更新账单的已收金额和状态
const newReceivedAmount = currentReceived + paymentAmount;
let newStatus = bill.status;
if (newReceivedAmount >= receivableAmount) {
newStatus = 'paid';
} else if (newReceivedAmount > 0) {
newStatus = 'partial';
}
await bill.update({
receivedAmount: newReceivedAmount,
status: newStatus,
updateBy: createBy
});
res.status(201).json({
code: 201,
data: {
payment,
bill: {
id: bill.id,
receivedAmount: newReceivedAmount,
status: newStatus
}
},
message: '收款成功'
});
} catch (error) {
console.error('创建支付流水失败:', error);
res.status(500).json({ code: 500, error: error.message });
}
};
// 删除支付流水(退款/撤销)
const deletePayment = async (req, res) => {
try {
const { id } = req.params;
const tenantId = req.user.tenantId;
const updateBy = req.user.id;
const payment = await BillPayment.findOne({
where: { id, tenantId, isDeleted: 0 }
});
if (!payment) {
return res.status(404).json({ code: 404, error: '支付流水不存在' });
}
// 查找关联账单
const bill = await Bill.findOne({
where: { id: payment.billId, tenantId, isDeleted: 0 }
});
if (!bill) {
return res.status(404).json({ code: 404, error: '关联账单不存在' });
}
// 软删除支付流水
await payment.update({ isDeleted: 1 });
// 重新计算账单的已收金额和状态
const remainingPayments = await BillPayment.findAll({
where: {
billId: bill.id,
tenantId,
isDeleted: 0
}
});
const newReceivedAmount = remainingPayments.reduce((sum, p) => {
return sum + parseFloat(p.amount);
}, 0);
let newStatus = 'unpaid';
if (newReceivedAmount >= parseFloat(bill.receivableAmount)) {
newStatus = 'paid';
} else if (newReceivedAmount > 0) {
newStatus = 'partial';
}
await bill.update({
receivedAmount: newReceivedAmount,
status: newStatus,
updateBy
});
res.status(200).json({
code: 200,
data: {
bill: {
id: bill.id,
receivedAmount: newReceivedAmount,
status: newStatus
}
},
message: '支付流水已删除,账单状态已更新'
});
} catch (error) {
console.error('删除支付流水失败:', error);
res.status(500).json({ code: 500, error: error.message });
}
};
// 获取支付流水统计
const getPaymentStatistics = async (req, res) => {
try {
const tenantId = req.user.tenantId;
const { startDate, endDate } = req.query;
const where = {
tenantId,
isDeleted: 0
};
if (startDate && endDate) {
where.paymentTime = {
[Op.between]: [new Date(startDate), new Date(endDate)]
};
}
const payments = await BillPayment.findAll({
where,
attributes: ['paymentMethod', [sequelize.fn('SUM', sequelize.col('amount')), 'totalAmount'], [sequelize.fn('COUNT', sequelize.col('id')), 'count']],
group: ['paymentMethod']
});
res.status(200).json({
code: 200,
data: payments,
message: 'success'
});
} catch (error) {
console.error('获取支付统计失败:', error);
res.status(500).json({ code: 500, error: error.message });
}
};
module.exports = {
getPaymentsByBillId,
createPayment,
deletePayment,
getPaymentStatistics
};