rentease-backend-new/controllers/billPaymentController.js

198 lines
5.4 KiB
JavaScript
Raw Normal View History

2026-04-20 06:43:09 +00:00
const { BillPayment, Bill } = require('../models');
2026-06-11 13:45:33 +00:00
const { Op, fn, col } = require('sequelize');
2026-04-22 06:48:32 +00:00
const response = require('../utils/response');
2026-06-11 13:45:33 +00:00
const rentalBillingService = require('../services/rentalBillingService');
2026-04-20 06:43:09 +00:00
// 获取账单的所有支付流水
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']]
});
2026-04-22 06:48:32 +00:00
response.success(res, '获取成功', payments);
2026-04-20 06:43:09 +00:00
} catch (error) {
console.error('获取支付流水失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '获取支付流水失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 创建支付流水(收款)
const createPayment = async (req, res) => {
2026-06-11 13:45:33 +00:00
const transaction = await require('../config/db').transaction();
2026-04-20 06:43:09 +00:00
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({
2026-06-11 13:45:33 +00:00
where: { id: billId, tenantId, isDeleted: 0 },
transaction
2026-04-20 06:43:09 +00:00
});
if (!bill) {
2026-06-11 13:45:33 +00:00
await transaction.rollback();
2026-04-22 06:48:32 +00:00
return response.notFound(res, '账单不存在');
2026-04-20 06:43:09 +00:00
}
2026-06-11 13:45:33 +00:00
if (transactionNo) {
const existingPayment = await BillPayment.findOne({
where: { transactionNo, billId, tenantId, isDeleted: 0 },
transaction
});
if (existingPayment) {
await transaction.rollback();
return response.badRequest(res, '该交易流水号已存在,请勿重复提交');
}
2026-04-20 06:43:09 +00:00
}
2026-06-11 13:45:33 +00:00
let paymentInfo;
try {
paymentInfo = rentalBillingService.validatePaymentAmount(bill, amount);
} catch (validationError) {
await transaction.rollback();
return response.badRequest(res, validationError.message);
2026-04-20 06:43:09 +00:00
}
const payment = await BillPayment.create({
billId,
2026-06-11 13:45:33 +00:00
amount: paymentInfo.paymentAmount,
2026-04-20 06:43:09 +00:00
paymentMethod,
paymentTime: paymentTime || new Date(),
transactionNo: transactionNo || null,
remark: remark || null,
tenantId,
createBy,
isDeleted: 0
2026-06-11 13:45:33 +00:00
}, { transaction });
2026-04-20 06:43:09 +00:00
await bill.update({
2026-06-11 13:45:33 +00:00
receivedAmount: paymentInfo.newReceivedAmount,
status: paymentInfo.newStatus,
2026-04-20 06:43:09 +00:00
updateBy: createBy
2026-06-11 13:45:33 +00:00
}, { transaction });
await transaction.commit();
2026-04-20 06:43:09 +00:00
2026-04-22 06:48:32 +00:00
response.created(res, '收款成功', {
payment,
bill: {
id: bill.id,
2026-06-11 13:45:33 +00:00
receivedAmount: paymentInfo.newReceivedAmount,
status: paymentInfo.newStatus
2026-04-22 06:48:32 +00:00
}
2026-04-20 06:43:09 +00:00
});
} catch (error) {
2026-06-11 13:45:33 +00:00
await transaction.rollback();
2026-04-20 06:43:09 +00:00
console.error('创建支付流水失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '创建支付流水失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 删除支付流水(退款/撤销)
const deletePayment = async (req, res) => {
2026-06-11 13:45:33 +00:00
const transaction = await require('../config/db').transaction();
2026-04-20 06:43:09 +00:00
try {
const { id } = req.params;
const tenantId = req.user.tenantId;
const updateBy = req.user.id;
const payment = await BillPayment.findOne({
2026-06-11 13:45:33 +00:00
where: { id, tenantId, isDeleted: 0 },
transaction
2026-04-20 06:43:09 +00:00
});
if (!payment) {
2026-06-11 13:45:33 +00:00
await transaction.rollback();
2026-04-22 06:48:32 +00:00
return response.notFound(res, '支付流水不存在');
2026-04-20 06:43:09 +00:00
}
const bill = await Bill.findOne({
2026-06-11 13:45:33 +00:00
where: { id: payment.billId, tenantId, isDeleted: 0 },
transaction
2026-04-20 06:43:09 +00:00
});
if (!bill) {
2026-06-11 13:45:33 +00:00
await transaction.rollback();
2026-04-22 06:48:32 +00:00
return response.notFound(res, '关联账单不存在');
2026-04-20 06:43:09 +00:00
}
2026-06-11 13:45:33 +00:00
await payment.update({ isDeleted: 1 }, { transaction });
2026-04-20 06:43:09 +00:00
const remainingPayments = await BillPayment.findAll({
2026-06-11 13:45:33 +00:00
where: { billId: bill.id, tenantId, isDeleted: 0 },
transaction
2026-04-20 06:43:09 +00:00
});
2026-06-11 13:45:33 +00:00
const newReceivedAmount = remainingPayments.reduce((sum, p) => sum + parseFloat(p.amount), 0);
2026-04-20 06:43:09 +00:00
let newStatus = 'unpaid';
if (newReceivedAmount >= parseFloat(bill.receivableAmount)) {
newStatus = 'paid';
} else if (newReceivedAmount > 0) {
newStatus = 'partial';
}
await bill.update({
receivedAmount: newReceivedAmount,
status: newStatus,
updateBy
2026-06-11 13:45:33 +00:00
}, { transaction });
2026-04-20 06:43:09 +00:00
2026-06-11 13:45:33 +00:00
await transaction.commit();
response.success(res, '支付流水已撤销,账单状态已更新', {
bill: { id: bill.id, receivedAmount: newReceivedAmount, status: newStatus }
2026-04-20 06:43:09 +00:00
});
} catch (error) {
2026-06-11 13:45:33 +00:00
await transaction.rollback();
console.error('撤销支付流水失败:', error);
response.serverError(res, '撤销支付流水失败', error);
2026-04-20 06:43:09 +00:00
}
};
// 获取支付流水统计
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,
2026-06-11 13:45:33 +00:00
attributes: ['paymentMethod', [fn('SUM', col('amount')), 'totalAmount'], [fn('COUNT', col('id')), 'count']],
2026-04-20 06:43:09 +00:00
group: ['paymentMethod']
});
2026-04-22 06:48:32 +00:00
response.success(res, '获取成功', payments);
2026-04-20 06:43:09 +00:00
} catch (error) {
console.error('获取支付统计失败:', error);
2026-04-22 06:48:32 +00:00
response.serverError(res, '获取支付统计失败', error);
2026-04-20 06:43:09 +00:00
}
};
module.exports = {
getPaymentsByBillId,
createPayment,
deletePayment,
getPaymentStatistics
};