@tamu-dor/famis-db 1.3.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.
Files changed (58) hide show
  1. package/change.txt +123 -0
  2. package/changes.md +405 -0
  3. package/docs/assets/anchor.js +350 -0
  4. package/docs/assets/bass-addons.css +12 -0
  5. package/docs/assets/bass.css +544 -0
  6. package/docs/assets/fonts/EOT/SourceCodePro-Bold.eot +0 -0
  7. package/docs/assets/fonts/EOT/SourceCodePro-Regular.eot +0 -0
  8. package/docs/assets/fonts/LICENSE.txt +93 -0
  9. package/docs/assets/fonts/OTF/SourceCodePro-Bold.otf +0 -0
  10. package/docs/assets/fonts/OTF/SourceCodePro-Regular.otf +0 -0
  11. package/docs/assets/fonts/TTF/SourceCodePro-Bold.ttf +0 -0
  12. package/docs/assets/fonts/TTF/SourceCodePro-Regular.ttf +0 -0
  13. package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff +0 -0
  14. package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff +0 -0
  15. package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff +0 -0
  16. package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff +0 -0
  17. package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 +0 -0
  18. package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 +0 -0
  19. package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 +0 -0
  20. package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 +0 -0
  21. package/docs/assets/fonts/source-code-pro.css +23 -0
  22. package/docs/assets/github.css +123 -0
  23. package/docs/assets/site.js +168 -0
  24. package/docs/assets/split.css +15 -0
  25. package/docs/assets/split.js +782 -0
  26. package/docs/assets/style.css +147 -0
  27. package/docs/index.html +3737 -0
  28. package/docs.md +591 -0
  29. package/famisDb.pdf +0 -0
  30. package/index.js +1497 -0
  31. package/package.json +25 -0
  32. package/readme.md +38 -0
  33. package/readme.wiki +332 -0
  34. package/schemas/00-initial-data.sql +116 -0
  35. package/schemas/migrations/201906101221.sql +29 -0
  36. package/schemas/migrations/201907081530.sql +51 -0
  37. package/schemas/migrations/201908230849.sql +40 -0
  38. package/schemas/migrations/201910031358.sql +73 -0
  39. package/schemas/migrations/20191024.sql +38 -0
  40. package/schemas/migrations/201911060915.sql +3 -0
  41. package/schemas/migrations/202001221335.sql +58 -0
  42. package/schemas/migrations/202003041114.sql +53 -0
  43. package/schemas/migrations/202003261143.sql +47 -0
  44. package/schemas/migrations/202004201456.sql +3 -0
  45. package/schemas/migrations/20200722.sql +92 -0
  46. package/schemas/migrations/202007281124.sql +17 -0
  47. package/schemas/migrations/20200729.sql +76 -0
  48. package/schemas/migrations/20200806-FCF.sql +72 -0
  49. package/schemas/migrations/20200806-IMAC.sql +60 -0
  50. package/schemas/migrations/20200811.sql +46 -0
  51. package/schemas/migrations/20200813.sql +36 -0
  52. package/schemas/migrations/202010210924.sql +66 -0
  53. package/schemas/migrations/202010211558.sql +20 -0
  54. package/schemas/migrations/202011130651.sql +4 -0
  55. package/schemas/migrations/202011130951.sql +17 -0
  56. package/schemas/migrations/202101201051.sql +33 -0
  57. package/schemas/migrations/postponed-202004221221.sql +66 -0
  58. package/schemas/schema.sql +155 -0
