230 lines
5.8 KiB
JavaScript
230 lines
5.8 KiB
JavaScript
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
|
|
};
|