253 lines
9.5 KiB
JavaScript
253 lines
9.5 KiB
JavaScript
/**
|
|||
|
|
* 测试付款执行统一页面功能
|
||
|
|
* 遵循设计方案:采购-付款-物流-退库一体化流程设计方案.md
|
||
|
|
* 章节:七、付款执行统一页面
|
||
|
|
*
|
||
|
|
* 测试内容:
|
||
|
|
* 1. 获取待执行付款列表
|
||
|
|
* 2. 验证整合所有支付类型
|
||
|
|
* 3. 执行付款(必须上传凭证)
|
||
|
|
* 4. 验证付款后状态更新
|
||
|
|
*/
|
||
|
|
|
||
|
|
const sqlite3 = require('sqlite3').verbose();
|
||
|
|
const path = require('path');
|
||
|
|
|
||
|
|
const dbPath = path.join(__dirname, 'company_finance.db');
|
||
|
|
const db = new sqlite3.Database(dbPath, (err) => {
|
||
|
|
if (err) {
|
||
|
|
console.error('数据库连接失败:', err.message);
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
console.log('SQLite数据库连接成功:', dbPath);
|
||
|
|
});
|
||
|
|
|
||
|
|
const runSQL = (sql, params = []) => {
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
db.run(sql, params, function(err) {
|
||
|
|
if (err) {
|
||
|
|
reject(err);
|
||
|
|
} else {
|
||
|
|
resolve({ lastID: this.lastID, changes: this.changes });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
const runAllSQL = (sql, params = []) => {
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
db.all(sql, params, (err, rows) => {
|
||
|
|
if (err) {
|
||
|
|
reject(err);
|
||
|
|
} else {
|
||
|
|
resolve(rows);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
async function test() {
|
||
|
|
let passed = 0;
|
||
|
|
let failed = 0;
|
||
|
|
const errors = [];
|
||
|
|
let testOrderId = null;
|
||
|
|
let testPlanId = null;
|
||
|
|
let testLogisticsId = null;
|
||
|
|
|
||
|
|
try {
|
||
|
|
console.log('\n========================================');
|
||
|
|
console.log('测试付款执行统一页面功能');
|
||
|
|
console.log('========================================\n');
|
||
|
|
|
||
|
|
console.log('--- 测试1:创建测试数据 ---\n');
|
||
|
|
const orderCode = 'TEST-PO-' + Date.now();
|
||
|
|
const orderResult = await runSQL(`
|
||
|
|
INSERT INTO purchase_orders
|
||
|
|
(code, total_amount, currency, status, created_by, created_at, updated_at)
|
||
|
|
VALUES (?, 10000, 'CNY', 'confirmed', '测试人员', datetime('now'), datetime('now'))
|
||
|
|
`, [orderCode]);
|
||
|
|
testOrderId = orderResult.lastID;
|
||
|
|
console.log(` ✅ 创建测试订单,ID: ${testOrderId}`);
|
||
|
|
passed++;
|
||
|
|
|
||
|
|
const planCode = 'PP' + Date.now();
|
||
|
|
const planResult = await runSQL(`
|
||
|
|
INSERT INTO payment_plans
|
||
|
|
(code, purchase_order_id, stage, planned_date, planned_amount, amount, status, created_at, updated_at)
|
||
|
|
VALUES (?, ?, '预付款', date('now'), 3000, 3000, 'pending', datetime('now'), datetime('now'))
|
||
|
|
`, [planCode, testOrderId]);
|
||
|
|
testPlanId = planResult.lastID;
|
||
|
|
console.log(` ✅ 创建付款计划,ID: ${testPlanId}`);
|
||
|
|
passed++;
|
||
|
|
|
||
|
|
const logisticsCode = 'LR' + Date.now();
|
||
|
|
const logisticsResult = await runSQL(`
|
||
|
|
INSERT INTO logistics_records
|
||
|
|
(code, purchase_order_id, ship_from, primary_freight, primary_freight_currency, primary_freight_status,
|
||
|
|
secondary_freight, secondary_freight_currency, secondary_freight_status, status, created_at, updated_at)
|
||
|
|
VALUES (?, ?, 'China', 500, 'CNY', 'pending', 200, 'LAK', 'pending', 'pending', datetime('now'), datetime('now'))
|
||
|
|
`, [logisticsCode, testOrderId]);
|
||
|
|
testLogisticsId = logisticsResult.lastID;
|
||
|
|
console.log(` ✅ 创建物流单,ID: ${testLogisticsId}`);
|
||
|
|
passed++;
|
||
|
|
|
||
|
|
console.log('\n--- 测试2:验证待执行付款列表整合所有类型 ---\n');
|
||
|
|
const pendingPayments = await runAllSQL(`
|
||
|
|
SELECT 'material' as payment_type, pp.id, pp.planned_amount as amount, pp.status
|
||
|
|
FROM payment_plans pp WHERE pp.status = 'pending'
|
||
|
|
UNION ALL
|
||
|
|
SELECT 'primary_freight', lr.id, lr.primary_freight, lr.primary_freight_status
|
||
|
|
FROM logistics_records lr WHERE lr.primary_freight_status = 'pending' AND lr.primary_freight > 0
|
||
|
|
UNION ALL
|
||
|
|
SELECT 'secondary_freight', lr.id, lr.secondary_freight, lr.secondary_freight_status
|
||
|
|
FROM logistics_records lr WHERE lr.secondary_freight_status = 'pending' AND lr.secondary_freight > 0
|
||
|
|
`);
|
||
|
|
|
||
|
|
const materialPayments = pendingPayments.filter(p => p.payment_type === 'material');
|
||
|
|
const primaryFreightPayments = pendingPayments.filter(p => p.payment_type === 'primary_freight');
|
||
|
|
const secondaryFreightPayments = pendingPayments.filter(p => p.payment_type === 'secondary_freight');
|
||
|
|
|
||
|
|
if (materialPayments.length > 0) {
|
||
|
|
console.log(` ✅ 材料采购付款: ${materialPayments.length} 条`);
|
||
|
|
passed++;
|
||
|
|
} else {
|
||
|
|
console.log(` ❌ 材料采购付款: 无`);
|
||
|
|
failed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (primaryFreightPayments.length > 0) {
|
||
|
|
console.log(` ✅ 一次运费付款: ${primaryFreightPayments.length} 条`);
|
||
|
|
passed++;
|
||
|
|
} else {
|
||
|
|
console.log(` ❌ 一次运费付款: 无`);
|
||
|
|
failed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (secondaryFreightPayments.length > 0) {
|
||
|
|
console.log(` ✅ 二次运费付款: ${secondaryFreightPayments.length} 条`);
|
||
|
|
passed++;
|
||
|
|
} else {
|
||
|
|
console.log(` ❌ 二次运费付款: 无`);
|
||
|
|
failed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n--- 测试3:执行材料采购付款(必须上传凭证)---\n');
|
||
|
|
await runSQL(`
|
||
|
|
UPDATE payment_plans
|
||
|
|
SET status = 'paid', actual_amount = 3000, actual_date = date('now'), updated_at = datetime('now')
|
||
|
|
WHERE id = ?
|
||
|
|
`, [testPlanId]);
|
||
|
|
|
||
|
|
const planAfterPay = await runAllSQL('SELECT * FROM payment_plans WHERE id = ?', [testPlanId]);
|
||
|
|
if (planAfterPay[0].status === 'paid') {
|
||
|
|
console.log(` ✅ 付款计划状态更新为 paid`);
|
||
|
|
passed++;
|
||
|
|
} else {
|
||
|
|
console.log(` ❌ 状态更新失败: ${planAfterPay[0].status}`);
|
||
|
|
failed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
const orderAfterPay = await runAllSQL('SELECT * FROM purchase_orders WHERE id = ?', [testOrderId]);
|
||
|
|
if (orderAfterPay[0].paid_amount >= 3000) {
|
||
|
|
console.log(` ✅ 订单已付金额更新: ${orderAfterPay[0].paid_amount}`);
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n--- 测试4:执行一次运费付款(必须上传物流单)---\n');
|
||
|
|
await runSQL(`
|
||
|
|
UPDATE logistics_records
|
||
|
|
SET primary_freight_status = 'paid', primary_freight_document = '/uploads/voucher_001.pdf', updated_at = datetime('now')
|
||
|
|
WHERE id = ?
|
||
|
|
`, [testLogisticsId]);
|
||
|
|
|
||
|
|
const logisticsAfterPay = await runAllSQL('SELECT * FROM logistics_records WHERE id = ?', [testLogisticsId]);
|
||
|
|
if (logisticsAfterPay[0].primary_freight_status === 'paid') {
|
||
|
|
console.log(` ✅ 一次运费状态更新为 paid`);
|
||
|
|
passed++;
|
||
|
|
} else {
|
||
|
|
console.log(` ❌ 状态更新失败: ${logisticsAfterPay[0].primary_freight_status}`);
|
||
|
|
failed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (logisticsAfterPay[0].primary_freight_document) {
|
||
|
|
console.log(` ✅ 已上传付款凭证: ${logisticsAfterPay[0].primary_freight_document}`);
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n--- 测试5:执行二次运费付款(必须填写司机信息)---\n');
|
||
|
|
await runSQL(`
|
||
|
|
UPDATE logistics_records
|
||
|
|
SET secondary_freight_status = 'paid', driver_phone = '020-12345678', cargo_weight = 500, transport_distance = 100, updated_at = datetime('now')
|
||
|
|
WHERE id = ?
|
||
|
|
`, [testLogisticsId]);
|
||
|
|
|
||
|
|
const logisticsAfterSecondPay = await runAllSQL('SELECT * FROM logistics_records WHERE id = ?', [testLogisticsId]);
|
||
|
|
if (logisticsAfterSecondPay[0].secondary_freight_status === 'paid') {
|
||
|
|
console.log(` ✅ 二次运费状态更新为 paid`);
|
||
|
|
passed++;
|
||
|
|
} else {
|
||
|
|
console.log(` ❌ 状态更新失败: ${logisticsAfterSecondPay[0].secondary_freight_status}`);
|
||
|
|
failed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (logisticsAfterSecondPay[0].driver_phone && logisticsAfterSecondPay[0].cargo_weight && logisticsAfterSecondPay[0].transport_distance) {
|
||
|
|
console.log(` ✅ 二次运费信息完整: 司机=${logisticsAfterSecondPay[0].driver_phone}`);
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n--- 测试6:验证付款统计 ---\n');
|
||
|
|
const stats = await runAllSQL(`
|
||
|
|
SELECT
|
||
|
|
SUM(CASE WHEN status = 'paid' THEN actual_amount ELSE 0 END) as paid_amount,
|
||
|
|
COUNT(CASE WHEN status = 'paid' THEN 1 END) as paid_count
|
||
|
|
FROM payment_plans
|
||
|
|
`);
|
||
|
|
|
||
|
|
if (stats[0].paid_count > 0) {
|
||
|
|
console.log(` ✅ 已执行付款统计: ${stats[0].paid_count} 笔,总金额 ${stats[0].paid_amount}`);
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n--- 清理测试数据 ---\n');
|
||
|
|
await runSQL('DELETE FROM payment_plans WHERE purchase_order_id = ?', [testOrderId]);
|
||
|
|
await runSQL('DELETE FROM logistics_records WHERE purchase_order_id = ?', [testOrderId]);
|
||
|
|
await runSQL('DELETE FROM purchase_orders WHERE id = ?', [testOrderId]);
|
||
|
|
console.log(' 测试数据已清理');
|
||
|
|
|
||
|
|
console.log('\n========================================');
|
||
|
|
console.log('测试结果汇总');
|
||
|
|
console.log('========================================\n');
|
||
|
|
console.log(`通过: ${passed}`);
|
||
|
|
console.log(`失败: ${failed}`);
|
||
|
|
|
||
|
|
if (errors.length > 0) {
|
||
|
|
console.log('\n错误详情:');
|
||
|
|
errors.forEach(err => console.log(` - ${err}`));
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n========================================');
|
||
|
|
if (failed === 0) {
|
||
|
|
console.log('✅ 所有测试通过!付款执行统一页面功能符合设计方案。');
|
||
|
|
} else {
|
||
|
|
console.log('❌ 部分测试失败,请检查错误详情。');
|
||
|
|
}
|
||
|
|
console.log('========================================\n');
|
||
|
|
|
||
|
|
db.close();
|
||
|
|
process.exit(failed > 0 ? 1 : 0);
|
||
|
|
} catch (error) {
|
||
|
|
console.error('测试失败:', error);
|
||
|
|
if (testOrderId) {
|
||
|
|
try {
|
||
|
|
await runSQL('DELETE FROM payment_plans WHERE purchase_order_id = ?', [testOrderId]);
|
||
|
|
await runSQL('DELETE FROM logistics_records WHERE purchase_order_id = ?', [testOrderId]);
|
||
|
|
await runSQL('DELETE FROM purchase_orders WHERE id = ?', [testOrderId]);
|
||
|
|
} catch (e) {}
|
||
|
|
}
|
||
|
|
db.close();
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
test();
|