@tamu-dor/famis-db 1.3.3 → 2.0.3

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.
Files changed (68) hide show
  1. package/.github/workflows/actions.yml +16 -0
  2. package/docs/index.html +1453 -335
  3. package/docs.md +363 -190
  4. package/index.d.ts +619 -0
  5. package/index.js +451 -102
  6. package/package.json +3 -3
  7. package/readme.md +2 -2
  8. package/schemas/migrations/202102041628.sql +26 -0
  9. package/schemas/migrations/202102261131.sql +68 -0
  10. package/schemas/migrations/202104011516.sql +12 -0
  11. package/schemas/migrations/202104210829.sql +69 -0
  12. package/schemas/migrations/202104210926.sql +77 -0
  13. package/schemas/migrations/202105201344.sql +17 -0
  14. package/schemas/migrations/202105201355.sql +26 -0
  15. package/schemas/migrations/202105251323.sql +17 -0
  16. package/schemas/migrations/202106081436.sql +20 -0
  17. package/schemas/migrations/202106221333.sql +20 -0
  18. package/schemas/migrations/202107291406.sql +35 -0
  19. package/schemas/migrations/202108181427.sql +26 -0
  20. package/schemas/migrations/202110041133.sql +75 -0
  21. package/schemas/migrations/202110251113.sql +20 -0
  22. package/schemas/migrations/202111021104.sql +13 -0
  23. package/schemas/migrations/202111021110.sql +16 -0
  24. package/schemas/migrations/202111100901.sql +16 -0
  25. package/schemas/migrations/202111101041.sql +79 -0
  26. package/schemas/migrations/20211115.sql +71 -0
  27. package/schemas/migrations/202112171038.sql +89 -0
  28. package/schemas/migrations/202201211055.sql +97 -0
  29. package/schemas/migrations/202201211124.sql +24 -0
  30. package/schemas/migrations/202201261015.sql +17 -0
  31. package/schemas/migrations/202201311403.sql +91 -0
  32. package/schemas/migrations/202202081201.sql +41 -0
  33. package/schemas/migrations/202202081205.sql +45 -0
  34. package/schemas/migrations/202202141101.sql +21 -0
  35. package/schemas/migrations/202202141117.sql +76 -0
  36. package/schemas/migrations/202202151329.sql +21 -0
  37. package/schemas/migrations/202202171025.sql +4 -0
  38. package/schemas/migrations/20220225.sql +23 -0
  39. package/schemas/migrations/202203150618.sql +13 -0
  40. package/schemas/migrations/202204041316.sql +12 -0
  41. package/schemas/migrations/202204141018.sql +78 -0
  42. package/schemas/migrations/202204141301.sql +36 -0
  43. package/schemas/migrations/202205061236.sql +15 -0
  44. package/schemas/migrations/202206021248.sql +20 -0
  45. package/schemas/migrations/20220615.sql +39 -0
  46. package/schemas/migrations/202206291132.sql +15 -0
  47. package/schemas/migrations/202207290901.sql +31 -0
  48. package/schemas/migrations/202207290907.sql +26 -0
  49. package/schemas/migrations/202208241422.sql +21 -0
  50. package/schemas/migrations/202209141529.sql +21 -0
  51. package/schemas/migrations/202209300911.sql +35 -0
  52. package/schemas/migrations/202210111429.sql +35 -0
  53. package/schemas/migrations/202210111456.sql +57 -0
  54. package/schemas/migrations/202210171517.sql +23 -0
  55. package/schemas/migrations/202211091403.sql +26 -0
  56. package/schemas/migrations/202211091410.sql +26 -0
  57. package/schemas/migrations/202211091417.sql +31 -0
  58. package/schemas/migrations/202211161451.sql +81 -0
  59. package/schemas/migrations/202212141236.sql +37 -0
  60. package/schemas/migrations/202302201117.sql +73 -0
  61. package/schemas/migrations/202303081110.sql +78 -0
  62. package/schemas/migrations/202304191238.sql +12 -0
  63. package/schemas/migrations/202304271214.sql +7 -0
  64. package/schemas/schema.sql +57 -22
  65. package/change.txt +0 -123
  66. package/changes.md +0 -405
  67. package/famisDb.pdf +0 -0
  68. package/readme.wiki +0 -332
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const knex = require('knex');
2
- const cuid = require('cuid');
3
- const { map } = require('awaity');
2
+ const { createId } = require('@paralleldrive/cuid2');
3
+ const { each, map } = require('awaity');
4
4
  const revisionHash = require('rev-hash');
5
5
 
