1// Direct Pax8 product sync test (no Redis)
2// Override DB config to use production BEFORE loading modules
3delete require.cache[require.resolve('../services/db')];
4process.env.DATABASE_URL = '';
5process.env.DB_HOST = 'rmm-psa-db-do-user-28531160-0.i.db.ondigitalocean.com';
6process.env.DB_PORT = '25060';
7process.env.DB_USER = 'doadmin';
8process.env.DB_PASSWORD = 'AVNS_J8RJAmsEwsHFG52_-F2';
9process.env.DB_NAME = 'defaultdb';
10process.env.DB_SSL = 'true';
12const pool = require('../services/db');
13const Pax8Service = require('../services/pax8Service');
15const tenantId = '00000000-0000-0000-0000-000000000001'; // Independent Business Group
16const vendor = 'Microsoft';
18console.log('Starting direct Pax8 product sync...');
19console.log(`Tenant: ${tenantId}`);
20console.log(`Vendor: ${vendor}\n`);
25async function syncProducts() {
27 const pax8 = new Pax8Service(tenantId);
29 console.log('Fetching products from Pax8 API...');
30 const products = await pax8.listProducts({ vendor });
32 if (!products || products.length === 0) {
33 console.log('No products found');
37 console.log(`Found ${products.length} products\n`);
44 for (const product of products) {
46 const existingResult = await pool.query(
47 'SELECT product_id, last_synced_at FROM products WHERE pax8_product_id = $1',
51 const name = product.name || product.productName || 'Unknown Product';
52 const description = product.description || product.productDescription || '';
53 const priceRetail = product.pricing?.retail || product.price || 0;
54 const priceExTax = product.pricing?.cost || priceRetail;
55 const pax8Vendor = product.vendor || vendor;
56 const pax8Category = product.category || null;
57 const pax8Subcategory = product.subcategory || product.subCategory || null;
58 const pax8Sku = product.sku || product.productSku || null;
59 const billingTerm = product.billingTerm || product.billing?.term || 'monthly';
60 const isAutoRenew = product.autoRenew !== false;
61 const pax8Metadata = JSON.stringify(product);
63 if (existingResult.rows.length > 0) {
66 name = $1, description = $2, price_retail = $3, price_ex_tax = $4,
67 pax8_vendor = $5, pax8_category = $6, pax8_subcategory = $7, pax8_sku = $8,
68 billing_term = $9, is_auto_renew = $10, pax8_metadata = $11,
69 last_synced_at = NOW(), updated_at = NOW()
70 WHERE pax8_product_id = $12`,
71 [name, description, priceRetail, priceExTax, pax8Vendor, pax8Category, pax8Subcategory, pax8Sku,
72 billingTerm, isAutoRenew, pax8Metadata, product.id]
75 console.log(`✓ Updated: ${name}`);
78 `INSERT INTO products (
79 tenant_id, name, description, supplier, price_retail, price_ex_tax,
80 is_service, divisible, is_stock,
81 pax8_product_id, pax8_vendor, pax8_category, pax8_subcategory,
82 pax8_sku, billing_term, is_auto_renew, pax8_metadata,
83 is_active, last_synced_at, created_at, updated_at
85 $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, NOW(), NOW(), NOW()
87 [tenantId, name, description, 'Pax8', priceRetail, priceExTax,
88 true, true, false, product.id, pax8Vendor, pax8Category, pax8Subcategory,
89 pax8Sku, billingTerm, isAutoRenew, pax8Metadata, true]
92 console.log(`✓ Added: ${name}`);
95 } catch (productErr) {
97 console.error(`✗ Error processing product ${product.id}:`, productErr.message);
101 console.log('\n=== Sync Complete ===');
102 console.log(`Total: ${products.length}`);
103 console.log(`Synced: ${synced}`);
104 console.log(`Updated: ${updated}`);
105 console.log(`Skipped: ${skipped}`);
106 console.log(`Errors: ${errors}`);
112 console.error('Sync failed:', err.message);
113 console.error(err.stack);