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