@dhyasama/totem-models 8.3.0 → 8.4.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 CHANGED
@@ -64,6 +64,7 @@ var bootstrap = function(mongoose, config) {
64
64
  require('./lib/Message.js')(mongoose, config);
65
65
  require('./lib/News.js')(mongoose, config);
66
66
  require('./lib/Snapshot.js')(mongoose, config);
67
+ require('./lib/Sync.js')(mongoose, config);
67
68
  require('./lib/Webhook.js')(mongoose, config);
68
69
 
69
70
  };
package/lib/Financials.js CHANGED
@@ -121,10 +121,10 @@ module.exports = function(mongoose, config) {
121
121
 
122
122
  company: {
123
123
 
124
- sendTo: {
124
+ sendTo: [{
125
125
  email: { type: String, trim: true },
126
126
  name: { type: String, trim: true }
127
- },
127
+ }],
128
128
 
129
129
  initial: {
130
130
  sendOn: { type: Date, required: false },
@@ -343,7 +343,7 @@ module.exports = function(mongoose, config) {
343
343
  let query = self.find({
344
344
  'snapshots': {
345
345
  $elemMatch: {
346
- 'notifications.company.sendTo.email': { $ne: null },
346
+ 'notifications.company.sendTo': { $gt: [] },
347
347
  'notifications.company.initial.sendOn': { $lte: now },
348
348
  'notifications.company.initial.sentOn': null,
349
349
  'submittedOn': null
@@ -363,7 +363,7 @@ module.exports = function(mongoose, config) {
363
363
 
364
364
  snapshots = _.filter(snapshots, function(snapshot) {
365
365
 
366
- let bool = !!snapshot.notifications.company.sendTo.email;
366
+ let bool = !!snapshot.notifications.company.sendTo.length > 0;
367
367
  bool = bool && snapshot.notifications.company.initial.sendOn < now;
368
368
  bool = bool && !snapshot.notifications.company.initial.sentOn;
369
369
 
@@ -385,7 +385,7 @@ module.exports = function(mongoose, config) {
385
385
  let query = self.find({
386
386
  'snapshots': {
387
387
  $elemMatch: {
388
- 'notifications.company.sendTo.email': { $ne: null },
388
+ 'notifications.company.sendTo': { $gt: [] },
389
389
  'notifications.company.reminder.sendOn': { $lte: now },
390
390
  'notifications.company.reminder.sentOn': null,
391
391
  'submittedOn': null
@@ -405,7 +405,7 @@ module.exports = function(mongoose, config) {
405
405
 
406
406
  snapshots = _.filter(snapshots, function(snapshot) {
407
407
 
408
- let bool = !!snapshot.notifications.company.sendTo.email;
408
+ let bool = !!snapshot.notifications.company.sendTo.length > 0;
409
409
  bool = bool && snapshot.notifications.company.reminder.sendOn < now;
410
410
  bool = bool && !snapshot.notifications.company.reminder.sentOn;
411
411
 
package/lib/Fund.js CHANGED
@@ -7,7 +7,6 @@ module.exports = function(mongoose, config) {
7
7
  var _ = require('underscore');
8
8
 
9
9
  var Fund = new Schema({
10
-
11
10
  name: { type: String, required: true, unique: true },
12
11
  slug: { type: String, required: true, unique: true },
13
12
  shortName: { type: String, required: true },
@@ -16,8 +15,12 @@ module.exports = function(mongoose, config) {
16
15
  hexColorCode: { type: String, required: true, default: '#cccccc' },
17
16
  closeDate: { type: Date },
18
17
  amount: { type: Number },
19
- crunchbase: { uuid: { type: String, default: '', unique: true } }
20
-
18
+ crunchbase: { uuid: { type: String, default: '', unique: true } },
19
+ transactions: [{
20
+ type: { type: String, enum: ['fees', 'expenses', 'carry'] },
21
+ amount: { type: Number, default: 0 },
22
+ date: { type: Date, default: null },
23
+ }],
21
24
  });
22
25
 
23
26
  /************* BASIC FIELDS **********************/
@@ -175,6 +178,18 @@ module.exports = function(mongoose, config) {
175
178
 
176
179
  };
177
180
 
181
+ Fund.statics.removeTransactions = function removeTransactions(cb) {
182
+
183
+ const self = this;
184
+
185
+ let query = self.update(
186
+ { $set: { transactions: [] } },
187
+ { multi : true }
188
+ );
189
+ query.exec(cb);
190
+
191
+ };
192
+
178
193
  Fund.set('autoIndex', false);
179
194
  Fund.on('index', function(err) { console.log('error building fund indexes: ' + err); });
180
195
 
package/lib/Investment.js CHANGED
@@ -63,7 +63,8 @@ module.exports = function(mongoose, config) {
63
63
  // Catch-all for customer specific key-value pairs from sheet that aren't supported by our schema
64
64
  details: [{
65
65
  key: { type: String, trim: true, required: true },
66
- value: { type: String, trim: true, required: true },
66
+ value: { type: Schema.Types.Mixed, required: true },
67
+ format: { type: String, enum: [null, 'number', 'decimal', 'money', 'percentage', 'date']},
67
68
  _id: false
68
69
  }],
69
70
 
@@ -129,6 +130,10 @@ module.exports = function(mongoose, config) {
129
130
  };
130
131
 
131
132
  Investment.statics.upsert = function upsert(investment, cb) {
133
+
134
+ // Required for mixed types
135
+ investment.markModified('details');
136
+
132
137
  if (!investment) { return cb(new Error('investment is required'), null); }
133
138
  investment.save(cb);
134
139
  };
@@ -37,10 +37,11 @@ module.exports = function(mongoose, config) {
37
37
  quarterlyAccountStatement: { type: String, default: '' }
38
38
  },
39
39
 
40
- fundsInvested: [{
40
+ transactions: [{
41
41
  fund: {type: Schema.ObjectId, ref: 'Fund'},
42
- committed: {type: Number, default: 0},
43
- called: {type: Number, default: 0}
42
+ type: { type: String, enum: ['commitment', 'contribution', 'distribution'] },
43
+ amount: { type: Number, default: 0 },
44
+ date: { type: Date, default: null },
44
45
  }],
45
46
 
46
47
  contact: {
@@ -98,7 +99,61 @@ module.exports = function(mongoose, config) {
98
99
 
99
100
  LimitedPartner.virtual('totalCommitted').get(function () {
100
101
  const self = this;
101
- return _.reduce(self.fundsInvested, function(memo, fund) { return memo + (fund.committed > 0 ? fund.committed : 0); }, 0);
102
+ return _.reduce(self.fundsInvested, function (memo, fund) {
103
+ return memo + (fund.committed > 0 ? fund.committed : 0);
104
+ }, 0);
105
+ });
106
+
107
+ LimitedPartner.virtual('totalCommitment').get(function () {
108
+ var self = this;
109
+ return _.reduce(self.transactions, function(memo, transaction) {
110
+ return memo + ((transaction.type === 'commitment' && transaction.amount > 0) ? transaction.amount : 0);
111
+ }, 0);
112
+ });
113
+
114
+ LimitedPartner.virtual('totalContribution').get(function () {
115
+ var self = this;
116
+ return _.reduce(self.transactions, function(memo, transaction) {
117
+ return memo + ((transaction.type === 'contribution' && transaction.amount > 0) ? transaction.amount : 0);
118
+ }, 0);
119
+ });
120
+
121
+ LimitedPartner.virtual('totalDistribution').get(function () {
122
+ var self = this;
123
+ return _.reduce(self.transactions, function(memo, transaction) {
124
+ return memo + ((transaction.type === 'distribution' && transaction.amount > 0) ? transaction.amount : 0);
125
+ }, 0);
126
+ });
127
+
128
+ LimitedPartner.virtual('fundsInvested').get(function () {
129
+
130
+ var self = this;
131
+ var fundsInvested = [];
132
+
133
+ _.each(self.transactions, function(transaction) {
134
+
135
+ var fundMatch = _.find(fundsInvested, function(fund) { return fund._id === transaction.fund._id; });
136
+
137
+ if(!fundMatch) {
138
+ fundsInvested.push({
139
+ _id: transaction.fund._id,
140
+ name: transaction.fund.name,
141
+ shortName: transaction.fund.shortName,
142
+ abbreviation: transaction.fund.abbreviation,
143
+ commitment: 0,
144
+ contribution: 0,
145
+ distribution: 0
146
+ });
147
+ fundMatch = _.last(fundsInvested);
148
+ }
149
+
150
+ // and increment the transaction type by the transaction amount
151
+ fundMatch[transaction.type] += transaction.amount;
152
+
153
+ });
154
+
155
+ return fundsInvested;
156
+
102
157
  });
103
158
 
104
159
  LimitedPartner.virtual('email.primary').get(function () {
@@ -300,7 +355,7 @@ module.exports = function(mongoose, config) {
300
355
  query = self.findOne({ '_id': id, customer: options.CUSTOMER_ID }, self.getReadFilterKeys(options.role));
301
356
  }
302
357
 
303
- query.populate('fundsInvested.fund');
358
+ query.populate('transactions.fund');
304
359
  query.populate('people');
305
360
  query.populate({
306
361
  path: 'notes',
@@ -350,7 +405,8 @@ module.exports = function(mongoose, config) {
350
405
  if (!options.isWorkerProcess) { return cb(null, []); }
351
406
 
352
407
  let query = self.findOne({'name': lpName}, this.getReadFilterKeys(options.role));
353
- query.populate('fundsInvested.fund');
408
+
409
+ query.populate('transactions.fund');
354
410
  query.exec(cb);
355
411
 
356
412
  };
@@ -377,7 +433,7 @@ module.exports = function(mongoose, config) {
377
433
  query = self.find({'people': personId, customer: options.CUSTOMER_ID }, self.getReadFilterKeys(options.role));
378
434
  }
379
435
 
380
- query.populate('fundsInvested.fund');
436
+ query.populate('transactions.fund');
381
437
  query.populate('people', 'name');
382
438
 
383
439
  query.exec(function (err, lps) {
@@ -453,7 +509,7 @@ module.exports = function(mongoose, config) {
453
509
  LimitedPartner.statics.getSources = function(lpid, options, cb) {
454
510
 
455
511
  const self = this;
456
-
512
+
457
513
  if (!cb) { throw new Error('cb is required'); }
458
514
  if (!lpid) { return cb(new Error('lpid is required'), null); }
459
515
  if (!mongoose.Types.ObjectId.isValid(lpid)) { return cb(new Error('lpid is not a valid ObjectId'), null); }
@@ -474,44 +530,44 @@ module.exports = function(mongoose, config) {
474
530
 
475
531
  query.exec(function(err, lp) {
476
532
 
477
- if (err) { return cb(err, null); }
478
- if (!lp) { return cb(null, null); }
479
-
480
- Organization.collection.findById(options.CUSTOMER_ID, function(err, customer) {
533
+ if (err) { return cb(err, null); }
534
+ if (!lp) { return cb(null, null); }
481
535
 
482
- if (err) { return cb(err, null); }
483
- if (!customer) { return cb(null, null); }
536
+ Organization.collection.findById(options.CUSTOMER_ID, function(err, customer) {
484
537
 
485
- let current = [];
486
- let past = [];
487
- let all = [];
488
- let lpSources = helpers.getPeopleSources(lp.people);
538
+ if (err) { return cb(err, null); }
539
+ if (!customer) { return cb(null, null); }
489
540
 
490
- _.each(customer.people, function(p) {
541
+ let current = [];
542
+ let past = [];
543
+ let all = [];
544
+ let lpSources = helpers.getPeopleSources(lp.people);
491
545
 
492
- let source = _.find(lpSources, function(ls) {
493
- if (!ls || !ls.person || !ls.person._id) return false;
494
- return ls.person._id.toString() === p.person.toString();
495
- });
546
+ _.each(customer.people, function(p) {
496
547
 
497
- if (!source) { return; }
548
+ let source = _.find(lpSources, function(ls) {
549
+ if (!ls || !ls.person || !ls.person._id) return false;
550
+ return ls.person._id.toString() === p.person.toString();
551
+ });
498
552
 
499
- if (p.current) { current.push(source); }
500
- if (!p.current) { past.push(source); }
501
- all.push(source);
553
+ if (!source) { return; }
502
554
 
503
- });
555
+ if (p.current) { current.push(source); }
556
+ if (!p.current) { past.push(source); }
557
+ all.push(source);
504
558
 
505
- return cb(null, {
506
- all: helpers.sortPeopleSources(all, options.CUSTOMER_ID),
507
- current: helpers.sortPeopleSources(current, options.CUSTOMER_ID),
508
- past: helpers.sortPeopleSources(past, options.CUSTOMER_ID)
509
- });
559
+ });
510
560
 
561
+ return cb(null, {
562
+ all: helpers.sortPeopleSources(all, options.CUSTOMER_ID),
563
+ current: helpers.sortPeopleSources(current, options.CUSTOMER_ID),
564
+ past: helpers.sortPeopleSources(past, options.CUSTOMER_ID)
511
565
  });
512
566
 
513
567
  });
514
568
 
569
+ });
570
+
515
571
  };
516
572
 
517
573
  LimitedPartner.statics.listByFund = function (fundId, options, cb) {
@@ -527,9 +583,9 @@ module.exports = function(mongoose, config) {
527
583
 
528
584
  options = helpers.getDefaultOptions(options);
529
585
 
530
- let query = self.find({ 'fundsInvested.fund': fundId, customer: options.CUSTOMER_ID }, self.getReadFilterKeys(options.role));
586
+ let query = self.find({ 'transactions.fund': fundId, customer: options.CUSTOMER_ID }, self.getReadFilterKeys(options.role));
531
587
 
532
- query.populate('fundsInvested.fund');
588
+ query.populate('transactions.fund');
533
589
  query.sort({ 'name': -1 });
534
590
  query.exec(cb);
535
591
 
@@ -555,15 +611,20 @@ module.exports = function(mongoose, config) {
555
611
 
556
612
  };
557
613
 
558
- LimitedPartner.statics.removeCustomerCommitments = function removeCustomerCommitments(customerId, cb) {
614
+ LimitedPartner.statics.removeCustomerTransactions = function removeCustomerTransactions(customerId, cb) {
559
615
 
560
616
  const self = this;
561
617
 
618
+ if (!cb) { throw new Error('cb is required'); }
619
+ if (!customerId) { return cb(new Error('customerId is required'), null); }
620
+ if (!mongoose.Types.ObjectId.isValid(customerId)) { return cb(new Error('customerId is not a valid ObjectId'), null); }
621
+
562
622
  let query = self.update(
563
623
  { 'customer': customerId },
564
- { $set: { fundsInvested: [] } },
624
+ { $set: { transactions: [] } },
565
625
  { multi : true }
566
626
  );
627
+
567
628
  query.exec(cb);
568
629
 
569
630
  };
@@ -591,7 +652,7 @@ module.exports = function(mongoose, config) {
591
652
  query = self.find({ 'name': new RegExp(terms, 'i'), customer: options.CUSTOMER_ID }, self.getReadFilterKeys(options.role));
592
653
  }
593
654
 
594
- query.populate('fundsInvested.fund');
655
+ query.populate('transactions.fund');
595
656
  query.sort({ 'name': -1 });
596
657
  query.exec(cb);
597
658
 
@@ -649,4 +710,4 @@ module.exports = function(mongoose, config) {
649
710
 
650
711
  mongoose.model('LimitedPartner', LimitedPartner);
651
712
 
652
- };
713
+ };
@@ -179,6 +179,8 @@ module.exports = function(mongoose, config) {
179
179
 
180
180
  },
181
181
 
182
+ locale: { type: String, default: 'en-us', trim: true },
183
+
182
184
  beanstalk: {
183
185
  environmentName: { type: String, trim: true },
184
186
  restartOnPull: { type: Boolean, default: true }
package/lib/Round.js CHANGED
@@ -147,6 +147,7 @@ module.exports = function(mongoose, config) {
147
147
  // construct the org
148
148
  var org = {
149
149
  _id: rounds[0].organization._id,
150
+ slug: rounds[0].organization.slug,
150
151
  name: rounds[0].organization.name,
151
152
  logoUrl: rounds[0].organization.logoUrl,
152
153
  description: rounds[0].organization.description,
@@ -650,7 +651,7 @@ module.exports = function(mongoose, config) {
650
651
  let query = self.find({ 'vehicles.fund': fundId });
651
652
 
652
653
  query.select('organization vehicles preMoneyValuation');
653
- query.populate('organization', 'name logoUrl description contact filters status ipo closed acquired operating website websiteAliases');
654
+ query.populate('organization', 'name slug logoUrl description contact filters status ipo closed acquired operating website websiteAliases');
654
655
  query.populate('vehicles.fund');
655
656
 
656
657
  if (options.isWorkerProcess) {
@@ -698,7 +699,7 @@ module.exports = function(mongoose, config) {
698
699
  let query = self.find({ 'vehicles.fund': { $in: fundIds } });
699
700
 
700
701
  query.select('organization vehicles preMoneyValuation');
701
- query.populate('organization', 'name logoUrl description contact chairs filters status ipo closed acquired operating website websiteAliases');
702
+ query.populate('organization', 'name slug logoUrl description contact chairs filters status ipo closed acquired operating website websiteAliases');
702
703
  query.deepPopulate([
703
704
  'organization.chairs.first',
704
705
  'organization.chairs.second',
package/lib/Sync.js ADDED
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+
3
+ module.exports = function(mongoose, config) {
4
+
5
+ var
6
+
7
+ Schema = mongoose.Schema,
8
+ env = process.env.NODE_ENV || 'development',
9
+ _ = require('underscore');
10
+
11
+ var Sync = new Schema({
12
+ customer: { type: String, required: true },
13
+ syncedOn: { type: Date, required: true },
14
+ completedOn: { type: Date },
15
+ syncedBy: { type: String, trim: true },
16
+ steps: [{
17
+ _id: false,
18
+ name: { type: String, trim: true },
19
+ tasks: [{
20
+ _id: false,
21
+ name: { type: String, trim: true },
22
+ issues: [{ type: String, trim: true }],
23
+ }]
24
+ }]
25
+ });
26
+
27
+ Sync.statics.getById = function (id, customerId, cb) {
28
+
29
+ var self = this;
30
+
31
+ self.findOne({
32
+ '_id': id,
33
+ 'customer': customerId
34
+ }).exec(cb);
35
+
36
+ };
37
+
38
+ Sync.statics.upsert = function(sync, cb) {
39
+ sync.syncedOn = new Date();
40
+ sync.save(cb);
41
+ };
42
+
43
+ Sync.set('autoIndex', false);
44
+
45
+ mongoose.model('Sync', Sync, 'syncs');
46
+
47
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhyasama/totem-models",
3
- "version": "8.3.0",
3
+ "version": "8.4.0",
4
4
  "author": "Jason Reynolds",
5
5
  "license": "UNLICENSED",
6
6
  "description": "Models for Totem platform",
@@ -116,10 +116,25 @@ describe('Limited Partner', function() {
116
116
  lp.name = 'United Testers';
117
117
  lp.customer = organization;
118
118
 
119
- lp.fundsInvested.push({
119
+ // transactions: [{
120
+ // fund: {type: Schema.ObjectId, ref: 'Fund'},
121
+ // type: { type: String, enum: ['commitment', 'contribution', 'distribution'] },
122
+ // amount: { type: Number, default: 0 },
123
+ // date: { type: Date, default: null },
124
+ // }],
125
+
126
+ lp.transactions.push({
120
127
  fund: fund,
121
- committed: 1000000,
122
- called: 400000
128
+ type: 'commitment',
129
+ amount: 100000,
130
+ date: new Date()
131
+ });
132
+
133
+ lp.transactions.push({
134
+ fund: fund,
135
+ type: 'contribution',
136
+ amount: 400000,
137
+ date: new Date()
123
138
  });
124
139
 
125
140
  lp.contact.phone.push({