Initial commit: ERP system with advance verification fixes
This commit is contained in:
@@ -0,0 +1,467 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const db = require('./db');
|
||||
|
||||
// 获取所有付款节点
|
||||
router.get('/payment-nodes', async (req, res) => {
|
||||
try {
|
||||
const result = await db.query(`
|
||||
SELECT
|
||||
pn.*,
|
||||
pr.project_name,
|
||||
pr.project_code
|
||||
FROM payment_nodes pn
|
||||
LEFT JOIN projects pr ON pn.project_id = pr.project_id
|
||||
ORDER BY pn.due_date ASC
|
||||
`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: result.rows,
|
||||
count: result.rows.length
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取付款节点失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取付款节点失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取单个付款节点
|
||||
router.get('/payment-nodes/:id', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const result = await db.query(`
|
||||
SELECT
|
||||
pn.*,
|
||||
pr.project_name,
|
||||
pr.project_code
|
||||
FROM payment_nodes pn
|
||||
LEFT JOIN projects pr ON pn.project_id = pr.project_id
|
||||
WHERE pn.node_id = $1
|
||||
`, [id]);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '付款节点不存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: result.rows[0]
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取付款节点失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取付款节点失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 创建付款节点
|
||||
router.post('/payment-nodes', async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
project_id,
|
||||
node_type,
|
||||
node_name,
|
||||
node_name_zh,
|
||||
node_name_th,
|
||||
node_name_en,
|
||||
amount,
|
||||
currency,
|
||||
due_date,
|
||||
status,
|
||||
notes
|
||||
} = req.body;
|
||||
|
||||
const result = await db.query(`
|
||||
INSERT INTO payment_nodes (
|
||||
project_id, node_type, node_name,
|
||||
node_name_zh, node_name_th, node_name_en,
|
||||
amount, currency, due_date, status, notes
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
RETURNING *
|
||||
`, [
|
||||
project_id, node_type, node_name,
|
||||
node_name_zh, node_name_th, node_name_en,
|
||||
amount, currency, due_date, status || 'pending', notes
|
||||
]);
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: '付款节点创建成功',
|
||||
data: result.rows[0]
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建付款节点失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '创建付款节点失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 更新付款节点
|
||||
router.put('/payment-nodes/:id', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const {
|
||||
node_type,
|
||||
node_name,
|
||||
node_name_zh,
|
||||
node_name_th,
|
||||
node_name_en,
|
||||
amount,
|
||||
currency,
|
||||
due_date,
|
||||
status,
|
||||
notes
|
||||
} = req.body;
|
||||
|
||||
const result = await db.query(`
|
||||
UPDATE payment_nodes
|
||||
SET
|
||||
node_type = COALESCE($1, node_type),
|
||||
node_name = COALESCE($2, node_name),
|
||||
node_name_zh = COALESCE($3, node_name_zh),
|
||||
node_name_th = COALESCE($4, node_name_th),
|
||||
node_name_en = COALESCE($5, node_name_en),
|
||||
amount = COALESCE($6, amount),
|
||||
currency = COALESCE($7, currency),
|
||||
due_date = COALESCE($8, due_date),
|
||||
status = COALESCE($9, status),
|
||||
notes = COALESCE($10, notes),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE node_id = $11
|
||||
RETURNING *
|
||||
`, [
|
||||
node_type, node_name, node_name_zh, node_name_th, node_name_en,
|
||||
amount, currency, due_date, status, notes, id
|
||||
]);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '付款节点不存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '付款节点更新成功',
|
||||
data: result.rows[0]
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新付款节点失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '更新付款节点失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 删除付款节点
|
||||
router.delete('/payment-nodes/:id', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const result = await db.query(
|
||||
'DELETE FROM payment_nodes WHERE node_id = $1 RETURNING *',
|
||||
[id]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '付款节点不存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '付款节点删除成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('删除付款节点失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '删除付款节点失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取付款记录
|
||||
router.get('/payment-records', async (req, res) => {
|
||||
try {
|
||||
const { node_id, record_type, start_date, end_date } = req.query;
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
pr.*,
|
||||
pn.node_name,
|
||||
pn.project_id,
|
||||
proj.project_name
|
||||
FROM payment_records pr
|
||||
LEFT JOIN payment_nodes pn ON pr.node_id = pn.node_id
|
||||
LEFT JOIN projects proj ON pn.project_id = proj.project_id
|
||||
WHERE 1=1
|
||||
`;
|
||||
const params = [];
|
||||
let paramIndex = 1;
|
||||
|
||||
if (node_id) {
|
||||
query += ` AND pr.node_id = $${paramIndex}`;
|
||||
params.push(node_id);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
if (record_type) {
|
||||
query += ` AND pr.record_type = $${paramIndex}`;
|
||||
params.push(record_type);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
if (start_date) {
|
||||
query += ` AND pr.payment_date >= $${paramIndex}`;
|
||||
params.push(start_date);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
if (end_date) {
|
||||
query += ` AND pr.payment_date <= $${paramIndex}`;
|
||||
params.push(end_date);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
query += ` ORDER BY pr.payment_date DESC, pr.created_at DESC`;
|
||||
|
||||
const result = await db.query(query, params);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: result.rows,
|
||||
count: result.rows.length
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取付款记录失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取付款记录失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 创建付款记录
|
||||
router.post('/payment-records', async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
node_id,
|
||||
record_type,
|
||||
amount,
|
||||
currency,
|
||||
exchange_rate,
|
||||
payment_date,
|
||||
payment_method,
|
||||
reference_number,
|
||||
status,
|
||||
notes
|
||||
} = req.body;
|
||||
|
||||
const result = await db.query(`
|
||||
INSERT INTO payment_records (
|
||||
node_id, record_type, amount, currency, exchange_rate,
|
||||
payment_date, payment_method, reference_number, status, notes
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||
RETURNING *
|
||||
`, [
|
||||
node_id, record_type, amount, currency, exchange_rate || 1.0,
|
||||
payment_date, payment_method, reference_number, status || 'completed', notes
|
||||
]);
|
||||
|
||||
// 如果是付款记录,更新付款节点状态
|
||||
if (record_type === 'payment') {
|
||||
await db.query(`
|
||||
UPDATE payment_nodes
|
||||
SET status = 'paid', updated_at = CURRENT_TIMESTAMP
|
||||
WHERE node_id = $1
|
||||
`, [node_id]);
|
||||
}
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: '付款记录创建成功',
|
||||
data: result.rows[0]
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建付款记录失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '创建付款记录失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取汇率
|
||||
router.get('/exchange-rates', async (req, res) => {
|
||||
try {
|
||||
const { from_currency, to_currency, effective_date } = req.query;
|
||||
|
||||
let query = 'SELECT * FROM exchange_rates WHERE 1=1';
|
||||
const params = [];
|
||||
let paramIndex = 1;
|
||||
|
||||
if (from_currency) {
|
||||
query += ` AND from_currency = $${paramIndex}`;
|
||||
params.push(from_currency);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
if (to_currency) {
|
||||
query += ` AND to_currency = $${paramIndex}`;
|
||||
params.push(to_currency);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
if (effective_date) {
|
||||
query += ` AND effective_date = $${paramIndex}`;
|
||||
params.push(effective_date);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
query += ` ORDER BY effective_date DESC, created_at DESC`;
|
||||
|
||||
const result = await db.query(query, params);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: result.rows,
|
||||
count: result.rows.length
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取汇率失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取汇率失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 创建/更新汇率
|
||||
router.post('/exchange-rates', async (req, res) => {
|
||||
try {
|
||||
const { from_currency, to_currency, rate, effective_date } = req.body;
|
||||
|
||||
// 检查是否已存在
|
||||
const checkResult = await db.query(`
|
||||
SELECT * FROM exchange_rates
|
||||
WHERE from_currency = $1 AND to_currency = $2 AND effective_date = $3
|
||||
`, [from_currency, to_currency, effective_date]);
|
||||
|
||||
let result;
|
||||
if (checkResult.rows.length > 0) {
|
||||
// 更新
|
||||
result = await db.query(`
|
||||
UPDATE exchange_rates
|
||||
SET rate = $1, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE from_currency = $2 AND to_currency = $3 AND effective_date = $4
|
||||
RETURNING *
|
||||
`, [rate, from_currency, to_currency, effective_date]);
|
||||
} else {
|
||||
// 创建
|
||||
result = await db.query(`
|
||||
INSERT INTO exchange_rates (from_currency, to_currency, rate, effective_date)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING *
|
||||
`, [from_currency, to_currency, rate, effective_date]);
|
||||
}
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: '汇率保存成功',
|
||||
data: result.rows[0]
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('保存汇率失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '保存汇率失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 财务统计
|
||||
router.get('/finance-stats', async (req, res) => {
|
||||
try {
|
||||
// 付款节点统计
|
||||
const nodesStats = await db.query(`
|
||||
SELECT
|
||||
COUNT(*) as total_nodes,
|
||||
COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending_nodes,
|
||||
COUNT(CASE WHEN status = 'paid' THEN 1 END) as paid_nodes,
|
||||
COUNT(CASE WHEN status = 'overdue' THEN 1 END) as overdue_nodes,
|
||||
SUM(amount) as total_amount,
|
||||
SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) as pending_amount,
|
||||
SUM(CASE WHEN status = 'paid' THEN amount ELSE 0 END) as paid_amount
|
||||
FROM payment_nodes
|
||||
`);
|
||||
|
||||
// 付款记录统计
|
||||
const recordsStats = await db.query(`
|
||||
SELECT
|
||||
COUNT(*) as total_records,
|
||||
COUNT(CASE WHEN record_type = 'payment' THEN 1 END) as payment_count,
|
||||
COUNT(CASE WHEN record_type = 'receipt' THEN 1 END) as receipt_count,
|
||||
SUM(CASE WHEN record_type = 'payment' THEN amount ELSE 0 END) as total_payments,
|
||||
SUM(CASE WHEN record_type = 'receipt' THEN amount ELSE 0 END) as total_receipts
|
||||
FROM payment_records
|
||||
`);
|
||||
|
||||
// 货币分布
|
||||
const currencyStats = await db.query(`
|
||||
SELECT
|
||||
currency,
|
||||
COUNT(*) as node_count,
|
||||
SUM(amount) as total_amount
|
||||
FROM payment_nodes
|
||||
GROUP BY currency
|
||||
ORDER BY total_amount DESC
|
||||
`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
nodes: nodesStats.rows[0],
|
||||
records: recordsStats.rows[0],
|
||||
currencies: currencyStats.rows,
|
||||
summary: {
|
||||
net_cash_flow: (recordsStats.rows[0]?.total_receipts || 0) - (recordsStats.rows[0]?.total_payments || 0),
|
||||
outstanding_amount: nodesStats.rows[0]?.pending_amount || 0
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取财务统计失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取财务统计失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user