package/index.js ADDED
@@ -0,0 +1,1497 @@
1
+ const knex = require('knex');
2
+ const cuid = require('cuid');
3
+ const { map } = require('awaity');
4
+ const revisionHash = require('rev-hash');
5
+
6
+ const famisInvoiceNumbers = [
7
+ {
8
+ start: 300128,
9
+ end: 399999,
10
+ prefix: 'I',
11
+ aliases: [
12
+ 'ilabs',
13
+ ]
14
+ },
15
+ {
16
+ start: 100000,
17
+ end: 999999,
18
+ prefix: 'V',
19
+ aliases: [
20
+ 'mosaic',
21
+ ]
22
+ },
23
+ ];
24
+ const returningColumns = ['uid', 'number', 'lab', 'totalAmount', 'data', 'date', 'type', 'famisInvoiceNumber', 'customerAccount', 'sellingAccount'];
25
+
26
+ const pad = (str, max, right) => {
27
+ let retVal = str;
28
+ str = str.toString();
29
+ if (str.length < max) {
30
+ retVal = pad("0" + str, max);
31
+ } else if (str.length > max) {
32
+ retVal = str.substring(0, max);
33
+ }
34
+ if (right) {
35
+ retVal = retVal.length < max ? pad(retVal + "0", max, right) : retVal;
36
+ }
37
+ return retVal;
38
+ };
39
+
40
+ const sanitizeAccountNumber = (account) => pad(account.replace(/\D/g,''), 13, true);
41
+
42
+ const getCoreAccountNumber = (famis) => {
43
+ const { sellingCampusCode, sellingAccountNumber, sellingSupportAccount } = famis;
44
+ const account = `${sellingCampusCode}${sellingAccountNumber}${sellingSupportAccount}`;
45
+ return sanitizeAccountNumber(account);
46
+ };
47
+
48
+ const sortObjectKeys = (obj) => {
49
+ if (obj === null || obj === undefined) {
50
+ return obj;
51
+ }
52
+ if (typeof obj !== 'object') {
53
+ // it is a primitive: number/string (in an array)
54
+ return obj;
55
+ }
56
+ const result = Object.keys(obj).sort().reduce(
57
+ (acc,key) => {
58
+ if (Array.isArray(obj[key])) {
59
+ acc[key] = obj[key].map(sortObjectKeys);
60
+ } else if (typeof obj[key] === 'object') {
61
+ acc[key] = sortObjectKeys(obj[key]);
62
+ } else {
63
+ acc[key] = obj[key];
64
+ }
65
+ return acc;
66
+ },
67
+ {},
68
+ );
69
+ return result;
70
+ };
71
+
72
+ class FAMISDb {
73
+ constructor(config, people) {
74
+ if (config) {
75
+ this.init(config, people);
76
+ }
77
+ }
78
+
79
+ init(config, people) {
80
+ this.db = knex({
81
+ client: 'pg',
82
+ connection: config,
83
+ });
84
+ this.people = people;
85
+ }
86
+
87
+ /**
88
+ *
89
+ * Extract customer account and po number
90
+ * @param {object} famis
91
+ * @param {object} replace_data
92
+ * @returns {object} account number object
93
+ * @memberof FAMISDb
94
+ */
95
+ getAccountNumber(famis, replace_data) {
96
+ const retVal = {
97
+ accountNumber: null,
98
+ poNumber: null,
99
+ };
100
+
101
+ if (famis.customerAccountNumber || (replace_data && replace_data.customerAccountNumber)) {
102
+ retVal.accountNumber = replace_data && replace_data.customerAccountNumber ? replace_data.customerAccountNumber : famis.customerAccountNumber;
103
+ } else if (famis.customerPONumber.includes('|') || (replace_data && replace_data.customerPONumber.includes('|'))) {
104
+ const result = replace_data && replace_data.customerPONumber.includes('|') ? replace_data.customerPONumber.split('|') : famis.customerPONumber.split('|');
105
+ retVal.accountNumber = sanitizeAccountNumber(result[0]);
106
+ retVal.poNumber = result[1].trim();
107
+ } else {
108
+ retVal.accountNumber = replace_data && replace_data.customerPONumber ? sanitizeAccountNumber(replace_data.customerPONumber) : sanitizeAccountNumber(famis.customerPONumber);
109
+ }
110
+
111
+ return retVal;
112
+ }
113
+
114
+ /**
115
+ *
116
+ * Process an invoice to have all necessary relationships
117
+ * @param {object} invoice
118
+ * @returns{Promise<object>} invoice object
119
+ * @memberof FAMISDb
120
+ */
121
+ async processInvoice(invoice) {
122
+ // 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]));
140
+ }
141
+ }
142
+ return invoice;
143
+ }
144
+
145
+
146
+ /**
147
+ *
148
+ * Get invoice by uid
149
+ * @param {string} uid
150
+ * @returns{Promise<object>} invoice object
151
+ * @memberof FAMISDb
152
+ */
153
+ async getInvoiceByUid(uid) {
154
+ let records;
155
+ let retVal;
156
+
157
+ try {
158
+ records = await this.db('invoices').where('uid', uid);
159
+ if (records.length) {
160
+ retVal = this.processInvoice(records[0]);
161
+ }
162
+ } catch (e) {
163
+ throw e;
164
+ }
165
+
166
+ return retVal;
167
+ }
168
+
169
+ /**
170
+ *
171
+ * Get invoice by originating system assigned number
172
+ * @param {string} number
173
+ * @returns{Promise<object>} invoice object
174
+ * @memberof FAMISDb
175
+ */
176
+ async getInvoiceByNumber(number) {
177
+ let records;
178
+ let retVal;
179
+
180
+ try {
181
+ records = await this.db('invoices').where('number', number);
182
+ if (records.length) {
183
+ retVal = this.processInvoice(records[0]);
184
+ }
185
+ } catch (e) {
186
+ throw e;
187
+ }
188
+ return retVal;
189
+ }
190
+
191
+ /**
192
+ *
193
+ * Get invoice by fingerprint
194
+ * @param {string} fingerPrint
195
+ * @returns{Promise<object>} invoice object
196
+ * @memberof FAMISDb
197
+ */
198
+ async getInvoiceByFingerPrint(fingerPrint) {
199
+ let records;
200
+ let retVal;
201
+
202
+ try {
203
+ records = await this.db('invoices').where('fingerprint', fingerPrint);
204
+ if (records.length) {
205
+ retVal = this.processInvoice(records[0]);
206
+ }
207
+ } catch (e) {
208
+ throw e;
209
+ }
210
+ return retVal;
211
+ }
212
+
213
+ /**
214
+ *
215
+ * Get all invoices associated with a specified account number
216
+ * @param {string} accountNumber
217
+ * @returns{Promise<array>} invoice objects
218
+ * @memberof FAMISDb
219
+ */
220
+ async getInvoicesByAccount(accountNumber) {
221
+ const self = this;
222
+ let records;
223
+ let retVal;
224
+
225
+ try {
226
+ let records = await this.db('invoices')
227
+ .whereNull('deleted')
228
+ .andWhere(function() {
229
+ this.where('customerAccount', accountNumber);
230
+ this.orWhere('sellingAccount', accountNumber);
231
+ this.orWhereRaw("replace_data->>'customerAccountNumber' = ?",[accountNumber]);
232
+ this.orWhereRaw("replace_data->>'customerPONumber' LIKE ?",[`${accountNumber}%`]);
233
+ });
234
+ if (records.length) {
235
+ records = await map(
236
+ records,
237
+ async (record) => {
238
+ const rec = self.processInvoice(record);
239
+ return rec;
240
+ }
241
+ );
242
+ }
243
+ retVal = records;
244
+ } catch (e) {
245
+ throw e;
246
+ }
247
+
248
+ return retVal;
249
+ }
250
+
251
+ /**
252
+ *
253
+ * Get all invoice ordered by and sorted by paramaters passed
254
+ * @param {string} [orderBy='date']
255
+ * @param {string} [dir='desc']
256
+ * @param {boolean} [deleted=false]
257
+ * @returns{Promise<array>} invoice objects
258
+ * @memberof FAMISDb
259
+ */
260
+ async getAllInvoices(orderBy='date', dir='desc', deleted=false) {
261
+ const self = this;
262
+ let records;
263
+ try {
264
+ const sql = this.db('invoices')
265
+ if (!deleted) {
266
+ sql.whereNull('deleted')
267
+ }
268
+ records = await sql.orderBy(orderBy, dir);
269
+ records = await map(
270
+ records,
271
+ async (record) => {
272
+ const rec = self.processInvoice(record);
273
+ return rec;
274
+ }
275
+ );
276
+ } catch (e) {
277
+ throw e;
278
+ }
279
+ return records;
280
+ }
281
+
282
+ /**
283
+ *
284
+ * Retreives invoices from the latest date
285
+ * @returns{Promise<array>} invoice objects
286
+ * @memberof FAMISDb
287
+ */
288
+ async getLatestInvoices() {
289
+ const self = this;
290
+ let records;
291
+
292
+ try {
293
+ records = await this.db('invoices')
294
+ .whereNull('deleted')
295
+ .whereIn('date', function() {
296
+ this.max('date').from('invoices');
297
+ });
298
+ records = await map(
299
+ records,
300
+ async (record) => {
301
+ const rec = self.processInvoice(record);
302
+ return rec;
303
+ }
304
+ );
305
+ } catch (e) {
306
+ throw e;
307
+ }
308
+ return records;
309
+ }
310
+
311
+ /**
312
+ *
313
+ * Returns all held invoices
314
+ * @returns{Promise<array>} held invoice objects
315
+ * @memberof FAMISDb
316
+ */
317
+ async getHeldInvoices() {
318
+ const self = this;
319
+ let records;
320
+
321
+ try {
322
+ records = await this.db('invoices')
323
+ .whereNull('deleted')
324
+ .andWhere('invoiced', '0');
325
+ records = await map(
326
+ records,
327
+ async (record) => {
328
+ const rec = self.processInvoice(record);
329
+ return rec;
330
+ }
331
+ );
332
+ } catch (e) {
333
+ throw e;
334
+ }
335
+ return records;
336
+ }
337
+
338
+ /**
339
+ *
340
+ * Returns all awaiting email invoices
341
+ * @returns{Promise<array>} awaiting email invoice objects
342
+ * @memberof FAMISDb
343
+ */
344
+ async getInvoicesAwaitingEmail() {
345
+ const self = this;
346
+ let records;
347
+
348
+ try {
349
+ records = await this.db('invoices')
350
+ .whereNull('deleted')
351
+ .andWhere('emailed', 'False');
352
+ records = await map(
353
+ records,
354
+ async (record) => {
355
+ const rec = self.processInvoice(record);
356
+ return rec;
357
+ }
358
+ );
359
+ } catch (e) {
360
+ throw e;
361
+ }
362
+ return records;
363
+ }
364
+
365
+ /**
366
+ *
367
+ * Search invoices by originating system generated invoice number
368
+ * @param {string} number
369
+ * @returns{Promise<array>} invoice objects
370
+ * @memberof FAMISDb
371
+ */
372
+ async searchInvoicesByNumber(number) {
373
+ const self = this;
374
+ let records;
375
+ let retVal;
376
+
377
+ try {
378
+ records = await this.db('invoices')
379
+ .whereNull('deleted')
380
+ .andWhere('number', 'ilike', `${number}%`);
381
+ if (records.length) {
382
+ retVal = await map(
383
+ records,
384
+ async (record) => {
385
+ const rec = self.processInvoice(record);
386
+ return rec;
387
+ }
388
+ );
389
+ }
390
+ } catch (e) {
391
+ throw e;
392
+ }
393
+ return retVal;
394
+ }
395
+
396
+ /**
397
+ *
398
+ * Search invoices by FAMIS invoice number
399
+ * @param {string} famis
400
+ * @returns{Promise<array>} invoice objects
401
+ * @memberof FAMISDb
402
+ */
403
+ async searchInvoicesByFamis(famis) {
404
+ const self = this;
405
+ let records;
406
+ let retVal;
407
+
408
+ try {
409
+ records = await this.db('invoices')
410
+ .whereNull('deleted')
411
+ .andWhere('famisInvoiceNumber', 'ilike', `${famis}%`);
412
+ if (records.length) {
413
+ retVal = await map(
414
+ records,
415
+ async (record) => {
416
+ const rec = self.processInvoice(record);
417
+ return rec;
418
+ }
419
+ );
420
+ }
421
+ } catch (e) {
422
+ throw e;
423
+ }
424
+ return retVal;
425
+ }
426
+
427
+ /**
428
+ *
429
+ * Adds an invoice
430
+ * @param {object} invoice
431
+ * @param {string} type
432
+ * @param {string} famisInvoiceNumber
433
+ * @returns{Promise<object>} invoice
434
+ * @memberof FAMISDb
435
+ */
436
+ async addInvoice(invoice, type, famisInvoiceNumber) {
437
+ let records;
438
+
439
+ try {
440
+ famisInvoiceNumber = (typeof famisInvoiceNumber === 'undefined') ? null : famisInvoiceNumber;
441
+ famisInvoiceNumber = famisInvoiceNumber ? famisInvoiceNumber : await this.getNextFAMISInvoiceNumber(type);
442
+ invoice.details.forEach(d => {
443
+ d.famis.invoiceNumber = famisInvoiceNumber;
444
+ if (!d.other) {
445
+ d.other = '0.00';
446
+ }
447
+ if (!d.comments) {
448
+ d.comments = null;
449
+ }
450
+ if (!d.billingPeriod) {
451
+ d.billingPeriod = null;
452
+ }
453
+ });
454
+ records = await this.db('invoices')
455
+ .returning(returningColumns)
456
+ .insert({
457
+ number: invoice.number,
458
+ lab: invoice.lab,
459
+ totalAmount: parseFloat(invoice.totalAmount),
460
+ data: JSON.stringify(invoice),
461
+ date: invoice.date,
462
+ uid: cuid(),
463
+ fingerprint: invoice.fingerprint,
464
+ type: type,
465
+ famisInvoiceNumber: famisInvoiceNumber,
466
+ customerAccount: this.getAccountNumber(invoice.details[0].famis).accountNumber,
467
+ sellingAccount: getCoreAccountNumber(invoice.details[0].famis),
468
+ });
469
+ } catch (e) {
470
+ throw e;
471
+ }
472
+
473
+ return records;
474
+ }
475
+
476
+ /**
477
+ *
478
+ * Updates an invoice
479
+ * @param {string} uid
480
+ * @param {object} invoice
481
+ * @returns{Promise<object>} invoice object
482
+ * @memberof FAMISDb
483
+ */
484
+ async updateInvoice(uid, invoice) {
485
+ let records;
486
+ invoice.details.forEach(d => {
487
+ if (!d.other) {
488
+ d.other = '0.00';
489
+ }
490
+ if (!d.comments) {
491
+ d.comments = null;
492
+ }
493
+ if (!d.billingPeriod) {
494
+ d.billingPeriod = null;
495
+ }
496
+ });
497
+ try {
498
+ records = await this.db('invoices')
499
+ .returning(returningColumns)
500
+ .update({
501
+ number: invoice.number,
502
+ lab: invoice.lab,
503
+ totalAmount: parseFloat(invoice.totalAmount),
504
+ data: JSON.stringify(invoice),
505
+ date: invoice.date,
506
+ customerAccount: this.getAccountNumber(invoice.details[0].famis).accountNumber,
507
+ sellingAccount: getCoreAccountNumber(invoice.details[0].famis),
508
+ fingerprint: invoice.fingerprint ? invoice.fingerprint : null,
509
+ })
510
+ .where('uid', uid);
511
+ } catch (e) {
512
+ throw e;
513
+ }
514
+ return records;
515
+ }
516
+
517
+ /**
518
+ *
519
+ * Toggles an invoice as paid
520
+ * @param {string} uid
521
+ * @param {boolean} invoiced
522
+ * @returns{Promise<object>} invoice object
523
+ * @memberof FAMISDb
524
+ */
525
+ async markInvoiced(uid, invoiced) {
526
+ let records;
527
+
528
+ try {
529
+ records = await this.db('invoices')
530
+ .returning(returningColumns)
531
+ .update({
532
+ invoiced,
533
+ })
534
+ .where('uid', uid);
535
+ } catch (e) {
536
+ throw e;
537
+ }
538
+ return records;
539
+ }
540
+
541
+ /**
542
+ *
543
+ * Toggles an invoice as emailed
544
+ * @param {string} uid
545
+ * @param {boolean} emailed
546
+ * @returns{Promise<object>} invoice object
547
+ * @memberof FAMISDb
548
+ */
549
+ async markEmailed(uid, emailed) {
550
+ let records;
551
+
552
+ try {
553
+ records = await this.db('invoices')
554
+ .returning(returningColumns)
555
+ .update({
556
+ emailed,
557
+ })
558
+ .where('uid', uid);
559
+ } catch (e) {
560
+ throw e;
561
+ }
562
+ return records;
563
+ }
564
+
565
+ /**
566
+ *
567
+ * Sets an invoice's deletion date
568
+ * @param {string} uid
569
+ * @param {date} deleted
570
+ * @returns{Promise<object>} invoice object
571
+ * @memberof FAMISDb
572
+ */
573
+ async setDeleted(uid, deleted) {
574
+ let records;
575
+
576
+ try {
577
+ records = await this.db('invoices')
578
+ .returning(returningColumns)
579
+ .update({
580
+ deleted,
581
+ })
582
+ .where('uid', uid);
583
+ } catch (e) {
584
+ throw e;
585
+ }
586
+ return records;
587
+ }
588
+
589
+ /**
590
+ *
591
+ * Sets an invoice's posted date
592
+ * @param {string} uid
593
+ * @param {date} postedDate
594
+ * @returns{Promise<object>} invoice object
595
+ * @memberof FAMISDb
596
+ */
597
+ async setInvoicePostedDate(uid, postedDate) {
598
+ let records;
599
+
600
+ try {
601
+ records = await this.db('invoices')
602
+ .returning(returningColumns)
603
+ .update({
604
+ postedDate,
605
+ })
606
+ .where('uid', uid);
607
+ } catch (e) {
608
+ throw e;
609
+ }
610
+ return records;
611
+ }
612
+
613
+ /**
614
+ *
615
+ * Sets an invoice's fingerprint
616
+ * @param {string} uid
617
+ * @param {string} fingerprint
618
+ * @returns{Promise<object>} invoice object
619
+ * @memberof FAMISDb
620
+ */
621
+ async setInvoiceFingerPrint(uid, fingerprint) {
622
+ let records;
623
+
624
+ try {
625
+ records = await this.db('invoices')
626
+ .returning(returningColumns)
627
+ .update({
628
+ fingerprint,
629
+ })
630
+ .where('uid', uid);
631
+ } catch (e) {
632
+ throw e;
633
+ }
634
+ return records;
635
+ }
636
+
637
+ /**
638
+ *
639
+ * Get PI accounts by account number
640
+ * @param {string} number
641
+ * @returns{Promise<object>} account object
642
+ * @memberof FAMISDb
643
+ */
644
+ async getByAccountNumber(number) {
645
+ let records;
646
+ let retVal;
647
+ const self = this;
648
+
649
+ if (!number) console.log('Null account number');
650
+ try {
651
+ records = await this.db('accounts')
652
+ .leftJoin('departments',
653
+ function() {
654
+ this
655
+ .on('accounts.department', '=', 'departments.dept')
656
+ .on('departments.part', '=', self.db.raw('?', [number.substring(0,2)]))
657
+ }
658
+ )
659
+ .leftJoin('accounts as parent_account',
660
+ function() {
661
+ this
662
+ .on('accounts.campus_code', '=', 'parent_account.campus_code')
663
+ .on('accounts.account', '=', 'parent_account.account')
664
+ .on('parent_account.support_account', '=', self.db.raw('?', ["00000"]))
665
+ .on('accounts.fiscal_year', '=', 'parent_account.fiscal_year')
666
+ }
667
+ )
668
+ .select(
669
+ 'accounts.*',
670
+ 'departments.idt_email as billingEmailId',
671
+ 'parent_account.idt_allowed as parent_account_idt_allowed'
672
+ )
673
+ .whereNull('departments.sub')
674
+ .andWhere(function() {
675
+ this.whereNull('departments.exp_date').orWhere('departments.exp_date', '>', self.db.raw('CURRENT_DATE'))
676
+ })
677
+ .andWhere('accounts.account_number', number);
678
+ if (records.length) {
679
+ retVal = records[0];
680
+ } else {
681
+ records = await this.db('customers')
682
+ .where('account_number', number);
683
+ if (records.length) {
684
+ retVal = Object.assign(
685
+ {},
686
+ records[0],
687
+ {
688
+ idt_allowed: false,
689
+ parent_account_idt_allowed: false,
690
+ billingEmailId: records[0].email,
691
+ }
692
+ );
693
+ }
694
+ }
695
+ } catch (e) {
696
+ throw e;
697
+ }
698
+ return retVal;
699
+ }
700
+
701
+ /**
702
+ *
703
+ * Search PI accounts by partial account number
704
+ * @param {string} number
705
+ * @returns{Promise<array>} account object(s)
706
+ * @memberof FAMISDb
707
+ */
708
+ async searchByAccountNumber(number) {
709
+ let records;
710
+ const self = this;
711
+
712
+ try {
713
+ const pis = await this.db('accounts')
714
+ .leftJoin('departments',
715
+ function() {
716
+ this
717
+ .on('accounts.department', '=', 'departments.dept')
718
+ .on('departments.part', '=', self.db.raw('?', [number.substring(0,2)]))
719
+ }
720
+ )
721
+ .leftJoin('account_balances',
722
+ function() {
723
+ this
724
+ .on('account_balances.account_number', '=', 'accounts.budget_account_number')
725
+ .on('account_balances.fiscal_year', '=', 'accounts.fiscal_year')
726
+ }
727
+ )
728
+ .select('accounts.*', 'departments.idt_email as billingEmailId', 'account_balances.balance')
729
+ .whereNull('departments.sub')
730
+ .andWhere(function() {
731
+ this.whereNull('departments.exp_date').orWhere('departments.exp_date', '>', self.db.raw('CURRENT_DATE'))
732
+ })
733
+ .where('accounts.account_number', 'ilike', `%${number}%`);
734
+ const customers = await this.db('customers')
735
+ .where('customers.account_number', 'ilike', `%${number}%`)
736
+ .whereNotIn('customers.account_number', pis.map(p => p.account_number));
737
+ records = [...customers, ...pis];
738
+ } catch (e) {
739
+ throw e;
740
+ }
741
+ return records;
742
+ }
743
+
744
+ /**
745
+ *
746
+ * Get PI Accounts by UIN
747
+ * @param {string} uin
748
+ * @returns{Promise<array>} account object array
749
+ * @memberof FAMISDb
750
+ */
751
+ async getAccountsByUin(uin) {
752
+ let records;
753
+ const self = this;
754
+
755
+ try {
756
+ records = await this.db('accounts')
757
+ .join('departments',
758
+ function() {
759
+ this
760
+ .on('accounts.department', '=', 'departments.dept')
761
+ .on('accounts.campus_code', '=', 'departments.part')
762
+ },
763
+ 'left'
764
+ )
765
+ .select('accounts.*', 'departments.idt_email as billingEmailId')
766
+ .whereNull('departments.sub')
767
+ .andWhere(function() {
768
+ this.whereNull('departments.exp_date').orWhere('departments.exp_date', '>', self.db.raw('CURRENT_DATE'))
769
+ })
770
+ .where('uin', uin);
771
+ } catch (e) {
772
+ throw e;
773
+ }
774
+ return records;
775
+ }
776
+
777
+ /**
778
+ *
779
+ * Get PI accounts by responsible UIN
780
+ * @param {string} uin
781
+ * @returns{Promise<array>} account object array
782
+ * @memberof FAMISDb
783
+ */
784
+ async getAccountsByResponsibleUin(uin) {
785
+ let records;
786
+ const self = this;
787
+
788
+ try {
789
+ records = await this.db('accounts')
790
+ .join('departments',
791
+ function() {
792
+ this
793
+ .on('accounts.department', '=', 'departments.dept')
794
+ .on('accounts.campus_code', '=', 'departments.part')
795
+ },
796
+ 'left'
797
+ )
798
+ .select('accounts.*', 'departments.idt_email as billingEmailId')
799
+ .whereNull('departments.sub')
800
+ .andWhere(function() {
801
+ this.whereNull('departments.exp_date').orWhere('departments.exp_date', '>', self.db.raw('CURRENT_DATE'))
802
+ })
803
+ .where('responsible_uin', uin);
804
+ } catch (e) {
805
+ throw e;
806
+ }
807
+ return records;
808
+ }
809
+
810
+ /**
811
+ *
812
+ * Get next FAMIS invoice number in sequence for specified invoice type
813
+ * @param {string} invoice
814
+ * @returns{Promise<string>} next invoice number in sequence
815
+ * @memberof FAMISDb
816
+ */
817
+ async getNextFAMISInvoiceNumber(type) {
818
+ let records;
819
+ let prefix;
820
+ let retVal;
821
+ famisInvoiceNumbers.forEach(f => {
822
+ if (f.aliases.includes(type)) {
823
+ prefix = f;
824
+ }
825
+ });
826
+ try {
827
+ retVal = `${prefix.prefix}${prefix.start}`;
828
+ records = await this.db('invoices').whereIn('type', prefix.aliases).orderBy('uid', 'desc');
829
+ if (records.length) {
830
+ const number = parseInt(records[0].famisInvoiceNumber.substring(1), 10) + 1;
831
+ retVal = `${prefix.prefix}${number}`;
832
+ }
833
+ } catch (e) {
834
+ throw e;
835
+ }
836
+ return retVal;
837
+ }
838
+
839
+ /**
840
+ *
841
+ * Get matching expense code for specified revenue code
842
+ * @param {string} revenue
843
+ * @returns{Promise<string>} expense code
844
+ * @memberof FAMISDb
845
+ */
846
+ async getExpenseCode(revenue) {
847
+ let records;
848
+ let retVal;
849
+ try {
850
+ records = await this.db('codes').where('revenue', revenue).orderBy('id', 'desc');
851
+ if (records.length) {
852
+ retVal = records[0].expense;
853
+ }
854
+ } catch (e) {
855
+ throw e;
856
+ }
857
+ return retVal;
858
+ }
859
+
860
+ /**
861
+ *
862
+ * Get revenue code object
863
+ * @param {string} revenue
864
+ * @returns{Promise<object>} revenue code object
865
+ * @memberof FAMISDb
866
+ */
867
+ async getRevenueCode(revenue) {
868
+ let records;
869
+ let retVal;
870
+ try {
871
+ records = await this.db('codes').where('revenue', revenue).orderBy('id', 'desc');
872
+ if (records.length) {
873
+ retVal = records[0];
874
+ }
875
+ } catch (e) {
876
+ throw e;
877
+ }
878
+ return retVal;
879
+ }
880
+
881
+ /**
882
+ *
883
+ * Check if expense code is within the allowable range for specified account and the specified fiscal year (defaults to current)
884
+ * @param {string} account
885
+ * @param {string} code
886
+ * @param {integer} fiscal
887
+ * @returns{Promise<boolean>} truthy value
888
+ * @memberof FAMISDb
889
+ */
890
+ async allowableExpenseCode(accountNumber, code, fiscal) {
891
+ let records;
892
+ let retVal = false;
893
+ let d = new Date();
894
+ let year = fiscal ? fiscal : this.getCurrentFiscalYear();
895
+ try {
896
+ records = await this.db('subcode_edits')
897
+ .select('allowed')
898
+ .where('campus_code', accountNumber.substring(0, 2))
899
+ .andWhere('account', accountNumber.substring(2, 8))
900
+ .andWhere('support_account', accountNumber.substring(8, 13))
901
+ .andWhere('fiscal_year', year)
902
+ .andWhereRaw('? BETWEEN low AND high', [parseInt(code)]);
903
+ if (records.length) {
904
+ retVal = records[0].allowed;
905
+ } else {
906
+ records = await this.db('abr_rules')
907
+ .select('abr_rules.*')
908
+ .join('accounts',
909
+ function() {
910
+ this
911
+ .on('accounts.abr_rule', '=', 'abr_rules.abr_rule')
912
+ .on('accounts.campus_code', '=', 'abr_rules.campus_code')
913
+ .on('accounts.fiscal_year', '=', 'abr_rules.fiscal_year')
914
+ },
915
+ 'left'
916
+ )
917
+ .where('accounts.account_number', accountNumber)
918
+ .andWhere('accounts.fiscal_year', year)
919
+ .andWhereRaw('? BETWEEN abr_rules.low AND abr_rules.high', [parseInt(code)]);
920
+ if (records.length) {
921
+ retVal = true;
922
+ }
923
+ }
924
+ } catch (e) {
925
+ throw e;
926
+ }
927
+ return retVal;
928
+ }
929
+
930
+ /**
931
+ *
932
+ * Get allowable expense code ranges for specified account
933
+ * @param {string} account
934
+ * @returns{Promise<boolean>} expense code range object(s)
935
+ * @memberof FAMISDb
936
+ */
937
+ async getAllowableExpenseCodes(accountNumber, fiscal) {
938
+ let abr;
939
+ let subcode;
940
+ let disallowed;
941
+ let retVal = {
942
+ allowed: [],
943
+ disallowed: [],
944
+ };
945
+ let year = fiscal ? fiscal : this.getCurrentFiscalYear();
946
+ try {
947
+ subcode = await this.db('subcode_edits')
948
+ .select('low', 'high')
949
+ .where('campus_code', accountNumber.substring(0, 2))
950
+ .andWhere('account', accountNumber.substring(2, 8))
951
+ .andWhere('support_account', accountNumber.substring(8, 13))
952
+ .andWhere('fiscal_year', year)
953
+ .andWhere('allowed', true)
954
+ .orderBy('low', 'asc');
955
+ disallowed = await this.db('subcode_edits')
956
+ .select('low', 'high')
957
+ .where('campus_code', accountNumber.substring(0, 2))
958
+ .andWhere('account', accountNumber.substring(2, 8))
959
+ .andWhere('support_account', accountNumber.substring(8, 13))
960
+ .andWhere('fiscal_year', year)
961
+ .andWhere('allowed', false)
962
+ .orderBy('low', 'asc');
963
+ abr = await this.db('abr_rules')
964
+ .select('abr_rules.low', 'abr_rules.high')
965
+ .join('accounts',
966
+ function() {
967
+ this
968
+ .on('accounts.abr_rule', '=', 'abr_rules.abr_rule')
969
+ .on('accounts.campus_code', '=', 'abr_rules.campus_code')
970
+ .on('accounts.fiscal_year', '=', 'abr_rules.fiscal_year')
971
+ },
972
+ 'left'
973
+ )
974
+ .where('accounts.account_number', accountNumber)
975
+ .andWhere('accounts.fiscal_year', year)
976
+ .orderBy('low', 'asc');
977
+ if (abr.length || subcode.length) {
978
+ const allowed = [...abr, ...subcode];
979
+ retVal = {
980
+ allowed,
981
+ disallowed,
982
+ };
983
+ }
984
+ } catch (e) {
985
+ throw e;
986
+ }
987
+ return retVal;
988
+ }
989
+
990
+ /**
991
+ *
992
+ * Get core by id
993
+ * @param {string} id
994
+ * @returns{Promise<object>} core object
995
+ * @memberof FAMISDb
996
+ */
997
+ async getCoreById(id) {
998
+ let records;
999
+ let retVal;
1000
+ try {
1001
+ const maxDates = this.db('core_accounts')
1002
+ .select(
1003
+ 'coreId'
1004
+ )
1005
+ .max('effective', {as: 'effective'})
1006
+ .groupBy('coreId')
1007
+ .where('effective', '<=', this.db.raw('now()'))
1008
+ .as("max_dates");
1009
+ const accounts = this.db('core_accounts')
1010
+ .select(
1011
+ 'core_accounts.coreId',
1012
+ 'core_accounts.account',
1013
+ 'core_accounts.effective',
1014
+ )
1015
+ .join(maxDates,
1016
+ function() {
1017
+ this
1018
+ .on('core_accounts.coreId', '=', 'max_dates.coreId')
1019
+ .andOn('core_accounts.effective', '=', 'max_dates.effective')
1020
+ }
1021
+ )
1022
+ .as("core_accounts");
1023
+ records = await this.db('cores')
1024
+ .select(
1025
+ 'cores.id',
1026
+ 'core_accounts.account',
1027
+ 'core_accounts.effective',
1028
+ 'cores.facility',
1029
+ 'cores.contact',
1030
+ 'cores.contactEmail',
1031
+ 'cores.systemId',
1032
+ 'system.name as partName',
1033
+ 'system.part as partNumber',
1034
+ 'cores.enabled',
1035
+ 'cores.deleted',
1036
+ 'cores.coreEmail',
1037
+ 'cores.corePhone',
1038
+ 'cores.coreAddress',
1039
+ 'cores.from_email',
1040
+ 'cores.invoice_email'
1041
+ )
1042
+ .join(accounts, 'cores.id', '=', 'core_accounts.coreId')
1043
+ .join('system', 'cores.systemId', '=', 'system.id')
1044
+ .where('cores.id', id)
1045
+ .orderBy('cores.id', 'desc');
1046
+ if (records.length) {
1047
+ retVal = records[0];
1048
+ }
1049
+ } catch (e) {
1050
+ throw e;
1051
+ }
1052
+ return retVal;
1053
+ }
1054
+
1055
+ /**
1056
+ *
1057
+ * Get core by account number
1058
+ * @param {string} account
1059
+ * @returns{Promise<object>} core object
1060
+ * @memberof FAMISDb
1061
+ */
1062
+ async getCoreByAccount(account) {
1063
+ let records;
1064
+ let retVal;
1065
+ try {
1066
+ records = await this.db('cores')
1067
+ .select(
1068
+ 'cores.id',
1069
+ 'core_accounts.account',
1070
+ 'core_accounts.effective',
1071
+ 'cores.facility',
1072
+ 'cores.contact',
1073
+ 'cores.contactEmail',
1074
+ 'cores.systemId',
1075
+ 'cores.enabled',
1076
+ 'cores.deleted',
1077
+ 'cores.coreEmail',
1078
+ 'cores.corePhone',
1079
+ 'cores.coreAddress',
1080
+ 'cores.from_email',
1081
+ 'cores.invoice_email'
1082
+ )
1083
+ .join('core_accounts', 'cores.id', '=', 'core_accounts.coreId')
1084
+ .where('core_accounts.account', account)
1085
+ .orderBy('cores.id', 'desc');
1086
+ if (records.length) {
1087
+ retVal = records[0];
1088
+ }
1089
+ } catch (e) {
1090
+ throw e;
1091
+ }
1092
+ return retVal;
1093
+ }
1094
+
1095
+ /**
1096
+ *
1097
+ * Get core current revenue account number
1098
+ * @param {string} coreId
1099
+ * @returns{Promise<object>} core object
1100
+ * @memberof FAMISDb
1101
+ */
1102
+ async getCoreCurrentAccount(coreId) {
1103
+ let records;
1104
+ let retVal;
1105
+ try {
1106
+ const maxDates = this.db('core_accounts')
1107
+ .select(
1108
+ 'coreId'
1109
+ )
1110
+ .max('effective', {as: 'effective'})
1111
+ .groupBy('coreId')
1112
+ .where('effective', '<=', this.db.raw('now()'))
1113
+ .andWhere('coreId', '=', coreId)
1114
+ .as("max_dates");
1115
+ const accounts = this.db('core_accounts')
1116
+ .select(
1117
+ 'core_accounts.coreId',
1118
+ 'core_accounts.account',
1119
+ 'core_accounts.effective',
1120
+ )
1121
+ .join(maxDates,
1122
+ function() {
1123
+ this
1124
+ .on('core_accounts.coreId', '=', 'max_dates.coreId')
1125
+ .andOn('core_accounts.effective', '=', 'max_dates.effective')
1126
+ }
1127
+ )
1128
+ .as("core_accounts");
1129
+ records = await this.db('cores')
1130
+ .select(
1131
+ 'cores.id',
1132
+ 'core_accounts.account',
1133
+ 'core_accounts.effective',
1134
+ 'cores.facility',
1135
+ 'cores.contact',
1136
+ 'cores.contactEmail',
1137
+ 'cores.systemId',
1138
+ 'cores.enabled',
1139
+ 'cores.deleted',
1140
+ 'cores.coreEmail',
1141
+ 'cores.corePhone',
1142
+ 'cores.coreAddress',
1143
+ 'cores.from_email',
1144
+ 'cores.invoice_email'
1145
+ )
1146
+ .join(accounts, 'cores.id', '=', 'core_accounts.coreId')
1147
+ .orderBy('cores.id', 'desc');
1148
+ if (records.length) {
1149
+ retVal = records[0];
1150
+ }
1151
+ } catch (e) {
1152
+ throw e;
1153
+ }
1154
+ return retVal;
1155
+ }
1156
+
1157
+ /**
1158
+ *
1159
+ * Get system part by ID
1160
+ * @param {number} id
1161
+ * @returns{Promise<object>} system part object
1162
+ * @memberof FAMISDb
1163
+ */
1164
+ async getSystemById(id) {
1165
+ let records;
1166
+ let retVal;
1167
+ try {
1168
+ records = await this.db('system').where('id', id).orderBy('id', 'desc');
1169
+ if (records.length) {
1170
+ retVal = records[0];
1171
+ }
1172
+ } catch (e) {
1173
+ throw e;
1174
+ }
1175
+ return retVal;
1176
+ }
1177
+
1178
+ /**
1179
+ *
1180
+ * Get system part by two digit part number
1181
+ * @param {string} number
1182
+ * @returns{Promise<object>} system part object
1183
+ * @memberof FAMISDb
1184
+ */
1185
+ async getSystemByPartNumber(number) {
1186
+ let records;
1187
+ let retVal;
1188
+ try {
1189
+ records = await this.db('system').where('part', number).orderBy('id', 'desc');
1190
+ if (records.length) {
1191
+ retVal = records[0];
1192
+ }
1193
+ } catch (e) {
1194
+ throw e;
1195
+ }
1196
+ return retVal;
1197
+ }
1198
+
1199
+ /**
1200
+ *
1201
+ * Get all enabled cores
1202
+ * @param {string} date
1203
+ * @returns{Promise<array>} core objects
1204
+ * @memberof FAMISDb
1205
+ */
1206
+ async getEnabledCores(date) {
1207
+ let records;
1208
+ let retVal = [];
1209
+ try {
1210
+ const maxDates = this.db('core_accounts')
1211
+ .select(
1212
+ 'coreId'
1213
+ )
1214
+ .max('effective', {as: 'effective'})
1215
+ .groupBy('coreId')
1216
+ .where('effective', '<=', date ? date : this.db.raw('now()'))
1217
+ .as("max_dates");
1218
+ const accounts = this.db('core_accounts')
1219
+ .select(
1220
+ 'core_accounts.coreId',
1221
+ 'core_accounts.account',
1222
+ 'core_accounts.effective',
1223
+ )
1224
+ .join(maxDates,
1225
+ function() {
1226
+ this
1227
+ .on('core_accounts.coreId', '=', 'max_dates.coreId')
1228
+ .andOn('core_accounts.effective', '=', 'max_dates.effective')
1229
+ }
1230
+ )
1231
+ .as("core_accounts");
1232
+ records = await this.db('cores')
1233
+ .select(
1234
+ 'cores.id',
1235
+ 'core_accounts.account',
1236
+ 'core_accounts.effective',
1237
+ 'cores.facility',
1238
+ 'cores.contact',
1239
+ 'cores.contactEmail',
1240
+ 'cores.systemId',
1241
+ 'cores.enabled',
1242
+ 'cores.deleted',
1243
+ 'cores.coreEmail',
1244
+ 'cores.corePhone',
1245
+ 'cores.coreAddress',
1246
+ 'cores.from_email',
1247
+ 'cores.invoice_email'
1248
+ )
1249
+ .join(accounts, 'cores.id', '=', 'core_accounts.coreId')
1250
+ .where('enabled', '1')
1251
+ .orderBy('cores.id', 'desc');
1252
+ if (records.length) {
1253
+ retVal = records;
1254
+ }
1255
+ } catch (e) {
1256
+ throw e;
1257
+ }
1258
+ return retVal;
1259
+ }
1260
+
1261
+ /**
1262
+ *
1263
+ * Get all cores
1264
+ * @returns{Promise<array>} core objects
1265
+ * @memberof FAMISDb
1266
+ */
1267
+ async getAllCores() {
1268
+ let records;
1269
+ let retVal = [];
1270
+ try {
1271
+ records = await this.db('cores').orderBy('id', 'asc');
1272
+ if (records.length) {
1273
+ retVal = records;
1274
+ }
1275
+ } catch (e) {
1276
+ throw e;
1277
+ }
1278
+ return retVal;
1279
+ }
1280
+
1281
+ /**
1282
+ *
1283
+ * Get a core's users by core ID
1284
+ * @param {number} coreId
1285
+ * @returns{Promise<array>} user objects
1286
+ * @memberof FAMISDb
1287
+ */
1288
+ async getCoreUsers(coreId) {
1289
+ let retVal;
1290
+ try {
1291
+ retVal = await this.db('user_cores')
1292
+ .join('users', 'user_cores.userId', '=', 'users.id')
1293
+ .where('coreId', coreId)
1294
+ .select(
1295
+ 'users.*',
1296
+ 'user_cores.id as userCoreId',
1297
+ 'user_cores.coreId',
1298
+ 'user_cores.email',
1299
+ );
1300
+ } catch (e) {
1301
+ throw e;
1302
+ }
1303
+ return retVal;
1304
+ }
1305
+
1306
+ /**
1307
+ *
1308
+ * Get a user's cores they manage
1309
+ * @param {string} userId
1310
+ * @returns{Promise<array>} core objects
1311
+ * @memberof FAMISDb
1312
+ */
1313
+ async getUserCores(userId) {
1314
+ let retVal;
1315
+ try {
1316
+ retVal = await this.db('user_cores')
1317
+ .join('cores', 'user_cores.coreId', '=', 'cores.id')
1318
+ .join('users', 'user_cores.userId', '=', 'users.id')
1319
+ .where('users.userId', userId)
1320
+ .select(
1321
+ 'cores.*',
1322
+ 'user_cores.id as userCoreId',
1323
+ 'user_cores.userId',
1324
+ 'user_cores.email',
1325
+ );
1326
+ } catch (e) {
1327
+ throw e;
1328
+ }
1329
+ return retVal;
1330
+ }
1331
+
1332
+ /**
1333
+ *
1334
+ * Get a system part's users by system ID
1335
+ * @param {number} systemId
1336
+ * @returns{Promise<array>} user objects
1337
+ * @memberof FAMISDb
1338
+ */
1339
+ async getSystemUsers(systemId) {
1340
+ let retVal;
1341
+ try {
1342
+ retVal = await this.db('user_systems')
1343
+ .join('users', 'user_systems.userId', '=', 'users.id')
1344
+ .where('systemId', systemId)
1345
+ .select(
1346
+ 'users.*',
1347
+ 'user_systems.id as userSystemId',
1348
+ 'user_systems.systemId',
1349
+ 'user_systems.email',
1350
+ );
1351
+ } catch (e) {
1352
+ throw e;
1353
+ }
1354
+ return retVal;
1355
+ }
1356
+
1357
+ /**
1358
+ *
1359
+ * Get a user's system parts they manage
1360
+ * @param {*} userId
1361
+ * @returns{Promise<object>} system objects
1362
+ * @memberof FAMISDb
1363
+ */
1364
+ async getUserSystemParts(userId) {
1365
+ let records;
1366
+ let retVal;
1367
+ try {
1368
+ retVal = await this.db('user_systems')
1369
+ .join('system', 'user_systems.systemId', '=', 'system.id')
1370
+ .join('users', 'user_systems.userId', '=', 'users.id')
1371
+ .where('users.userId', userId)
1372
+ .select(
1373
+ 'system.*',
1374
+ 'user_systems.id as userSystemId',
1375
+ 'user_systems.userId',
1376
+ 'user_systems.email',
1377
+ );
1378
+ } catch (e) {
1379
+ throw e;
1380
+ }
1381
+ return retVal;
1382
+ }
1383
+
1384
+ /**
1385
+ *
1386
+ * Get all system parts
1387
+ * @returns{Promise<object>} system objects
1388
+ * @memberof FAMISDb
1389
+ */
1390
+ async getAllSystemParts() {
1391
+ let records;
1392
+ let retVal;
1393
+ try {
1394
+ retVal = await this.db('system').orderBy('id', 'asc');
1395
+ } catch (e) {
1396
+ throw e;
1397
+ }
1398
+ return retVal;
1399
+ }
1400
+
1401
+ /**
1402
+ *
1403
+ * Get user
1404
+ * @param {string} userId
1405
+ * @returns{Promise<object>} user object
1406
+ * @memberof FAMISDb
1407
+ */
1408
+ async getUser(userId) {
1409
+ let records;
1410
+ let retVal;
1411
+ try {
1412
+ records = await this.db('users').where('userId', userId);
1413
+ if (records.length) {
1414
+ retVal = records[0];
1415
+ retVal.cores = await this.getUserCores(userId);
1416
+ retVal.systems = await this.getUserSystemParts(userId);
1417
+ }
1418
+ } catch (e) {
1419
+ throw e;
1420
+ }
1421
+ return retVal;
1422
+ }
1423
+
1424
+ /**
1425
+ *
1426
+ * Get customer by customer account number
1427
+ * @param {string} accountNumber
1428
+ * @param {string} campusCode
1429
+ * @returns{Promise<object>} customer account object
1430
+ * @memberof FAMISDb
1431
+ */
1432
+ async getCustomerNumber(accountNumber, campusCode) {
1433
+ let records;
1434
+ let retVal;
1435
+ const code = pad(campusCode, 2);
1436
+
1437
+ try {
1438
+ records = await this.db('customers')
1439
+ .where('uid', `${code}${accountNumber}`);
1440
+ if (records.length) {
1441
+ retVal = records[0];
1442
+ }
1443
+ } catch (e) {
1444
+ throw e;
1445
+ }
1446
+ return retVal;
1447
+ }
1448
+
1449
+ /**
1450
+ *
1451
+ * Get current fiscal year
1452
+ * @returns{<integer>} fiscal year
1453
+ * @memberof FAMISDb
1454
+ */
1455
+ getCurrentFiscalYear() {
1456
+ let year;
1457
+ let today = new Date();
1458
+ if ((today.getMonth() + 1) >= 9) {
1459
+ year = today.getFullYear() + 1;
1460
+ } else {
1461
+ year = today.getFullYear();
1462
+ }
1463
+ return year;
1464
+ }
1465
+
1466
+ /**
1467
+ *
1468
+ * Return fingerprint of invoice
1469
+ * @param {object} invoice json object
1470
+ * @returns{<string>} fingerprint
1471
+ * @memberof FAMISDb
1472
+ */
1473
+ getInvoiceFingerPrint(invoice) {
1474
+ const fingerPrint = revisionHash(
1475
+ JSON.stringify(
1476
+ sortObjectKeys(invoice),
1477
+ (k, v) => undefined ? "undef" : v
1478
+ )
1479
+ );
1480
+ return fingerPrint;
1481
+ }
1482
+
1483
+ /**
1484
+ *
1485
+ * Return formatted account number
1486
+ * @param {string} accountNumber unformatted 13 digit famis account number
1487
+ * @returns{<string>} formatted 13 digits famis account number
1488
+ * @memberof FAMISDb
1489
+ */
1490
+ formatAccountNumber(accountNumber) {
1491
+ const formatted = accountNumber.replace(/(\d{2})(\d{6})(\d{5})/, "$1-$2-$3");
1492
+
1493
+ return formatted;
1494
+ }
1495
+ }
1496
+
1497
+ module.exports = FAMISDb;