@tomei/rental 0.4.5 → 0.5.1

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 (46) hide show
  1. package/.gitlab-ci.yml +16 -0
  2. package/dist/src/components/booking/booking.d.ts +40 -0
  3. package/dist/src/components/booking/booking.js +206 -0
  4. package/dist/src/components/booking/booking.js.map +1 -0
  5. package/dist/src/components/booking/booking.repository.d.ts +8 -0
  6. package/dist/src/components/booking/booking.repository.js +67 -0
  7. package/dist/src/components/booking/booking.repository.js.map +1 -0
  8. package/dist/src/components/rental/rental.d.ts +1 -1
  9. package/dist/src/components/rental/rental.js +4 -4
  10. package/dist/src/components/rental/rental.js.map +1 -1
  11. package/dist/src/database.js +2 -0
  12. package/dist/src/database.js.map +1 -1
  13. package/dist/src/enum/booking.enum.d.ts +5 -0
  14. package/dist/src/enum/booking.enum.js +10 -0
  15. package/dist/src/enum/booking.enum.js.map +1 -0
  16. package/dist/src/enum/index.d.ts +2 -1
  17. package/dist/src/enum/index.js +3 -1
  18. package/dist/src/enum/index.js.map +1 -1
  19. package/dist/src/index.d.ts +3 -1
  20. package/dist/src/index.js +5 -1
  21. package/dist/src/index.js.map +1 -1
  22. package/dist/src/interfaces/booking-attr.interface.d.ts +18 -0
  23. package/dist/src/interfaces/booking-attr.interface.js +3 -0
  24. package/dist/src/interfaces/booking-attr.interface.js.map +1 -0
  25. package/dist/src/interfaces/index.d.ts +2 -1
  26. package/dist/src/models/booking.entity.d.ts +21 -0
  27. package/dist/src/models/booking.entity.js +128 -0
  28. package/dist/src/models/booking.entity.js.map +1 -0
  29. package/dist/src/models/index.d.ts +2 -1
  30. package/dist/src/models/index.js +3 -1
  31. package/dist/src/models/index.js.map +1 -1
  32. package/dist/tsconfig.tsbuildinfo +1 -1
  33. package/migrations/booking-table-migration.js +79 -0
  34. package/package.json +5 -1
  35. package/sonar-project.properties +13 -0
  36. package/src/components/booking/booking.repository.ts +51 -0
  37. package/src/components/booking/booking.ts +291 -0
  38. package/src/components/rental/rental.ts +4 -4
  39. package/src/database.ts +2 -0
  40. package/src/enum/booking.enum.ts +5 -0
  41. package/src/enum/index.ts +2 -1
  42. package/src/index.ts +4 -0
  43. package/src/interfaces/booking-attr.interface.ts +19 -0
  44. package/src/interfaces/index.ts +7 -1
  45. package/src/models/booking.entity.ts +105 -0
  46. package/src/models/index.ts +2 -1
