Files
yunhaifinance/backend/routes/verifications.js
T

365 lines
13 KiB
JavaScript

const express = require('express');
const db = require('../db');
const { authenticate, requireAdmin } = require('../middleware/auth');
const router = express.Router();
router.get('/', async (req, res) => {
try {
const { advance_id } = req.query;
let query = `
SELECT v.*, a.advance_code, a.applicant_id as advance_applicant_id
FROM verifications v
LEFT JOIN advances a ON v.advance_id = a.id
`;
const params = [];
if (advance_id) {
query += ` WHERE v.advance_id = $1`;
params.push(advance_id);
}
query += ` ORDER BY v.created_at DESC`;
const result = await db.query(query, params);
const data = result.rows.map(item => {
if (item.attachments) {
try {
item.attachments = JSON.parse(item.attachments);
} catch (error) {
item.attachments = [];
}
} else {
item.attachments = [];
}
if (item.detail_items) {
try {
item.detail_items = JSON.parse(item.detail_items);
} catch (error) {
item.detail_items = [];
}
} else {
item.detail_items = [];
}
return item;
});
res.json({ success: true, data, count: data.length });
} catch (error) {
console.error('获取核销记录失败:', error);
res.status(500).json({ success: false, message: '获取核销记录失败' });
}
});
router.post('/', async (req, res) => {
try {
const { verification_date, advance_id, advance_code, advance_amount, currency, reason, detail_items, attachments, applicant, expense_type, project_id, settlement, settlement_amount } = req.body;
// 生成核销编号
const verificationCode = `VER-${Date.now()}`;
const amount = detail_items?.reduce((sum, item) => sum + (item.amount || 0), 0) || 0;
// 验证关联预支单
if (!advance_id && !advance_code) {
return res.status(400).json({ success: false, message: '关联预支单是必填项' });
}
let finalAdvanceCode = advance_code;
let finalAdvanceId = advance_id;
// 如果advance_code为空,根据advance_id查询预支单的advance_code
if (!finalAdvanceCode && finalAdvanceId) {
const advanceResult = await db.query('SELECT advance_code FROM advances WHERE id = $1', [finalAdvanceId]);
if (advanceResult.rows.length > 0) {
finalAdvanceCode = advanceResult.rows[0].advance_code;
} else {
return res.status(400).json({ success: false, message: '关联的预支单不存在' });
}
}
// 如果advance_id为空,根据advance_code查询预支单的id
if (!finalAdvanceId && finalAdvanceCode) {
const advanceResult = await db.query('SELECT id FROM advances WHERE advance_code = $1', [finalAdvanceCode]);
if (advanceResult.rows.length > 0) {
finalAdvanceId = advanceResult.rows[0].id;
} else {
return res.status(400).json({ success: false, message: '关联的预支单不存在' });
}
}
// 如果仍然为空,返回错误
if (!finalAdvanceCode || !finalAdvanceId) {
return res.status(400).json({ success: false, message: '关联预支单不存在' });
}
// 开始事务
await db.query('BEGIN TRANSACTION');
try {
// 插入核销申请
const result = await db.query(
'INSERT INTO verifications (advance_id, amount, currency, reason, verification_date, verification_code, status, applicant, advance_code, advance_amount, detail_items, attachments, expense_type, project_id, settlement, settlement_amount) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)',
[finalAdvanceId, amount, currency || 'CNY', reason, verification_date, verificationCode, 'pending', applicant, finalAdvanceCode, advance_amount || 0, JSON.stringify(detail_items || []), JSON.stringify(attachments || []), expense_type || 'company', project_id, settlement ? 1 : 0, settlement_amount || 0]
);
// 提交事务
await db.query('COMMIT');
// SQLite不支持RETURNING,所以需要查询刚插入的数据
const lastInsert = await db.query('SELECT * FROM verifications ORDER BY id DESC LIMIT 1');
res.json({ success: true, data: lastInsert.rows[0] });
} catch (error) {
// 回滚事务
await db.query('ROLLBACK');
throw error;
}
} catch (error) {
console.error('创建核销申请失败:', error);
res.status(500).json({ success: false, message: '创建核销申请失败' });
}
});
router.get('/:id', async (req, res) => {
try {
const { id } = req.params;
const result = await db.query('SELECT * FROM verifications WHERE id = $1', [id]);
if (result.rows.length > 0) {
const data = result.rows[0];
if (data.attachments) {
try {
data.attachments = JSON.parse(data.attachments);
} catch (error) {
data.attachments = [];
}
} else {
data.attachments = [];
}
if (data.detail_items) {
try {
data.detail_items = JSON.parse(data.detail_items);
} catch (error) {
data.detail_items = [];
}
} else {
data.detail_items = [];
}
res.json({ success: true, data });
} else {
res.status(404).json({ success: false, message: '核销申请不存在' });
}
} catch (error) {
console.error('获取核销申请失败:', error);
res.status(500).json({ success: false, message: '获取核销申请失败' });
}
});
router.put('/:id', async (req, res) => {
try {
const { id } = req.params;
const { verification_date, advance_id, advance_code, advance_amount, currency, reason, detail_items, attachments, applicant, status, expense_type, project_id, settlement, settlement_amount } = req.body;
const amount = detail_items?.reduce((sum, item) => sum + (item.amount || 0), 0) || 0;
// 开始事务
await db.query('BEGIN TRANSACTION');
try {
// 获取原核销金额
const oldVerification = await db.query('SELECT amount, advance_id FROM verifications WHERE id = $1', [id]);
const oldAmount = oldVerification.rows[0]?.amount || 0;
const oldAdvanceId = oldVerification.rows[0]?.advance_id;
let finalAdvanceCode = advance_code;
// 如果advance_code为空,根据advance_id查询预支单的advance_code
if (!finalAdvanceCode && advance_id) {
const advanceResult = await db.query('SELECT advance_code FROM advances WHERE id = $1', [advance_id]);
if (advanceResult.rows.length > 0) {
finalAdvanceCode = advanceResult.rows[0].advance_code;
}
}
// 如果仍然为空,使用默认值
if (!finalAdvanceCode) {
finalAdvanceCode = 'UNKNOWN';
}
// 更新核销申请
const result = await db.query(
'UPDATE verifications SET verification_date = $1, advance_id = $2, amount = $3, currency = $4, reason = $5, advance_code = $6, advance_amount = $7, detail_items = $8, attachments = $9, applicant = $10, status = $11, expense_type = $12, project_id = $13, settlement = $14, settlement_amount = $15 WHERE id = $16',
[verification_date, advance_id, amount, currency, reason, finalAdvanceCode, advance_amount || 0, JSON.stringify(detail_items || []), JSON.stringify(attachments || []), applicant, status, expense_type || 'company', project_id, settlement ? 1 : 0, settlement_amount || 0, id]
);
// 不在这里更新预支单已核销金额,而是在执行核销时更新
// if (oldAdvanceId) {
// const amountDiff = amount - oldAmount;
// if (amountDiff !== 0) {
// await db.query(
// 'UPDATE advances SET total_reimbursed = total_reimbursed + $1 WHERE id = $2',
// [amountDiff, oldAdvanceId]
// );
// }
// }
// 提交事务
await db.query('COMMIT');
if (result.changes > 0) {
res.json({ success: true, message: '更新成功' });
} else {
res.status(404).json({ success: false, message: '核销申请不存在' });
}
} catch (error) {
// 回滚事务
await db.query('ROLLBACK');
throw error;
}
} catch (error) {
console.error('更新核销申请失败:', error);
res.status(500).json({ success: false, message: '更新核销申请失败' });
}
});
router.delete('/:id', async (req, res) => {
try {
const { id } = req.params;
// 开始事务
await db.query('BEGIN TRANSACTION');
try {
// 获取核销金额和预支单ID
const verification = await db.query('SELECT amount, advance_id FROM verifications WHERE id = $1', [id]);
const amount = verification.rows[0]?.amount || 0;
const advanceId = verification.rows[0]?.advance_id;
// 删除核销申请
const result = await db.query('DELETE FROM verifications WHERE id = $1', [id]);
// 不在这里恢复预支单已核销金额,因为只有执行的核销才会增加已核销金额
// if (advanceId && amount > 0) {
// await db.query(
// 'UPDATE advances SET total_reimbursed = total_reimbursed - $1 WHERE id = $2',
// [amount, advanceId]
// );
// }
// 提交事务
await db.query('COMMIT');
if (result.changes > 0) {
res.json({ success: true, message: '删除成功' });
} else {
res.status(404).json({ success: false, message: '核销申请不存在' });
}
} catch (error) {
// 回滚事务
await db.query('ROLLBACK');
throw error;
}
} catch (error) {
console.error('删除核销申请失败:', error);
res.status(500).json({ success: false, message: '删除核销申请失败' });
}
});
router.post('/:id/submit', async (req, res) => {
try {
const { id } = req.params;
const result = await db.query('UPDATE verifications SET status = $1 WHERE id = $2', ['pending', id]);
if (result.changes > 0) {
res.json({ success: true, message: '提交成功' });
} else {
res.status(404).json({ success: false, message: '核销申请不存在' });
}
} catch (error) {
console.error('提交核销申请失败:', error);
res.status(500).json({ success: false, message: '提交核销申请失败' });
}
});
router.post('/:id/withdraw', async (req, res) => {
try {
const { id } = req.params;
const result = await db.query('UPDATE verifications SET status = $1 WHERE id = $2', ['withdrawn', id]);
if (result.changes > 0) {
res.json({ success: true, message: '撤回成功' });
} else {
res.status(404).json({ success: false, message: '核销申请不存在' });
}
} catch (error) {
console.error('撤回核销申请失败:', error);
res.status(500).json({ success: false, message: '撤回核销申请失败' });
}
});
router.post('/:id/approve', async (req, res) => {
try {
const { id } = req.params;
const { remark } = req.body;
const result = await db.query('UPDATE verifications SET status = $1, approval_remark = $2 WHERE id = $3', ['approved', remark, id]);
if (result.changes > 0) {
res.json({ success: true, message: '审批通过成功' });
} else {
res.status(404).json({ success: false, message: '核销申请不存在' });
}
} catch (error) {
console.error('审批核销申请失败:', error);
res.status(500).json({ success: false, message: '审批核销申请失败' });
}
});
router.post('/:id/reject', async (req, res) => {
try {
const { id } = req.params;
const { rejectReason } = req.body;
// 开始事务
await db.query('BEGIN TRANSACTION');
try {
// 获取核销金额和预支单ID
const verification = await db.query('SELECT amount, advance_id FROM verifications WHERE id = $1', [id]);
const amount = verification.rows[0]?.amount || 0;
const advanceId = verification.rows[0]?.advance_id;
// 退回核销申请
const result = await db.query('UPDATE verifications SET status = $1 WHERE id = $2', ['pending_edit', id]);
// 不在这里恢复预支单已核销金额,因为只有执行的核销才会增加已核销金额
// if (advanceId && amount > 0) {
// await db.query(
// 'UPDATE advances SET total_reimbursed = total_reimbursed - $1 WHERE id = $2',
// [amount, advanceId]
// );
// }
// 提交事务
await db.query('COMMIT');
if (result.changes > 0) {
res.json({ success: true, message: '退回成功' });
} else {
res.status(404).json({ success: false, message: '核销申请不存在' });
}
} catch (error) {
// 回滚事务
await db.query('ROLLBACK');
throw error;
}
} catch (error) {
console.error('退回核销申请失败:', error);
res.status(500).json({ success: false, message: '退回核销申请失败' });
}
});
module.exports = router;