@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 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
- 'snapshots.uuid': snapshotUUID,
373
- 'snapshots.metrics.name': metric.name,
374
- 'snapshots.metrics.scenario': metric.scenario
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhyasama/totem-models",
3
- "version": "11.124.0",
3
+ "version": "11.126.0",
4
4
  "author": "Jason Reynolds",
5
5
  "license": "UNLICENSED",
6
6
  "description": "Models for Totem platform",
@@ -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
+ }