@dhyasama/totem-models 6.35.0 → 7.0.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 +230 -17
- package/lib/Organization.js +13 -1
- package/package.json +1 -1
package/lib/Financials.js
CHANGED
|
@@ -23,13 +23,29 @@ module.exports = function(mongoose, config) {
|
|
|
23
23
|
|
|
24
24
|
currency: { type: String, required: true, default: 'USD' },
|
|
25
25
|
|
|
26
|
+
notifications: {
|
|
27
|
+
|
|
28
|
+
company: {
|
|
29
|
+
|
|
30
|
+
contact: {
|
|
31
|
+
|
|
32
|
+
exclude: { type: Boolean, default: false, required: true },
|
|
33
|
+
email: { type: String, trim: true },
|
|
34
|
+
name: { type: String, trim: true }
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
},
|
|
41
|
+
|
|
26
42
|
snapshots: [{
|
|
27
|
-
|
|
43
|
+
|
|
28
44
|
uuid: { type: String },
|
|
29
|
-
|
|
45
|
+
|
|
30
46
|
year: { type: Number, default: 0 },
|
|
31
|
-
|
|
32
|
-
|
|
47
|
+
period: { type: String, enum: ['Annual', 'Q1', 'Q2', 'Q3', 'Q4', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] },
|
|
48
|
+
|
|
33
49
|
cash: {
|
|
34
50
|
amount: { type: Number, default: 0 },
|
|
35
51
|
},
|
|
@@ -42,11 +58,11 @@ module.exports = function(mongoose, config) {
|
|
|
42
58
|
},
|
|
43
59
|
runway: {
|
|
44
60
|
amount: { type: Number, default: 0 },
|
|
45
|
-
period: { type: String, enum: [null, 'monthly', 'quarterly', 'yearly']},
|
|
61
|
+
period: { type: String, enum: [null, 'monthly', 'quarterly', 'yearly']},
|
|
46
62
|
},
|
|
47
63
|
|
|
48
64
|
// income statement
|
|
49
|
-
revenue: {
|
|
65
|
+
revenue: {
|
|
50
66
|
amount: { type: Number, default: 0 },
|
|
51
67
|
projected: { type: Number, default: 0 },
|
|
52
68
|
breakdown: [{
|
|
@@ -55,7 +71,7 @@ module.exports = function(mongoose, config) {
|
|
|
55
71
|
_id: false
|
|
56
72
|
}]
|
|
57
73
|
},
|
|
58
|
-
operatingExpenses: {
|
|
74
|
+
operatingExpenses: {
|
|
59
75
|
amount: { type: Number, default: 0 },
|
|
60
76
|
projected: { type: Number, default: 0 },
|
|
61
77
|
breakdown: [{
|
|
@@ -64,7 +80,7 @@ module.exports = function(mongoose, config) {
|
|
|
64
80
|
_id: false
|
|
65
81
|
}]
|
|
66
82
|
},
|
|
67
|
-
grossProfit: {
|
|
83
|
+
grossProfit: {
|
|
68
84
|
amount: { type: Number, default: 0 },
|
|
69
85
|
projected: { type: Number, default: 0 },
|
|
70
86
|
breakdown: [{
|
|
@@ -73,7 +89,7 @@ module.exports = function(mongoose, config) {
|
|
|
73
89
|
_id: false
|
|
74
90
|
}]
|
|
75
91
|
},
|
|
76
|
-
operatingIncome: {
|
|
92
|
+
operatingIncome: {
|
|
77
93
|
amount: { type: Number, default: 0 },
|
|
78
94
|
projected: { type: Number, default: 0 },
|
|
79
95
|
breakdown: [{
|
|
@@ -95,13 +111,61 @@ module.exports = function(mongoose, config) {
|
|
|
95
111
|
_id: false
|
|
96
112
|
}],
|
|
97
113
|
|
|
114
|
+
// Catch-all for customer specific key-value pairs from sheet that aren't supported by our schema
|
|
115
|
+
details: [{
|
|
116
|
+
key: { type: String, trim: true },
|
|
117
|
+
value: { type: String, trim: true },
|
|
118
|
+
_id: false
|
|
119
|
+
}],
|
|
120
|
+
|
|
98
121
|
comment: { type: String, trim: true },
|
|
99
122
|
documents: [ { type: Schema.ObjectId, ref: 'Document' } ],
|
|
100
123
|
|
|
101
124
|
submittedOn: { type: Date, index: false },
|
|
102
|
-
submittedBy: { type: String, trim: true }
|
|
103
|
-
|
|
104
|
-
|
|
125
|
+
submittedBy: { type: String, trim: true },
|
|
126
|
+
|
|
127
|
+
notifications: {
|
|
128
|
+
|
|
129
|
+
company: {
|
|
130
|
+
|
|
131
|
+
sendTo: {
|
|
132
|
+
email: { type: String, trim: true },
|
|
133
|
+
name: { type: String, trim: true }
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
initial: {
|
|
137
|
+
sendOn: { type: Date, required: false },
|
|
138
|
+
sentOn: { type: Date, required: false },
|
|
139
|
+
postmarkMessageId: { type: String, trim: true },
|
|
140
|
+
status: { type: String, enum: [null, 'Sent', 'Bounced', 'Delivered', 'Opened', 'Clicked']}
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
reminder: {
|
|
144
|
+
sendOn: { type: Date, required: false },
|
|
145
|
+
sentOn: { type: Date, required: false },
|
|
146
|
+
postmarkMessageId: { type: String, trim: true },
|
|
147
|
+
status: { type: String, enum: [null, 'Sent', 'Bounced', 'Delivered', 'Opened', 'Clicked']}
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
history: [{
|
|
151
|
+
email: { type: String, trim: true },
|
|
152
|
+
postmarkMessageId: { type: String, trim: true },
|
|
153
|
+
status: { type: String, enum: [null, 'Sent', 'Bounced', 'Delivered', 'Opened', 'Clicked']}
|
|
154
|
+
}]
|
|
155
|
+
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
share: {
|
|
159
|
+
recipients: [{
|
|
160
|
+
email: { type: String, trim: true },
|
|
161
|
+
postmarkMessageId: { type: String, trim: true },
|
|
162
|
+
status: { type: String, enum: [null, 'Sent', 'Bounced', 'Delivered', 'Opened', 'Clicked']}
|
|
163
|
+
}]
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
}]
|
|
105
169
|
|
|
106
170
|
});
|
|
107
171
|
|
|
@@ -110,6 +174,36 @@ module.exports = function(mongoose, config) {
|
|
|
110
174
|
// Properties that are not persisted to the database
|
|
111
175
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
112
176
|
|
|
177
|
+
Financials.virtual('snapshotNames').get(function () {
|
|
178
|
+
return _.map(this.snapshots, function(snapshot) {
|
|
179
|
+
return snapshot.year + ' ' + snapshot.period;
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
186
|
+
// METHODS
|
|
187
|
+
// Methods operate on a single document
|
|
188
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
189
|
+
|
|
190
|
+
Financials.methods.snapshotStatus = function(uuid) {
|
|
191
|
+
|
|
192
|
+
if (!uuid) { return null; }
|
|
193
|
+
|
|
194
|
+
var snapshot = _.find(this.snapshots, function(s) {
|
|
195
|
+
if (!s || !s.uuid) { return; }
|
|
196
|
+
return s.uuid.toLowerCase() === uuid.toLowerCase();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
if (!snapshot) { return null; }
|
|
200
|
+
else if (snapshot.submittedOn) { return "Submitted"; }
|
|
201
|
+
else if (snapshot.notifications.company.reminder.status) { return snapshot.notifications.company.reminder.status; }
|
|
202
|
+
else if (snapshot.notifications.company.initial.status) { return snapshot.notifications.company.initial.status; }
|
|
203
|
+
else { return null; }
|
|
204
|
+
|
|
205
|
+
};
|
|
206
|
+
|
|
113
207
|
|
|
114
208
|
|
|
115
209
|
//////////////////////////////////////////////////////
|
|
@@ -121,7 +215,7 @@ module.exports = function(mongoose, config) {
|
|
|
121
215
|
|
|
122
216
|
var self = this;
|
|
123
217
|
|
|
124
|
-
var query = self.
|
|
218
|
+
var query = self.findOne({
|
|
125
219
|
'customer': customerId,
|
|
126
220
|
'organization': orgId
|
|
127
221
|
}).populate({
|
|
@@ -133,20 +227,138 @@ module.exports = function(mongoose, config) {
|
|
|
133
227
|
|
|
134
228
|
};
|
|
135
229
|
|
|
230
|
+
Financials.statics.getByPostmarkMessageId = function getByPostmarkMessageId(postmarkMessageId, cb) {
|
|
231
|
+
|
|
232
|
+
var self = this;
|
|
233
|
+
|
|
234
|
+
var query = self.findOne({
|
|
235
|
+
$or: [
|
|
236
|
+
{ "snapshots.notifications.company.initial.postmarkMessageId": postmarkMessageId },
|
|
237
|
+
{ "snapshots.notifications.company.reminder.postmarkMessageId": postmarkMessageId }
|
|
238
|
+
]
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
query.exec(cb);
|
|
242
|
+
|
|
243
|
+
};
|
|
244
|
+
|
|
136
245
|
Financials.statics.getByUUID = function getByUUID(customerId, uuid, cb) {
|
|
137
246
|
|
|
138
247
|
var self = this;
|
|
139
248
|
|
|
249
|
+
var query = self.findOne({
|
|
250
|
+
'customer': customerId,
|
|
251
|
+
'snapshots.uuid': uuid
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
query.populate('organization', 'name logoUrl');
|
|
255
|
+
query.populate('customer', 'name logoUrl ');
|
|
256
|
+
query.populate({
|
|
257
|
+
path: 'snapshots.documents',
|
|
258
|
+
match: { customer: customerId }
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
query.exec(cb);
|
|
262
|
+
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
Financials.statics.getForCampaign = function getForCampaign(customerId, cb) {
|
|
266
|
+
|
|
267
|
+
var self = this;
|
|
268
|
+
|
|
140
269
|
var query = self.find({
|
|
141
270
|
'customer': customerId,
|
|
271
|
+
'notification.contact.exclude': { $ne: true }, // null, false, or non-existing field
|
|
272
|
+
'notification.contact.email': { $ne: null } // field exists and has a value
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
query.exec(cb);
|
|
276
|
+
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
Financials.statics.getForCustomer = function getForCustomer(customerId, cb) {
|
|
280
|
+
|
|
281
|
+
var self = this;
|
|
282
|
+
|
|
283
|
+
var query = self.find({
|
|
284
|
+
'customer': customerId
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
query.exec(cb);
|
|
288
|
+
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
Financials.statics.getToSend = function getToSend(uuid, cb) {
|
|
292
|
+
|
|
293
|
+
var self = this;
|
|
294
|
+
|
|
295
|
+
var query = self.findOne({
|
|
142
296
|
'snapshots.uuid': uuid
|
|
143
297
|
});
|
|
144
298
|
|
|
145
|
-
query.populate('organization', 'name logoUrl')
|
|
299
|
+
query.populate('organization', 'name logoUrl');
|
|
300
|
+
query.populate('customer', 'name logoUrl customer.totemUrl');
|
|
301
|
+
|
|
146
302
|
query.exec(cb);
|
|
147
303
|
|
|
148
304
|
};
|
|
149
305
|
|
|
306
|
+
Financials.statics.getUUIDsToSendInitial = function getUUIDsToSendInitial(cb) {
|
|
307
|
+
|
|
308
|
+
var self = this;
|
|
309
|
+
var now = new Date();
|
|
310
|
+
|
|
311
|
+
var query = self.find({
|
|
312
|
+
"snapshots.notifications.company.initial.sendOn": { $lte: now },
|
|
313
|
+
"snapshots.notifications.company.initial.sentOn": null
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
query.exec(function(err, result) {
|
|
317
|
+
|
|
318
|
+
if (err) { return cb(err, null); }
|
|
319
|
+
|
|
320
|
+
var snapshots = _.pluck(result || [], 'snapshots');
|
|
321
|
+
|
|
322
|
+
snapshots = _.flatten(snapshots);
|
|
323
|
+
|
|
324
|
+
snapshots = _.filter(snapshots, function(snapshot) {
|
|
325
|
+
return snapshot.notifications.company.initial.sendOn < now && !snapshot.notifications.company.initial.sentOn;
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
return cb(null, _.pluck(snapshots, 'uuid'));
|
|
329
|
+
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
Financials.statics.getUUIDsToSendReminder = function getUUIDsToSendReminder(cb) {
|
|
335
|
+
|
|
336
|
+
var self = this;
|
|
337
|
+
var now = new Date();
|
|
338
|
+
|
|
339
|
+
var query = self.find({
|
|
340
|
+
"snapshots.notifications.company.reminder.sendOn": { $lte: now },
|
|
341
|
+
"snapshots.notifications.company.reminder.sentOn": null
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
query.exec(function(err, result) {
|
|
345
|
+
|
|
346
|
+
if (err) { return cb(err, null); }
|
|
347
|
+
|
|
348
|
+
var snapshots = _.pluck(result || [], 'snapshots');
|
|
349
|
+
|
|
350
|
+
snapshots = _.flatten(snapshots);
|
|
351
|
+
|
|
352
|
+
snapshots = _.filter(snapshots, function(snapshot) {
|
|
353
|
+
return snapshot.notifications.company.reminder.sendOn < now && !snapshot.notifications.company.reminder.sentOn;
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
return cb(null, _.pluck(snapshots, 'uuid'));
|
|
357
|
+
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
};
|
|
361
|
+
|
|
150
362
|
Financials.statics.removeCustomerFinancials = function removeCustomerFinancials(customerId, cb) {
|
|
151
363
|
|
|
152
364
|
// this is only used to wipe out financials created by the google sheet import process
|
|
@@ -164,10 +376,11 @@ module.exports = function(mongoose, config) {
|
|
|
164
376
|
};
|
|
165
377
|
|
|
166
378
|
Financials.statics.upsert = function upsert(financials, cb) {
|
|
379
|
+
|
|
167
380
|
if (!financials) { return cb(new Error('financials is required'), null); }
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
381
|
+
|
|
382
|
+
financials.save(cb);
|
|
383
|
+
|
|
171
384
|
};
|
|
172
385
|
|
|
173
386
|
|
package/lib/Organization.js
CHANGED
|
@@ -401,7 +401,19 @@ module.exports = function(mongoose, config) {
|
|
|
401
401
|
// Funds belonging to this organization (which is typically, but not necessarily, what we'd call an investor)
|
|
402
402
|
// An example of a non-"investor" with funds would be Slack with it's Slack Fund
|
|
403
403
|
// Another way to put it, these are funds from which this organization makes investments
|
|
404
|
-
funds: [{ type: Schema.ObjectId, ref: 'Fund' }]
|
|
404
|
+
funds: [{ type: Schema.ObjectId, ref: 'Fund' }],
|
|
405
|
+
|
|
406
|
+
financials: [{
|
|
407
|
+
|
|
408
|
+
customer: { type: Schema.ObjectId, ref: 'Organization' },
|
|
409
|
+
|
|
410
|
+
// ok to send emails to collect financials
|
|
411
|
+
allowed: { type: Boolean, default: true },
|
|
412
|
+
|
|
413
|
+
// email to send link to
|
|
414
|
+
email: { type: String, trim: true }
|
|
415
|
+
|
|
416
|
+
}]
|
|
405
417
|
|
|
406
418
|
});
|
|
407
419
|
|