@dhyasama/totem-models 11.124.0 → 11.126.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Financials.js +19 -6
- package/package.json +1 -1
- package/scripts/migrate-all-customers.js +194 -0
package/lib/Financials.js
CHANGED
|
@@ -366,12 +366,22 @@ module.exports = function(mongoose, config) {
|
|
|
366
366
|
console.log('Upserting metric breakdown:', metric.breakdown);
|
|
367
367
|
|
|
368
368
|
// Check if the metric exists and update it
|
|
369
|
+
// Use $elemMatch to ensure we find a metric with BOTH name AND scenario matching
|
|
370
|
+
// (without $elemMatch, MongoDB could match name on one metric and scenario on another)
|
|
369
371
|
return self.findOneAndUpdate(
|
|
370
372
|
{
|
|
371
373
|
_id: financialsId,
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
374
|
+
snapshots: {
|
|
375
|
+
$elemMatch: {
|
|
376
|
+
uuid: snapshotUUID,
|
|
377
|
+
metrics: {
|
|
378
|
+
$elemMatch: {
|
|
379
|
+
name: metric.name,
|
|
380
|
+
scenario: metric.scenario
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
375
385
|
},
|
|
376
386
|
{
|
|
377
387
|
$set: {
|
|
@@ -632,7 +642,8 @@ module.exports = function(mongoose, config) {
|
|
|
632
642
|
$elemMatch: {
|
|
633
643
|
'notifications.company.initial.sendTo': { $gt: [] },
|
|
634
644
|
'notifications.company.initial.sendOn': { $lte: now },
|
|
635
|
-
'notifications.company.initial.sentOn': null
|
|
645
|
+
'notifications.company.initial.sentOn': null,
|
|
646
|
+
'status': { $nin: ['Pending', 'Completed', 'Archived'] }
|
|
636
647
|
}
|
|
637
648
|
}
|
|
638
649
|
});
|
|
@@ -687,7 +698,8 @@ module.exports = function(mongoose, config) {
|
|
|
687
698
|
$elemMatch: {
|
|
688
699
|
'notifications.company.reminders.sendTo': { $gt: [] },
|
|
689
700
|
'notifications.company.reminders.sendOn': { $lte: now },
|
|
690
|
-
'notifications.company.reminders.sentOn': null
|
|
701
|
+
'notifications.company.reminders.sentOn': null,
|
|
702
|
+
'status': { $nin: ['Pending', 'Completed', 'Archived'] }
|
|
691
703
|
}
|
|
692
704
|
}
|
|
693
705
|
});
|
|
@@ -746,7 +758,8 @@ module.exports = function(mongoose, config) {
|
|
|
746
758
|
$elemMatch: {
|
|
747
759
|
'notifications.company.rejections.sendTo': { $gt: [] },
|
|
748
760
|
'notifications.company.rejections.sendOn': { $lte: now },
|
|
749
|
-
'notifications.company.rejections.sentOn': null
|
|
761
|
+
'notifications.company.rejections.sentOn': null,
|
|
762
|
+
'status': { $nin: ['Pending', 'Completed', 'Archived'] }
|
|
750
763
|
}
|
|
751
764
|
}
|
|
752
765
|
});
|
package/package.json
CHANGED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wrapper script to run financials migration for all customers
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* NODE_ENV=production node scripts/migrate-all-customers.js [--config <configPath>] [--dry-run]
|
|
8
|
+
*
|
|
9
|
+
* Examples:
|
|
10
|
+
* # Dry run for all customers using totem-web production config
|
|
11
|
+
* NODE_ENV=production node scripts/migrate-all-customers.js --config ../totem-web/config/config.js --dry-run
|
|
12
|
+
*
|
|
13
|
+
* # Actual migration for all customers
|
|
14
|
+
* NODE_ENV=production node scripts/migrate-all-customers.js --config ../totem-web/config/config.js
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const mongoose = require('mongoose');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const { spawn } = require('child_process');
|
|
20
|
+
|
|
21
|
+
// Parse command line arguments
|
|
22
|
+
const args = process.argv.slice(2);
|
|
23
|
+
const DRY_RUN = args.includes('--dry-run');
|
|
24
|
+
|
|
25
|
+
// Get config path or db uri
|
|
26
|
+
let configPath = null;
|
|
27
|
+
let dbUri = null;
|
|
28
|
+
|
|
29
|
+
const configIndex = args.indexOf('--config');
|
|
30
|
+
if (configIndex !== -1 && args[configIndex + 1]) {
|
|
31
|
+
configPath = path.resolve(args[configIndex + 1]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const dbUriIndex = args.indexOf('--db-uri');
|
|
35
|
+
if (dbUriIndex !== -1 && args[dbUriIndex + 1]) {
|
|
36
|
+
dbUri = args[dbUriIndex + 1];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check for DB_URI environment variable
|
|
40
|
+
if (!dbUri && process.env.DB_URI) {
|
|
41
|
+
dbUri = process.env.DB_URI;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Validate arguments
|
|
45
|
+
if (!configPath && !dbUri) {
|
|
46
|
+
console.error('Error: Either --config, --db-uri, or DB_URI environment variable is required');
|
|
47
|
+
console.error('Usage: node scripts/migrate-all-customers.js [--config <configPath>] [--db-uri <mongoUri>] [--dry-run]');
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Load config if provided
|
|
52
|
+
if (configPath && !dbUri) {
|
|
53
|
+
console.log(`Loading config from: ${configPath}`);
|
|
54
|
+
try {
|
|
55
|
+
const config = require(configPath);
|
|
56
|
+
dbUri = config.db.uri;
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.error(`Failed to load config: ${err.message}`);
|
|
59
|
+
console.error('Please provide DB_URI environment variable or use --db-uri flag instead');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log('Migration Configuration:');
|
|
65
|
+
console.log(' Database URI:', dbUri.replace(/\/\/[^:]+:[^@]+@/, '//*****:*****@')); // Mask credentials
|
|
66
|
+
console.log(' Dry Run:', DRY_RUN);
|
|
67
|
+
console.log('');
|
|
68
|
+
|
|
69
|
+
// Connect to MongoDB
|
|
70
|
+
const mongooseOptions = {
|
|
71
|
+
useNewUrlParser: true,
|
|
72
|
+
useUnifiedTopology: true
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
mongoose.connect(dbUri, mongooseOptions);
|
|
76
|
+
|
|
77
|
+
const db = mongoose.connection;
|
|
78
|
+
|
|
79
|
+
db.on('error', (err) => {
|
|
80
|
+
console.error('MongoDB connection error:', err);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
db.once('open', async () => {
|
|
85
|
+
console.log('Connected to MongoDB');
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
await migrateAllCustomers();
|
|
89
|
+
console.log('\n=== All migrations completed successfully! ===');
|
|
90
|
+
process.exit(0);
|
|
91
|
+
} catch (err) {
|
|
92
|
+
console.error('\nMigration failed:', err);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
async function migrateAllCustomers() {
|
|
98
|
+
const Financials = db.collection('financials');
|
|
99
|
+
|
|
100
|
+
// Get all unique customer IDs from financials
|
|
101
|
+
const customerIds = await Financials.distinct('customer');
|
|
102
|
+
|
|
103
|
+
console.log(`Found ${customerIds.length} unique customer(s) with financials to migrate\n`);
|
|
104
|
+
|
|
105
|
+
if (customerIds.length === 0) {
|
|
106
|
+
console.log('No customers with financials found.');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Create customer objects with just the ID
|
|
111
|
+
const customers = customerIds.map(id => ({ _id: id, name: `Customer ${id}` }));
|
|
112
|
+
|
|
113
|
+
let successCount = 0;
|
|
114
|
+
let failureCount = 0;
|
|
115
|
+
const failures = [];
|
|
116
|
+
|
|
117
|
+
// Close the mongoose connection so child processes can connect
|
|
118
|
+
await mongoose.connection.close();
|
|
119
|
+
console.log('Closed initial connection\n');
|
|
120
|
+
|
|
121
|
+
// Run migration for each customer
|
|
122
|
+
for (let i = 0; i < customers.length; i++) {
|
|
123
|
+
const customer = customers[i];
|
|
124
|
+
const customerId = customer._id.toString();
|
|
125
|
+
const customerName = customer.name || 'Unknown';
|
|
126
|
+
|
|
127
|
+
console.log(`\n${'='.repeat(80)}`);
|
|
128
|
+
console.log(`[${i + 1}/${customers.length}] Migrating customer: ${customerName} (${customerId})`);
|
|
129
|
+
console.log('='.repeat(80));
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
await runMigrationForCustomer(customerId, configPath, dbUri, DRY_RUN);
|
|
133
|
+
successCount++;
|
|
134
|
+
console.log(`✓ Customer ${customerName} (${customerId}) migration completed`);
|
|
135
|
+
} catch (err) {
|
|
136
|
+
failureCount++;
|
|
137
|
+
failures.push({ customerId, customerName, error: err.message });
|
|
138
|
+
console.error(`✗ Customer ${customerName} (${customerId}) migration failed:`, err.message);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
console.log('\n' + '='.repeat(80));
|
|
143
|
+
console.log('=== FINAL SUMMARY ===');
|
|
144
|
+
console.log('='.repeat(80));
|
|
145
|
+
console.log(`Total customers: ${customers.length}`);
|
|
146
|
+
console.log(`Successful migrations: ${successCount}`);
|
|
147
|
+
console.log(`Failed migrations: ${failureCount}`);
|
|
148
|
+
|
|
149
|
+
if (failures.length > 0) {
|
|
150
|
+
console.log('\nFailed customers:');
|
|
151
|
+
failures.forEach(({ customerId, customerName, error }) => {
|
|
152
|
+
console.log(` - ${customerName} (${customerId}): ${error}`);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (DRY_RUN) {
|
|
157
|
+
console.log('\nThis was a dry run. No changes were made to the database.');
|
|
158
|
+
console.log('Run without --dry-run to apply changes.');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function runMigrationForCustomer(customerId, configPath, dbUri, dryRun) {
|
|
163
|
+
return new Promise((resolve, reject) => {
|
|
164
|
+
const scriptPath = path.join(__dirname, 'migrate-financials-schema.js');
|
|
165
|
+
const scriptArgs = [scriptPath, customerId];
|
|
166
|
+
|
|
167
|
+
if (configPath) {
|
|
168
|
+
scriptArgs.push('--config', configPath);
|
|
169
|
+
} else if (dbUri) {
|
|
170
|
+
scriptArgs.push('--db-uri', dbUri);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (dryRun) {
|
|
174
|
+
scriptArgs.push('--dry-run');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const child = spawn('node', scriptArgs, {
|
|
178
|
+
stdio: 'inherit',
|
|
179
|
+
env: { ...process.env }
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
child.on('close', (code) => {
|
|
183
|
+
if (code === 0) {
|
|
184
|
+
resolve();
|
|
185
|
+
} else {
|
|
186
|
+
reject(new Error(`Migration script exited with code ${code}`));
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
child.on('error', (err) => {
|
|
191
|
+
reject(err);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
}
|