Spaces:
Sleeping
Sleeping
| const pool = require('./config'); | |
| const MIGRATION_KEY = 'migrate8_single_global_bill_counter'; | |
| const migrate8 = async () => { | |
| const client = await pool.connect(); | |
| try { | |
| console.log('Starting database migration (migrate8)...'); | |
| await client.query('BEGIN'); | |
| // Ensure migration_history table exists | |
| await client.query(` | |
| CREATE TABLE IF NOT EXISTS migration_history ( | |
| key VARCHAR(120) PRIMARY KEY, | |
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | |
| ) | |
| `); | |
| const already = await client.query( | |
| 'SELECT key FROM migration_history WHERE key = $1', | |
| [MIGRATION_KEY] | |
| ); | |
| if (already.rows.length > 0) { | |
| await client.query('COMMIT'); | |
| console.log('migrate8 already applied. Skipping.'); | |
| return; | |
| } | |
| // Problem: Previously there were 8+ separate counters per bill type (J, A, P-J, P-A, etc.) | |
| // plus orphaned migration prefixes (JAWAAK, AWAAK, etc.). | |
| // Bills were NOT globally sequential — each type had its own sequence. | |
| // | |
| // Fix: Replace all separate counters with ONE global counter ('BILL'). | |
| // Seed it with the MAX bill number found across ALL tables and ALL existing counters. | |
| // 1. Find max last_number from ALL existing bill_counters rows | |
| const counterMax = await client.query( | |
| 'SELECT COALESCE(MAX(last_number), 0) as max_num FROM bill_counters' | |
| ); | |
| const maxFromCounters = parseInt(counterMax.rows[0].max_num) || 0; | |
| console.log(` Max from existing counters: ${maxFromCounters}`); | |
| // 2. Find max numeric bill number from transactions table | |
| // Filter out Date.now() timestamps (13+ digits) — those were from the old broken fallback | |
| const txMax = await client.query(` | |
| SELECT COALESCE(MAX( | |
| CASE | |
| WHEN bill_number ~ '^[0-9]+$' AND LENGTH(bill_number) <= 6 THEN CAST(bill_number AS INTEGER) | |
| WHEN bill_number ~ '-[0-9]+$' AND LENGTH(substring(bill_number from '-([0-9]+)$')) <= 6 THEN CAST(substring(bill_number from '-([0-9]+)$') AS INTEGER) | |
| ELSE 0 | |
| END | |
| ), 0) as max_num | |
| FROM transactions | |
| `); | |
| const maxFromTx = parseInt(txMax.rows[0].max_num) || 0; | |
| console.log(` Max from transactions table: ${maxFromTx}`); | |
| // 3. Find max numeric bill number from patti_transactions table | |
| const pattiMax = await client.query(` | |
| SELECT COALESCE(MAX( | |
| CASE | |
| WHEN bill_number ~ '^[0-9]+$' AND LENGTH(bill_number) <= 6 THEN CAST(bill_number AS INTEGER) | |
| WHEN bill_number ~ '-[0-9]+$' AND LENGTH(substring(bill_number from '-([0-9]+)$')) <= 6 THEN CAST(substring(bill_number from '-([0-9]+)$') AS INTEGER) | |
| ELSE 0 | |
| END | |
| ), 0) as max_num | |
| FROM patti_transactions | |
| `); | |
| const maxFromPatti = parseInt(pattiMax.rows[0].max_num) || 0; | |
| console.log(` Max from patti_transactions table: ${maxFromPatti}`); | |
| // 4. Take the overall maximum | |
| const globalMax = Math.max(maxFromCounters, maxFromTx, maxFromPatti); | |
| console.log(` Global max bill number: ${globalMax}`); | |
| // 5. Delete ALL old counter rows (they're no longer needed) | |
| await client.query('DELETE FROM bill_counters'); | |
| console.log(' Deleted all old counter rows'); | |
| // 6. Insert the single global counter | |
| await client.query( | |
| `INSERT INTO bill_counters (prefix, last_number, updated_at) VALUES ('BILL', $1, CURRENT_TIMESTAMP)`, | |
| [globalMax] | |
| ); | |
| console.log(` Created global counter 'BILL' starting at: ${globalMax}`); | |
| console.log(` Next bill number will be: ${globalMax + 1}`); | |
| // Record migration | |
| await client.query( | |
| 'INSERT INTO migration_history(key) VALUES ($1)', | |
| [MIGRATION_KEY] | |
| ); | |
| await client.query('COMMIT'); | |
| console.log('migrate8 completed successfully!'); | |
| } catch (error) { | |
| await client.query('ROLLBACK'); | |
| console.error('migrate8 failed:', error); | |
| throw error; | |
| } finally { | |
| client.release(); | |
| await pool.end(); | |
| } | |
| }; | |
| migrate8().catch(err => { | |
| console.error('Fatal error:', err); | |
| process.exit(1); | |
| }); | |