备份:修复前完整项目快照 2026-04-19
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* 业务台账服务
|
||||
* 为合作伙伴提供统一的业务台账数据
|
||||
*/
|
||||
const db = require('../db');
|
||||
|
||||
class LedgerService {
|
||||
static async getSubcontractorLedger(subcontractorId) {
|
||||
try {
|
||||
const projectsResult = await db.query(`
|
||||
SELECT p.id, p.code as project_code, p.name, p.contract_amount, p.status
|
||||
FROM projects p
|
||||
WHERE p.subcontractor_id = ?
|
||||
ORDER BY p.created_at DESC
|
||||
`, [subcontractorId]);
|
||||
|
||||
const projects = projectsResult.rows;
|
||||
const totalContract = projects.reduce((sum, p) => sum + (parseFloat(p.contract_amount) || 0), 0);
|
||||
|
||||
let totalPaid = 0;
|
||||
try {
|
||||
const paymentsResult = await db.query(`
|
||||
SELECT COALESCE(SUM(amount), 0) as paid_amount
|
||||
FROM payment_requests
|
||||
WHERE payee_type = 'subcontractor' AND payee_id = ? AND status = 'paid'
|
||||
`, [subcontractorId]);
|
||||
totalPaid = parseFloat(paymentsResult.rows[0]?.paid_amount) || 0;
|
||||
} catch (e) { /* payment_requests may not have payee_type column */ }
|
||||
|
||||
return {
|
||||
summary: {
|
||||
item_count: projects.length,
|
||||
total_contract_amount: totalContract,
|
||||
total_paid_amount: totalPaid,
|
||||
total_unpaid_amount: totalContract - totalPaid
|
||||
},
|
||||
items: projects.map(p => ({
|
||||
id: p.id, type: 'project', code: p.project_code, name: p.name,
|
||||
contract_amount: parseFloat(p.contract_amount) || 0,
|
||||
paid_amount: 0, unpaid_amount: parseFloat(p.contract_amount) || 0,
|
||||
status: p.status
|
||||
}))
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('获取分包商台账失败:', error);
|
||||
return { summary: { item_count: 0, total_contract_amount: 0, total_paid_amount: 0, total_unpaid_amount: 0 }, items: [] };
|
||||
}
|
||||
}
|
||||
|
||||
static async getCustomerLedger(customerId) {
|
||||
try {
|
||||
const projectsResult = await db.query(`
|
||||
SELECT p.id, p.code as project_code, p.name, p.contract_amount, p.status
|
||||
FROM projects p
|
||||
WHERE p.customer_id = ?
|
||||
ORDER BY p.created_at DESC
|
||||
`, [customerId]);
|
||||
|
||||
const projects = projectsResult.rows;
|
||||
const totalContract = projects.reduce((sum, p) => sum + (parseFloat(p.contract_amount) || 0), 0);
|
||||
|
||||
let totalReceived = 0;
|
||||
try {
|
||||
const receiptsResult = await db.query(`
|
||||
SELECT COALESCE(SUM(amount), 0) as received_amount
|
||||
FROM payment_records
|
||||
WHERE customer_id = ? AND type = 'income'
|
||||
`, [customerId]);
|
||||
totalReceived = parseFloat(receiptsResult.rows[0]?.received_amount) || 0;
|
||||
} catch (e) { /* ignore */ }
|
||||
|
||||
return {
|
||||
summary: {
|
||||
item_count: projects.length,
|
||||
total_contract_amount: totalContract,
|
||||
total_received_amount: totalReceived,
|
||||
total_receivable_amount: totalContract - totalReceived
|
||||
},
|
||||
items: projects.map(p => ({
|
||||
id: p.id, type: 'project', code: p.project_code, name: p.name,
|
||||
contract_amount: parseFloat(p.contract_amount) || 0,
|
||||
received_amount: 0, receivable_amount: parseFloat(p.contract_amount) || 0,
|
||||
status: p.status
|
||||
}))
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('获取客户台账失败:', error);
|
||||
return { summary: { item_count: 0, total_contract_amount: 0, total_received_amount: 0, total_receivable_amount: 0 }, items: [] };
|
||||
}
|
||||
}
|
||||
|
||||
static async getSupplierLedger(supplierId) {
|
||||
try {
|
||||
const ordersResult = await db.query(`
|
||||
SELECT po.id, po.code, po.total_amount, po.status, po.created_at,
|
||||
p.name as project_name
|
||||
FROM purchase_orders po
|
||||
LEFT JOIN projects p ON po.project_id = p.id
|
||||
WHERE po.supplier_id = ?
|
||||
ORDER BY po.created_at DESC
|
||||
`, [supplierId]);
|
||||
|
||||
const orders = ordersResult.rows;
|
||||
const totalAmount = orders.reduce((sum, o) => sum + (parseFloat(o.total_amount) || 0), 0);
|
||||
|
||||
let totalPaid = 0;
|
||||
try {
|
||||
const paymentsResult = await db.query(`
|
||||
SELECT COALESCE(SUM(pp.actual_amount), 0) as paid_amount
|
||||
FROM payment_plans pp
|
||||
JOIN purchase_orders po ON pp.purchase_order_id = po.id
|
||||
WHERE po.supplier_id = ? AND pp.status = 'paid'
|
||||
`, [supplierId]);
|
||||
totalPaid = parseFloat(paymentsResult.rows[0]?.paid_amount) || 0;
|
||||
} catch (e) { /* ignore */ }
|
||||
|
||||
return {
|
||||
summary: {
|
||||
item_count: orders.length,
|
||||
total_order_amount: totalAmount,
|
||||
total_paid_amount: totalPaid,
|
||||
total_unpaid_amount: totalAmount - totalPaid
|
||||
},
|
||||
items: orders.map(o => ({
|
||||
id: o.id, type: 'purchase_order', code: o.code, name: o.project_name || o.code,
|
||||
order_amount: parseFloat(o.total_amount) || 0,
|
||||
paid_amount: 0, unpaid_amount: parseFloat(o.total_amount) || 0,
|
||||
status: o.status, date: o.created_at
|
||||
}))
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('获取供应商台账失败:', error);
|
||||
return { summary: { item_count: 0, total_order_amount: 0, total_paid_amount: 0, total_unpaid_amount: 0 }, items: [] };
|
||||
}
|
||||
}
|
||||
|
||||
static async getLogisticsCompanyLedger(companyId) {
|
||||
try {
|
||||
const ordersResult = await db.query(`
|
||||
SELECT lr.id, lr.code, lr.ship_date, lr.status,
|
||||
lr.primary_freight, lr.primary_freight_currency, lr.primary_freight_status,
|
||||
lr.secondary_freight, lr.secondary_freight_currency, lr.secondary_freight_status,
|
||||
po.code as order_code, p.name as project_name
|
||||
FROM logistics_records lr
|
||||
LEFT JOIN purchase_orders po ON lr.purchase_order_id = po.id
|
||||
LEFT JOIN projects p ON po.project_id = p.id
|
||||
WHERE lr.logistics_company_id = ?
|
||||
ORDER BY lr.created_at DESC
|
||||
`, [companyId]);
|
||||
|
||||
const orders = ordersResult.rows;
|
||||
const totalPrimary = orders.reduce((sum, o) => sum + (parseFloat(o.primary_freight) || 0), 0);
|
||||
const totalSecondary = orders.reduce((sum, o) => sum + (parseFloat(o.secondary_freight) || 0), 0);
|
||||
const paidPrimary = orders.filter(o => o.primary_freight_status === 'paid').reduce((sum, o) => sum + (parseFloat(o.primary_freight) || 0), 0);
|
||||
const paidSecondary = orders.filter(o => o.secondary_freight_status === 'paid').reduce((sum, o) => sum + (parseFloat(o.secondary_freight) || 0), 0);
|
||||
|
||||
return {
|
||||
summary: {
|
||||
item_count: orders.length,
|
||||
total_primary_freight: totalPrimary,
|
||||
total_secondary_freight: totalSecondary,
|
||||
total_freight: totalPrimary + totalSecondary,
|
||||
paid_primary_freight: paidPrimary,
|
||||
paid_secondary_freight: paidSecondary,
|
||||
paid_amount: paidPrimary + paidSecondary,
|
||||
unpaid_amount: (totalPrimary + totalSecondary) - (paidPrimary + paidSecondary)
|
||||
},
|
||||
items: orders.map(o => ({
|
||||
id: o.id, type: 'logistics_record', code: o.code, name: o.order_code || o.code,
|
||||
project_name: o.project_name,
|
||||
primary_freight: parseFloat(o.primary_freight) || 0,
|
||||
primary_freight_currency: o.primary_freight_currency || 'CNY',
|
||||
primary_freight_status: o.primary_freight_status,
|
||||
secondary_freight: parseFloat(o.secondary_freight) || 0,
|
||||
secondary_freight_currency: o.secondary_freight_currency || 'LAK',
|
||||
secondary_freight_status: o.secondary_freight_status,
|
||||
status: o.status, date: o.ship_date
|
||||
}))
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('获取物流公司台账失败:', error);
|
||||
return { summary: { item_count: 0, total_primary_freight: 0, total_secondary_freight: 0, total_freight: 0, paid_primary_freight: 0, paid_secondary_freight: 0, paid_amount: 0, unpaid_amount: 0 }, items: [] };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LedgerService;
|
||||
Reference in New Issue
Block a user