269 lines
9.8 KiB
JavaScript
269 lines
9.8 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 testProjectId = null;
|
||
|
|
let testOrderId = null;
|
||
|
|
let testProductId = null;
|
||
|
|
|
||
|
|
try {
|
||
|
|
console.log('\n========================================');
|
||
|
|
console.log('测试项目材料管理功能');
|
||
|
|
console.log('========================================\n');
|
||
|
|
|
||
|
|
console.log('--- 测试1:创建测试数据 ---\n');
|
||
|
|
|
||
|
|
const projectCode = 'TEST-PRJ-' + Date.now();
|
||
|
|
const projectResult = await runSQL(`
|
||
|
|
INSERT INTO projects (code, name, status, created_at, updated_at)
|
||
|
|
VALUES (?, '测试项目材料', 'active', datetime('now'), datetime('now'))
|
||
|
|
`, [projectCode]);
|
||
|
|
testProjectId = projectResult.lastID;
|
||
|
|
console.log(` ✅ 创建测试项目,ID: ${testProjectId}`);
|
||
|
|
passed++;
|
||
|
|
|
||
|
|
const orderCode = 'TEST-PO-' + Date.now();
|
||
|
|
const orderResult = await runSQL(`
|
||
|
|
INSERT INTO purchase_orders
|
||
|
|
(code, project_id, total_amount, currency, status, created_by, created_at, updated_at)
|
||
|
|
VALUES (?, ?, 5000, 'CNY', 'confirmed', '测试人员', datetime('now'), datetime('now'))
|
||
|
|
`, [orderCode, testProjectId]);
|
||
|
|
testOrderId = orderResult.lastID;
|
||
|
|
console.log(` ✅ 创建测试订单,ID: ${testOrderId}`);
|
||
|
|
passed++;
|
||
|
|
|
||
|
|
const productResult = await runSQL(`
|
||
|
|
INSERT INTO products (name, specification, unit, created_at, updated_at)
|
||
|
|
VALUES ('测试材料A', '规格1', '个', datetime('now'), datetime('now'))
|
||
|
|
`);
|
||
|
|
testProductId = productResult.lastID;
|
||
|
|
console.log(` ✅ 创建测试商品,ID: ${testProductId}`);
|
||
|
|
passed++;
|
||
|
|
|
||
|
|
console.log('\n--- 测试2:项目材料库存 ---\n');
|
||
|
|
|
||
|
|
const inventoryResult = await runSQL(`
|
||
|
|
INSERT INTO project_material_inventory
|
||
|
|
(project_id, product_id, product_name, unit, purchased_quantity, received_quantity,
|
||
|
|
used_quantity, returned_quantity, current_quantity, total_amount, average_price, created_at, updated_at)
|
||
|
|
VALUES (?, ?, '测试材料A', '个', 100, 100, 20, 5, 75, 3750, 50, datetime('now'), datetime('now'))
|
||
|
|
`, [testProjectId, testProductId]);
|
||
|
|
console.log(` ✅ 创建材料库存记录,ID: ${inventoryResult.lastID}`);
|
||
|
|
passed++;
|
||
|
|
|
||
|
|
const inventory = await runAllSQL('SELECT * FROM project_material_inventory WHERE project_id = ?', [testProjectId]);
|
||
|
|
if (inventory.length > 0) {
|
||
|
|
const inv = inventory[0];
|
||
|
|
console.log(` ✅ 库存查询成功:`);
|
||
|
|
console.log(` 采购数量: ${inv.purchased_quantity}`);
|
||
|
|
console.log(` 收货数量: ${inv.received_quantity}`);
|
||
|
|
console.log(` 已用数量: ${inv.used_quantity}`);
|
||
|
|
console.log(` 退库数量: ${inv.returned_quantity}`);
|
||
|
|
console.log(` 当前库存: ${inv.current_quantity}`);
|
||
|
|
passed++;
|
||
|
|
} else {
|
||
|
|
console.log(` ❌ 库存查询失败`);
|
||
|
|
failed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n--- 测试3:项目材料库存汇总 ---\n');
|
||
|
|
|
||
|
|
const summary = await runAllSQL(`
|
||
|
|
SELECT
|
||
|
|
COUNT(*) as item_count,
|
||
|
|
SUM(purchased_quantity) as total_purchased,
|
||
|
|
SUM(received_quantity) as total_received,
|
||
|
|
SUM(used_quantity) as total_used,
|
||
|
|
SUM(returned_quantity) as total_returned,
|
||
|
|
SUM(current_quantity) as total_current,
|
||
|
|
SUM(total_amount) as total_value
|
||
|
|
FROM project_material_inventory
|
||
|
|
WHERE project_id = ?
|
||
|
|
`, [testProjectId]);
|
||
|
|
|
||
|
|
if (summary.length > 0) {
|
||
|
|
console.log(` ✅ 库存汇总:`);
|
||
|
|
console.log(` 材料种类: ${summary[0].item_count}`);
|
||
|
|
console.log(` 总采购数量: ${summary[0].total_purchased}`);
|
||
|
|
console.log(` 总当前库存: ${summary[0].total_current}`);
|
||
|
|
console.log(` 总金额: ${summary[0].total_value}`);
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n--- 测试4:项目采购记录 ---\n');
|
||
|
|
|
||
|
|
const purchases = await runAllSQL(`
|
||
|
|
SELECT po.*, s.name as supplier_name
|
||
|
|
FROM purchase_orders po
|
||
|
|
LEFT JOIN suppliers s ON po.supplier_id = s.id
|
||
|
|
WHERE po.project_id = ?
|
||
|
|
ORDER BY po.created_at DESC
|
||
|
|
`, [testProjectId]);
|
||
|
|
|
||
|
|
if (purchases.length > 0) {
|
||
|
|
console.log(` ✅ 采购记录查询成功,共 ${purchases.length} 条记录`);
|
||
|
|
console.log(` 订单号: ${purchases[0].code}`);
|
||
|
|
console.log(` 状态: ${purchases[0].status}`);
|
||
|
|
passed++;
|
||
|
|
} else {
|
||
|
|
console.log(` ❌ 采购记录查询失败`);
|
||
|
|
failed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n--- 测试5:材料价格历史 ---\n');
|
||
|
|
|
||
|
|
const priceHistoryResult = await runSQL(`
|
||
|
|
INSERT INTO material_price_history
|
||
|
|
(product_id, purchase_order_id, supplier_id, unit_price, currency, quantity, purchase_date, created_at)
|
||
|
|
VALUES (?, ?, NULL, 50, 'CNY', 100, date('now'), datetime('now'))
|
||
|
|
`, [testProductId, testOrderId]);
|
||
|
|
console.log(` ✅ 创建价格历史记录,ID: ${priceHistoryResult.lastID}`);
|
||
|
|
passed++;
|
||
|
|
|
||
|
|
const priceHistory = await runAllSQL(`
|
||
|
|
SELECT * FROM material_price_history WHERE product_id = ?
|
||
|
|
ORDER BY purchase_date DESC
|
||
|
|
`, [testProductId]);
|
||
|
|
|
||
|
|
if (priceHistory.length > 0) {
|
||
|
|
console.log(` ✅ 价格历史查询成功,共 ${priceHistory.length} 条记录`);
|
||
|
|
console.log(` 单价: ${priceHistory[0].unit_price} ${priceHistory[0].currency}`);
|
||
|
|
console.log(` 数量: ${priceHistory[0].quantity}`);
|
||
|
|
console.log(` 采购日期: ${priceHistory[0].purchase_date}`);
|
||
|
|
passed++;
|
||
|
|
} else {
|
||
|
|
console.log(` ❌ 价格历史查询失败`);
|
||
|
|
failed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n--- 测试6:材料平均价格 ---\n');
|
||
|
|
|
||
|
|
const avgPrice = await runAllSQL(`
|
||
|
|
SELECT
|
||
|
|
AVG(unit_price) as avg_price,
|
||
|
|
MIN(unit_price) as min_price,
|
||
|
|
MAX(unit_price) as max_price,
|
||
|
|
COUNT(*) as purchase_count,
|
||
|
|
SUM(quantity) as total_quantity
|
||
|
|
FROM material_price_history
|
||
|
|
WHERE product_id = ?
|
||
|
|
`, [testProductId]);
|
||
|
|
|
||
|
|
if (avgPrice.length > 0) {
|
||
|
|
console.log(` ✅ 平均价格统计:`);
|
||
|
|
console.log(` 平均价格: ${avgPrice[0].avg_price}`);
|
||
|
|
console.log(` 最低价格: ${avgPrice[0].min_price}`);
|
||
|
|
console.log(` 最高价格: ${avgPrice[0].max_price}`);
|
||
|
|
console.log(` 采购次数: ${avgPrice[0].purchase_count}`);
|
||
|
|
passed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n--- 测试7:验证库存计算逻辑 ---\n');
|
||
|
|
console.log(' 库存计算公式:');
|
||
|
|
console.log(' 当前库存 = 收货数量 - 已用数量 - 退库数量');
|
||
|
|
console.log(' 当前库存 = 100 - 20 - 5 = 75');
|
||
|
|
|
||
|
|
const invCheck = await runAllSQL('SELECT * FROM project_material_inventory WHERE project_id = ?', [testProjectId]);
|
||
|
|
if (invCheck[0].current_quantity === 75) {
|
||
|
|
console.log(` ✅ 库存计算正确: ${invCheck[0].current_quantity}`);
|
||
|
|
passed++;
|
||
|
|
} else {
|
||
|
|
console.log(` ❌ 库存计算错误: ${invCheck[0].current_quantity}`);
|
||
|
|
failed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('\n--- 清理测试数据 ---\n');
|
||
|
|
await runSQL('DELETE FROM material_price_history WHERE product_id = ?', [testProductId]);
|
||
|
|
await runSQL('DELETE FROM project_material_inventory WHERE project_id = ?', [testProjectId]);
|
||
|
|
await runSQL('DELETE FROM purchase_orders WHERE id = ?', [testOrderId]);
|
||
|
|
await runSQL('DELETE FROM products WHERE id = ?', [testProductId]);
|
||
|
|
await runSQL('DELETE FROM projects WHERE id = ?', [testProjectId]);
|
||
|
|
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 (testProjectId) {
|
||
|
|
try {
|
||
|
|
await runSQL('DELETE FROM material_price_history WHERE product_id = ?', [testProductId]);
|
||
|
|
await runSQL('DELETE FROM project_material_inventory WHERE project_id = ?', [testProjectId]);
|
||
|
|
await runSQL('DELETE FROM purchase_orders WHERE id = ?', [testOrderId]);
|
||
|
|
await runSQL('DELETE FROM products WHERE id = ?', [testProductId]);
|
||
|
|
await runSQL('DELETE FROM projects WHERE id = ?', [testProjectId]);
|
||
|
|
} catch (e) {}
|
||
|
|
}
|
||
|
|
db.close();
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
test();
|