@tomei/rental 0.9.3 → 0.9.5

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 (51) hide show
  1. package/.commitlintrc.json +22 -22
  2. package/.eslintrc +16 -16
  3. package/.eslintrc.js +35 -35
  4. package/.gitlab-ci.yml +16 -16
  5. package/.husky/commit-msg +15 -15
  6. package/.husky/pre-commit +7 -7
  7. package/.prettierrc +4 -4
  8. package/Jenkinsfile +51 -51
  9. package/README.md +8 -8
  10. package/dist/src/components/rental/rental.js +30 -16
  11. package/dist/src/components/rental/rental.js.map +1 -1
  12. package/dist/tsconfig.tsbuildinfo +1 -1
  13. package/jest.config.js +10 -10
  14. package/migrations/booking-table-migration.js +79 -79
  15. package/migrations/joint-hirer-table-migration.js +52 -52
  16. package/migrations/rental-aggrement-table-migration.js +22 -22
  17. package/migrations/rental-price-table-migration.js +32 -32
  18. package/migrations/rental-table-migrations.js +96 -96
  19. package/package.json +75 -75
  20. package/sonar-project.properties +12 -12
  21. package/src/components/agreement/agreement.repository.ts +54 -54
  22. package/src/components/agreement/agreement.ts +43 -43
  23. package/src/components/booking/booking.repository.ts +51 -51
  24. package/src/components/booking/booking.ts +291 -291
  25. package/src/components/joint-hirer/joint-hirer.repository.ts +54 -54
  26. package/src/components/rental/rental.repository.ts +51 -51
  27. package/src/components/rental/rental.ts +720 -706
  28. package/src/components/rental-price/rental-price.repository.ts +54 -54
  29. package/src/components/rental-price/rental-price.ts +100 -100
  30. package/src/database.ts +27 -27
  31. package/src/enum/account-type.enum.ts +4 -4
  32. package/src/enum/booking.enum.ts +5 -5
  33. package/src/enum/index.ts +5 -5
  34. package/src/enum/rental-status.enum.ts +39 -39
  35. package/src/index.ts +28 -28
  36. package/src/interfaces/agreement-attr.interface.ts +4 -4
  37. package/src/interfaces/booking-attr.interface.ts +19 -19
  38. package/src/interfaces/index.ts +13 -13
  39. package/src/interfaces/joint-hirer-attr.interface.ts +10 -10
  40. package/src/interfaces/rental-attr.interface.ts +25 -25
  41. package/src/interfaces/rental-find-all-search-attr.interface.ts +11 -11
  42. package/src/interfaces/rental-price-attr.interface.ts +7 -7
  43. package/src/models/agreement.entity.ts +26 -26
  44. package/src/models/booking.entity.ts +105 -105
  45. package/src/models/index.ts +13 -13
  46. package/src/models/joint-hirer.entity.ts +63 -63
  47. package/src/models/rental-price.entity.ts +38 -38
  48. package/src/models/rental.entity.ts +133 -133
  49. package/tomei-rental-0.9.4.tgz +0 -0
  50. package/tsconfig.build.json +5 -5
  51. package/tsconfig.json +23 -23
