tripstorekrabi-shared 1.23.7 → 1.23.9

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 (2) hide show
  1. package/package.json +4 -4
  2. package/price.js +81 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tripstorekrabi-shared",
3
- "version": "1.23.7",
3
+ "version": "1.23.9",
4
4
  "description": "Shared library for Trip Store Krabi",
5
5
  "author": "Stefan Sommer <tonprince@gmail.com>",
6
6
  "repository": {
@@ -17,9 +17,9 @@
17
17
  "./telegram": "./telegram.js"
18
18
  },
19
19
  "dependencies": {
20
- "dayjs": "^1.11.19",
21
- "libphonenumber-js": "^1.12.38",
22
- "nanoid": "^5.1.6"
20
+ "dayjs": "^1.11.20",
21
+ "libphonenumber-js": "^1.12.41",
22
+ "nanoid": "^5.1.7"
23
23
  },
24
24
  "scripts": {
25
25
  "deploy": "npm publish"
package/price.js CHANGED
@@ -27,6 +27,49 @@ const SELLING_MODE = 0;
27
27
  const PARTNER_MODE = 1;
28
28
  const OPERATOR_MODE = 2;
29
29
 
30
+ export function getActiveRevision(booking, pricing) {
31
+ if (!pricing?.revisions || pricing.revisions.length === 0) return null;
32
+
33
+ const getSafeDate = (dateField) => {
34
+ if (!dateField) return null;
35
+ if (typeof dateField.toDate === 'function') return dayjs(dateField.toDate());
36
+ return dayjs(dateField);
37
+ };
38
+
39
+ const bookingDate = getSafeDate(booking.date)?.startOf('day');
40
+ if (!bookingDate || !bookingDate.isValid()) return null;
41
+
42
+ const candidateRevisions = pricing.revisions.filter((rev) => {
43
+ if (rev.isActive === false) return false;
44
+
45
+ const revStart = getSafeDate(rev.startDate)?.startOf('day');
46
+ if (!revStart || !revStart.isValid()) return false;
47
+
48
+ return revStart.isSame(bookingDate) || revStart.isBefore(bookingDate);
49
+ });
50
+
51
+ if (candidateRevisions.length === 0) return null;
52
+
53
+ return candidateRevisions.sort((a, b) => {
54
+ const aTime = getSafeDate(a.startDate)?.valueOf() || 0;
55
+ const bTime = getSafeDate(b.startDate)?.valueOf() || 0;
56
+ return bTime - aTime;
57
+ })[0];
58
+ }
59
+
60
+ export function getActivePricing(booking, pricing) {
61
+ const activeRevision = getActiveRevision(booking, pricing);
62
+
63
+ if (!activeRevision) {
64
+ return pricing;
65
+ }
66
+
67
+ return {
68
+ ...pricing,
69
+ ...activeRevision
70
+ };
71
+ }
72
+
30
73
  export function calculateProductSellingPrice(booking, pricing) {
31
74
  return booking.customerPaymentStatus === "Refunded" ? 0 : calculateProductPrice(booking, pricing, { mode: SELLING_MODE });
32
75
  }
@@ -70,22 +113,35 @@ export function calculateInflatedSellingPrice(price, config, forceInflation = fa
70
113
  }
71
114
 
72
115
  function calculateProductPrice(booking, pricing, options = { mode: SELLING_MODE }) {
73
- if (pricing.promotion) {
116
+ const activeRevision = getActiveRevision(booking, pricing);
117
+
118
+ if (!activeRevision) {
119
+ throw new Error("No active pricing revision found for this booking date.");
120
+ }
121
+
122
+ let activeVolumes = activeRevision.volumes;
123
+
124
+ if (activeRevision.promotion) {
74
125
  const departureDate = booking.departureDate instanceof Date ? dayjs(booking.departureDate) : typeof booking.departureDate?.toDate === 'function' ? dayjs(booking.departureDate.toDate()) : null;
75
- const startDate = pricing.promotion.startDate instanceof Date ? pricing.promotion.startDate : typeof pricing.promotion.startDate.toDate === 'function' ? pricing.promotion.startDate.toDate() : null;
76
- const endDate = pricing.promotion.endDate instanceof Date ? pricing.promotion.endDate : typeof pricing.promotion.endDate.toDate === 'function' ? pricing.promotion.endDate.toDate() : null;
126
+ const startDate = activeRevision.promotion.startDate instanceof Date ? activeRevision.promotion.startDate : typeof activeRevision.promotion.startDate.toDate === 'function' ? activeRevision.promotion.startDate.toDate() : null;
127
+ const endDate = activeRevision.promotion.endDate instanceof Date ? activeRevision.promotion.endDate : typeof activeRevision.promotion.endDate.toDate === 'function' ? activeRevision.promotion.endDate.toDate() : null;
77
128
 
78
- if (departureDate?.isBetween(startDate, endDate, "day", "[]")) {
79
- pricing = { ...pricing, volumes: pricing.promotion.volumes };
129
+ if (departureDate?.isValid() && departureDate?.isBetween(dayjs(startDate), dayjs(endDate), "day", "[]")) {
130
+ activeVolumes = activeRevision.promotion.volumes;
80
131
  }
81
132
  }
82
133
 
83
- const type = pricing.type;
134
+ const context = {
135
+ ...pricing,
136
+ volumes: activeVolumes
137
+ };
138
+
84
139
  let total = 0;
140
+ const type = context.type;
85
141
 
86
142
  switch (type) {
87
143
  case "person": {
88
- const volume = findVolume(booking, pricing);
144
+ const volume = findVolume(booking, context);
89
145
  if (!volume) {
90
146
  console.error(`No volume price found for the total amount of ${booking.adults + booking.children} people`);
91
147
  return undefined;
@@ -96,13 +152,13 @@ function calculateProductPrice(booking, pricing, options = { mode: SELLING_MODE
96
152
  const customPricing = volume[bookingSourceKey];
97
153
 
98
154
  if (options.mode === SELLING_MODE) {
99
- const commissionRate = pricing.commissionRates?.[bookingSourceKey];
155
+ const commissionRate = context.commissionRates?.[bookingSourceKey];
100
156
  const baseNetPriceAdult = customPricing.adult.partnerNetPrice;
101
157
  const baseRetailPriceAdult = calculateSellingPrice(commissionRate, baseNetPriceAdult);
102
158
  const finalPriceAdult = calculateInflatedSellingPrice(baseRetailPriceAdult, customPricing);
103
159
 
104
160
  let finalPriceChild = 0;
105
- if (pricing.ageBands.child.active && volume.child && booking.children) {
161
+ if (context.ageBands.child.active && volume.child && booking.children) {
106
162
  const baseNetPriceChild = customPricing.child.partnerNetPrice;
107
163
  const baseRetailPriceChild = calculateSellingPrice(commissionRate, baseNetPriceChild);
108
164
  finalPriceChild = calculateInflatedSellingPrice(baseRetailPriceChild, customPricing);
@@ -110,22 +166,22 @@ function calculateProductPrice(booking, pricing, options = { mode: SELLING_MODE
110
166
 
111
167
  total = booking.adults * finalPriceAdult + (booking.children ? booking.children * finalPriceChild : 0);
112
168
  } else if (options.mode === PARTNER_MODE) {
113
- total = booking.adults * customPricing.adult.partnerNetPrice + (pricing.ageBands.child.active && volume.child && booking.children ? booking.children * customPricing.child.partnerNetPrice : 0);
169
+ total = booking.adults * customPricing.adult.partnerNetPrice + (context.ageBands.child.active && volume.child && booking.children ? booking.children * customPricing.child.partnerNetPrice : 0);
114
170
  } else if (options.mode === OPERATOR_MODE) {
115
- total = booking.adults * (customPricing.adult.operatorNetPrice ?? volume.adult.operatorNetPrice) + (pricing.ageBands.child.active && volume.child && booking.children ? (booking.children * (customPricing.child.operatorNetPrice ?? volume.child.operatorNetPrice)) : 0);
171
+ total = booking.adults * (customPricing.adult.operatorNetPrice ?? volume.adult.operatorNetPrice) + (context.ageBands.child.active && volume.child && booking.children ? (booking.children * (customPricing.child.operatorNetPrice ?? volume.child.operatorNetPrice)) : 0);
116
172
  }
117
173
  } else {
118
174
  if (options.mode === SELLING_MODE || options.mode === PARTNER_MODE) {
119
- total = booking.adults * volume.adult.sellingPrice + (pricing.ageBands.child.active && volume.child && booking.children ? booking.children * volume.child.sellingPrice : 0);
175
+ total = booking.adults * volume.adult.sellingPrice + (context.ageBands.child.active && volume.child && booking.children ? booking.children * volume.child.sellingPrice : 0);
120
176
  } else if (options.mode === OPERATOR_MODE) {
121
- total = booking.adults * volume.adult.operatorNetPrice + (pricing.ageBands.child.active && volume.child && booking.children ? booking.children * volume.child.operatorNetPrice : 0);
177
+ total = booking.adults * volume.adult.operatorNetPrice + (context.ageBands.child.active && volume.child && booking.children ? booking.children * volume.child.operatorNetPrice : 0);
122
178
  }
123
179
  }
124
180
  break;
125
181
  }
126
182
  }
127
183
  case "group": {
128
- const volume = findVolume(booking, pricing);
184
+ const volume = findVolume(booking, context);
129
185
  if (!volume) {
130
186
  console.error(`No volume price found for the total amount of ${booking.adults + booking.children} people`);
131
187
  return undefined;
@@ -136,7 +192,7 @@ function calculateProductPrice(booking, pricing, options = { mode: SELLING_MODE
136
192
  const customPricing = volume[bookingSourceKey];
137
193
 
138
194
  if (options.mode === SELLING_MODE) {
139
- const commissionRate = pricing.commissionRates?.[bookingSourceKey];
195
+ const commissionRate = context.commissionRates?.[bookingSourceKey];
140
196
  const baseNetPrice = customPricing.partnerNetPrice;
141
197
  const baseRetailPrice = calculateSellingPrice(commissionRate, baseNetPrice);
142
198
  const finalPrice = calculateInflatedSellingPrice(baseRetailPrice, customPricing);
@@ -164,14 +220,21 @@ function calculateProductPrice(booking, pricing, options = { mode: SELLING_MODE
164
220
  return total;
165
221
  }
166
222
 
167
- export function findVolume(people, pricing) {
223
+ export function findVolume(people, context) {
168
224
  let total = (people.adults ?? 0) + (people.children ?? 0);
169
- return [...pricing.volumes].sort((v1, v2) => v1.max - v2.max).find((item, i) => {
225
+
226
+ if (!context?.volumes || context.volumes.length === 0) return undefined;
227
+
228
+ const sortedVolumes = [...context.volumes].sort((v1, v2) => v1.max - v2.max);
229
+
230
+ return sortedVolumes.find((item, i) => {
170
231
  if (total <= item.max) {
171
232
  return true;
172
- } else if (i === pricing.volumes.length - 1) {
233
+ }
234
+ else if (i === sortedVolumes.length - 1) {
173
235
  return true;
174
236
  }
237
+ return false;
175
238
  });
176
239
  }
177
240