6
6
  const famisInvoiceNumbers = [
@@ -37,7 +37,13 @@ const pad = (str, max, right) => {
37
37
  return retVal;
38
38
  };
39
39
 
40
- const sanitizeAccountNumber = (account) => pad(account.replace(/\D/g,''), 13, true);
40
+ const sanitizeAccountNumber = (account) => {
41
+ if (account.substring(0,2) === 'RC') {
42
+ return account.replace(/\W/g, '');
43
+ } else {
44
+ return pad(account.replace(/\D/g,''), 13, true);
45
+ }
46
+ };
41
47
 
42
48
  const getCoreAccountNumber = (famis) => {
43
49
  const { sellingCampusCode, sellingAccountNumber, sellingSupportAccount } = famis;
@@ -80,6 +86,15 @@ class FAMISDb {
80
86
  this.db = knex({
81
87
  client: 'pg',
82
88
  connection: config,
89
+ pool: {
90
+ min: 0,
91
+ max: 10,
92
+ createTimeoutMillis: 30000,
93
+ acquireTimeoutMillis: 30000,
94
+ idleTimeoutMillis: 30000,
95
+ reapIntervalMillis: 1000,
96
+ createRetryIntervalMillis: 100,
97
+ },
83
98
  });
84
99
  this.people = people;
85
100
  }
@@ -114,30 +129,53 @@ class FAMISDb {
114
129
  /**
115
130
  *
116
131
  * Process an invoice to have all necessary relationships
117
- * @param {object} invoice
118
- * @returns{Promise<object>} invoice object
132
+ * @param {object} invoice - the invoice object sent by iLab
133
+ * @param {boolean} [historical=false] - if true use historical accounts too
134
+ * @returns {Promise<object>} invoice object
119
135
  * @memberof FAMISDb
120
136
  */
121
- async processInvoice(invoice) {
137
+ async processInvoice(invoice, historical=false) {
122
138
  // console.log(invoice);
123
- const account = getCoreAccountNumber(invoice.data.details[0].famis);
124
- invoice.core = await this.getCoreByAccount(account);
125
- if (invoice.core) {
126
- invoice.core.systemPart = await this.getSystemById(invoice.core.systemId);
127
- } else {
128
- const e = Error(`Revenue account ${account} is not associated with a core.`)
129
- throw(e);
130
- }
131
- const customerAccountNumber = this.getAccountNumber(invoice.data.details[0].famis, invoice.replace_data);
132
- invoice.isIdt = customerAccountNumber && (customerAccountNumber.accountNumber.substring(0,2) === account.substring(0,2));
133
- invoice.customerAccountInfo = await this.getByAccountNumber(customerAccountNumber.accountNumber);
134
- invoice.poNumber = customerAccountNumber.poNumber;
135
- invoice.customerAccount = customerAccountNumber.accountNumber;
136
- if (invoice.customerAccountInfo && this.people) {
137
- const pi = invoice.customerAccountInfo.uin ? await this.people.getByUin(invoice.customerAccountInfo.uin) : [];
138
- if (pi.length) {
139
- invoice.pi = JSON.parse(JSON.stringify(pi[0]));
139
+ try {
140
+ const account = getCoreAccountNumber(invoice.data.details[0].famis);
141
+ invoice.core = await this.getCoreByAccount(account);
142
+ if (invoice.core) {
143
+ invoice.core.systemPart = await this.getSystemById(invoice.core.systemId);
144
+ } else {
145
+ const e = Error(`Revenue account ${account} is not associated with a core.`)
146
+ throw(e);
140
147
  }
148
+ const campus = account.substring(0,2);
149
+ const revenuAccount = await this.getByAccountNumber(account, campus, historical);
150
+ const customerAccountNumber = this.getAccountNumber(invoice.data.details[0].famis, invoice.replace_data);
151
+ invoice.customerAccountInfo = await this.getByAccountNumber(customerAccountNumber.accountNumber, campus, historical);
152
+ if (invoice.customerAccountInfo) {
153
+ let idtAllowed = 'idt_allowed' in invoice.customerAccountInfo && invoice.customerAccountInfo.idt_allowed !== null ?
154
+ invoice.customerAccountInfo.idt_allowed :
155
+ 'parent_account_idt_allowed' in invoice.customerAccountInfo && invoice.customerAccountInfo.parent_account_idt_allowed;
156
+ idtAllowed = idtAllowed &&
157
+ !( invoice.replace_data &&
158
+ typeof invoice.replace_data === 'object' &&
159
+ invoice.replace_data.forcedAr
160
+ );
161
+ const isIdt = customerAccountNumber && (customerAccountNumber.accountNumber.substring(0,2) === account.substring(0,2)) && idtAllowed;
162
+ invoice.isIdt = isIdt;
163
+ } else {
164
+ invoice.isIdt = false;
165
+ }
166
+ let poNumber = (customerAccountNumber.accountNumber.substring(0,2) !== '68') ? `${campus}-${revenuAccount.department}` : customerAccountNumber.poNumber;
167
+ invoice.poNumber = poNumber;
168
+ invoice.customerAccount = customerAccountNumber.accountNumber;
169
+ if (invoice.customerAccountInfo && this.people) {
170
+ const pi = invoice.customerAccountInfo.uin ? await this.people.getByUin(invoice.customerAccountInfo.uin) : [];
171
+ if (pi.length) {
172
+ invoice.pi = JSON.parse(JSON.stringify(pi[0]));
173
+ }
174
+ }
175
+ invoice.highRiskInfo = await this.isSrsHighRisk(invoice);
176
+ invoice.comments = await this.getInvoiceComments(invoice.uid);
177
+ } catch (e) {
178
+ throw e;
141
179
  }
142
180
  return invoice;
143
181
  }
@@ -147,7 +185,7 @@ class FAMISDb {
147
185
  *
148
186
  * Get invoice by uid
149
187
  * @param {string} uid
150
- * @returns{Promise<object>} invoice object
188
+ * @returns {Promise<object>} invoice object
151
189
  * @memberof FAMISDb
152
190
  */
153
191
  async getInvoiceByUid(uid) {
@@ -170,7 +208,7 @@ class FAMISDb {
170
208
  *
171
209
  * Get invoice by originating system assigned number
172
210
  * @param {string} number
173
- * @returns{Promise<object>} invoice object
211
+ * @returns {Promise<object>} invoice object
174
212
  * @memberof FAMISDb
175
213
  */
176
214
  async getInvoiceByNumber(number) {
@@ -178,10 +216,10 @@ class FAMISDb {
178
216
  let retVal;
179
217
 
180
218
  try {
181
- records = await this.db('invoices').where('number', number);
219
+ records = await this.db('invoices').whereILike('number', `${number}%`);
182
220
  if (records.length) {
183
221
  retVal = this.processInvoice(records[0]);
184
- }
222
+ }
185
223
  } catch (e) {
186
224
  throw e;
187
225
  }
@@ -192,7 +230,7 @@ class FAMISDb {
192
230
  *
193
231
  * Get invoice by fingerprint
194
232
  * @param {string} fingerPrint
195
- * @returns{Promise<object>} invoice object
233
+ * @returns {Promise<object>} invoice object
196
234
  * @memberof FAMISDb
197
235
  */
198
236
  async getInvoiceByFingerPrint(fingerPrint) {
@@ -214,7 +252,7 @@ class FAMISDb {
214
252
  *
215
253
  * Get all invoices associated with a specified account number
216
254
  * @param {string} accountNumber
217
- * @returns{Promise<array>} invoice objects
255
+ * @returns {Promise<array>} invoice objects
218
256
  * @memberof FAMISDb
219
257
  */
220
258
  async getInvoicesByAccount(accountNumber) {
@@ -254,35 +292,51 @@ class FAMISDb {
254
292
  * @param {string} [orderBy='date']
255
293
  * @param {string} [dir='desc']
256
294
  * @param {boolean} [deleted=false]
257
- * @returns{Promise<array>} invoice objects
295
+ * @param {integer} [page=null]
296
+ * @param {integer} [limit=null]
297
+ * @returns {Promise<array>} invoice objects
258
298
  * @memberof FAMISDb
259
299
  */
260
- async getAllInvoices(orderBy='date', dir='desc', deleted=false) {
300
+ async getAllInvoices(orderBy='date', dir='desc', deleted=false, page=null, limit=null) {
261
301
  const self = this;
262
302
  let records;
303
+ let metadata;
263
304
  try {
264
305
  const sql = this.db('invoices')
306
+ const meta = this.db('invoices');
265
307
  if (!deleted) {
266
- sql.whereNull('deleted')
308
+ sql.whereNull('deleted');
309
+ meta.whereNull('deleted');
310
+ }
311
+ //console.log(page, limit);
312
+ if (page && limit) {
313
+ sql.limit(limit).offset((page-1)*limit);
267
314
  }
268
315
  records = await sql.orderBy(orderBy, dir);
316
+ metadata = await meta.orderBy(orderBy, dir);
317
+ //console.log(records);
269
318
  records = await map(
270
319
  records,
271
320
  async (record) => {
272
- const rec = self.processInvoice(record);
321
+ const rec = self.processInvoice(record, true);
273
322
  return rec;
274
323
  }
275
324
  );
276
325
  } catch (e) {
277
326
  throw e;
278
327
  }
279
- return records;
328
+ return {
329
+ records,
330
+ metadata: {
331
+ total: metadata.length,
332
+ },
333
+ }
280
334
  }
281
335
 
282
336
  /**
283
337
  *
284
338
  * Retreives invoices from the latest date
285
- * @returns{Promise<array>} invoice objects
339
+ * @returns {Promise<array>} invoice objects
286
340
  * @memberof FAMISDb
287
341
  */
288
342
  async getLatestInvoices() {
@@ -311,17 +365,27 @@ class FAMISDb {
311
365
  /**
312
366
  *
313
367
  * Returns all held invoices
314
- * @returns{Promise<array>} held invoice objects
368
+ * @returns {Promise<array>} held invoice objects
315
369
  * @memberof FAMISDb
316
370
  */
317
- async getHeldInvoices() {
371
+ async getHeldInvoices(orderBy='date', dir='desc', page=null, limit=null) {
318
372
  const self = this;
319
373
  let records;
320
-
374
+ let metadata;
375
+ const sql = this.db('invoices');
376
+ const meta = this.db('invoices');
321
377
  try {
322
- records = await this.db('invoices')
378
+ if (page && limit) {
379
+ sql.limit(limit).offset((page-1)*limit);
380
+ }
381
+ records = await sql
382
+ .whereNull('deleted')
383
+ .andWhere('invoiced', '0')
384
+ .orderBy(orderBy, dir);
385
+ metadata = await meta
323
386
  .whereNull('deleted')
324
- .andWhere('invoiced', '0');
387
+ .andWhere('invoiced', '0')
388
+ .orderBy(orderBy, dir);
325
389
  records = await map(
326
390
  records,
327
391
  async (record) => {
@@ -332,13 +396,18 @@ class FAMISDb {
332
396
  } catch (e) {
333
397
  throw e;
334
398
  }
335
- return records;
399
+ return {
400
+ records,
401
+ metadata: {
402
+ total: metadata.length,
403
+ },
404
+ };
336
405
  }
337
406
 
338
407
  /**
339
408
  *
340
409
  * Returns all awaiting email invoices
341
- * @returns{Promise<array>} awaiting email invoice objects
410
+ * @returns {Promise<array>} awaiting email invoice objects
342
411
  * @memberof FAMISDb
343
412
  */
344
413
  async getInvoicesAwaitingEmail() {
@@ -366,7 +435,7 @@ class FAMISDb {
366
435
  *
367
436
  * Search invoices by originating system generated invoice number
368
437
  * @param {string} number
369
- * @returns{Promise<array>} invoice objects
438
+ * @returns {Promise<array>} invoice objects
370
439
  * @memberof FAMISDb
371
440
  */
372
441
  async searchInvoicesByNumber(number) {
@@ -397,7 +466,7 @@ class FAMISDb {
397
466
  *
398
467
  * Search invoices by FAMIS invoice number
399
468
  * @param {string} famis
400
- * @returns{Promise<array>} invoice objects
469
+ * @returns {Promise<array>} invoice objects
401
470
  * @memberof FAMISDb
402
471
  */
403
472
  async searchInvoicesByFamis(famis) {
@@ -430,7 +499,7 @@ class FAMISDb {
430
499
  * @param {object} invoice
431
500
  * @param {string} type
432
501
  * @param {string} famisInvoiceNumber
433
- * @returns{Promise<object>} invoice
502
+ * @returns {Promise<object>} invoice
434
503
  * @memberof FAMISDb
435
504
  */
436
505
  async addInvoice(invoice, type, famisInvoiceNumber) {
@@ -459,7 +528,7 @@ class FAMISDb {
459
528
  totalAmount: parseFloat(invoice.totalAmount),
460
529
  data: JSON.stringify(invoice),
461
530
  date: invoice.date,
462
- uid: cuid(),
531
+ uid: createId(),
463
532
  fingerprint: invoice.fingerprint,
464
533
  type: type,
465
534
  famisInvoiceNumber: famisInvoiceNumber,
@@ -478,7 +547,7 @@ class FAMISDb {
478
547
  * Updates an invoice
479
548
  * @param {string} uid
480
549
  * @param {object} invoice
481
- * @returns{Promise<object>} invoice object
550
+ * @returns {Promise<object>} invoice object
482
551
  * @memberof FAMISDb
483
552
  */
484
553
  async updateInvoice(uid, invoice) {
@@ -506,6 +575,7 @@ class FAMISDb {
506
575
  customerAccount: this.getAccountNumber(invoice.details[0].famis).accountNumber,
507
576
  sellingAccount: getCoreAccountNumber(invoice.details[0].famis),
508
577
  fingerprint: invoice.fingerprint ? invoice.fingerprint : null,
578
+ replace_data: invoice.replace_data,
509
579
  })
510
580
  .where('uid', uid);
511
581
  } catch (e) {
@@ -519,7 +589,7 @@ class FAMISDb {
519
589
  * Toggles an invoice as paid
520
590
  * @param {string} uid
521
591
  * @param {boolean} invoiced
522
- * @returns{Promise<object>} invoice object
592
+ * @returns {Promise<object>} invoice object
523
593
  * @memberof FAMISDb
524
594
  */
525
595
  async markInvoiced(uid, invoiced) {
@@ -543,7 +613,7 @@ class FAMISDb {
543
613
  * Toggles an invoice as emailed
544
614
  * @param {string} uid
545
615
  * @param {boolean} emailed
546
- * @returns{Promise<object>} invoice object
616
+ * @returns {Promise<object>} invoice object
547
617
  * @memberof FAMISDb
548
618
  */
549
619
  async markEmailed(uid, emailed) {
@@ -567,7 +637,7 @@ class FAMISDb {
567
637
  * Sets an invoice's deletion date
568
638
  * @param {string} uid
569
639
  * @param {date} deleted
570
- * @returns{Promise<object>} invoice object
640
+ * @returns {Promise<object>} invoice object
571
641
  * @memberof FAMISDb
572
642
  */
573
643
  async setDeleted(uid, deleted) {
@@ -591,7 +661,7 @@ class FAMISDb {
591
661
  * Sets an invoice's posted date
592
662
  * @param {string} uid
593
663
  * @param {date} postedDate
594
- * @returns{Promise<object>} invoice object
664
+ * @returns {Promise<object>} invoice object
595
665
  * @memberof FAMISDb
596
666
  */
597
667
  async setInvoicePostedDate(uid, postedDate) {
@@ -615,7 +685,7 @@ class FAMISDb {
615
685
  * Sets an invoice's fingerprint
616
686
  * @param {string} uid
617
687
  * @param {string} fingerprint
618
- * @returns{Promise<object>} invoice object
688
+ * @returns {Promise<object>} invoice object
619
689
  * @memberof FAMISDb
620
690
  */
621
691
  async setInvoiceFingerPrint(uid, fingerprint) {
@@ -638,35 +708,40 @@ class FAMISDb {
638
708
  *
639
709
  * Get PI accounts by account number
640
710
  * @param {string} number
641
- * @returns{Promise<object>} account object
711
+ * @param {string} campus
712
+ * @param {boolean} [historical=false]
713
+ * @returns {Promise<object>} account object
642
714
  * @memberof FAMISDb
643
715
  */
644
- async getByAccountNumber(number) {
716
+ async getByAccountNumber(number, campus, historical=false) {
645
717
  let records;
646
718
  let retVal;
719
+ let table = historical ? 'accounts_all' : 'accounts'
647
720
  const self = this;
648
721
 
649
- if (!number) console.log('Null account number');
722
+ if (!number) {
723
+ throw Error('Null account number');
724
+ }
650
725
  try {
651
- records = await this.db('accounts')
726
+ records = await this.db(`${table}`)
652
727
  .leftJoin('departments',
653
728
  function() {
654
729
  this
655
- .on('accounts.department', '=', 'departments.dept')
730
+ .on(`${table}.department`, '=', 'departments.dept')
656
731
  .on('departments.part', '=', self.db.raw('?', [number.substring(0,2)]))
657
732
  }
658
733
  )
659
- .leftJoin('accounts as parent_account',
734
+ .leftJoin(`${table} as parent_account`,
660
735
  function() {
661
736
  this
662
- .on('accounts.campus_code', '=', 'parent_account.campus_code')
663
- .on('accounts.account', '=', 'parent_account.account')
737
+ .on(`${table}.campus_code`, '=', 'parent_account.campus_code')
738
+ .on(`${table}.account`, '=', 'parent_account.account')
664
739
  .on('parent_account.support_account', '=', self.db.raw('?', ["00000"]))
665
- .on('accounts.fiscal_year', '=', 'parent_account.fiscal_year')
740
+ .on(`${table}.fiscal_year`, '=', 'parent_account.fiscal_year')
666
741
  }
667
742
  )
668
743
  .select(
669
- 'accounts.*',
744
+ `${table}.*`,
670
745
  'departments.idt_email as billingEmailId',
671
746
  'parent_account.idt_allowed as parent_account_idt_allowed'
672
747
  )
@@ -674,12 +749,13 @@ class FAMISDb {
674
749
  .andWhere(function() {
675
750
  this.whereNull('departments.exp_date').orWhere('departments.exp_date', '>', self.db.raw('CURRENT_DATE'))
676
751
  })
677
- .andWhere('accounts.account_number', number);
752
+ .andWhere(`${table}.account_number`, number);
678
753
  if (records.length) {
679
754
  retVal = records[0];
680
755
  } else {
681
756
  records = await this.db('customers')
682
- .where('account_number', number);
757
+ .where('account_number', number)
758
+ .andWhere('campus_code', campus);
683
759
  if (records.length) {
684
760
  retVal = Object.assign(
685
761
  {},
@@ -690,7 +766,7 @@ class FAMISDb {
690
766
  billingEmailId: records[0].email,
691
767
  }
692
768
  );
693
- }
769
+ }
694
770
  }
695
771
  } catch (e) {
696
772
  throw e;
@@ -702,7 +778,7 @@ class FAMISDb {
702
778
  *
703
779
  * Search PI accounts by partial account number
704
780
  * @param {string} number
705
- * @returns{Promise<array>} account object(s)
781
+ * @returns {Promise<array>} account object(s)
706
782
  * @memberof FAMISDb
707
783
  */
708
784
  async searchByAccountNumber(number) {
@@ -745,7 +821,7 @@ class FAMISDb {
745
821
  *
746
822
  * Get PI Accounts by UIN
747
823
  * @param {string} uin
748
- * @returns{Promise<array>} account object array
824
+ * @returns {Promise<array>} account object array
749
825
  * @memberof FAMISDb
750
826
  */
751
827
  async getAccountsByUin(uin) {
@@ -778,7 +854,7 @@ class FAMISDb {
778
854
  *
779
855
  * Get PI accounts by responsible UIN
780
856
  * @param {string} uin
781
- * @returns{Promise<array>} account object array
857
+ * @returns {Promise<array>} account object array
782
858
  * @memberof FAMISDb
783
859
  */
784
860
  async getAccountsByResponsibleUin(uin) {
@@ -811,7 +887,7 @@ class FAMISDb {
811
887
  *
812
888
  * Get next FAMIS invoice number in sequence for specified invoice type
813
889
  * @param {string} invoice
814
- * @returns{Promise<string>} next invoice number in sequence
890
+ * @returns {Promise<string>} next invoice number in sequence
815
891
  * @memberof FAMISDb
816
892
  */
817
893
  async getNextFAMISInvoiceNumber(type) {
@@ -825,7 +901,7 @@ class FAMISDb {
825
901
  });
826
902
  try {
827
903
  retVal = `${prefix.prefix}${prefix.start}`;
828
- records = await this.db('invoices').whereIn('type', prefix.aliases).orderBy('famisInvoiceNumber', 'desc').limit(5);
904
+ records = await this.db('invoices').whereIn('type', prefix.aliases).orderBy('famisInvoiceNumber', 'desc');
829
905
  if (records.length) {
830
906
  const number = parseInt(records[0].famisInvoiceNumber.substring(1), 10) + 1;
831
907
  retVal = `${prefix.prefix}${number}`;
@@ -857,18 +933,18 @@ class FAMISDb {
857
933
  return retVal;
858
934
  }
859
935
 
860
- /**
936
+ /**
861
937
  *
862
- * Get expense code object
863
- * @param {string} code
864
- * @returns {Promise<object>} expense code object
938
+ * Get revenue code object
939
+ * @param {string} revenue
940
+ * @returns {Promise<object>} revenue code object
865
941
  * @memberof FAMISDb
866
942
  */
867
- async getExpenseCode(code) {
943
+ async getRevenueCode(revenue) {
868
944
  let records;
869
945
  let retVal;
870
946
  try {
871
- records = await this.db('codes').where('expense', code).orderBy('id', 'desc');
947
+ records = await this.db('codes').where('revenue', revenue).orderBy('id', 'desc');
872
948
  if (records.length) {
873
949
  retVal = records[0];
874
950
  }
@@ -878,19 +954,18 @@ class FAMISDb {
878
954
  return retVal;
879
955
  }
880
956
 
881
-
882
957
  /**
883
958
  *
884
- * Get revenue code object
885
- * @param {string} revenue
886
- * @returns{Promise<object>} revenue code object
959
+ * Get expense code object
960
+ * @param {string} code
961
+ * @returns {Promise<object>} expense code object
887
962
  * @memberof FAMISDb
888
963
  */
889
- async getRevenueCode(revenue) {
964
+ async getExpenseCode(code) {
890
965
  let records;
891
966
  let retVal;
892
967
  try {
893
- records = await this.db('codes').where('revenue', revenue).orderBy('id', 'desc');
968
+ records = await this.db('codes').where('expense', code).orderBy('id', 'desc');
894
969
  if (records.length) {
895
970
  retVal = records[0];
896
971
  }
@@ -906,7 +981,7 @@ class FAMISDb {
906
981
  * @param {string} account
907
982
  * @param {string} code
908
983
  * @param {integer} fiscal
909
- * @returns{Promise<boolean>} truthy value
984
+ * @returns {Promise<boolean>} truthy value
910
985
  * @memberof FAMISDb
911
986
  */
912
987
  async allowableExpenseCode(accountNumber, code, fiscal) {
@@ -953,7 +1028,7 @@ class FAMISDb {
953
1028
  *
954
1029
  * Get allowable expense code ranges for specified account
955
1030
  * @param {string} account
956
- * @returns{Promise<boolean>} expense code range object(s)
1031
+ * @returns {Promise<boolean>} expense code range object(s)
957
1032
  * @memberof FAMISDb
958
1033
  */
959
1034
  async getAllowableExpenseCodes(accountNumber, fiscal) {
@@ -1013,7 +1088,7 @@ class FAMISDb {
1013
1088
  *
1014
1089
  * Get core by id
1015
1090
  * @param {string} id
1016
- * @returns{Promise<object>} core object
1091
+ * @returns {Promise<object>} core object
1017
1092
  * @memberof FAMISDb
1018
1093
  */
1019
1094
  async getCoreById(id) {
@@ -1078,7 +1153,7 @@ class FAMISDb {
1078
1153
  *
1079
1154
  * Get core by account number
1080
1155
  * @param {string} account
1081
- * @returns{Promise<object>} core object
1156
+ * @returns {Promise<object>} core object
1082
1157
  * @memberof FAMISDb
1083
1158
  */
1084
1159
  async getCoreByAccount(account) {
@@ -1118,7 +1193,7 @@ class FAMISDb {
1118
1193
  *
1119
1194
  * Get core current revenue account number
1120
1195
  * @param {string} coreId
1121
- * @returns{Promise<object>} core object
1196
+ * @returns {Promise<object>} core object
1122
1197
  * @memberof FAMISDb
1123
1198
  */
1124
1199
  async getCoreCurrentAccount(coreId) {
@@ -1180,7 +1255,7 @@ class FAMISDb {
1180
1255
  *
1181
1256
  * Get system part by ID
1182
1257
  * @param {number} id
1183
- * @returns{Promise<object>} system part object
1258
+ * @returns {Promise<object>} system part object
1184
1259
  * @memberof FAMISDb
1185
1260
  */
1186
1261
  async getSystemById(id) {
@@ -1201,7 +1276,7 @@ class FAMISDb {
1201
1276
  *
1202
1277
  * Get system part by two digit part number
1203
1278
  * @param {string} number
1204
- * @returns{Promise<object>} system part object
1279
+ * @returns {Promise<object>} system part object
1205
1280
  * @memberof FAMISDb
1206
1281
  */
1207
1282
  async getSystemByPartNumber(number) {
@@ -1222,7 +1297,7 @@ class FAMISDb {
1222
1297
  *
1223
1298
  * Get all enabled cores
1224
1299
  * @param {string} date
1225
- * @returns{Promise<array>} core objects
1300
+ * @returns {Promise<array>} core objects
1226
1301
  * @memberof FAMISDb
1227
1302
  */
1228
1303
  async getEnabledCores(date) {
@@ -1283,7 +1358,7 @@ class FAMISDb {
1283
1358
  /**
1284
1359
  *
1285
1360
  * Get all cores
1286
- * @returns{Promise<array>} core objects
1361
+ * @returns {Promise<array>} core objects
1287
1362
  * @memberof FAMISDb
1288
1363
  */
1289
1364
  async getAllCores() {
@@ -1304,7 +1379,7 @@ class FAMISDb {
1304
1379
  *
1305
1380
  * Get a core's users by core ID
1306
1381
  * @param {number} coreId
1307
- * @returns{Promise<array>} user objects
1382
+ * @returns {Promise<array>} user objects
1308
1383
  * @memberof FAMISDb
1309
1384
  */
1310
1385
  async getCoreUsers(coreId) {
@@ -1329,7 +1404,7 @@ class FAMISDb {
1329
1404
  *
1330
1405
  * Get a user's cores they manage
1331
1406
  * @param {string} userId
1332
- * @returns{Promise<array>} core objects
1407
+ * @returns {Promise<array>} core objects
1333
1408
  * @memberof FAMISDb
1334
1409
  */
1335
1410
  async getUserCores(userId) {
@@ -1355,7 +1430,7 @@ class FAMISDb {
1355
1430
  *
1356
1431
  * Get a system part's users by system ID
1357
1432
  * @param {number} systemId
1358
- * @returns{Promise<array>} user objects
1433
+ * @returns {Promise<array>} user objects
1359
1434
  * @memberof FAMISDb
1360
1435
  */
1361
1436
  async getSystemUsers(systemId) {
@@ -1380,7 +1455,7 @@ class FAMISDb {
1380
1455
  *
1381
1456
  * Get a user's system parts they manage
1382
1457
  * @param {*} userId
1383
- * @returns{Promise<object>} system objects
1458
+ * @returns {Promise<object>} system objects
1384
1459
  * @memberof FAMISDb
1385
1460
  */
1386
1461
  async getUserSystemParts(userId) {
@@ -1406,7 +1481,7 @@ class FAMISDb {
1406
1481
  /**
1407
1482
  *
1408
1483
  * Get all system parts
1409
- * @returns{Promise<object>} system objects
1484
+ * @returns {Promise<object>} system objects
1410
1485
  * @memberof FAMISDb
1411
1486
  */
1412
1487
  async getAllSystemParts() {
@@ -1420,11 +1495,27 @@ class FAMISDb {
1420
1495
  return retVal;
1421
1496
  }
1422
1497
 
1498
+ /**
1499
+ *
1500
+ * Get all admin users
1501
+ * @returns {Promise<array>} array of user objects
1502
+ * @memberof FAMISDb
1503
+ */
1504
+ async getAdminUsers() {
1505
+ let retVal;
1506
+ try {
1507
+ retVal = await this.db('users').where('admin', true);
1508
+ } catch (e) {
1509
+ throw e;
1510
+ }
1511
+ return retVal;
1512
+ }
1513
+
1423
1514
  /**
1424
1515
  *
1425
1516
  * Get user
1426
1517
  * @param {string} userId
1427
- * @returns{Promise<object>} user object
1518
+ * @returns {Promise<object>} user object
1428
1519
  * @memberof FAMISDb
1429
1520
  */
1430
1521
  async getUser(userId) {
@@ -1443,12 +1534,33 @@ class FAMISDb {
1443
1534
  return retVal;
1444
1535
  }
1445
1536
 
1537
+ /**
1538
+ *
1539
+ * Update user
1540
+ * @param {object} user
1541
+ * @returns {Promise<object>} user object
1542
+ * @memberof FAMISDb
1543
+ */
1544
+ async updateUser(user) {
1545
+ let retVal;
1546
+ const columns = ['id', 'userId', 'admin', 'role', 'roleName', 'roleEmail', 'deleted'];
1547
+ try {
1548
+ if ('id' in user) retVal = await this.db('users')
1549
+ .returning(columns)
1550
+ .update(user)
1551
+ .where('id', user.id);
1552
+ } catch (e) {
1553
+ throw e;
1554
+ }
1555
+ return retVal;
1556
+ }
1557
+
1446
1558
  /**
1447
1559
  *
1448
1560
  * Get customer by customer account number
1449
1561
  * @param {string} accountNumber
1450
1562
  * @param {string} campusCode
1451
- * @returns{Promise<object>} customer account object
1563
+ * @returns {Promise<object>} customer account object
1452
1564
  * @memberof FAMISDb
1453
1565
  */
1454
1566
  async getCustomerNumber(accountNumber, campusCode) {
@@ -1461,7 +1573,7 @@ class FAMISDb {
1461
1573
  .where('uid', `${code}${accountNumber}`);
1462
1574
  if (records.length) {
1463
1575
  retVal = records[0];
1464
- }
1576
+ }
1465
1577
  } catch (e) {
1466
1578
  throw e;
1467
1579
  }
@@ -1471,7 +1583,7 @@ class FAMISDb {
1471
1583
  /**
1472
1584
  *
1473
1585
  * Get current fiscal year
1474
- * @returns{<integer>} fiscal year
1586
+ * @returns {<integer>} fiscal year
1475
1587
  * @memberof FAMISDb
1476
1588
  */
1477
1589
  getCurrentFiscalYear() {
@@ -1489,7 +1601,7 @@ class FAMISDb {
1489
1601
  *
1490
1602
  * Return fingerprint of invoice
1491
1603
  * @param {object} invoice json object
1492
- * @returns{<string>} fingerprint
1604
+ * @returns {<string>} fingerprint
1493
1605
  * @memberof FAMISDb
1494
1606
  */
1495
1607
  getInvoiceFingerPrint(invoice) {
@@ -1506,7 +1618,7 @@ class FAMISDb {
1506
1618
  *
1507
1619
  * Return formatted account number
1508
1620
  * @param {string} accountNumber unformatted 13 digit famis account number
1509
- * @returns{<string>} formatted 13 digits famis account number
1621
+ * @returns {<string>} formatted 13 digits famis account number
1510
1622
  * @memberof FAMISDb
1511
1623
  */
1512
1624
  formatAccountNumber(accountNumber) {
@@ -1514,6 +1626,243 @@ class FAMISDb {
1514
1626
 
1515
1627
  return formatted;
1516
1628
  }
1629
+
1630
+ /**
1631
+ * @typedef {Object} HighRisk
1632
+ * @property {boolean} isHighRisk - indicates if invoice triggers SRS high risk policy
1633
+ * @property {object} flaggedTransactions - object of transactions that flag
1634
+ */
1635
+
1636
+ /**
1637
+ *
1638
+ * Is invoice flagged by SRS high risk policies
1639
+ * @param {object} invoice json object
1640
+ * @returns {Promise<HighRisk>} high risk object
1641
+ * @memberof FAMISDb
1642
+ */
1643
+ async isSrsHighRisk(invoice) {
1644
+ let srsHighRisk = false;
1645
+ const objectCodes = new Map();
1646
+ //console.log(invoice);
1647
+ try {
1648
+ await each(
1649
+ invoice.data.details,
1650
+ async (detail) => {
1651
+ //console.log(detail);
1652
+ if (detail.famis.customerAccountNumber && detail.famis.sellingCampusCode) {
1653
+ const acct = await this.getByAccountNumber(detail.famis.customerAccountNumber, detail.famis.sellingCampusCode);
1654
+ const acctNum = this.formatAccountNumber(detail.famis.customerAccountNumber);
1655
+ const objCode = await this.getRevenueCode(detail.sellingObjectCode);
1656
+ const isFederal = acct && acct.cfda_no && (acct.sponsor_type && acct.sponsor_type === 'F');
1657
+ const srsApproved = invoice.replace_data && "srs_approved" in invoice.replace_data ? invoice.replace_data.srs_approved : false;
1658
+ if (objCode && objCode.srs && acct && acct.srs && isFederal && !srsApproved && invoice.isIdt) {
1659
+ srsHighRisk = true;
1660
+ let val = [detail];
1661
+ if (objectCodes.has(objCode.expense)) val.push(...objectCodes.get(objCode.expense));
1662
+ objectCodes.set(objCode.expense, val);
1663
+ }
1664
+ }
1665
+ }
1666
+ );
1667
+ } catch (e) {
1668
+ //console.log(invoice);
1669
+ console.log(e);
1670
+ }
1671
+ return {
1672
+ isHighRisk: srsHighRisk,
1673
+ flaggedTransactions: Object.fromEntries(objectCodes),
1674
+ }
1675
+ }
1676
+
1677
+ /**
1678
+ * @typedef {Object} Comment
1679
+ * @property {integer} id - db generated id
1680
+ * @property {string} uid - uid
1681
+ * @property {string} invoice_id - invoice id
1682
+ * @property {string} user_id - user uid
1683
+ * @property {string} comment - text of comment
1684
+ * @property {string} type - type of comment
1685
+ * @property {date} created - created date
1686
+ * @property {date} deleted - deleted date
1687
+ */
1688
+
1689
+ /**
1690
+ *
1691
+ * Create/update invoice comment
1692
+ * @param {Comment} comment json object
1693
+ * @returns {Promise<Comment>} comment object
1694
+ * @memberof FAMISDb
1695
+ */
1696
+ async saveComment(comment) {
1697
+ const returningColumns = [
1698
+ 'id',
1699
+ 'uid',
1700
+ 'invoice_id',
1701
+ 'user_id',
1702
+ 'comment',
1703
+ 'type',
1704
+ 'created',
1705
+ 'deleted',
1706
+ ];
1707
+ let response;
1708
+ try {
1709
+ const records = await this.db('invoice_comments').where({ uid: comment.uid });
1710
+ if (records.length) {
1711
+ response = await this.db('invoice_comments')
1712
+ .returning(returningColumns)
1713
+ .update(comment)
1714
+ .where('uid', comment.uid);
1715
+ } else {
1716
+ response = await this.db('invoice_comments')
1717
+ .returning(returningColumns)
1718
+ .insert(comment);
1719
+ }
1720
+
1721
+ if (response.length) {
1722
+ response = response[0];
1723
+ }
1724
+ } catch (e) {
1725
+ //console.log(JSON.stringify(comment, null, 2));
1726
+ console.log(e);
1727
+ throw (e);
1728
+ }
1729
+ return response;
1730
+ }
1731
+
1732
+ /**
1733
+ *
1734
+ * Get invoice comments
1735
+ * @param {string} invoiceUid invoice uid
1736
+ * @returns {Promise(<Comment[]>} array of comment objects
1737
+ * @memberof FAMISDb
1738
+ */
1739
+ async getInvoiceComments(invoiceUid) {
1740
+ let self = this;
1741
+ let response;
1742
+ try {
1743
+ const records = await this.db('invoice_comments')
1744
+ .select(
1745
+ 'invoice_comments.*',
1746
+ )
1747
+ .where({ invoice_id: invoiceUid })
1748
+ .orderBy('created', 'desc');
1749
+ response = await map(
1750
+ records,
1751
+ async (r) => {
1752
+ const retVal = r;
1753
+ const files = await self.getCommentFiles(r.uid);
1754
+ r.files = files;
1755
+ if (self.people) {
1756
+ const user = await self.people.getByUid(r.user_id);
1757
+ if (user) {
1758
+ retVal.user = user;
1759
+ }
1760
+ }
1761
+ return retVal;
1762
+ }
1763
+ );
1764
+ } catch (e) {
1765
+ console.log(e);
1766
+ throw (e);
1767
+ }
1768
+ return response;
1769
+ }
1770
+
1771
+ /**
1772
+ * @typedef {Object} CommentFile
1773
+ * @property {integer} id - db generated id
1774
+ * @property {string} uid - uid
1775
+ * @property {string} invoice_id - invoice uid
1776
+ * @property {string} comment_id - comment uid
1777
+ * @property {string} original_filename - original file name
1778
+ * @property {string} filename - generate unique filename on filesystem
1779
+ * @property {date} created - created date
1780
+ * @property {date} deleted - deleted date
1781
+ */
1782
+
1783
+ /**
1784
+ *
1785
+ * Create/update invoice comment file
1786
+ * @param {CommentFile} commentFile json object
1787
+ * @returns {Promise<CommentFile>} comment object
1788
+ * @memberof FAMISDb
1789
+ */
1790
+ async saveCommentFile(commentFile) {
1791
+ const returningColumns = [
1792
+ 'id',
1793
+ 'uid',
1794
+ 'invoice_id',
1795
+ 'comment_id',
1796
+ 'original_filename',
1797
+ 'filename',
1798
+ 'created',
1799
+ 'deleted',
1800
+ ];
1801
+ let response;
1802
+ try {
1803
+ const records = await this.db('invoice_comment_files').where({ uid: commentFile.uid });
1804
+ if (records.length) {
1805
+ response = await this.db('invoice_comment_files')
1806
+ .returning(returningColumns)
1807
+ .update(commentFile)
1808
+ .where('uid', commentFile.uid);
1809
+ } else {
1810
+ response = await this.db('invoice_comment_files')
1811
+ .returning(returningColumns)
1812
+ .insert(commentFile);
1813
+ }
1814
+
1815
+ if (response.length) {
1816
+ response = response[0];
1817
+ }
1818
+ } catch (e) {
1819
+ //console.log(JSON.stringify(comment, null, 2));
1820
+ console.log(e);
1821
+ throw (e);
1822
+ }
1823
+ return response;
1824
+ }
1825
+
1826
+ /**
1827
+ *
1828
+ * Get invoice comment files
1829
+ * @param {string} commentUid comment uid
1830
+ * @returns {Promise(<CommentFile[]>} array of comment file objects
1831
+ * @memberof FAMISDb
1832
+ */
1833
+ async getCommentFiles(commentUid) {
1834
+ let response;
1835
+ try {
1836
+ const records = await this.db('invoice_comment_files')
1837
+ .where({ comment_id: commentUid })
1838
+ .orderBy('created', 'desc');
1839
+ response = records;
1840
+ } catch (e) {
1841
+ console.log(e);
1842
+ throw (e);
1843
+ }
1844
+ return response;
1845
+ }
1846
+
1847
+ /**
1848
+ *
1849
+ * Get invoice comment file
1850
+ * @param {string} fileUid file uid
1851
+ * @returns {Promise(<CommentFile>} array of comment file objects
1852
+ * @memberof FAMISDb
1853
+ */
1854
+ async getCommentFile(fileUid) {
1855
+ let response;
1856
+ try {
1857
+ const records = await this.db('invoice_comment_files')
1858
+ .where({ uid: fileUid });
1859
+ if (records.length) response = records[0];
1860
+ } catch (e) {
1861
+ console.log(e);
1862
+ throw (e);
1863
+ }
1864
+ return response;
1865
+ }
1517
1866
  }
1518
1867
 
1519
1868
  module.exports = FAMISDb;