@dhyasama/totem-models 9.51.0 → 9.53.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/index.js +1 -0
- package/lib/Deal.js +15 -1
- package/lib/Financials.js +4 -3
- package/lib/Message.js +18 -30
- package/lib/MessageRecipient.js +90 -0
- package/lib/Round.js +0 -90
- package/package.json +2 -1
package/index.js
CHANGED
|
@@ -57,6 +57,7 @@ var bootstrap = function(mongoose, config) {
|
|
|
57
57
|
require('./lib/Investment.js')(mongoose, config);
|
|
58
58
|
require('./lib/List.js')(mongoose, config);
|
|
59
59
|
require('./lib/Message.js')(mongoose, config);
|
|
60
|
+
require('./lib/MessageRecipient.js')(mongoose, config);
|
|
60
61
|
require('./lib/News.js')(mongoose, config);
|
|
61
62
|
require('./lib/Snapshot.js')(mongoose, config);
|
|
62
63
|
require('./lib/Sync.js')(mongoose, config);
|
package/lib/Deal.js
CHANGED
|
@@ -59,7 +59,11 @@ module.exports = function(mongoose, config) {
|
|
|
59
59
|
description: { type: String, trim: true, required: true }
|
|
60
60
|
}],
|
|
61
61
|
|
|
62
|
-
customFields: { type: Schema.Types.Mixed }
|
|
62
|
+
customFields: { type: Schema.Types.Mixed },
|
|
63
|
+
|
|
64
|
+
latestInteraction: { type: Schema.ObjectId, ref: 'Interaction', required: false },
|
|
65
|
+
|
|
66
|
+
latestMessage: { type: Schema.ObjectId, ref: 'Message', required: false }
|
|
63
67
|
|
|
64
68
|
});
|
|
65
69
|
|
|
@@ -210,6 +214,16 @@ module.exports = function(mongoose, config) {
|
|
|
210
214
|
};
|
|
211
215
|
|
|
212
216
|
let query = self.find(terms);
|
|
217
|
+
|
|
218
|
+
if (options.populate) {
|
|
219
|
+
query.populate({ path: 'documents', match: { customer: options.CUSTOMER_ID } });
|
|
220
|
+
query.populate({ path: 'messages', match: { customer: options.CUSTOMER_ID }, select: '-raw' });
|
|
221
|
+
query.populate('organization', 'name aliases description logoUrl website websiteAliases chairs contact people');
|
|
222
|
+
query.populate('referrer.person', 'name avatarUrl title');
|
|
223
|
+
query.populate('latestInteraction');
|
|
224
|
+
query.populate('latestMessage');
|
|
225
|
+
}
|
|
226
|
+
|
|
213
227
|
query.exec(cb);
|
|
214
228
|
|
|
215
229
|
};
|
package/lib/Financials.js
CHANGED
|
@@ -84,6 +84,7 @@ module.exports = function(mongoose, config) {
|
|
|
84
84
|
type: { type: String, enum: [null, 'header', 'block', 'document', 'metric', 'question']}
|
|
85
85
|
}],
|
|
86
86
|
|
|
87
|
+
// health block
|
|
87
88
|
cash: {
|
|
88
89
|
amount: { type: Number, default: 0 },
|
|
89
90
|
},
|
|
@@ -99,7 +100,7 @@ module.exports = function(mongoose, config) {
|
|
|
99
100
|
period: { type: String, enum: [null, 'monthly', 'quarterly', 'yearly']},
|
|
100
101
|
},
|
|
101
102
|
|
|
102
|
-
// income statement
|
|
103
|
+
// income statement block
|
|
103
104
|
revenue: {
|
|
104
105
|
amount: { type: Number, default: 0 },
|
|
105
106
|
projected: { type: Number, default: 0 },
|
|
@@ -121,7 +122,7 @@ module.exports = function(mongoose, config) {
|
|
|
121
122
|
breakdown: { type: Schema.Types.Mixed }
|
|
122
123
|
},
|
|
123
124
|
|
|
124
|
-
// balance sheet
|
|
125
|
+
// balance sheet block
|
|
125
126
|
assets: {
|
|
126
127
|
amount: { type: Number, default: 0 },
|
|
127
128
|
breakdown: { type: Schema.Types.Mixed }
|
|
@@ -135,7 +136,7 @@ module.exports = function(mongoose, config) {
|
|
|
135
136
|
breakdown: { type: Schema.Types.Mixed }
|
|
136
137
|
},
|
|
137
138
|
|
|
138
|
-
// cash flow
|
|
139
|
+
// cash flow block
|
|
139
140
|
operatingActivities: {
|
|
140
141
|
amount: { type: Number, default: 0 },
|
|
141
142
|
breakdown: { type: Schema.Types.Mixed }
|
package/lib/Message.js
CHANGED
|
@@ -30,21 +30,8 @@ module.exports = function(mongoose, config) {
|
|
|
30
30
|
},
|
|
31
31
|
notes: [ { type: Schema.ObjectId, ref: 'Note' } ],
|
|
32
32
|
documents: [ { type: Schema.ObjectId, ref: 'Document' } ],
|
|
33
|
-
raw: { type: Schema.Types.Mixed, required: true }
|
|
34
|
-
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
///////////////////////////////////////
|
|
38
|
-
|
|
39
|
-
Message.virtual('messageDate').get(function () {
|
|
40
|
-
|
|
41
|
-
// A little helper to get the message date since
|
|
42
|
-
// the original message date isn't always contained
|
|
43
|
-
// in the email. In its absence, use created on.
|
|
44
|
-
|
|
45
|
-
const self = this;
|
|
46
|
-
|
|
47
|
-
return self.originalMessageDate || self.createdOn;
|
|
33
|
+
raw: { type: Schema.Types.Mixed, required: true },
|
|
34
|
+
messageDate: { type: Date, required: true },
|
|
48
35
|
|
|
49
36
|
});
|
|
50
37
|
|
|
@@ -242,28 +229,23 @@ module.exports = function(mongoose, config) {
|
|
|
242
229
|
|
|
243
230
|
const self = this;
|
|
244
231
|
|
|
232
|
+
// Must match customer
|
|
245
233
|
let query = self.find({ customer: options.CUSTOMER_ID });
|
|
246
234
|
|
|
235
|
+
// Match either the org or a list of people
|
|
247
236
|
query.where({ $or: [{organization: orgId}, {'recipients.external': { $in : personIds }}] });
|
|
248
237
|
|
|
249
|
-
|
|
238
|
+
// Optionally limit search space to message newer than some timestamp
|
|
239
|
+
if (options.timestamp) query.where({'messageDate': { $gte: options.timestamp }});
|
|
250
240
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}
|
|
254
|
-
else if (!messages) {
|
|
255
|
-
return cb(null, null);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
messages = _.sortBy(messages, function(message) {
|
|
259
|
-
return message.originalMessageDate || message.createdOn;
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
var message = _.last(messages);
|
|
241
|
+
// Don't need the full raw message
|
|
242
|
+
query.select({ 'raw': -1 });
|
|
263
243
|
|
|
264
|
-
|
|
244
|
+
// Only need one
|
|
245
|
+
query.sort({ 'messageDate': -1 });
|
|
246
|
+
query.limit(1);
|
|
265
247
|
|
|
266
|
-
|
|
248
|
+
query.exec(cb);
|
|
267
249
|
|
|
268
250
|
};
|
|
269
251
|
|
|
@@ -409,9 +391,15 @@ module.exports = function(mongoose, config) {
|
|
|
409
391
|
|
|
410
392
|
const timestamp = new Date();
|
|
411
393
|
|
|
394
|
+
// Use now if created on is empty
|
|
412
395
|
message.createdOn = message.createdOn || timestamp;
|
|
396
|
+
|
|
397
|
+
// Updated on is always now
|
|
413
398
|
message.updatedOn = timestamp;
|
|
414
399
|
|
|
400
|
+
// The original message date isn't always contained in the email. In its absence, use created on.
|
|
401
|
+
message.messageDate = message.messageDate || message.originalMessageDate || message.createdOn;
|
|
402
|
+
|
|
415
403
|
message.save(cb);
|
|
416
404
|
|
|
417
405
|
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
module.exports = function(mongoose, config) {
|
|
4
|
+
|
|
5
|
+
let Schema = mongoose.Schema;
|
|
6
|
+
|
|
7
|
+
let MessageRecipient = new Schema({
|
|
8
|
+
|
|
9
|
+
message: { type: Schema.ObjectId, ref: 'Message', required: true },
|
|
10
|
+
customer: { type: Schema.ObjectId, ref: 'Organization', required: true },
|
|
11
|
+
organization: { type: Schema.ObjectId, ref: 'Organization', required: true },
|
|
12
|
+
recipient: { type: Schema.ObjectId, ref: 'Person', required: true },
|
|
13
|
+
messageDate: { type: Date, required: true },
|
|
14
|
+
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
///////////////////////////////////////
|
|
18
|
+
|
|
19
|
+
MessageRecipient.statics.getMostRecent = function getMostRecent(orgId, customerId, personId, options, cb) {
|
|
20
|
+
|
|
21
|
+
if (!cb) { throw new Error('cb is required'); }
|
|
22
|
+
if (!orgId) { return cb(new Error('orgId is required'), null); }
|
|
23
|
+
if (!mongoose.Types.ObjectId.isValid(orgId)) { return cb(new Error('orgId is not a valid ObjectId'), null); }
|
|
24
|
+
if (!customerId) { return cb(new Error('customerId is required'), null); }
|
|
25
|
+
if (!mongoose.Types.ObjectId.isValid(customerId)) { return cb(new Error('customerId is not a valid ObjectId'), null); }
|
|
26
|
+
if (!personId) { return cb(new Error('personId is required'), null); }
|
|
27
|
+
if (!mongoose.Types.ObjectId.isValid(personId)) { return cb(new Error('personId is not a valid ObjectId'), null); }
|
|
28
|
+
|
|
29
|
+
const self = this;
|
|
30
|
+
|
|
31
|
+
options = options || {};
|
|
32
|
+
|
|
33
|
+
let query = self.find({
|
|
34
|
+
customer: options.CUSTOMER_ID,
|
|
35
|
+
organization: orgId,
|
|
36
|
+
recipient: personId
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Optionally limit search space to message newer than some timestamp
|
|
40
|
+
if (options.timestamp) query.where({'messageDate': { $gte: options.timestamp }});
|
|
41
|
+
|
|
42
|
+
// Only need one
|
|
43
|
+
query.sort({ 'messageDate': -1 });
|
|
44
|
+
query.limit(1);
|
|
45
|
+
|
|
46
|
+
query.exec(cb);
|
|
47
|
+
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
MessageRecipient.statics.getMostRecentBatch = function getMostRecentBatch(orgId, customerId, personIds, options, cb) {
|
|
51
|
+
|
|
52
|
+
if (!cb) { throw new Error('cb is required'); }
|
|
53
|
+
if (!orgId) { return cb(new Error('orgId is required'), null); }
|
|
54
|
+
if (!mongoose.Types.ObjectId.isValid(orgId)) { return cb(new Error('orgId is not a valid ObjectId'), null); }
|
|
55
|
+
if (!customerId) { return cb(new Error('customerId is required'), null); }
|
|
56
|
+
if (!mongoose.Types.ObjectId.isValid(customerId)) { return cb(new Error('customerId is not a valid ObjectId'), null); }
|
|
57
|
+
if (!personIds) { return cb(new Error('personIds is required'), null); }
|
|
58
|
+
if (!Array.isArray(personIds)) { return cb(new Error('personIds must be an array'), null); }
|
|
59
|
+
|
|
60
|
+
const self = this;
|
|
61
|
+
|
|
62
|
+
options = options || {};
|
|
63
|
+
|
|
64
|
+
let query = self.find({
|
|
65
|
+
customer: options.CUSTOMER_ID,
|
|
66
|
+
organization: orgId
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
query.where({ 'recipient': { $in : personIds }});
|
|
70
|
+
|
|
71
|
+
// Optionally limit search space to message newer than some timestamp
|
|
72
|
+
if (options.timestamp) query.where({'messageDate': { $gte: options.timestamp }});
|
|
73
|
+
|
|
74
|
+
// Only need one
|
|
75
|
+
query.sort({ 'messageDate': -1 });
|
|
76
|
+
query.limit(1);
|
|
77
|
+
|
|
78
|
+
query.exec(cb);
|
|
79
|
+
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
MessageRecipient.statics.upsert = function(message, cb) {
|
|
83
|
+
message.save(cb);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
///////////////////////////////////////
|
|
87
|
+
|
|
88
|
+
mongoose.model('MessageRecipient', MessageRecipient);
|
|
89
|
+
|
|
90
|
+
};
|
package/lib/Round.js
CHANGED
|
@@ -29,14 +29,6 @@ module.exports = function(mongoose, config) {
|
|
|
29
29
|
|
|
30
30
|
roundName: { type: String, trim: true, required: true },
|
|
31
31
|
|
|
32
|
-
// People that participated in this round
|
|
33
|
-
// This is a public list of people that invested
|
|
34
|
-
// Use the addPerson method and removePerson static
|
|
35
|
-
people: [{
|
|
36
|
-
person: { type: Schema.ObjectId, ref: 'Person', index: true },
|
|
37
|
-
_id: false
|
|
38
|
-
}],
|
|
39
|
-
|
|
40
32
|
// Investment vehicles that participated in this round
|
|
41
33
|
// Currently only funds. May expand to SPVs.
|
|
42
34
|
// Recall that a fund belongs to an organization
|
|
@@ -146,15 +138,11 @@ module.exports = function(mongoose, config) {
|
|
|
146
138
|
// Fuck shit up so it gets taken care of
|
|
147
139
|
|
|
148
140
|
var vehicles = _.compact(_.flatten(_.pluck(rounds, 'vehicles')));
|
|
149
|
-
var people = _.compact(_.flatten(_.pluck(rounds, 'people')));
|
|
150
141
|
var badData = null;
|
|
151
142
|
|
|
152
143
|
badData = _.find(rounds, function(item) { return !item.organization; });
|
|
153
144
|
if (badData) return new Error(fnName + ' has one or more orgs that is not populated which means there is bad data');
|
|
154
145
|
|
|
155
|
-
badData = _.find(people, function(p) { return !p.person; });
|
|
156
|
-
if (badData) return new Error(fnName + ' has one or more people that is not populated which means there is bad data');
|
|
157
|
-
|
|
158
146
|
badData = _.find(vehicles, function(item) { return !item.fund; });
|
|
159
147
|
if (badData) return new Error(fnName + ' has one or more funds that is not populated which means there is bad data');
|
|
160
148
|
|
|
@@ -244,34 +232,6 @@ module.exports = function(mongoose, config) {
|
|
|
244
232
|
|
|
245
233
|
};
|
|
246
234
|
|
|
247
|
-
Round.methods.addPerson = function addPerson(person) {
|
|
248
|
-
|
|
249
|
-
// Add a reference to a person that participated in this round
|
|
250
|
-
|
|
251
|
-
var self = this;
|
|
252
|
-
|
|
253
|
-
if (!person) throw new Error('Must supply person to add');
|
|
254
|
-
|
|
255
|
-
// Do our best to accept an object or an objectid
|
|
256
|
-
if (!mongoose.Types.ObjectId.isValid(person)) {
|
|
257
|
-
person = person._id;
|
|
258
|
-
if (!mongoose.Types.ObjectId.isValid(person)) throw new Error('Need a valid objectid!');
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Check if person is already added
|
|
262
|
-
var match = _.find(self.people, function(existingPerson) {
|
|
263
|
-
var p = existingPerson.person || existingPerson;
|
|
264
|
-
var id = mongoose.Types.ObjectId.isValid(p) ? p : p._id;
|
|
265
|
-
return id.toString() === person.toString();
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
// If not, add it
|
|
269
|
-
if (!match) self.people.push({
|
|
270
|
-
person: person
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
};
|
|
274
|
-
|
|
275
235
|
Round.methods.addVehicle = function addVehicle(fund) {
|
|
276
236
|
|
|
277
237
|
// Add a vehicle, which is a fund
|
|
@@ -338,7 +298,6 @@ module.exports = function(mongoose, config) {
|
|
|
338
298
|
});
|
|
339
299
|
|
|
340
300
|
query.populate('organization', 'name logoUrl website websiteAliases');
|
|
341
|
-
query.populate('people.person', 'name avatarUrl title');
|
|
342
301
|
query.populate('vehicles.fund', 'name shortName');
|
|
343
302
|
|
|
344
303
|
if (options.isWorkerProcess) {
|
|
@@ -399,7 +358,6 @@ module.exports = function(mongoose, config) {
|
|
|
399
358
|
});
|
|
400
359
|
|
|
401
360
|
query.populate('organization', 'name logoUrl website websiteAliases');
|
|
402
|
-
query.populate('people.person', 'name avatarUrl');
|
|
403
361
|
query.populate('vehicles.fund');
|
|
404
362
|
|
|
405
363
|
if (options.isWorkerProcess) {
|
|
@@ -646,40 +604,6 @@ module.exports = function(mongoose, config) {
|
|
|
646
604
|
|
|
647
605
|
};
|
|
648
606
|
|
|
649
|
-
Round.statics.getPortfolioByPerson = function getPortfolioByPerson(personId, options, cb) {
|
|
650
|
-
|
|
651
|
-
// Returns a list of orgs that have rounds participated in by the given person id
|
|
652
|
-
|
|
653
|
-
if (!cb) { throw new Error('cb is required'); }
|
|
654
|
-
if (!personId) { throw new Error('personId is required'); }
|
|
655
|
-
if (!mongoose.Types.ObjectId.isValid(personId)) { return cb(new Error('personId is not a valid ObjectId'), null); }
|
|
656
|
-
|
|
657
|
-
const self = this;
|
|
658
|
-
|
|
659
|
-
let query = self.find({ 'people.person': personId });
|
|
660
|
-
|
|
661
|
-
query.select('organization');
|
|
662
|
-
query.populate('organization', 'name logoUrl description website websiteAliases');
|
|
663
|
-
|
|
664
|
-
query.exec(function(err, rounds) {
|
|
665
|
-
|
|
666
|
-
if (err) return cb(err, null);
|
|
667
|
-
if (!rounds || rounds.length === 0) return cb(null, []);
|
|
668
|
-
|
|
669
|
-
let error = checkForUnpopulatedData(rounds, 'Round.getPortfolioByPerson');
|
|
670
|
-
if (error) return cb(error, null);
|
|
671
|
-
|
|
672
|
-
// Return a list of orgs, not a list of rounds
|
|
673
|
-
let portfolio = _.pluck(rounds, 'organization');
|
|
674
|
-
portfolio = _.uniq(portfolio, function(org) { return org.name; });
|
|
675
|
-
portfolio = _.sortBy(portfolio, 'name');
|
|
676
|
-
|
|
677
|
-
return cb(null, portfolio);
|
|
678
|
-
|
|
679
|
-
});
|
|
680
|
-
|
|
681
|
-
};
|
|
682
|
-
|
|
683
607
|
Round.statics.removeInvestment = function(investmentId, cb) {
|
|
684
608
|
|
|
685
609
|
// Do not call this directly. It will leave an orphaned investment document.
|
|
@@ -714,20 +638,6 @@ module.exports = function(mongoose, config) {
|
|
|
714
638
|
|
|
715
639
|
};
|
|
716
640
|
|
|
717
|
-
Round.statics.removePerson = function(roundId, personId, cb) {
|
|
718
|
-
|
|
719
|
-
const self = this;
|
|
720
|
-
|
|
721
|
-
self
|
|
722
|
-
.findOneAndUpdate(
|
|
723
|
-
{ '_id': roundId },
|
|
724
|
-
{ $pull : { 'people': { 'person': personId } } },
|
|
725
|
-
{ multi : false }
|
|
726
|
-
)
|
|
727
|
-
.exec(cb);
|
|
728
|
-
|
|
729
|
-
};
|
|
730
|
-
|
|
731
641
|
Round.statics.removeVehicle = function(roundId, fundId, cb) {
|
|
732
642
|
|
|
733
643
|
const self = this;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dhyasama/totem-models",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.53.0",
|
|
4
4
|
"author": "Jason Reynolds",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"description": "Models for Totem platform",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@dhyasama/totem-utilities": "^3.0.0",
|
|
19
|
+
"algoliasearch": "^4.13.0",
|
|
19
20
|
"async": "^2.6.3",
|
|
20
21
|
"awesome-phonenumber": "^1.0.14",
|
|
21
22
|
"bluebird": "^3.7.2",
|