3 * Add line items to invoices that don't have any
4 * Typically needed for migrated WHMCS invoices
7const pool = require('../services/db');
9async function addMissingLineItems() {
10 console.log('[Add Line Items] Starting...\n');
12 const client = await pool.connect();
17 // Find all invoices without line items
18 const invoicesResult = await client.query(`
29 LEFT JOIN invoice_items ii ON i.invoice_id = ii.invoice_id
30 WHERE ii.item_id IS NULL
34 console.log(`Found ${invoicesResult.rows.length} invoices without line items\n`);
36 for (const invoice of invoicesResult.rows) {
38 await client.query('BEGIN');
40 // Calculate unit price ex GST
41 const subtotal = parseFloat(invoice.subtotal || invoice.total || 0);
42 const taxAmount = parseFloat(invoice.tax_amount || 0);
43 const total = parseFloat(invoice.total || 0);
44 const taxRate = parseFloat(invoice.tax_rate || 10);
46 // Generate description
47 let description = invoice.description || 'Migrated Invoice Services';
48 if (description.includes('Migrated from WHMCS')) {
49 // Extract WHMCS invoice number if available
50 const match = description.match(/Invoice #(\d+)/);
52 description = `WHMCS Invoice #${match[1]} - Services`;
54 description = 'Migrated Services';
58 // Insert single line item representing the full invoice
60 INSERT INTO invoice_items (
66 ) VALUES ($1, $2, $3, $4, $5)
71 subtotal, // unit price ex GST
72 subtotal // total (same as unit_price since quantity=1)
75 await client.query('COMMIT');
78 if (processed % 50 === 0) {
79 console.log(`Progress: ${processed}/${invoicesResult.rows.length} invoices processed`);
82 await client.query('ROLLBACK');
83 console.error(`Error processing invoice ${invoice.invoice_id}:`, err.message);
88 console.log(`\n[Add Line Items] Complete!`);
89 console.log(`✅ Successfully processed: ${processed} invoices`);
91 console.log(`❌ Errors: ${errors} invoices`);
95 console.error('[Add Line Items] Fatal error:', err);
103addMissingLineItems().catch(console.error);