@dhyasama/totem-models 12.30.0 → 12.33.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 +60 -19
- package/package.json +1 -1
- package/test/Financials.js +37 -0
- package/test/FinancialsSkippedUnit.js +234 -0
package/lib/Financials.js
CHANGED
|
@@ -155,7 +155,9 @@ module.exports = function(mongoose, config) {
|
|
|
155
155
|
_id: false,
|
|
156
156
|
timestamp: { type: Date, required: true, default: Date.now },
|
|
157
157
|
user: { type: String, trim: true, required: true },
|
|
158
|
-
|
|
158
|
+
// 'confirmed' = a re-extraction found the identical value: freshness signal only,
|
|
159
|
+
// never a change — it does not touch value or verified state.
|
|
160
|
+
action: { type: String, enum: ['updated', 'deleted', 'verified', 'confirmed'], required: true },
|
|
159
161
|
}],
|
|
160
162
|
previous: {
|
|
161
163
|
_id: false,
|
|
@@ -195,7 +197,7 @@ module.exports = function(mongoose, config) {
|
|
|
195
197
|
_id: false,
|
|
196
198
|
timestamp: { type: Date },
|
|
197
199
|
user: { type: String, trim: true },
|
|
198
|
-
action: { type: String, enum: ['updated', 'deleted', 'verified'] },
|
|
200
|
+
action: { type: String, enum: ['updated', 'deleted', 'verified', 'confirmed'] },
|
|
199
201
|
}]
|
|
200
202
|
}
|
|
201
203
|
}],
|
|
@@ -874,10 +876,11 @@ module.exports = function(mongoose, config) {
|
|
|
874
876
|
var query = this.find({
|
|
875
877
|
'snapshots': {
|
|
876
878
|
$elemMatch: {
|
|
879
|
+
'form.0': { $exists: true },
|
|
877
880
|
'notifications.company.initial.sendTo': { $gt: [] },
|
|
878
881
|
'notifications.company.initial.sendOn': { $lte: now },
|
|
879
882
|
'notifications.company.initial.sentOn': null,
|
|
880
|
-
'status': { $nin: ['Pending', 'Completed', 'Archived'] }
|
|
883
|
+
'status': { $nin: ['Pending', 'Completed', 'Archived', 'Skipped'] }
|
|
881
884
|
}
|
|
882
885
|
}
|
|
883
886
|
}).select({
|
|
@@ -887,6 +890,8 @@ module.exports = function(mongoose, config) {
|
|
|
887
890
|
'snapshots.uuid': 1,
|
|
888
891
|
'snapshots.year': 1,
|
|
889
892
|
'snapshots.period': 1,
|
|
893
|
+
'snapshots.form._id': 1,
|
|
894
|
+
'snapshots.status': 1,
|
|
890
895
|
'snapshots.notifications.company.initial.sendTo': 1,
|
|
891
896
|
'snapshots.notifications.company.initial.sendOn': 1,
|
|
892
897
|
'snapshots.notifications.company.initial.sentOn': 1,
|
|
@@ -899,15 +904,20 @@ module.exports = function(mongoose, config) {
|
|
|
899
904
|
|
|
900
905
|
_.each(financial.snapshots, function(snapshot) {
|
|
901
906
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
var
|
|
907
|
+
if (!snapshot.form || snapshot.form.length === 0) return;
|
|
908
|
+
if (_.contains(['Pending', 'Completed', 'Archived', 'Skipped'], snapshot.status)) return;
|
|
909
|
+
var initial = snapshot.notifications && snapshot.notifications.company && snapshot.notifications.company.initial;
|
|
910
|
+
if (!initial) return;
|
|
911
|
+
|
|
912
|
+
var hasSendTo = initial.sendTo && initial.sendTo.length > 0;
|
|
913
|
+
var hasSendOnLessThanNow = initial.sendOn && initial.sendOn < now;
|
|
914
|
+
var hasSentOn = initial.sentOn;
|
|
905
915
|
|
|
906
916
|
var conditions = hasSendTo && hasSendOnLessThanNow && !hasSentOn;
|
|
907
917
|
|
|
908
918
|
if(conditions) {
|
|
909
919
|
|
|
910
|
-
var recipients =
|
|
920
|
+
var recipients = initial.sendTo.map(function(sendTo) {
|
|
911
921
|
return sendTo.email;
|
|
912
922
|
});
|
|
913
923
|
|
|
@@ -940,10 +950,11 @@ module.exports = function(mongoose, config) {
|
|
|
940
950
|
var query = this.find({
|
|
941
951
|
'snapshots': {
|
|
942
952
|
$elemMatch: {
|
|
953
|
+
'form.0': { $exists: true },
|
|
943
954
|
'notifications.company.reminders.sendTo': { $gt: [] },
|
|
944
955
|
'notifications.company.reminders.sendOn': { $lte: now },
|
|
945
956
|
'notifications.company.reminders.sentOn': null,
|
|
946
|
-
'status': { $nin: ['Pending', 'Completed', 'Archived'] }
|
|
957
|
+
'status': { $nin: ['Pending', 'Completed', 'Archived', 'Skipped'] }
|
|
947
958
|
}
|
|
948
959
|
}
|
|
949
960
|
}).select({
|
|
@@ -953,6 +964,8 @@ module.exports = function(mongoose, config) {
|
|
|
953
964
|
'snapshots.uuid': 1,
|
|
954
965
|
'snapshots.year': 1,
|
|
955
966
|
'snapshots.period': 1,
|
|
967
|
+
'snapshots.form._id': 1,
|
|
968
|
+
'snapshots.status': 1,
|
|
956
969
|
'snapshots.notifications.company.reminders.sendTo': 1,
|
|
957
970
|
'snapshots.notifications.company.reminders.sendOn': 1,
|
|
958
971
|
'snapshots.notifications.company.reminders.sentOn': 1,
|
|
@@ -965,7 +978,12 @@ module.exports = function(mongoose, config) {
|
|
|
965
978
|
|
|
966
979
|
_.each(financial.snapshots, function(snapshot) {
|
|
967
980
|
|
|
968
|
-
|
|
981
|
+
if (!snapshot.form || snapshot.form.length === 0) return;
|
|
982
|
+
if (_.contains(['Pending', 'Completed', 'Archived', 'Skipped'], snapshot.status)) return;
|
|
983
|
+
var reminders = snapshot.notifications && snapshot.notifications.company && snapshot.notifications.company.reminders;
|
|
984
|
+
if (!Array.isArray(reminders)) return;
|
|
985
|
+
|
|
986
|
+
_.each(reminders, function(reminder) {
|
|
969
987
|
|
|
970
988
|
var hasSendTo = reminder.sendTo && reminder.sendTo.length > 0;
|
|
971
989
|
var hasSendOnLessThanNow = reminder.sendOn && reminder.sendOn < now;
|
|
@@ -1010,10 +1028,11 @@ module.exports = function(mongoose, config) {
|
|
|
1010
1028
|
var query = this.find({
|
|
1011
1029
|
'snapshots': {
|
|
1012
1030
|
$elemMatch: {
|
|
1031
|
+
'form.0': { $exists: true },
|
|
1013
1032
|
'notifications.company.rejections.sendTo': { $gt: [] },
|
|
1014
1033
|
'notifications.company.rejections.sendOn': { $lte: now },
|
|
1015
1034
|
'notifications.company.rejections.sentOn': null,
|
|
1016
|
-
'status': { $nin: ['Pending', 'Completed', 'Archived'] }
|
|
1035
|
+
'status': { $nin: ['Pending', 'Completed', 'Archived', 'Skipped'] }
|
|
1017
1036
|
}
|
|
1018
1037
|
}
|
|
1019
1038
|
}).select({
|
|
@@ -1023,6 +1042,8 @@ module.exports = function(mongoose, config) {
|
|
|
1023
1042
|
'snapshots.uuid': 1,
|
|
1024
1043
|
'snapshots.year': 1,
|
|
1025
1044
|
'snapshots.period': 1,
|
|
1045
|
+
'snapshots.form._id': 1,
|
|
1046
|
+
'snapshots.status': 1,
|
|
1026
1047
|
'snapshots.notifications.company.rejections.sendTo': 1,
|
|
1027
1048
|
'snapshots.notifications.company.rejections.sendOn': 1,
|
|
1028
1049
|
'snapshots.notifications.company.rejections.sentOn': 1,
|
|
@@ -1035,7 +1056,12 @@ module.exports = function(mongoose, config) {
|
|
|
1035
1056
|
|
|
1036
1057
|
_.each(financial.snapshots, function(snapshot) {
|
|
1037
1058
|
|
|
1038
|
-
|
|
1059
|
+
if (!snapshot.form || snapshot.form.length === 0) return;
|
|
1060
|
+
if (_.contains(['Pending', 'Completed', 'Archived', 'Skipped'], snapshot.status)) return;
|
|
1061
|
+
var rejections = snapshot.notifications && snapshot.notifications.company && snapshot.notifications.company.rejections;
|
|
1062
|
+
if (!Array.isArray(rejections)) return;
|
|
1063
|
+
|
|
1064
|
+
_.each(rejections, function(rejection) {
|
|
1039
1065
|
|
|
1040
1066
|
var hasSendTo = rejection.sendTo && rejection.sendTo.length > 0;
|
|
1041
1067
|
var hasSendOnLessThanNow = rejection.sendOn && rejection.sendOn < now;
|
|
@@ -1253,7 +1279,9 @@ module.exports = function(mongoose, config) {
|
|
|
1253
1279
|
const query = this.find({
|
|
1254
1280
|
'snapshots': {
|
|
1255
1281
|
$elemMatch: {
|
|
1256
|
-
'
|
|
1282
|
+
'form.0': { $exists: true },
|
|
1283
|
+
'submittedOn': null,
|
|
1284
|
+
'status': { $nin: ['Pending', 'Completed', 'Archived', 'Overdue', 'Skipped'] },
|
|
1257
1285
|
'dueOn': { $lte: new Date() }
|
|
1258
1286
|
}
|
|
1259
1287
|
}
|
|
@@ -1337,27 +1365,40 @@ module.exports = function(mongoose, config) {
|
|
|
1337
1365
|
var isApproved = snapshot.approvedOn;
|
|
1338
1366
|
var isRejected = snapshot.rejectedOn && snapshot.rejection;
|
|
1339
1367
|
var isArchived = snapshot.archivedOn;
|
|
1340
|
-
var
|
|
1368
|
+
var hasForm = snapshot.form && snapshot.form.length > 0;
|
|
1369
|
+
var isOverdue = hasForm && !isSubmitted && snapshot.dueOn
|
|
1370
|
+
? moment(new Date()).isSameOrAfter(moment(snapshot.dueOn))
|
|
1371
|
+
: false;
|
|
1341
1372
|
|
|
1342
1373
|
var isOpened = false;
|
|
1343
1374
|
var isDelivered = false;
|
|
1344
1375
|
var isScheduled = false;
|
|
1376
|
+
var hasDeliveryAttempt = false;
|
|
1345
1377
|
if(snapshot.notifications && snapshot.notifications.company && snapshot.notifications.company.initial) {
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1378
|
+
var initial = snapshot.notifications.company.initial;
|
|
1379
|
+
isOpened = hasForm && (initial.status === 'Opened' || initial.status === 'Clicked');
|
|
1380
|
+
isDelivered = hasForm && initial.sentOn;
|
|
1381
|
+
isScheduled = hasForm && initial.sendOn;
|
|
1382
|
+
hasDeliveryAttempt = initial.sentOn || initial.postmarkMessageId || initial.status;
|
|
1349
1383
|
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1384
|
+
var isSkipped = snapshot.status === 'Skipped' && hasForm && isScheduled &&
|
|
1385
|
+
!hasDeliveryAttempt && !isSubmitted;
|
|
1386
|
+
|
|
1387
|
+
// Skipped represents a scheduled request that was unnecessary before
|
|
1388
|
+
// delivery. If someone later explicitly submits that visible form, the
|
|
1389
|
+
// normal submission/approval lifecycle must take precedence.
|
|
1390
|
+
if(isArchived) snapshot.status = 'Archived';
|
|
1391
|
+
else if(isSkipped) snapshot.status = 'Skipped';
|
|
1392
|
+
else if(snapshot.submittedBy === 'Totem Sheet') snapshot.status = 'Completed'; // sheet snapshots should always be completed
|
|
1352
1393
|
else if(needsApproval && isApproved) snapshot.status = 'Completed';
|
|
1353
1394
|
else if(!needsApproval && isSubmitted) snapshot.status = 'Completed';
|
|
1354
|
-
else if(isArchived) snapshot.status = 'Archived';
|
|
1355
1395
|
else if(needsApproval && isSubmitted && !isRejected) snapshot.status = 'Pending';
|
|
1356
1396
|
else if(needsApproval && isSubmitted && isRejected) snapshot.status = 'Opened';
|
|
1357
1397
|
else if(isOverdue) snapshot.status = 'Overdue';
|
|
1358
1398
|
else if(isDelivered && isOpened) snapshot.status = 'Opened';
|
|
1359
1399
|
else if(isDelivered) snapshot.status = 'Delivered';
|
|
1360
1400
|
else if(isScheduled) snapshot.status = 'Scheduled'; // when a snapshot is scheduled, but not yet sent (checks every 5 minutes)
|
|
1401
|
+
else snapshot.status = undefined;
|
|
1361
1402
|
|
|
1362
1403
|
});
|
|
1363
1404
|
|
package/package.json
CHANGED
package/test/Financials.js
CHANGED
|
@@ -163,6 +163,43 @@ describe('Financials', function() {
|
|
|
163
163
|
|
|
164
164
|
});
|
|
165
165
|
|
|
166
|
+
it('preserves Skipped and excludes skipped snapshots from sends and overdue work', async function() {
|
|
167
|
+
var uuid = 'complete-request-skipped';
|
|
168
|
+
var f = await Financials.create({
|
|
169
|
+
organization: new mongoose.Types.ObjectId(),
|
|
170
|
+
customer: new mongoose.Types.ObjectId(),
|
|
171
|
+
snapshots: [{
|
|
172
|
+
uuid: uuid,
|
|
173
|
+
year: 2026,
|
|
174
|
+
period: 'Q1',
|
|
175
|
+
status: 'Skipped',
|
|
176
|
+
dueOn: new Date(Date.now() - 86400000),
|
|
177
|
+
notifications: {
|
|
178
|
+
company: {
|
|
179
|
+
initial: {
|
|
180
|
+
sendOn: new Date(Date.now() - 3600000),
|
|
181
|
+
sendTo: [{ email: 'company@example.com' }]
|
|
182
|
+
},
|
|
183
|
+
reminders: [{
|
|
184
|
+
sendOn: new Date(Date.now() - 1800000),
|
|
185
|
+
sendTo: [{ email: 'company@example.com' }]
|
|
186
|
+
}]
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}]
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
var reloaded = await Financials.findById(f._id);
|
|
193
|
+
reloaded.snapshots[0].status.should.equal('Skipped');
|
|
194
|
+
|
|
195
|
+
var initial = await Financials.getCompanyInitialToSend();
|
|
196
|
+
initial.some(function(item) { return item.uuid === uuid; }).should.equal(false);
|
|
197
|
+
var reminders = await Financials.getCompanyReminderToSend();
|
|
198
|
+
reminders.some(function(item) { return item.uuid === uuid; }).should.equal(false);
|
|
199
|
+
var overdue = await Financials.getOverdue();
|
|
200
|
+
overdue.some(function(item) { return item._id.toString() === f._id.toString(); }).should.equal(false);
|
|
201
|
+
});
|
|
202
|
+
|
|
166
203
|
describe.skip('old so skip for now', function() {
|
|
167
204
|
|
|
168
205
|
it('gets financials for an org', function(done) {
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var should = require('should');
|
|
4
|
+
var mongoose = require('mongoose');
|
|
5
|
+
var config = require('./config')['test'];
|
|
6
|
+
|
|
7
|
+
if (!mongoose.models.Financials) { require('../index')(mongoose, config); }
|
|
8
|
+
var Financials = mongoose.model('Financials');
|
|
9
|
+
|
|
10
|
+
describe('Financials snapshot status policy (no database)', function() {
|
|
11
|
+
it('derives every snapshot status from one consistent precedence matrix', function() {
|
|
12
|
+
var now = Date.now();
|
|
13
|
+
var snapshots = [
|
|
14
|
+
{
|
|
15
|
+
uuid: 'scheduled', year: 2026, period: 'January',
|
|
16
|
+
notifications: { company: { initial: { sendOn: new Date(now + 60000) } } }
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
uuid: 'delivered', year: 2026, period: 'February',
|
|
20
|
+
notifications: { company: { initial: { sendOn: new Date(now - 60000), sentOn: new Date(now - 60000), status: 'Sent' } } }
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
uuid: 'opened', year: 2026, period: 'March',
|
|
24
|
+
notifications: { company: { initial: { sendOn: new Date(now - 60000), sentOn: new Date(now - 60000), status: 'Opened' } } }
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
uuid: 'overdue', year: 2026, period: 'April', dueOn: new Date(now - 60000),
|
|
28
|
+
notifications: { company: { initial: { sendOn: new Date(now - 120000), sentOn: new Date(now - 120000) } } }
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
uuid: 'skipped', year: 2026, period: 'May', status: 'Skipped',
|
|
32
|
+
form: [{ name: 'Revenue', type: 'metric' }],
|
|
33
|
+
notifications: { company: { initial: { sendOn: new Date(now + 60000) } } }
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
uuid: 'pending', year: 2026, period: 'June', approval: true,
|
|
37
|
+
submittedOn: new Date(now - 60000), submittedBy: 'company@example.com'
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
uuid: 'completed', year: 2026, period: 'July', approval: false,
|
|
41
|
+
submittedOn: new Date(now - 60000), submittedBy: 'investor@example.com'
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
uuid: 'approved', year: 2026, period: 'August', approval: true,
|
|
45
|
+
submittedOn: new Date(now - 120000), approvedOn: new Date(now - 60000)
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
uuid: 'rejected', year: 2026, period: 'September', approval: true,
|
|
49
|
+
submittedOn: new Date(now - 120000), rejectedOn: new Date(now - 60000), rejection: 'Please revise'
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
uuid: 'archived', year: 2026, period: 'October', status: 'Completed',
|
|
53
|
+
submittedOn: new Date(now - 120000), archivedOn: new Date(now - 60000)
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
uuid: 'sheet', year: 2026, period: 'November', submittedBy: 'Totem Sheet'
|
|
57
|
+
}
|
|
58
|
+
];
|
|
59
|
+
snapshots.forEach(function(snapshot) {
|
|
60
|
+
if (snapshot.uuid !== 'sheet') snapshot.form = [{ name: 'Revenue', type: 'metric' }];
|
|
61
|
+
});
|
|
62
|
+
var financials = Financials.hydrate({
|
|
63
|
+
_id: new mongoose.Types.ObjectId(),
|
|
64
|
+
customer: new mongoose.Types.ObjectId(),
|
|
65
|
+
organization: new mongoose.Types.ObjectId(),
|
|
66
|
+
snapshots: snapshots
|
|
67
|
+
});
|
|
68
|
+
var expected = {
|
|
69
|
+
scheduled: 'Scheduled',
|
|
70
|
+
delivered: 'Delivered',
|
|
71
|
+
opened: 'Opened',
|
|
72
|
+
overdue: 'Overdue',
|
|
73
|
+
skipped: 'Skipped',
|
|
74
|
+
pending: 'Pending',
|
|
75
|
+
completed: 'Completed',
|
|
76
|
+
approved: 'Completed',
|
|
77
|
+
rejected: 'Opened',
|
|
78
|
+
archived: 'Archived',
|
|
79
|
+
sheet: 'Completed'
|
|
80
|
+
};
|
|
81
|
+
financials.snapshots.forEach(function(snapshot) {
|
|
82
|
+
snapshot.status.should.equal(expected[snapshot.uuid]);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('preserves Skipped when a scheduled snapshot is hydrated', function() {
|
|
87
|
+
var financials = Financials.hydrate({
|
|
88
|
+
_id: new mongoose.Types.ObjectId(),
|
|
89
|
+
customer: new mongoose.Types.ObjectId(),
|
|
90
|
+
organization: new mongoose.Types.ObjectId(),
|
|
91
|
+
snapshots: [{
|
|
92
|
+
uuid: 'skipped-hydration',
|
|
93
|
+
year: 2026,
|
|
94
|
+
period: 'Q1',
|
|
95
|
+
status: 'Skipped',
|
|
96
|
+
form: [{ name: 'Revenue', type: 'metric' }],
|
|
97
|
+
notifications: { company: { initial: { sendOn: new Date() } } }
|
|
98
|
+
}]
|
|
99
|
+
});
|
|
100
|
+
financials.snapshots[0].status.should.equal('Skipped');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('lets an explicit submission supersede Skipped', function() {
|
|
104
|
+
var financials = Financials.hydrate({
|
|
105
|
+
_id: new mongoose.Types.ObjectId(),
|
|
106
|
+
customer: new mongoose.Types.ObjectId(),
|
|
107
|
+
organization: new mongoose.Types.ObjectId(),
|
|
108
|
+
snapshots: [{
|
|
109
|
+
uuid: 'submitted-after-skip',
|
|
110
|
+
year: 2026,
|
|
111
|
+
period: 'Q1',
|
|
112
|
+
status: 'Skipped',
|
|
113
|
+
form: [{ name: 'Revenue', type: 'metric' }],
|
|
114
|
+
submittedOn: new Date(),
|
|
115
|
+
submittedBy: 'investor@example.com',
|
|
116
|
+
approval: false,
|
|
117
|
+
notifications: { company: { initial: { sendOn: new Date() } } }
|
|
118
|
+
}]
|
|
119
|
+
});
|
|
120
|
+
financials.snapshots[0].status.should.equal('Completed');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('gives Archived precedence over completed and skipped states', function() {
|
|
124
|
+
var financials = Financials.hydrate({
|
|
125
|
+
_id: new mongoose.Types.ObjectId(),
|
|
126
|
+
customer: new mongoose.Types.ObjectId(),
|
|
127
|
+
organization: new mongoose.Types.ObjectId(),
|
|
128
|
+
snapshots: [{
|
|
129
|
+
uuid: 'archived-complete',
|
|
130
|
+
year: 2026,
|
|
131
|
+
period: 'Q1',
|
|
132
|
+
status: 'Completed',
|
|
133
|
+
submittedOn: new Date(),
|
|
134
|
+
archivedOn: new Date()
|
|
135
|
+
}, {
|
|
136
|
+
uuid: 'archived-skipped',
|
|
137
|
+
year: 2026,
|
|
138
|
+
period: 'Q2',
|
|
139
|
+
status: 'Skipped',
|
|
140
|
+
form: [{ name: 'Revenue', type: 'metric' }],
|
|
141
|
+
archivedOn: new Date(),
|
|
142
|
+
notifications: { company: { initial: { sendOn: new Date() } } }
|
|
143
|
+
}]
|
|
144
|
+
});
|
|
145
|
+
financials.snapshots[0].status.should.equal('Archived');
|
|
146
|
+
financials.snapshots[1].status.should.equal('Archived');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('does not preserve Skipped outside an unsent scheduled form', function() {
|
|
150
|
+
var financials = Financials.hydrate({
|
|
151
|
+
_id: new mongoose.Types.ObjectId(),
|
|
152
|
+
customer: new mongoose.Types.ObjectId(),
|
|
153
|
+
organization: new mongoose.Types.ObjectId(),
|
|
154
|
+
snapshots: [{
|
|
155
|
+
uuid: 'data-only-skipped', year: 2026, period: 'Q1', status: 'Skipped', form: []
|
|
156
|
+
}, {
|
|
157
|
+
uuid: 'data-only-scheduled', year: 2026, period: 'Q2', status: 'Scheduled', form: [],
|
|
158
|
+
notifications: { company: { initial: { sendOn: new Date() } } }
|
|
159
|
+
}, {
|
|
160
|
+
uuid: 'sent-skipped', year: 2026, period: 'Q3', status: 'Skipped',
|
|
161
|
+
form: [{ name: 'Revenue', type: 'metric' }],
|
|
162
|
+
notifications: { company: { initial: {
|
|
163
|
+
sendOn: new Date(), sentOn: new Date(), status: 'Opened'
|
|
164
|
+
} } }
|
|
165
|
+
}]
|
|
166
|
+
});
|
|
167
|
+
should(financials.snapshots[0].status).equal(undefined);
|
|
168
|
+
should(financials.snapshots[1].status).equal(undefined);
|
|
169
|
+
financials.snapshots[2].status.should.equal('Opened');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('only considers form-bearing, unsubmitted requests eligible for Overdue', async function() {
|
|
173
|
+
var capturedFilter;
|
|
174
|
+
var originalFind = Financials.find;
|
|
175
|
+
Financials.find = function(filter) {
|
|
176
|
+
capturedFilter = filter;
|
|
177
|
+
return Promise.resolve([]);
|
|
178
|
+
};
|
|
179
|
+
try {
|
|
180
|
+
await Financials.getOverdue();
|
|
181
|
+
var eligibility = capturedFilter.snapshots.$elemMatch;
|
|
182
|
+
eligibility['form.0'].should.deepEqual({ $exists: true });
|
|
183
|
+
should(eligibility.submittedOn).eql(null);
|
|
184
|
+
eligibility.status.$nin.should.containEql('Pending');
|
|
185
|
+
} finally {
|
|
186
|
+
Financials.find = originalFind;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('excludes Skipped from the company initial-send query', async function() {
|
|
191
|
+
var capturedFilter;
|
|
192
|
+
var originalFind = Financials.find;
|
|
193
|
+
Financials.find = function(filter) {
|
|
194
|
+
capturedFilter = filter;
|
|
195
|
+
return {
|
|
196
|
+
select: function() {
|
|
197
|
+
return { lean: async function() { return []; } };
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
try {
|
|
202
|
+
var results = await Financials.getCompanyInitialToSend();
|
|
203
|
+
results.should.deepEqual([]);
|
|
204
|
+
capturedFilter.snapshots.$elemMatch.status.$nin.should.containEql('Skipped');
|
|
205
|
+
capturedFilter.snapshots.$elemMatch['form.0'].should.deepEqual({ $exists: true });
|
|
206
|
+
} finally {
|
|
207
|
+
Financials.find = originalFind;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('requires a form in every company notification query', async function() {
|
|
212
|
+
var capturedFilters = [];
|
|
213
|
+
var originalFind = Financials.find;
|
|
214
|
+
Financials.find = function(filter) {
|
|
215
|
+
capturedFilters.push(filter);
|
|
216
|
+
return {
|
|
217
|
+
select: function() {
|
|
218
|
+
return { lean: async function() { return []; } };
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
try {
|
|
223
|
+
await Financials.getCompanyInitialToSend();
|
|
224
|
+
await Financials.getCompanyReminderToSend();
|
|
225
|
+
await Financials.getCompanyRejectionToSend();
|
|
226
|
+
capturedFilters.length.should.equal(3);
|
|
227
|
+
capturedFilters.forEach(function(filter) {
|
|
228
|
+
filter.snapshots.$elemMatch['form.0'].should.deepEqual({ $exists: true });
|
|
229
|
+
});
|
|
230
|
+
} finally {
|
|
231
|
+
Financials.find = originalFind;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
});
|