@@ -0,0 +1,13 @@
1
+ sonar.projectKey=all-tomei-projects_rental
2
+ sonar.organization=all-tomei-projects
3
+
4
+ # This is the name and version displayed in the SonarCloud UI.
5
+ #sonar.projectName=Rental
6
+ #sonar.projectVersion=1.0
7
+
8
+
9
+ # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
10
+ #sonar.sources=.
11
+
12
+ # Encoding of the source code. Default is default system encoding
13
+ #sonar.sourceEncoding=UTF-8
@@ -0,0 +1,51 @@
1
+ import { RepositoryBase, IRepositoryBase } from '@tomei/general';
2
+ import { BookingModel } from '../../models/booking.entity';
3
+
4
+ export class BookingRepository
5
+ extends RepositoryBase<BookingModel>
6
+ implements IRepositoryBase<BookingModel>
7
+ {
8
+ constructor() {
9
+ super(BookingModel);
10
+ }
11
+
12
+ async findByPk(id: string, transaction?: any): Promise<BookingModel | null> {
13
+ try {
14
+ const result = await BookingModel.findByPk(id, {
15
+ transaction: transaction,
16
+ });
17
+
18
+ return result;
19
+ } catch (error) {
20
+ throw new Error(`An Error occured when fetching : ${error.message}`);
21
+ }
22
+ }
23
+
24
+ async delete(BookingNo: string, dbTransaction?: any) {
25
+ try {
26
+ const options = {
27
+ where: {
28
+ BookingNo: BookingNo,
29
+ },
30
+ transaction: dbTransaction,
31
+ };
32
+ await BookingModel.destroy(options);
33
+ } catch (error) {
34
+ throw new Error(`An Error occured when delete : ${error.message}`);
35
+ }
36
+ }
37
+
38
+ async findAndCountAll(options?: any) {
39
+ try {
40
+ let Bookings: any;
41
+ if (options) {
42
+ Bookings = await BookingModel.findAndCountAll(options);
43
+ } else {
44
+ Bookings = await BookingModel.findAndCountAll();
45
+ }
46
+ return Bookings;
47
+ } catch (error) {
48
+ throw new Error(`An Error occured when retriving : ${error.message}`);
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,291 @@
1
+ import { ClassError, ObjectBase } from '@tomei/general';
2
+ import { BookingStatusEnum } from '../../enum/booking.enum';
3
+ import { IBookingAttr } from '../../interfaces/booking-attr.interface';
4
+ import { BookingRepository } from './booking.repository';
5
+ import { DateTime } from 'luxon';
6
+ import { LoginUser } from '@tomei/sso';
7
+ import { RentalPrice } from '../rental-price/rental-price';
8
+ import { ApplicationConfig } from '@tomei/config';
9
+ import { Op } from 'sequelize';
10
+ import { Rental } from '../rental/rental';
11
+ import { ActionEnum, Activity } from '@tomei/activity-history';
12
+
13
+ export class Booking extends ObjectBase {
14
+ ObjectId: string;
15
+ ObjectName: string;
16
+ ObjectType: string = 'Booking';
17
+ TableName = 'booking_Booking';
18
+ CustomerId: string;
19
+ CustomerType: string;
20
+ ItemId: string;
21
+ ItemType: string;
22
+ PriceId: string;
23
+ private _ScheduledStartDateTime: Date;
24
+ private _ScheduledEndDateTime: Date;
25
+ BookingFee: number;
26
+ Status: BookingStatusEnum;
27
+ CancelRemarks: string;
28
+ private _CreatedById: string;
29
+ private _CreatedAt: Date;
30
+ private _UpdatedById: string;
31
+ private _UpdatedAt: Date;
32
+
33
+ private static _Repo = new BookingRepository();
34
+
35
+ get BookingNo(): string {
36
+ return this.ObjectId;
37
+ }
38
+
39
+ set BookingNo(value: string) {
40
+ this.ObjectId = value;
41
+ }
42
+
43
+ get CreatedById(): string {
44
+ return this._CreatedById;
45
+ }
46
+
47
+ get CreatedAt(): Date {
48
+ return this._CreatedAt;
49
+ }
50
+
51
+ get UpdatedById(): string {
52
+ return this._UpdatedById;
53
+ }
54
+
55
+ get UpdatedAt(): Date {
56
+ return this._UpdatedAt;
57
+ }
58
+
59
+ get ScheduledStartDateTime(): Date {
60
+ return this._ScheduledStartDateTime;
61
+ }
62
+
63
+ get ScheduledEndDateTime(): Date {
64
+ return this._ScheduledEndDateTime;
65
+ }
66
+
67
+ async setScheduledStartDateTime(datetime: Date) {
68
+ const dateTime = DateTime.fromJSDate(datetime);
69
+ const currentDateTime = DateTime.now();
70
+ if (dateTime <= currentDateTime) {
71
+ throw new ClassError(
72
+ 'Booking',
73
+ 'BookingErrMsg01',
74
+ 'Booking must be for future date time.',
75
+ );
76
+ }
77
+ this._ScheduledStartDateTime = datetime;
78
+ }
79
+
80
+ async setScheduledEndDateTime(datetime: Date) {
81
+ const dateTime = DateTime.fromJSDate(datetime);
82
+ const currentDateTime = DateTime.now();
83
+ if (dateTime <= currentDateTime) {
84
+ throw new ClassError(
85
+ 'Booking',
86
+ 'BookingErrMsg01',
87
+ 'Booking must be for future date time.',
88
+ );
89
+ }
90
+
91
+ if (!this._ScheduledStartDateTime) {
92
+ throw new ClassError(
93
+ 'Booking',
94
+ 'BookingErrMsg01',
95
+ 'Booking start date time must be set before setting end date time.',
96
+ );
97
+ }
98
+
99
+ const startDateTime = DateTime.fromJSDate(this._ScheduledStartDateTime);
100
+ if (dateTime <= startDateTime) {
101
+ throw new ClassError(
102
+ 'Booking',
103
+ 'BookingErrMsg03',
104
+ 'Booking end date time must be more than start date time.',
105
+ );
106
+ }
107
+
108
+ this._ScheduledEndDateTime = datetime;
109
+ }
110
+
111
+ protected constructor(bookingAttr?: IBookingAttr) {
112
+ super();
113
+ if (bookingAttr) {
114
+ this.ObjectId = bookingAttr.BookingNo;
115
+ this.CustomerId = bookingAttr.CustomerId;
116
+ this.CustomerType = bookingAttr.CustomerType;
117
+ this.ItemId = bookingAttr.ItemId;
118
+ this.ItemType = bookingAttr.ItemType;
119
+ this.PriceId = bookingAttr.PriceId;
120
+ this._ScheduledStartDateTime = bookingAttr.ScheduledStartDateTime;
121
+ this._ScheduledEndDateTime = bookingAttr.ScheduledEndDateTime;
122
+ this.BookingFee = bookingAttr.BookingFee;
123
+ this.Status = bookingAttr.Status;
124
+ this.CancelRemarks = bookingAttr.CancelRemarks;
125
+ this._CreatedById = bookingAttr.CreatedById;
126
+ this._CreatedAt = bookingAttr.CreatedAt;
127
+ this._UpdatedById = bookingAttr.UpdatedById;
128
+ this._UpdatedAt = bookingAttr.UpdatedAt;
129
+ }
130
+ }
131
+
132
+ public static async init(dbTransaction?: any, bookingNo?: string) {
133
+ try {
134
+ if (bookingNo) {
135
+ const booking = await Booking._Repo.findByPk(bookingNo, {
136
+ transaction: dbTransaction,
137
+ });
138
+
139
+ if (booking) {
140
+ return new Booking(booking.get({ plain: true }));
141
+ } else {
142
+ throw new Error('Booking not found');
143
+ }
144
+ }
145
+ return new Booking();
146
+ } catch (error) {
147
+ throw error;
148
+ }
149
+ }
150
+
151
+ public async create(
152
+ dbTransaction: any,
153
+ loginUser: LoginUser,
154
+ rentalPrice: RentalPrice,
155
+ ) {
156
+ //This method will create new booking record.
157
+ try {
158
+ //Part 1: Check Privilege
159
+ const systemCode =
160
+ ApplicationConfig.getComponentConfigValue('system-code');
161
+ const isPrivileged = await loginUser.checkPrivileges(
162
+ systemCode,
163
+ 'Booking - Create',
164
+ );
165
+
166
+ if (!isPrivileged) {
167
+ throw new ClassError(
168
+ 'Booking',
169
+ 'BookingErrMsg02',
170
+ "You do not have 'Booking - Create' privilege.",
171
+ );
172
+ }
173
+
174
+ //Part 2: Booking Validation
175
+ //check if item and booking available
176
+ const isRentalAvailable = await Rental.isItemAvailable(
177
+ this.ItemId,
178
+ this.ItemType,
179
+ this._ScheduledStartDateTime,
180
+ this._ScheduledEndDateTime,
181
+ dbTransaction,
182
+ );
183
+
184
+ const isBookingAvailable = await Booking.isBookingItemAvailable(
185
+ dbTransaction,
186
+ this.ItemId,
187
+ this.ItemType,
188
+ this._ScheduledStartDateTime,
189
+ this._ScheduledEndDateTime,
190
+ );
191
+
192
+ if (!isRentalAvailable || !isBookingAvailable) {
193
+ throw new ClassError(
194
+ 'Booking',
195
+ 'BookingErrMsg02',
196
+ 'Booking is not available for the item on the chosen date.',
197
+ );
198
+ }
199
+
200
+ //Part 3: Insert Booking & The Agreed Rental Price
201
+ const rp = await rentalPrice.create(loginUser, dbTransaction);
202
+
203
+ //Set below Booking attributes:
204
+ this.BookingNo = this.createId();
205
+ this.PriceId = rp.PriceId;
206
+ this._CreatedById = loginUser.ObjectId;
207
+ this._CreatedAt = DateTime.now().toJSDate();
208
+ this._UpdatedById = loginUser.ObjectId;
209
+ this._UpdatedAt = DateTime.now().toJSDate();
210
+
211
+ //call this class repo create
212
+ const data: IBookingAttr = {
213
+ BookingNo: this.BookingNo,
214
+ CustomerId: this.CustomerId,
215
+ CustomerType: this.CustomerType,
216
+ ItemId: this.ItemId,
217
+ ItemType: this.ItemType,
218
+ PriceId: this.PriceId,
219
+ ScheduledStartDateTime: this._ScheduledStartDateTime,
220
+ ScheduledEndDateTime: this._ScheduledEndDateTime,
221
+ BookingFee: this.BookingFee,
222
+ Status: this.Status,
223
+ CancelRemarks: this.CancelRemarks,
224
+ CreatedById: this._CreatedById,
225
+ CreatedAt: this._CreatedAt,
226
+ UpdatedById: this._UpdatedById,
227
+ UpdatedAt: this._UpdatedAt,
228
+ };
229
+
230
+ await Booking._Repo.create(data, {
231
+ transaction: dbTransaction,
232
+ });
233
+
234
+ //Part 4: Record Create Booking Activity
235
+ const activity = new Activity();
236
+ activity.ActivityId = activity.createId();
237
+ activity.Action = ActionEnum.ADD;
238
+ activity.Description = 'Add Booking';
239
+ activity.ObjectId = this.BookingNo;
240
+ activity.EntityType = this.ObjectType;
241
+ activity.EntityValueBefore = JSON.stringify({});
242
+ activity.EntityValueAfter = JSON.stringify(data);
243
+
244
+ await activity.create(loginUser.ObjectId, dbTransaction);
245
+
246
+ return this;
247
+ } catch (error) {
248
+ throw error;
249
+ }
250
+ }
251
+
252
+ public static async isBookingItemAvailable(
253
+ dbTransaction: any,
254
+ itemId: string,
255
+ itemType: string,
256
+ startDateTime: Date,
257
+ endDateTime: Date,
258
+ ) {
259
+ //This method will check if booking item available.
260
+ try {
261
+ //call this class repo findOne method
262
+ const booking = await Booking._Repo.findOne({
263
+ where: {
264
+ ItemId: itemId,
265
+ ItemType: itemType,
266
+ [Op.and]: [
267
+ {
268
+ ScheduledStartDateTime: {
269
+ [Op.lte]: endDateTime,
270
+ },
271
+ },
272
+ {
273
+ ScheduledEndDateTime: {
274
+ [Op.gte]: startDateTime,
275
+ },
276
+ },
277
+ ],
278
+ },
279
+ transaction: dbTransaction,
280
+ });
281
+
282
+ //if booking record exists, return false.
283
+ if (booking) {
284
+ return false;
285
+ }
286
+ return true;
287
+ } catch (error) {
288
+ throw error;
289
+ }
290
+ }
291
+ }
@@ -144,7 +144,7 @@ export class Rental extends ObjectBase {
144
144
  }
145
145
 
146
146
  /*Part 2: Make Sure Rental Item Available*/
147
- const isItemAvailable = await this.isItemAvailable(
147
+ const isItemAvailable = await Rental.isItemAvailable(
148
148
  this.ItemId,
149
149
  this.ItemType,
150
150
  this.StartDateTime,
@@ -198,7 +198,7 @@ export class Rental extends ObjectBase {
198
198
 
199
199
  /*Part 4: Record Create Rental Activity*/
200
200
  const activity = new Activity();
201
- activity.ActivityId = this.createId();
201
+ activity.ActivityId = activity.createId();
202
202
  activity.Action = ActionEnum.ADD;
203
203
  activity.Description = 'Add Rental';
204
204
  activity.EntityType = 'Rental';
@@ -214,7 +214,7 @@ export class Rental extends ObjectBase {
214
214
  }
215
215
  }
216
216
 
217
- async isItemAvailable(
217
+ public static async isItemAvailable(
218
218
  itemId: string,
219
219
  itemType: string,
220
220
  startDateTime: Date,
@@ -494,7 +494,7 @@ export class Rental extends ObjectBase {
494
494
 
495
495
  // Record the Update Activity
496
496
  const activity = new Activity();
497
- activity.ActivityId = this.createId();
497
+ activity.ActivityId = activity.createId();
498
498
  activity.Action = ActionEnum.UPDATE;
499
499
  activity.Description = 'Set Rental as Terminated';
500
500
  activity.EntityType = 'Rental';
package/src/database.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Sequelize, SequelizeOptions } from 'sequelize-typescript';
2
2
  import { RentalModel } from './models/rental.entity';
3
3
  import { RentalPriceModel } from './models/rental-price.entity';
4
+ import { BookingModel } from './models/booking.entity';
4
5
 
5
6
  let sequelize: Sequelize;
6
7
 
@@ -11,6 +12,7 @@ function init(sequelizeOptions: SequelizeOptions) {
11
12
  // Add your models here
12
13
  RentalModel,
13
14
  RentalPriceModel,
15
+ BookingModel,
14
16
  ]);
15
17
  }
16
18
 
@@ -0,0 +1,5 @@
1
+ export enum BookingStatusEnum {
2
+ CONFIRMED = 'Confirmed',
3
+ PENDING = 'Pending',
4
+ CANCELLED = 'Cancelled',
5
+ }
package/src/enum/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { RentalStatusEnum } from './rental-status.enum';
2
+ import { BookingStatusEnum } from './booking.enum';
2
3
 
3
- export { RentalStatusEnum };
4
+ export { RentalStatusEnum, BookingStatusEnum };
package/src/index.ts CHANGED
@@ -2,6 +2,8 @@ import { RentalPriceRepository } from './components/rental-price/rental-price.re
2
2
  import { RentalRepository } from './components/rental/rental.repository';
3
3
  import { Rental } from './components/rental/rental';
4
4
  import { RentalPrice } from './components/rental-price/rental-price';
5
+ import { Booking } from './components/booking/booking';
6
+ import { BookingRepository } from './components/booking/booking.repository';
5
7
  import * as rentalDb from './database';
6
8
  export * from './interfaces';
7
9
  export * from './models';
@@ -12,5 +14,7 @@ export {
12
14
  RentalPrice,
13
15
  RentalRepository,
14
16
  RentalPriceRepository,
17
+ Booking,
18
+ BookingRepository,
15
19
  rentalDb,
16
20
  };
@@ -0,0 +1,19 @@
1
+ import { BookingStatusEnum } from '../enum/booking.enum';
2
+
3
+ export interface IBookingAttr {
4
+ BookingNo: string;
5
+ CustomerId: string;
6
+ CustomerType: string;
7
+ ItemId: string;
8
+ ItemType: string;
9
+ PriceId: string;
10
+ ScheduledStartDateTime: Date;
11
+ ScheduledEndDateTime: Date;
12
+ BookingFee: number;
13
+ Status: BookingStatusEnum;
14
+ CancelRemarks: string;
15
+ CreatedById: string;
16
+ CreatedAt: Date;
17
+ UpdatedById: string;
18
+ UpdatedAt: Date;
19
+ }
@@ -1,5 +1,11 @@
1
1
  import { IRentalAttr } from './rental-attr.interface';
2
2
  import { IRentalPriceAttr } from './rental-price-attr.interface';
3
3
  import { IRentalFindAllSearchAttr } from './rental-find-all-search-attr.interface';
4
+ import { IBookingAttr } from './booking-attr.interface';
4
5
 
5
- export { IRentalAttr, IRentalPriceAttr, IRentalFindAllSearchAttr };
6
+ export {
7
+ IRentalAttr,
8
+ IRentalPriceAttr,
9
+ IRentalFindAllSearchAttr,
10
+ IBookingAttr,
11
+ };
@@ -0,0 +1,105 @@
1
+ import {
2
+ Column,
3
+ DataType,
4
+ Table,
5
+ Model,
6
+ ForeignKey,
7
+ BelongsTo,
8
+ CreatedAt,
9
+ UpdatedAt,
10
+ } from 'sequelize-typescript';
11
+ import { RentalPriceModel } from './rental-price.entity';
12
+ import { BookingStatusEnum } from '../enum/booking.enum';
13
+
14
+ @Table({
15
+ tableName: 'booking_Booking',
16
+ })
17
+ export class BookingModel extends Model {
18
+ @Column({
19
+ primaryKey: true,
20
+ allowNull: false,
21
+ type: DataType.STRING(30),
22
+ })
23
+ BookingNo: string;
24
+
25
+ @Column({
26
+ allowNull: false,
27
+ type: DataType.STRING(30),
28
+ })
29
+ CustomerId: string;
30
+
31
+ @Column({
32
+ allowNull: false,
33
+ type: DataType.STRING(30),
34
+ })
35
+ CustomerType: string;
36
+
37
+ @Column({
38
+ allowNull: false,
39
+ type: DataType.STRING(30),
40
+ })
41
+ ItemId: string;
42
+
43
+ @Column({
44
+ allowNull: false,
45
+ type: DataType.STRING(30),
46
+ })
47
+ ItemType: string;
48
+
49
+ @ForeignKey(() => RentalPriceModel)
50
+ @Column({
51
+ allowNull: false,
52
+ type: DataType.STRING(30),
53
+ })
54
+ PriceId: string;
55
+
56
+ @Column({
57
+ allowNull: false,
58
+ type: DataType.DATE,
59
+ })
60
+ ScheduledStartDateTime: Date;
61
+
62
+ @Column({
63
+ allowNull: false,
64
+ type: DataType.DATE,
65
+ })
66
+ ScheduledEndDateTime: Date;
67
+
68
+ @Column({
69
+ allowNull: true,
70
+ type: DataType.DECIMAL(10, 2),
71
+ })
72
+ BookingFee: number;
73
+
74
+ @Column({
75
+ allowNull: false,
76
+ type: DataType.STRING(20),
77
+ })
78
+ Status: BookingStatusEnum;
79
+
80
+ @Column({
81
+ type: DataType.STRING(3000),
82
+ })
83
+ CancelRemarks: string;
84
+
85
+ @Column({
86
+ allowNull: false,
87
+ type: DataType.STRING(30),
88
+ })
89
+ CreatedById: string;
90
+
91
+ @CreatedAt
92
+ CreatedAt: Date;
93
+
94
+ @Column({
95
+ allowNull: false,
96
+ type: DataType.STRING(30),
97
+ })
98
+ UpdatedById: string;
99
+
100
+ @UpdatedAt
101
+ UpdatedAt: Date;
102
+
103
+ @BelongsTo(() => RentalPriceModel)
104
+ RentalPrice: RentalPriceModel;
105
+ }
@@ -1,4 +1,5 @@
1
1
  import { RentalModel } from './rental.entity';
2
2
  import { RentalPriceModel } from './rental-price.entity';
3
+ import { BookingModel } from './booking.entity';
3
4
 
4
- export { RentalModel, RentalPriceModel };
5
+ export { RentalModel, RentalPriceModel, BookingModel };