@@ -1,706 +1,720 @@
1
- import { IRentalAttr } from '../../interfaces/rental-attr.interface';
2
- import { RentalStatusEnum } from '../../enum/rental-status.enum';
3
- import { RentalRepository } from './rental.repository';
4
- import { ClassError, ObjectBase } from '@tomei/general';
5
- import { ApplicationConfig } from '@tomei/config';
6
- import { LoginUser } from '@tomei/sso';
7
- import { RentalPrice } from '../rental-price/rental-price';
8
- import { Op, QueryTypes } from 'sequelize';
9
- import { ActionEnum, Activity } from '@tomei/activity-history';
10
- import { IRentalFindAllSearchAttr } from '../../interfaces/rental-find-all-search-attr.interface';
11
- import { RentalAccountTypeEnum } from '../../enum/account-type.enum';
12
- import { JointHirer } from '../joint-hirer/joint-hirer';
13
- import { JointHirerModel } from '../../models/joint-hirer.entity';
14
- import { AgreementRepository } from '../agreement/agreement.repository';
15
- import * as rentalDb from '../../database';
16
- import { RentalModel } from '../../models/rental.entity';
17
- import { JointHirerRepository } from '../joint-hirer/joint-hirer.repository';
18
-
19
- export class Rental extends ObjectBase {
20
- ObjectId: string;
21
- ObjectName: string;
22
- ObjectType = 'Rental';
23
- TableName: string;
24
- CustomerId: string;
25
- CustomerType: string;
26
- ItemId: string;
27
- ItemType: string;
28
- PriceId: string;
29
- StartDateTime: Date;
30
- EndDateTime: Date;
31
- CancelRemarks: string;
32
- TerminateRemarks: string;
33
- AgreementNo: string;
34
- AccountType: RentalAccountTypeEnum;
35
- JointHirers: JointHirer[] = [];
36
- protected _Status: RentalStatusEnum;
37
- protected _EscheatmentYN: string = 'N';
38
- protected _CreatedById: string;
39
- protected _CreatedAt: Date;
40
- protected _UpdatedById: string;
41
- protected _UpdatedAt: Date;
42
- protected static _Repo = new RentalRepository();
43
- protected static _AgreementRepo = new AgreementRepository();
44
- protected static _JointHirerRepo = new JointHirerRepository();
45
-
46
- get RentalId(): string {
47
- return this.ObjectId;
48
- }
49
-
50
- set RentalId(value: string) {
51
- this.ObjectId = value;
52
- }
53
-
54
- get Status(): RentalStatusEnum {
55
- return this._Status;
56
- }
57
-
58
- get EscheatmentYN(): string {
59
- return this._EscheatmentYN;
60
- }
61
-
62
- get CreatedById(): string {
63
- return this._CreatedById;
64
- }
65
-
66
- get CreatedAt(): Date {
67
- return this._CreatedAt;
68
- }
69
-
70
- get UpdatedById(): string {
71
- return this._UpdatedById;
72
- }
73
-
74
- get UpdatedAt(): Date {
75
- return this._UpdatedAt;
76
- }
77
-
78
- private setTerminated() {
79
- this._Status = RentalStatusEnum.TERMINATED;
80
- }
81
-
82
- protected constructor(rentalAttr?: IRentalAttr) {
83
- super();
84
- if (rentalAttr) {
85
- this.RentalId = rentalAttr.RentalId;
86
- this.CustomerId = rentalAttr.CustomerId;
87
- this.CustomerType = rentalAttr.CustomerType;
88
- this.ItemId = rentalAttr.ItemId;
89
- this.ItemType = rentalAttr.ItemType;
90
- this.PriceId = rentalAttr.PriceId;
91
- this.StartDateTime = rentalAttr.StartDateTime;
92
- this.EndDateTime = rentalAttr.EndDateTime;
93
- this.CancelRemarks = rentalAttr.CancelRemarks;
94
- this.TerminateRemarks = rentalAttr.TerminateRemarks;
95
- this.AgreementNo = rentalAttr.AgreementNo;
96
- this.AccountType = rentalAttr.AccountType;
97
- this._Status = rentalAttr.Status;
98
- this._EscheatmentYN = rentalAttr.EscheatmentYN;
99
- this._CreatedById = rentalAttr.CreatedById;
100
- this._CreatedAt = rentalAttr.CreatedAt;
101
- this._UpdatedById = rentalAttr.UpdatedById;
102
- this._UpdatedAt = rentalAttr.UpdatedAt;
103
- }
104
- }
105
-
106
- public static async init(dbTransaction?: any, rentalId?: string) {
107
- try {
108
- if (rentalId) {
109
- const rental = await Rental._Repo.findByPk(rentalId, dbTransaction);
110
- if (rental) {
111
- return new Rental(rental);
112
- } else {
113
- throw new ClassError('Rental', 'RentalErrMsg00', 'Rental Not Found');
114
- }
115
- }
116
- return new Rental();
117
- } catch (error) {
118
- throw new ClassError(
119
- 'Rental',
120
- 'RentalErrMsg00',
121
- 'Failed To Initialize Price',
122
- );
123
- }
124
- }
125
-
126
- /**
127
- * Create a new Rental record.
128
- * @param {RentalPrice} rentalPrice - The rental pricing information.
129
- * @param {LoginUser} loginUser - The user initiating the creation.
130
- * @param {any} [dbTransaction] - Optional database transaction for atomic operations.
131
- * @throws {ClassError} Throws an error if:
132
- * 1. loginUser does not have 'Rental - Create' privilege.
133
- * 2. Rental item is not available at the current date.
134
- * @returns {Promise<any>} A Promise resolving to the created rental record.
135
- */
136
- public async create(
137
- rentalPrice: RentalPrice,
138
- loginUser: LoginUser,
139
- jointHirers?: JointHirer[],
140
- dbTransaction?: any,
141
- ): Promise<any> {
142
- try {
143
- /*Part 1: Check Privilege*/
144
- const systemCode =
145
- ApplicationConfig.getComponentConfigValue('system-code');
146
- const isPrivileged = await loginUser.checkPrivileges(
147
- systemCode,
148
- 'Rental - Create',
149
- );
150
-
151
- if (!isPrivileged) {
152
- throw new ClassError(
153
- 'Rental',
154
- 'RentalErrMsg01',
155
- "You do not have 'Rental - Create' privilege.",
156
- );
157
- }
158
-
159
- /*Part 2: Make Sure Rental Item Available*/
160
- const isItemAvailable = await Rental.isItemAvailable(
161
- this.ItemId,
162
- this.ItemType,
163
- this.StartDateTime,
164
- this.EndDateTime,
165
- dbTransaction,
166
- );
167
-
168
- if (!isItemAvailable) {
169
- throw new ClassError(
170
- 'Rental',
171
- 'RentalErrMsg02',
172
- 'Rental Item is not available at current date.',
173
- );
174
- }
175
-
176
- // Part 3: Create Rental Agreement Record
177
- // Call Rental._AgreementRepo create method by passing:
178
- // AgreementNo: this.AgreementNo
179
- // Status: "Not Generated"
180
- // dbTransaction
181
- await Rental._AgreementRepo.create(
182
- {
183
- AgreementNo: this.AgreementNo,
184
- Status: 'Not Generated',
185
- },
186
- {
187
- transaction: dbTransaction,
188
- },
189
- );
190
-
191
- /*Part 4: Insert Rental & The Agreed Rental Price*/
192
- await rentalPrice.create(loginUser, dbTransaction);
193
-
194
- this.PriceId = rentalPrice.PriceId;
195
-
196
- this.RentalId = this.createId();
197
- if (!this.Status) {
198
- this._Status = RentalStatusEnum.ACTIVE;
199
- }
200
- this._CreatedById = loginUser.ObjectId;
201
- this._UpdatedById = loginUser.ObjectId;
202
- this._CreatedAt = new Date();
203
- this._UpdatedAt = new Date();
204
-
205
- const data = {
206
- RentalId: this.RentalId,
207
- CustomerId: this.CustomerId,
208
- CustomerType: this.CustomerType,
209
- ItemId: this.ItemId,
210
- ItemType: this.ItemType,
211
- PriceId: this.PriceId,
212
- StartDateTime: this.StartDateTime,
213
- EndDateTime: this.EndDateTime,
214
- CancelRemarks: this.CancelRemarks,
215
- TerminateRemarks: this.TerminateRemarks,
216
- AgreementNo: this.AgreementNo,
217
- AccountType: this.AccountType,
218
- Status: this.Status,
219
- EscheatmentYN: this.EscheatmentYN,
220
- CreatedById: this.CreatedById,
221
- CreatedAt: this.CreatedAt,
222
- UpdatedById: this.UpdatedById,
223
- UpdatedAt: this.UpdatedAt,
224
- };
225
-
226
- await Rental._Repo.create(data, {
227
- transaction: dbTransaction,
228
- });
229
-
230
- //For every data inside Param.jointHirers, update the rentalId and call jointHirer.create
231
- if (jointHirers) {
232
- for (let i = 0; i < jointHirers.length; i++) {
233
- jointHirers[i].RentalId = this.RentalId;
234
- await jointHirers[i].create(loginUser, dbTransaction);
235
- this.JointHirers.push(jointHirers[i]);
236
- }
237
- }
238
-
239
- /*Part 5: Record Create Rental Activity*/
240
- const activity = new Activity();
241
- activity.ActivityId = activity.createId();
242
- activity.Action = ActionEnum.ADD;
243
- activity.Description = 'Add Rental';
244
- activity.EntityType = 'Rental';
245
- activity.EntityId = this.RentalId;
246
- activity.EntityValueBefore = JSON.stringify({});
247
- activity.EntityValueAfter = JSON.stringify(data);
248
- await activity.create(loginUser.ObjectId, dbTransaction);
249
-
250
- /*Part 6: Return Result*/
251
- return this;
252
- } catch (error) {
253
- throw error;
254
- }
255
- }
256
-
257
- public static async isItemAvailable(
258
- itemId: string,
259
- itemType: string,
260
- startDateTime: Date,
261
- endDateTime: Date,
262
- dbTransaction?: any,
263
- ) {
264
- try {
265
- const item = await Rental._Repo.findOne({
266
- where: {
267
- ItemId: itemId,
268
- ItemType: itemType,
269
- StartDateTime: {
270
- [Op.lte]: endDateTime,
271
- },
272
- EndDateTime: {
273
- [Op.gte]: startDateTime,
274
- },
275
- },
276
- transaction: dbTransaction,
277
- });
278
-
279
- if (item) {
280
- return false;
281
- } else {
282
- return true;
283
- }
284
- } catch (error) {
285
- throw error;
286
- }
287
- }
288
-
289
- public static async findAll(
290
- loginUser: LoginUser,
291
- dbTransaction: any,
292
- page?: number,
293
- row?: number,
294
- search?: IRentalFindAllSearchAttr,
295
- ) {
296
- try {
297
- const systemCode = await ApplicationConfig.getComponentConfigValue(
298
- 'system-code',
299
- );
300
-
301
- const isPrivileged = await loginUser.checkPrivileges(
302
- systemCode,
303
- 'Rental - View',
304
- );
305
-
306
- if (!isPrivileged) {
307
- throw new ClassError(
308
- 'Rental',
309
- 'RentalErrMsg01',
310
- "You do not have 'Rental - View' privilege.",
311
- );
312
- }
313
-
314
- const queryObj: any = {};
315
-
316
- let options: any = {
317
- transaction: dbTransaction,
318
- order: [['CreatedAt', 'DESC']],
319
- };
320
-
321
- if (page && row) {
322
- options = {
323
- ...options,
324
- limit: row,
325
- offset: row * (page - 1),
326
- };
327
- }
328
-
329
- if (search) {
330
- Object.entries(search).forEach(([key, value]) => {
331
- if (key === 'StartDateTime') {
332
- queryObj[key] = {
333
- [Op.gte]: value,
334
- };
335
- } else if (key === 'EndDateTime') {
336
- queryObj[key] = {
337
- [Op.lte]: value,
338
- };
339
- } else if (key === 'CustomerId') {
340
- queryObj[key] = {
341
- [Op.substring]: value,
342
- };
343
-
344
- options.include = [
345
- {
346
- model: JointHirerModel,
347
- required: false,
348
- where: {
349
- CustomerId: {
350
- [Op.substring]: value,
351
- },
352
- },
353
- },
354
- ];
355
- } else {
356
- queryObj[key] = {
357
- [Op.substring]: value,
358
- };
359
- }
360
- });
361
-
362
- options = {
363
- ...options,
364
- where: queryObj,
365
- };
366
- }
367
-
368
- return await Rental._Repo.findAndCountAll(options);
369
- } catch (err) {
370
- throw err;
371
- }
372
- }
373
-
374
- public static async checkActiveByItemId(
375
- loginUser: LoginUser,
376
- itemId: string,
377
- itemType: string,
378
- dbTransaction?: any,
379
- ) {
380
- try {
381
- const systemCode = await ApplicationConfig.getComponentConfigValue(
382
- 'system-code',
383
- );
384
-
385
- const isPrivileged = await loginUser.checkPrivileges(
386
- systemCode,
387
- 'Rental - View',
388
- );
389
-
390
- if (!isPrivileged) {
391
- throw new ClassError(
392
- 'Rental',
393
- 'RentalErrMsg01',
394
- "You do not have 'Rental - View' privilege.",
395
- );
396
- }
397
-
398
- const queryObj: any = {
399
- ItemId: itemId,
400
- ItemType: itemType,
401
- Status: RentalStatusEnum.ACTIVE,
402
- };
403
-
404
- const options: any = {
405
- transaction: dbTransaction,
406
- where: queryObj,
407
- };
408
-
409
- const rental = await Rental._Repo.findOne(options);
410
-
411
- if (rental) {
412
- return true;
413
- } else {
414
- return false;
415
- }
416
- } catch (err) {
417
- throw err;
418
- }
419
- }
420
-
421
- /**
422
- * Sets the StartDateTime property of the Rental class as custom setter.
423
- * @param {Date} startDateTime - The start date and time of the rental.
424
- * @throws {ClassError} Throws an error if:
425
- * 1. startDateTime is a past date.
426
- * 2. startDateTime is more than the EndDateTime.
427
- * @returns {void}
428
- */
429
- setStartDateTime(startDateTime: Date): void {
430
- const startDateTimeObject = new Date(startDateTime);
431
- startDateTimeObject.setHours(0, 0, 0, 0);
432
-
433
- /*Part 1: Make Sure Future Date Time*/
434
- if (startDateTimeObject < new Date(new Date().setHours(0, 0, 0, 0))) {
435
- throw new ClassError(
436
- 'Rental',
437
- 'RentalErrMsg02',
438
- 'StartDateTime cannot be a past datetime.',
439
- );
440
- }
441
-
442
- /*Part 2: Make Sure Less Than End Date Time*/
443
- if (this.EndDateTime && startDateTimeObject > this.EndDateTime) {
444
- throw new ClassError(
445
- 'Rental',
446
- 'RentalErrMsg03',
447
- 'StartDateTime cannot be more than EndDateTime.',
448
- );
449
- }
450
-
451
- /*Part 3: Set Status Whether Reserved or Active*/
452
- if (startDateTimeObject > new Date(new Date().setHours(0, 0, 0, 0))) {
453
- this._Status = RentalStatusEnum.RESERVED;
454
- } else {
455
- this._Status = RentalStatusEnum.ACTIVE;
456
- }
457
- }
458
-
459
- public async periodEndProcess(
460
- loginUser: LoginUser,
461
- dbTransaction: any,
462
- stockInventory: any,
463
- ) {
464
- try {
465
- // Privilege Checking
466
- const systemCode = await ApplicationConfig.getComponentConfigValue(
467
- 'system-code',
468
- );
469
-
470
- const isPrivileged = await loginUser.checkPrivileges(
471
- systemCode,
472
- 'Rental – PeriodEndProcess',
473
- );
474
-
475
- if (!isPrivileged) {
476
- throw new ClassError(
477
- 'Rental',
478
- 'RentalErrMsg04',
479
- "You do not have 'Rental - PeriodEndProcess' privilege.",
480
- );
481
- }
482
-
483
- // Validate Existing Rental
484
- if (this.AgreementNo === undefined || this.AgreementNo === null) {
485
- throw new ClassError(
486
- 'Rental',
487
- 'RentalErrMsg05',
488
- 'Rental must be existing rental.',
489
- );
490
- }
491
-
492
- // Validate Rental End Period
493
- if (this.EndDateTime === new Date(new Date().setHours(0, 0, 0, 0))) {
494
- throw new ClassError(
495
- 'Rental',
496
- 'RentalErrMsg06',
497
- 'Rental period is not ending today.',
498
- );
499
- }
500
-
501
- // Mark Rental Item as Available
502
- await stockInventory.setAvailable(loginUser, dbTransaction);
503
-
504
- // Capture Record Info Before Changes
505
- const entityValueBefore = {
506
- RentalId: this.RentalId,
507
- CustomerId: this.CustomerId,
508
- CustomerType: this.CustomerType,
509
- ItemId: this.ItemId,
510
- ItemType: this.ItemType,
511
- PriceId: this.PriceId,
512
- StartDateTime: this.StartDateTime,
513
- EndDateTime: this.EndDateTime,
514
- CancelRemarks: this.CancelRemarks,
515
- TerminateRemarks: this.TerminateRemarks,
516
- AgreementNo: this.AgreementNo,
517
- AccountType: this.AccountType,
518
- Status: this.Status,
519
- EscheatmentYN: this.EscheatmentYN,
520
- CreatedById: this.CreatedById,
521
- CreatedAt: this.CreatedAt,
522
- UpdatedById: this.UpdatedById,
523
- UpdatedAt: this.UpdatedAt,
524
- };
525
-
526
- // Mark Rental as Terminated and Capture Updater Info
527
- this.setTerminated();
528
- this._UpdatedById = loginUser.ObjectId;
529
- this._UpdatedAt = new Date();
530
-
531
- // Capture Record Info after Changes
532
- const entityValueAfter = {
533
- RentalId: this.RentalId,
534
- CustomerId: this.CustomerId,
535
- CustomerType: this.CustomerType,
536
- ItemId: this.ItemId,
537
- ItemType: this.ItemType,
538
- PriceId: this.PriceId,
539
- StartDateTime: this.StartDateTime,
540
- EndDateTime: this.EndDateTime,
541
- CancelRemarks: this.CancelRemarks,
542
- TerminateRemarks: this.TerminateRemarks,
543
- AgreementNo: this.AgreementNo,
544
- AccountType: this.AccountType,
545
- Status: this.Status,
546
- EscheatmentYN: this.EscheatmentYN,
547
- CreatedById: this.CreatedById,
548
- CreatedAt: this.CreatedAt,
549
- UpdatedById: this.UpdatedById,
550
- UpdatedAt: this.UpdatedAt,
551
- };
552
-
553
- // Record the Update Activity
554
- const activity = new Activity();
555
- activity.ActivityId = activity.createId();
556
- activity.Action = ActionEnum.UPDATE;
557
- activity.Description = 'Set Rental as Terminated';
558
- activity.EntityType = 'Rental';
559
- activity.EntityId = this.RentalId;
560
- activity.EntityValueBefore = JSON.stringify(entityValueBefore);
561
- activity.EntityValueAfter = JSON.stringify(entityValueAfter);
562
- await activity.create(loginUser.ObjectId, dbTransaction);
563
-
564
- return this;
565
- } catch (err) {
566
- throw err;
567
- }
568
- }
569
-
570
- async getCustomerActiveRentals(
571
- loginUser: LoginUser,
572
- dbTransaction: any,
573
- CustomerId: string,
574
- ): Promise<IRentalAttr[]> {
575
- try {
576
- // Part 1: Privilege Checking
577
- // Call loginUser.checkPrivileges() by passing:
578
- // SystemCode: <get_from_app_config>
579
- // PrivilegeCode: "RENTAL_VIEW"
580
- const systemCode =
581
- ApplicationConfig.getComponentConfigValue('system-code');
582
- const isPrivileged = loginUser.checkPrivileges(systemCode, 'RENTAL_VIEW');
583
-
584
- if (!isPrivileged) {
585
- throw new ClassError(
586
- 'Rental',
587
- 'RentalErrMsg01',
588
- "You do not have 'Rental - View' privilege.",
589
- );
590
- }
591
-
592
- // Part 2: Retrieve Rentals and Returns
593
- // Call Rental._Repo findAll method by passing:
594
- // where:
595
- // Status: "Active"
596
- // [Op.OR]:
597
- // CustomerId: Params.CustomerId
598
- // '$JointHirers.CustomerId$': Params.CustomerId
599
- // include:
600
- // model: JointHirerModel
601
- // attributes: []
602
- const query = `
603
- SELECT
604
- r.*
605
- FROM
606
- rental_Rental r
607
- LEFT JOIN
608
- rental_JointHirer jh ON r.RentalId = jh.RentalId
609
- WHERE
610
- r.Status = 'Active'
611
- AND (
612
- r.CustomerId = '${CustomerId}'
613
- OR jh.CustomerId = '${CustomerId}'
614
- );
615
- `;
616
- const db = rentalDb.getConnection();
617
- const result = await db.query(query, {
618
- type: QueryTypes.SELECT,
619
- transaction: dbTransaction,
620
- model: RentalModel,
621
- mapToModel: true,
622
- });
623
-
624
- // Format the returned records
625
- const records: IRentalAttr[] = result.map((record: RentalModel) => {
626
- return {
627
- RentalId: record.RentalId,
628
- CustomerId: record.CustomerId,
629
- CustomerType: record.CustomerType,
630
- ItemId: record.ItemId,
631
- ItemType: record.ItemType,
632
- PriceId: record.PriceId,
633
- StartDateTime: record.StartDateTime,
634
- EndDateTime: record.EndDateTime,
635
- CancelRemarks: record.CancelRemarks,
636
- TerminateRemarks: record.TerminateRemarks,
637
- AgreementNo: record.AgreementNo,
638
- AccountType: record.AccountType,
639
- Status: record.Status,
640
- EscheatmentYN: record.EscheatmentYN,
641
- CreatedById: record.CreatedById,
642
- CreatedAt: record.CreatedAt,
643
- UpdatedById: record.UpdatedById,
644
- UpdatedAt: record.UpdatedAt,
645
- };
646
- });
647
- // Return the returned records.
648
- return records;
649
- } catch (error) {
650
- throw error;
651
- }
652
- }
653
-
654
- async getCustomerIds(loginUser: LoginUser, dbTransaction: any) {
655
- try {
656
- // Part 1: Privilege Checking
657
- // Call loginUser.checkPrivileges() by passing:
658
- // SystemCode: <get_from_app_config>
659
- // PrivilegeCode: "RENTAL_VIEW"
660
- const systemCode =
661
- ApplicationConfig.getComponentConfigValue('system-code');
662
- const isPrivileged = loginUser.checkPrivileges(systemCode, 'RENTAL_VIEW');
663
-
664
- if (!isPrivileged) {
665
- throw new ClassError(
666
- 'Rental',
667
- 'RentalErrMsg01',
668
- "You do not have 'Rental - View' privilege.",
669
- );
670
- }
671
-
672
- // Part 2: Validation
673
- // Make sure this.RentalId exists, if not throw new ClassError by passing
674
- if (!this.RentalId) {
675
- throw new ClassError('Rental', 'RentalErrMsg01', 'RentalId is missing');
676
- }
677
-
678
- //Part 3: Retrieve Listing and Returns
679
- // 3.1 Call Rental._JointHirerRepo findAll method by passing:
680
- // where:
681
- // RentalId: this.RentalId
682
- // dbTransaction
683
- const options: any = {
684
- where: {
685
- RentalId: this.RentalId,
686
- },
687
- transaction: dbTransaction,
688
- };
689
-
690
- const joinHirers = await Rental._JointHirerRepo.findAll(options);
691
-
692
- // 3.2 Create a new array variable and set its value to joint hirer and Rental.CustomerId
693
- // array translated to only CustomerId. Then, append this.CustomerId to the array.
694
- const customerIds: string[] = [this.CustomerId];
695
- for (let i = 0; i < joinHirers.length; i++) {
696
- const jointHirer = joinHirers[i];
697
- customerIds.push(jointHirer.CustomerId);
698
- }
699
-
700
- // 3.3 Return the array.
701
- return customerIds;
702
- } catch (error) {
703
- throw error;
704
- }
705
- }
706
- }
1
+ import { IRentalAttr } from '../../interfaces/rental-attr.interface';
2
+ import { RentalStatusEnum } from '../../enum/rental-status.enum';
3
+ import { RentalRepository } from './rental.repository';
4
+ import { ClassError, ObjectBase } from '@tomei/general';
5
+ import { ApplicationConfig } from '@tomei/config';
6
+ import { LoginUser } from '@tomei/sso';
7
+ import { RentalPrice } from '../rental-price/rental-price';
8
+ import { Op, QueryTypes } from 'sequelize';
9
+ import { ActionEnum, Activity } from '@tomei/activity-history';
10
+ import { IRentalFindAllSearchAttr } from '../../interfaces/rental-find-all-search-attr.interface';
11
+ import { RentalAccountTypeEnum } from '../../enum/account-type.enum';
12
+ import { JointHirer } from '../joint-hirer/joint-hirer';
13
+ import { JointHirerModel } from '../../models/joint-hirer.entity';
14
+ import { AgreementRepository } from '../agreement/agreement.repository';
15
+ import * as rentalDb from '../../database';
16
+ import { RentalModel } from '../../models/rental.entity';
17
+ import { JointHirerRepository } from '../joint-hirer/joint-hirer.repository';
18
+ import { AgreementModel } from '../../models';
19
+
20
+ export class Rental extends ObjectBase {
21
+ ObjectId: string;
22
+ ObjectName: string;
23
+ ObjectType = 'Rental';
24
+ TableName: string;
25
+ CustomerId: string;
26
+ CustomerType: string;
27
+ ItemId: string;
28
+ ItemType: string;
29
+ PriceId: string;
30
+ StartDateTime: Date;
31
+ EndDateTime: Date;
32
+ CancelRemarks: string;
33
+ TerminateRemarks: string;
34
+ AgreementNo: string;
35
+ AccountType: RentalAccountTypeEnum;
36
+ JointHirers: JointHirer[] = [];
37
+ protected _Status: RentalStatusEnum;
38
+ protected _EscheatmentYN: string = 'N';
39
+ protected _CreatedById: string;
40
+ protected _CreatedAt: Date;
41
+ protected _UpdatedById: string;
42
+ protected _UpdatedAt: Date;
43
+ protected static _Repo = new RentalRepository();
44
+ protected static _AgreementRepo = new AgreementRepository();
45
+ protected static _JointHirerRepo = new JointHirerRepository();
46
+
47
+ get RentalId(): string {
48
+ return this.ObjectId;
49
+ }
50
+
51
+ set RentalId(value: string) {
52
+ this.ObjectId = value;
53
+ }
54
+
55
+ get Status(): RentalStatusEnum {
56
+ return this._Status;
57
+ }
58
+
59
+ get EscheatmentYN(): string {
60
+ return this._EscheatmentYN;
61
+ }
62
+
63
+ get CreatedById(): string {
64
+ return this._CreatedById;
65
+ }
66
+
67
+ get CreatedAt(): Date {
68
+ return this._CreatedAt;
69
+ }
70
+
71
+ get UpdatedById(): string {
72
+ return this._UpdatedById;
73
+ }
74
+
75
+ get UpdatedAt(): Date {
76
+ return this._UpdatedAt;
77
+ }
78
+
79
+ private setTerminated() {
80
+ this._Status = RentalStatusEnum.TERMINATED;
81
+ }
82
+
83
+ protected constructor(rentalAttr?: IRentalAttr) {
84
+ super();
85
+ if (rentalAttr) {
86
+ this.RentalId = rentalAttr.RentalId;
87
+ this.CustomerId = rentalAttr.CustomerId;
88
+ this.CustomerType = rentalAttr.CustomerType;
89
+ this.ItemId = rentalAttr.ItemId;
90
+ this.ItemType = rentalAttr.ItemType;
91
+ this.PriceId = rentalAttr.PriceId;
92
+ this.StartDateTime = rentalAttr.StartDateTime;
93
+ this.EndDateTime = rentalAttr.EndDateTime;
94
+ this.CancelRemarks = rentalAttr.CancelRemarks;
95
+ this.TerminateRemarks = rentalAttr.TerminateRemarks;
96
+ this.AgreementNo = rentalAttr.AgreementNo;
97
+ this.AccountType = rentalAttr.AccountType;
98
+ this._Status = rentalAttr.Status;
99
+ this._EscheatmentYN = rentalAttr.EscheatmentYN;
100
+ this._CreatedById = rentalAttr.CreatedById;
101
+ this._CreatedAt = rentalAttr.CreatedAt;
102
+ this._UpdatedById = rentalAttr.UpdatedById;
103
+ this._UpdatedAt = rentalAttr.UpdatedAt;
104
+ }
105
+ }
106
+
107
+ public static async init(dbTransaction?: any, rentalId?: string) {
108
+ try {
109
+ if (rentalId) {
110
+ const rental = await Rental._Repo.findByPk(rentalId, dbTransaction);
111
+ if (rental) {
112
+ return new Rental(rental);
113
+ } else {
114
+ throw new ClassError('Rental', 'RentalErrMsg00', 'Rental Not Found');
115
+ }
116
+ }
117
+ return new Rental();
118
+ } catch (error) {
119
+ throw new ClassError(
120
+ 'Rental',
121
+ 'RentalErrMsg00',
122
+ 'Failed To Initialize Price',
123
+ );
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Create a new Rental record.
129
+ * @param {RentalPrice} rentalPrice - The rental pricing information.
130
+ * @param {LoginUser} loginUser - The user initiating the creation.
131
+ * @param {any} [dbTransaction] - Optional database transaction for atomic operations.
132
+ * @throws {ClassError} Throws an error if:
133
+ * 1. loginUser does not have 'Rental - Create' privilege.
134
+ * 2. Rental item is not available at the current date.
135
+ * @returns {Promise<any>} A Promise resolving to the created rental record.
136
+ */
137
+ public async create(
138
+ rentalPrice: RentalPrice,
139
+ loginUser: LoginUser,
140
+ jointHirers?: JointHirer[],
141
+ dbTransaction?: any,
142
+ ): Promise<any> {
143
+ try {
144
+ /*Part 1: Check Privilege*/
145
+ const systemCode =
146
+ ApplicationConfig.getComponentConfigValue('system-code');
147
+ const isPrivileged = await loginUser.checkPrivileges(
148
+ systemCode,
149
+ 'Rental - Create',
150
+ );
151
+
152
+ if (!isPrivileged) {
153
+ throw new ClassError(
154
+ 'Rental',
155
+ 'RentalErrMsg01',
156
+ "You do not have 'Rental - Create' privilege.",
157
+ );
158
+ }
159
+
160
+ /*Part 2: Make Sure Rental Item Available*/
161
+ const isItemAvailable = await Rental.isItemAvailable(
162
+ this.ItemId,
163
+ this.ItemType,
164
+ this.StartDateTime,
165
+ this.EndDateTime,
166
+ dbTransaction,
167
+ );
168
+
169
+ if (!isItemAvailable) {
170
+ throw new ClassError(
171
+ 'Rental',
172
+ 'RentalErrMsg02',
173
+ 'Rental Item is not available at current date.',
174
+ );
175
+ }
176
+
177
+ // Part 3: Create Rental Agreement Record
178
+ // Call Rental._AgreementRepo create method by passing:
179
+ // AgreementNo: this.AgreementNo
180
+ // Status: "Not Generated"
181
+ // dbTransaction
182
+ await Rental._AgreementRepo.create(
183
+ {
184
+ AgreementNo: this.AgreementNo,
185
+ Status: 'Not Generated',
186
+ },
187
+ {
188
+ transaction: dbTransaction,
189
+ },
190
+ );
191
+
192
+ /*Part 4: Insert Rental & The Agreed Rental Price*/
193
+ await rentalPrice.create(loginUser, dbTransaction);
194
+
195
+ this.PriceId = rentalPrice.PriceId;
196
+
197
+ this.RentalId = this.createId();
198
+ // if (!this.Status) {
199
+ this._Status = RentalStatusEnum.PENDING_SIGNING;
200
+ // }
201
+ this._CreatedById = loginUser.ObjectId;
202
+ this._UpdatedById = loginUser.ObjectId;
203
+ this._CreatedAt = new Date();
204
+ this._UpdatedAt = new Date();
205
+
206
+ const data = {
207
+ RentalId: this.RentalId,
208
+ CustomerId: this.CustomerId,
209
+ CustomerType: this.CustomerType,
210
+ ItemId: this.ItemId,
211
+ ItemType: this.ItemType,
212
+ PriceId: this.PriceId,
213
+ StartDateTime: this.StartDateTime,
214
+ EndDateTime: this.EndDateTime,
215
+ CancelRemarks: this.CancelRemarks,
216
+ TerminateRemarks: this.TerminateRemarks,
217
+ AgreementNo: this.AgreementNo,
218
+ AccountType: this.AccountType,
219
+ Status: this.Status,
220
+ EscheatmentYN: this.EscheatmentYN,
221
+ CreatedById: this.CreatedById,
222
+ CreatedAt: this.CreatedAt,
223
+ UpdatedById: this.UpdatedById,
224
+ UpdatedAt: this.UpdatedAt,
225
+ };
226
+
227
+ await Rental._Repo.create(data, {
228
+ transaction: dbTransaction,
229
+ });
230
+
231
+ //For every data inside Param.jointHirers, update the rentalId and call jointHirer.create
232
+ if (jointHirers) {
233
+ for (let i = 0; i < jointHirers.length; i++) {
234
+ jointHirers[i].RentalId = this.RentalId;
235
+ await jointHirers[i].create(loginUser, dbTransaction);
236
+ this.JointHirers.push(jointHirers[i]);
237
+ }
238
+ }
239
+
240
+ /*Part 5: Record Create Rental Activity*/
241
+ const activity = new Activity();
242
+ activity.ActivityId = activity.createId();
243
+ activity.Action = ActionEnum.ADD;
244
+ activity.Description = 'Add Rental';
245
+ activity.EntityType = 'Rental';
246
+ activity.EntityId = this.RentalId;
247
+ activity.EntityValueBefore = JSON.stringify({});
248
+ activity.EntityValueAfter = JSON.stringify(data);
249
+ await activity.create(loginUser.ObjectId, dbTransaction);
250
+
251
+ /*Part 6: Return Result*/
252
+ return this;
253
+ } catch (error) {
254
+ throw error;
255
+ }
256
+ }
257
+
258
+ public static async isItemAvailable(
259
+ itemId: string,
260
+ itemType: string,
261
+ startDateTime: Date,
262
+ endDateTime: Date,
263
+ dbTransaction?: any,
264
+ ) {
265
+ try {
266
+ const item = await Rental._Repo.findOne({
267
+ where: {
268
+ ItemId: itemId,
269
+ ItemType: itemType,
270
+ StartDateTime: {
271
+ [Op.lte]: endDateTime,
272
+ },
273
+ EndDateTime: {
274
+ [Op.gte]: startDateTime,
275
+ },
276
+ },
277
+ transaction: dbTransaction,
278
+ });
279
+
280
+ if (item) {
281
+ return false;
282
+ } else {
283
+ return true;
284
+ }
285
+ } catch (error) {
286
+ throw error;
287
+ }
288
+ }
289
+
290
+ public static async findAll(
291
+ loginUser: LoginUser,
292
+ dbTransaction: any,
293
+ page?: number,
294
+ row?: number,
295
+ search?: IRentalFindAllSearchAttr,
296
+ ) {
297
+ try {
298
+ const systemCode = await ApplicationConfig.getComponentConfigValue(
299
+ 'system-code',
300
+ );
301
+
302
+ const isPrivileged = await loginUser.checkPrivileges(
303
+ systemCode,
304
+ 'Rental - View',
305
+ );
306
+
307
+ if (!isPrivileged) {
308
+ throw new ClassError(
309
+ 'Rental',
310
+ 'RentalErrMsg01',
311
+ "You do not have 'Rental - View' privilege.",
312
+ );
313
+ }
314
+
315
+ const queryObj: any = {};
316
+
317
+ let options: any = {
318
+ transaction: dbTransaction,
319
+ order: [['CreatedAt', 'DESC']],
320
+ };
321
+
322
+ if (page && row) {
323
+ options = {
324
+ ...options,
325
+ limit: row,
326
+ offset: row * (page - 1),
327
+ };
328
+ }
329
+
330
+ if (search) {
331
+ Object.entries(search).forEach(([key, value]) => {
332
+ if (key === 'StartDateTime') {
333
+ queryObj[key] = {
334
+ [Op.gte]: value,
335
+ };
336
+ } else if (key === 'EndDateTime') {
337
+ queryObj[key] = {
338
+ [Op.lte]: value,
339
+ };
340
+ } else if (key === 'CustomerId') {
341
+ queryObj[key] = {
342
+ [Op.substring]: value,
343
+ };
344
+
345
+ options.include = [
346
+ {
347
+ model: JointHirerModel,
348
+ required: false,
349
+ where: {
350
+ CustomerId: {
351
+ [Op.substring]: value,
352
+ },
353
+ },
354
+ },
355
+ ];
356
+ } else {
357
+ queryObj[key] = {
358
+ [Op.substring]: value,
359
+ };
360
+ }
361
+ });
362
+ if (options?.include?.length > 1) {
363
+ options.include.push({
364
+ model: AgreementModel,
365
+ required: false,
366
+ });
367
+ } else {
368
+ options.include = [
369
+ {
370
+ model: AgreementModel,
371
+ required: false,
372
+ },
373
+ ];
374
+ }
375
+
376
+ options = {
377
+ ...options,
378
+ where: queryObj,
379
+ };
380
+ }
381
+
382
+ return await Rental._Repo.findAndCountAll(options);
383
+ } catch (err) {
384
+ throw err;
385
+ }
386
+ }
387
+
388
+ public static async checkActiveByItemId(
389
+ loginUser: LoginUser,
390
+ itemId: string,
391
+ itemType: string,
392
+ dbTransaction?: any,
393
+ ) {
394
+ try {
395
+ const systemCode = await ApplicationConfig.getComponentConfigValue(
396
+ 'system-code',
397
+ );
398
+
399
+ const isPrivileged = await loginUser.checkPrivileges(
400
+ systemCode,
401
+ 'Rental - View',
402
+ );
403
+
404
+ if (!isPrivileged) {
405
+ throw new ClassError(
406
+ 'Rental',
407
+ 'RentalErrMsg01',
408
+ "You do not have 'Rental - View' privilege.",
409
+ );
410
+ }
411
+
412
+ const queryObj: any = {
413
+ ItemId: itemId,
414
+ ItemType: itemType,
415
+ Status: RentalStatusEnum.ACTIVE,
416
+ };
417
+
418
+ const options: any = {
419
+ transaction: dbTransaction,
420
+ where: queryObj,
421
+ };
422
+
423
+ const rental = await Rental._Repo.findOne(options);
424
+
425
+ if (rental) {
426
+ return true;
427
+ } else {
428
+ return false;
429
+ }
430
+ } catch (err) {
431
+ throw err;
432
+ }
433
+ }
434
+
435
+ /**
436
+ * Sets the StartDateTime property of the Rental class as custom setter.
437
+ * @param {Date} startDateTime - The start date and time of the rental.
438
+ * @throws {ClassError} Throws an error if:
439
+ * 1. startDateTime is a past date.
440
+ * 2. startDateTime is more than the EndDateTime.
441
+ * @returns {void}
442
+ */
443
+ setStartDateTime(startDateTime: Date): void {
444
+ const startDateTimeObject = new Date(startDateTime);
445
+ startDateTimeObject.setHours(0, 0, 0, 0);
446
+
447
+ /*Part 1: Make Sure Future Date Time*/
448
+ if (startDateTimeObject < new Date(new Date().setHours(0, 0, 0, 0))) {
449
+ throw new ClassError(
450
+ 'Rental',
451
+ 'RentalErrMsg02',
452
+ 'StartDateTime cannot be a past datetime.',
453
+ );
454
+ }
455
+
456
+ /*Part 2: Make Sure Less Than End Date Time*/
457
+ if (this.EndDateTime && startDateTimeObject > this.EndDateTime) {
458
+ throw new ClassError(
459
+ 'Rental',
460
+ 'RentalErrMsg03',
461
+ 'StartDateTime cannot be more than EndDateTime.',
462
+ );
463
+ }
464
+
465
+ /*Part 3: Set Status Whether Reserved or Active*/
466
+ if (startDateTimeObject > new Date(new Date().setHours(0, 0, 0, 0))) {
467
+ this._Status = RentalStatusEnum.RESERVED;
468
+ } else {
469
+ this._Status = RentalStatusEnum.ACTIVE;
470
+ }
471
+ }
472
+
473
+ public async periodEndProcess(
474
+ loginUser: LoginUser,
475
+ dbTransaction: any,
476
+ stockInventory: any,
477
+ ) {
478
+ try {
479
+ // Privilege Checking
480
+ const systemCode = await ApplicationConfig.getComponentConfigValue(
481
+ 'system-code',
482
+ );
483
+
484
+ const isPrivileged = await loginUser.checkPrivileges(
485
+ systemCode,
486
+ 'Rental – PeriodEndProcess',
487
+ );
488
+
489
+ if (!isPrivileged) {
490
+ throw new ClassError(
491
+ 'Rental',
492
+ 'RentalErrMsg04',
493
+ "You do not have 'Rental - PeriodEndProcess' privilege.",
494
+ );
495
+ }
496
+
497
+ // Validate Existing Rental
498
+ if (this.AgreementNo === undefined || this.AgreementNo === null) {
499
+ throw new ClassError(
500
+ 'Rental',
501
+ 'RentalErrMsg05',
502
+ 'Rental must be existing rental.',
503
+ );
504
+ }
505
+
506
+ // Validate Rental End Period
507
+ if (this.EndDateTime === new Date(new Date().setHours(0, 0, 0, 0))) {
508
+ throw new ClassError(
509
+ 'Rental',
510
+ 'RentalErrMsg06',
511
+ 'Rental period is not ending today.',
512
+ );
513
+ }
514
+
515
+ // Mark Rental Item as Available
516
+ await stockInventory.setAvailable(loginUser, dbTransaction);
517
+
518
+ // Capture Record Info Before Changes
519
+ const entityValueBefore = {
520
+ RentalId: this.RentalId,
521
+ CustomerId: this.CustomerId,
522
+ CustomerType: this.CustomerType,
523
+ ItemId: this.ItemId,
524
+ ItemType: this.ItemType,
525
+ PriceId: this.PriceId,
526
+ StartDateTime: this.StartDateTime,
527
+ EndDateTime: this.EndDateTime,
528
+ CancelRemarks: this.CancelRemarks,
529
+ TerminateRemarks: this.TerminateRemarks,
530
+ AgreementNo: this.AgreementNo,
531
+ AccountType: this.AccountType,
532
+ Status: this.Status,
533
+ EscheatmentYN: this.EscheatmentYN,
534
+ CreatedById: this.CreatedById,
535
+ CreatedAt: this.CreatedAt,
536
+ UpdatedById: this.UpdatedById,
537
+ UpdatedAt: this.UpdatedAt,
538
+ };
539
+
540
+ // Mark Rental as Terminated and Capture Updater Info
541
+ this.setTerminated();
542
+ this._UpdatedById = loginUser.ObjectId;
543
+ this._UpdatedAt = new Date();
544
+
545
+ // Capture Record Info after Changes
546
+ const entityValueAfter = {
547
+ RentalId: this.RentalId,
548
+ CustomerId: this.CustomerId,
549
+ CustomerType: this.CustomerType,
550
+ ItemId: this.ItemId,
551
+ ItemType: this.ItemType,
552
+ PriceId: this.PriceId,
553
+ StartDateTime: this.StartDateTime,
554
+ EndDateTime: this.EndDateTime,
555
+ CancelRemarks: this.CancelRemarks,
556
+ TerminateRemarks: this.TerminateRemarks,
557
+ AgreementNo: this.AgreementNo,
558
+ AccountType: this.AccountType,
559
+ Status: this.Status,
560
+ EscheatmentYN: this.EscheatmentYN,
561
+ CreatedById: this.CreatedById,
562
+ CreatedAt: this.CreatedAt,
563
+ UpdatedById: this.UpdatedById,
564
+ UpdatedAt: this.UpdatedAt,
565
+ };
566
+
567
+ // Record the Update Activity
568
+ const activity = new Activity();
569
+ activity.ActivityId = activity.createId();
570
+ activity.Action = ActionEnum.UPDATE;
571
+ activity.Description = 'Set Rental as Terminated';
572
+ activity.EntityType = 'Rental';
573
+ activity.EntityId = this.RentalId;
574
+ activity.EntityValueBefore = JSON.stringify(entityValueBefore);
575
+ activity.EntityValueAfter = JSON.stringify(entityValueAfter);
576
+ await activity.create(loginUser.ObjectId, dbTransaction);
577
+
578
+ return this;
579
+ } catch (err) {
580
+ throw err;
581
+ }
582
+ }
583
+
584
+ async getCustomerActiveRentals(
585
+ loginUser: LoginUser,
586
+ dbTransaction: any,
587
+ CustomerId: string,
588
+ ): Promise<IRentalAttr[]> {
589
+ try {
590
+ // Part 1: Privilege Checking
591
+ // Call loginUser.checkPrivileges() by passing:
592
+ // SystemCode: <get_from_app_config>
593
+ // PrivilegeCode: "RENTAL_VIEW"
594
+ const systemCode =
595
+ ApplicationConfig.getComponentConfigValue('system-code');
596
+ const isPrivileged = loginUser.checkPrivileges(systemCode, 'RENTAL_VIEW');
597
+
598
+ if (!isPrivileged) {
599
+ throw new ClassError(
600
+ 'Rental',
601
+ 'RentalErrMsg01',
602
+ "You do not have 'Rental - View' privilege.",
603
+ );
604
+ }
605
+
606
+ // Part 2: Retrieve Rentals and Returns
607
+ // Call Rental._Repo findAll method by passing:
608
+ // where:
609
+ // Status: "Active"
610
+ // [Op.OR]:
611
+ // CustomerId: Params.CustomerId
612
+ // '$JointHirers.CustomerId$': Params.CustomerId
613
+ // include:
614
+ // model: JointHirerModel
615
+ // attributes: []
616
+ const query = `
617
+ SELECT
618
+ r.*
619
+ FROM
620
+ rental_Rental r
621
+ LEFT JOIN
622
+ rental_JointHirer jh ON r.RentalId = jh.RentalId
623
+ WHERE
624
+ r.Status = 'Active'
625
+ AND (
626
+ r.CustomerId = '${CustomerId}'
627
+ OR jh.CustomerId = '${CustomerId}'
628
+ );
629
+ `;
630
+ const db = rentalDb.getConnection();
631
+ const result = await db.query(query, {
632
+ type: QueryTypes.SELECT,
633
+ transaction: dbTransaction,
634
+ model: RentalModel,
635
+ mapToModel: true,
636
+ });
637
+
638
+ // Format the returned records
639
+ const records: IRentalAttr[] = result.map((record: RentalModel) => {
640
+ return {
641
+ RentalId: record.RentalId,
642
+ CustomerId: record.CustomerId,
643
+ CustomerType: record.CustomerType,
644
+ ItemId: record.ItemId,
645
+ ItemType: record.ItemType,
646
+ PriceId: record.PriceId,
647
+ StartDateTime: record.StartDateTime,
648
+ EndDateTime: record.EndDateTime,
649
+ CancelRemarks: record.CancelRemarks,
650
+ TerminateRemarks: record.TerminateRemarks,
651
+ AgreementNo: record.AgreementNo,
652
+ AccountType: record.AccountType,
653
+ Status: record.Status,
654
+ EscheatmentYN: record.EscheatmentYN,
655
+ CreatedById: record.CreatedById,
656
+ CreatedAt: record.CreatedAt,
657
+ UpdatedById: record.UpdatedById,
658
+ UpdatedAt: record.UpdatedAt,
659
+ };
660
+ });
661
+ // Return the returned records.
662
+ return records;
663
+ } catch (error) {
664
+ throw error;
665
+ }
666
+ }
667
+
668
+ async getCustomerIds(loginUser: LoginUser, dbTransaction: any) {
669
+ try {
670
+ // Part 1: Privilege Checking
671
+ // Call loginUser.checkPrivileges() by passing:
672
+ // SystemCode: <get_from_app_config>
673
+ // PrivilegeCode: "RENTAL_VIEW"
674
+ const systemCode =
675
+ ApplicationConfig.getComponentConfigValue('system-code');
676
+ const isPrivileged = loginUser.checkPrivileges(systemCode, 'RENTAL_VIEW');
677
+
678
+ if (!isPrivileged) {
679
+ throw new ClassError(
680
+ 'Rental',
681
+ 'RentalErrMsg01',
682
+ "You do not have 'Rental - View' privilege.",
683
+ );
684
+ }
685
+
686
+ // Part 2: Validation
687
+ // Make sure this.RentalId exists, if not throw new ClassError by passing
688
+ if (!this.RentalId) {
689
+ throw new ClassError('Rental', 'RentalErrMsg01', 'RentalId is missing');
690
+ }
691
+
692
+ //Part 3: Retrieve Listing and Returns
693
+ // 3.1 Call Rental._JointHirerRepo findAll method by passing:
694
+ // where:
695
+ // RentalId: this.RentalId
696
+ // dbTransaction
697
+ const options: any = {
698
+ where: {
699
+ RentalId: this.RentalId,
700
+ },
701
+ transaction: dbTransaction,
702
+ };
703
+
704
+ const joinHirers = await Rental._JointHirerRepo.findAll(options);
705
+
706
+ // 3.2 Create a new array variable and set its value to joint hirer and Rental.CustomerId
707
+ // array translated to only CustomerId. Then, append this.CustomerId to the array.
708
+ const customerIds: string[] = [this.CustomerId];
709
+ for (let i = 0; i < joinHirers.length; i++) {
710
+ const jointHirer = joinHirers[i];
711
+ customerIds.push(jointHirer.CustomerId);
712
+ }
713
+
714
+ // 3.3 Return the array.
715
+ return customerIds;
716
+ } catch (error) {
717
+ throw error;
718
+ }
719
+ }
720
+ }