3 * Import customers from WHMCS export to PostgreSQL
4 * Reads from exports/whmcs_export.json or exports/whmcs_clients.csv
7require('dotenv').config();
8const fs = require('fs');
9const path = require('path');
10const pool = require('../services/db');
12const EXPORT_DIR = path.join(__dirname, '../exports');
14// Get tenant ID from Precise PCs tenant file or environment variable
18function getTenantId() {
19 const tenantFilePath = path.join(EXPORT_DIR, 'precise_pcs_tenant.json');
21 if (fs.existsSync(tenantFilePath)) {
23 const tenantData = JSON.parse(fs.readFileSync(tenantFilePath, 'utf8'));
24 console.log(`š Using tenant from file: ${tenantData.name} (${tenantData.tenant_id})`);
25 return tenantData.tenant_id;
27 console.warn('ā ļø Could not read tenant file, using default');
31 return process.env.TENANT_ID || process.env.DEFAULT_TENANT_ID || '00000000-0000-0000-0000-000000000001';
34const TENANT_ID = getTenantId();
37 * Import customers from WHMCS data
39async function importCustomers() {
41 console.log('========================================');
42 console.log('WHMCS Customer Import');
43 console.log('========================================\n');
45 // Check if export file exists
46 const jsonPath = path.join(EXPORT_DIR, 'whmcs_export.json');
47 if (!fs.existsSync(jsonPath)) {
48 throw new Error(`Export file not found: ${jsonPath}\nRun: node migration-scripts/fetch_whmcs_data.js`);
52 const exportData = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
53 const clients = exportData.clients || [];
55 console.log(`Found ${clients.length} clients to import`);
56 console.log(`Target tenant: ${TENANT_ID}\n`);
58 // Verify tenant exists
59 const tenantCheck = await pool.query(
60 'SELECT tenant_id, name FROM tenants WHERE tenant_id = $1',
64 if (tenantCheck.rows.length === 0) {
65 throw new Error(`Tenant ${TENANT_ID} not found in database`);
68 console.log(`ā
Tenant verified: ${tenantCheck.rows[0].name}\n`);
69 console.log('Starting import...\n');
76 for (const whmcsClient of clients) {
78 // Skip if not active (optional - you can import all)
79 if (whmcsClient.status !== 'Active') {
80 console.log(`āļø Skipping ${whmcsClient.email} - status: ${whmcsClient.status}`);
85 // Check if customer already exists
86 const existing = await pool.query(
87 'SELECT customer_id FROM customers WHERE email = $1 AND tenant_id = $2',
88 [whmcsClient.email, TENANT_ID]
91 if (existing.rows.length > 0) {
92 console.log(`āļø Skipping ${whmcsClient.email} - already exists (ID: ${existing.rows[0].customer_id})`);
97 // Map WHMCS data to PostgreSQL format
98 const customerName = whmcsClient.companyname ||
99 `${whmcsClient.firstname} ${whmcsClient.lastname}`.trim();
101 const contactName = `${whmcsClient.firstname} ${whmcsClient.lastname}`.trim();
104 const address = [whmcsClient.address1, whmcsClient.address2]
108 // Build migration notes
110 `Migrated from WHMCS (Client ID: ${whmcsClient.id})`,
112 `Original status: ${whmcsClient.status}`,
113 `Date created: ${whmcsClient.datecreated}`,
114 `Currency: ${whmcsClient.currency || 'AUD'}`
115 ].filter(Boolean).join('\n');
118 const result = await pool.query(`
119 INSERT INTO customers (
120 tenant_id, name, contact_name, email, phone,
121 address, city, state, postal_code, country,
122 status, created_at, notes
123 ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
124 RETURNING customer_id, name, email
130 whmcsClient.phonenumber || null,
132 whmcsClient.city || null,
133 whmcsClient.state || null,
134 whmcsClient.postcode || null,
135 whmcsClient.country || 'AU',
136 'active', // Always set to active for now
137 whmcsClient.datecreated || new Date(),
141 const newCustomer = result.rows[0];
142 console.log(`ā
Imported: ${newCustomer.name} (${newCustomer.email}) - ID: ${newCustomer.customer_id}`);
145 whmcs_id: whmcsClient.id,
146 postgres_id: newCustomer.customer_id,
147 name: newCustomer.name,
148 email: newCustomer.email,
155 console.error(`ā Error importing ${whmcsClient.email}:`, err.message);
157 whmcs_id: whmcsClient.id,
158 name: `${whmcsClient.firstname} ${whmcsClient.lastname}`,
159 email: whmcsClient.email,
168 const logPath = path.join(EXPORT_DIR, 'customer_import_log.json');
169 fs.writeFileSync(logPath, JSON.stringify(importLog, null, 2));
172 console.log('\n========================================');
173 console.log('Import Summary');
174 console.log('========================================');
175 console.log(`ā
Imported: ${imported}`);
176 console.log(`āļø Skipped: ${skipped}`);
177 console.log(`ā Errors: ${errors}`);
178 console.log(`\nImport log saved: ${logPath}`);
179 console.log('========================================\n');
182 console.log('Next steps:');
183 console.log('1. Review imported customers in dashboard');
184 console.log('2. Import domains: node migration-scripts/import_whmcs_domains.js');
185 console.log('3. Link products/services to customers\n');
189 console.error('\nā Import failed:', error.message);
190 console.error(error.stack);
197// Run if called directly
198if (require.main === module) {
202module.exports = { importCustomers };