/** * 采购订单路由 * 遵循设计方案:采购-付款-物流-退库一体化流程设计方案.md * 章节:三、采购订单页面设计 * * 多TAB设计: * - 基本信息:订单基本信息、供应商选择 * - 商品明细:订单商品列表 * - 付款信息:付款计划列表 * - 物流信息:物流单信息 * - 验收记录:验收单列表 */ const express = require('express'); const db = require('../db'); const router = express.Router(); /** * 获取采购订单列表 * 遵循设计方案:支持按项目、供应商、状态筛选 */ router.get('/', async (req, res) => { try { const { project_id, supplier_id, status } = req.query; let query = ` SELECT po.*, p.name as project_name, s.name as supplier_name, (SELECT SUM(planned_amount) FROM payment_plans WHERE purchase_order_id = po.id AND status = 'paid') as paid_amount FROM purchase_orders po LEFT JOIN projects p ON po.project_id = p.id LEFT JOIN suppliers s ON po.supplier_id = s.id `; const params = []; const conditions = []; if (project_id) { conditions.push('po.project_id = $1'); params.push(project_id); } if (supplier_id) { conditions.push('po.supplier_id = $1'); params.push(supplier_id); } if (status) { conditions.push('po.status = $1'); params.push(status); } if (conditions.length > 0) { query += ' WHERE ' + conditions.join(' AND '); } query += ' ORDER BY po.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 }); } }); /** * 获取采购订单详情(包含所有TAB数据) * 遵循设计方案:三、采购订单页面设计 - 多TAB */ router.get('/:id', async (req, res) => { try { const { id } = req.params; const orderResult = await db.query(` SELECT po.*, p.name as project_name, s.name as supplier_name, s.country as supplier_country FROM purchase_orders po LEFT JOIN projects p ON po.project_id = p.id LEFT JOIN suppliers s ON po.supplier_id = s.id WHERE po.id = ? `, [id]); if (orderResult.rows.length === 0) { return res.status(404).json({ success: false, message: '采购订单不存在' }); } const order = orderResult.rows[0]; const itemsResult = await db.query(` SELECT poi.*, p.name as product_name, p.specification, p.unit FROM purchase_order_items poi LEFT JOIN products p ON poi.product_id = p.id WHERE poi.purchase_order_id = ? ORDER BY poi.id `, [id]); order.items = itemsResult.rows; const paymentPlansResult = await db.query(` SELECT pp.*, pr.status as request_status FROM payment_plans pp LEFT JOIN payment_requests pr ON pp.payment_request_id = pr.id WHERE pp.purchase_order_id = ? ORDER BY pp.stage, pp.id `, [id]); order.payment_plans = paymentPlansResult.rows; const logisticsResult = await db.query(` SELECT lr.*, lc.name as logistics_company_name FROM logistics_records lr LEFT JOIN logistics_companies lc ON lr.logistics_company_id = lc.id WHERE lr.purchase_order_id = ? ORDER BY lr.id DESC `, [id]); order.logistics = logisticsResult.rows; const verificationResult = await db.query(` SELECT vr.*, p.name as project_name FROM verification_records vr LEFT JOIN projects p ON vr.project_id = p.id WHERE vr.purchase_order_id = ? ORDER BY vr.id DESC `, [id]); order.verifications = verificationResult.rows; const totalAmountResult = await db.query( 'SELECT SUM(total_price) as total FROM purchase_order_items WHERE purchase_order_id = $1', [id] ); order.total_amount = totalAmountResult.rows[0]?.total || 0; const paidAmountResult = await db.query( "SELECT SUM(actual_amount) as paid FROM payment_plans WHERE purchase_order_id = $1 AND status = 'paid'", [id] ); order.paid_amount = paidAmountResult.rows[0]?.paid || 0; res.json({ success: true, data: order }); } catch (error) { console.error('获取采购订单详情失败:', error); res.status(500).json({ success: false, message: '获取采购订单详情失败', error: error.message }); } }); /** * 创建采购订单 */ router.post('/', async (req, res) => { try { const { code, purchase_request_id, project_id, supplier_id, currency, remark, created_by } = req.body; const orderCode = code || 'PO' + new Date().toISOString().slice(0, 10).replace(/-/g, '') + String(Math.floor(Math.random() * 10000)).padStart(4, '0'); const result = await db.query(` INSERT INTO purchase_orders (code, purchase_request_id, project_id, supplier_id, currency, status, remark, created_by, created_at, updated_at) VALUES (?, ?, ?, ?, ?, 'draft', ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) `, [orderCode, purchase_request_id, project_id, supplier_id, currency || 'CNY', remark, created_by]); res.json({ success: true, message: '采购订单创建成功', data: { id: (result.rows[0]?.id || result.rows?.[0]?.id), code: orderCode } }); } catch (error) { console.error('创建采购订单失败:', error); res.status(500).json({ success: false, message: '创建采购订单失败', error: error.message }); } }); /** * 更新采购订单基本信息 */ router.put('/:id', async (req, res) => { try { const { id } = req.params; const { supplier_id, supplier_country, contract_url, quotation_url, remark } = req.body; const result = await db.query(` UPDATE purchase_orders SET supplier_id = ?, supplier_country = ?, contract_url = ?, quotation_url = ?, remark = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? `, [supplier_id, supplier_country, contract_url, quotation_url, remark, id]); if (result.changes === 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.post('/:id/confirm', async (req, res) => { try { const { id } = req.params; const { payment_stages } = req.body; const orderResult = await db.query('SELECT * FROM purchase_orders WHERE id = $1', [id]); if (orderResult.rows.length === 0) { return res.status(404).json({ success: false, message: '采购订单不存在' }); } const order = orderResult.rows[0]; const itemsResult = await db.query('SELECT * FROM purchase_order_items WHERE purchase_order_id = $1', [id]); const items = itemsResult.rows; if (items.length === 0) { return res.status(400).json({ success: false, message: '订单没有商品明细,无法确认' }); } await db.query('BEGIN TRANSACTION'); try { await db.query("UPDATE purchase_orders SET status = 'confirmed', updated_at = CURRENT_TIMESTAMP WHERE id = ?", [id]); const totalAmount = items.reduce((sum, item) => sum + (item.total_price || 0), 0); await db.query('UPDATE purchase_orders SET total_amount = $1 WHERE id = $2', [totalAmount, id]); for (const item of items) { await db.query(` INSERT INTO material_price_history (product_id, purchase_order_id, supplier_id, supplier_country, unit_price, currency, quantity, purchase_date, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_DATE, CURRENT_TIMESTAMP) `, [item.product_id, id, order.supplier_id, order.supplier_country, item.unit_price, order.currency, item.quantity]); } if (payment_stages && payment_stages.length > 0) { for (const stage of payment_stages) { await db.query(` INSERT INTO payment_plans (purchase_order_id, stage, planned_date, planned_amount, planned_percentage, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, 'pending', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) `, [id, stage.name, stage.date, stage.amount, stage.percentage]); } } await db.query('COMMIT'); res.json({ success: true, message: '订单确认成功,已记录材料价格历史' }); } catch (innerError) { await db.query('ROLLBACK'); throw innerError; } } catch (error) { console.error('确认订单失败:', error); res.status(500).json({ success: false, message: '确认订单失败', error: error.message }); } }); /** * 取消订单 */ router.post('/:id/cancel', async (req, res) => { try { const { id } = req.params; const result = await db.query( "UPDATE purchase_orders SET status = 'cancelled', updated_at = CURRENT_TIMESTAMP WHERE id = ?", [id] ); if (result.changes === 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('/:id/items', async (req, res) => { try { const { id } = req.params; const result = await db.query(` SELECT poi.*, p.name as product_name, p.specification, p.unit FROM purchase_order_items poi LEFT JOIN products p ON poi.product_id = p.id WHERE poi.purchase_order_id = ? ORDER BY poi.id `, [id]); res.json({ success: true, data: result.rows }); } catch (error) { console.error('获取订单商品明细失败:', error); res.status(500).json({ success: false, message: '获取订单商品明细失败', error: error.message }); } }); /** * 添加订单商品明细 */ router.post('/:id/items', async (req, res) => { try { const { id } = req.params; const { product_id, product_name, specification, unit, quantity, unit_price } = req.body; const total_price = (quantity || 0) * (unit_price || 0); const result = await db.query(` INSERT INTO purchase_order_items (purchase_order_id, product_id, product_name, specification, unit, quantity, unit_price, total_price, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) `, [id, product_id, product_name, specification, unit, quantity, unit_price, total_price]); res.json({ success: true, message: '商品明细添加成功', data: { id: (result.rows[0]?.id || result.rows?.[0]?.id) } }); } catch (error) { console.error('添加商品明细失败:', error); res.status(500).json({ success: false, message: '添加商品明细失败', error: error.message }); } }); /** * 更新订单商品明细 */ router.put('/:id/items/:itemId', async (req, res) => { try { const { id, itemId } = req.params; const { product_id, product_name, specification, unit, quantity, unit_price } = req.body; const total_price = (quantity || 0) * (unit_price || 0); const result = await db.query(` UPDATE purchase_order_items SET product_id = ?, product_name = ?, specification = ?, unit = ?, quantity = ?, unit_price = ?, total_price = ? WHERE id = ? AND purchase_order_id = ? `, [product_id, product_name, specification, unit, quantity, unit_price, total_price, itemId, id]); if (result.changes === 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.delete('/:id/items/:itemId', async (req, res) => { try { const { id, itemId } = req.params; const result = await db.query( 'DELETE FROM purchase_order_items WHERE id = $1 AND purchase_order_id = $2', [itemId, id] ); if (result.changes === 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('/:id/payment-plans', async (req, res) => { try { const { id } = req.params; const result = await db.query(` SELECT pp.*, pr.status as request_status FROM payment_plans pp LEFT JOIN payment_requests pr ON pp.payment_request_id = pr.id WHERE pp.purchase_order_id = ? ORDER BY pp.stage, pp.id `, [id]); res.json({ success: true, data: result.rows }); } catch (error) { console.error('获取付款计划失败:', error); res.status(500).json({ success: false, message: '获取付款计划失败', error: error.message }); } }); /** * 添加付款计划 */ router.post('/:id/payment-plans', async (req, res) => { try { const { id } = req.params; const { stage, planned_date, planned_amount, planned_percentage, remark } = req.body; const result = await db.query(` INSERT INTO payment_plans (purchase_order_id, stage, planned_date, planned_amount, planned_percentage, remark, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, 'pending', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) `, [id, stage, planned_date, planned_amount, planned_percentage, remark]); res.json({ success: true, message: '付款计划添加成功', data: { id: (result.rows[0]?.id || result.rows?.[0]?.id) } }); } catch (error) { console.error('添加付款计划失败:', error); res.status(500).json({ success: false, message: '添加付款计划失败', error: error.message }); } }); /** * 更新付款计划 */ router.put('/:id/payment-plans/:planId', async (req, res) => { try { const { id, planId } = req.params; const { stage, planned_date, planned_amount, planned_percentage, remark } = req.body; const result = await db.query(` UPDATE payment_plans SET stage = $1, planned_date = $2, planned_amount = $3, planned_percentage = $4, remark = $5, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND purchase_order_id = ? `, [stage, planned_date, planned_amount, planned_percentage, remark, planId, id]); if (result.changes === 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.delete('/:id/payment-plans/:planId', async (req, res) => { try { const { id, planId } = req.params; const result = await db.query( 'DELETE FROM payment_plans WHERE id = $1 AND purchase_order_id = $2', [planId, id] ); if (result.changes === 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('/:id/logistics', async (req, res) => { try { const { id } = req.params; const result = await db.query(` SELECT lr.*, lc.name as logistics_company_name FROM logistics_records lr LEFT JOIN logistics_companies lc ON lr.logistics_company_id = lc.id WHERE lr.purchase_order_id = ? ORDER BY lr.id DESC `, [id]); res.json({ success: true, data: result.rows }); } catch (error) { console.error('获取物流信息失败:', error); res.status(500).json({ success: false, message: '获取物流信息失败', error: error.message }); } }); /** * 获取订单验收记录 */ router.get('/:id/verifications', async (req, res) => { try { const { id } = req.params; const result = await db.query(` SELECT vr.*, p.name as project_name FROM verification_records vr LEFT JOIN projects p ON vr.project_id = p.id WHERE vr.purchase_order_id = ? ORDER BY vr.id DESC `, [id]); res.json({ success: true, data: result.rows }); } catch (error) { console.error('获取验收记录失败:', error); res.status(500).json({ success: false, message: '获取验收记录失败', error: error.message }); } }); /** * 删除采购订单 */ router.delete('/:id', async (req, res) => { try { const { id } = req.params; await db.query('BEGIN TRANSACTION'); try { await db.query('DELETE FROM purchase_order_items WHERE purchase_order_id = $1', [id]); await db.query('DELETE FROM payment_plans WHERE purchase_order_id = $1', [id]); await db.query('DELETE FROM purchase_orders WHERE id = $1', [id]); await db.query('COMMIT'); res.json({ success: true, message: '采购订单删除成功' }); } catch (innerError) { await db.query('ROLLBACK'); throw innerError; } } catch (error) { console.error('删除采购订单失败:', error); res.status(500).json({ success: false, message: '删除采购订单失败', error: error.message }); } }); module.exports = router;