ti2-tourplan 1.0.122 → 1.0.124

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.
package/README.md CHANGED
@@ -39,3 +39,134 @@ TL;DR Here's what the license entails:
39
39
  7. Any modifications of this code base MUST be distributed with the same license, GPLv3.
40
40
  8. This software is provided without warranty.
41
41
  9. The software author or license can not be held liable for any damages inflicted by the software.
42
+
43
+ ## Cancel Booking (HostConnect)
44
+
45
+ This plugin cancels bookings using `CancelServicesRequest` (not `CancelBookingRequest`).
46
+
47
+ ### HostConnect XML Request
48
+
49
+ ```xml
50
+ <Request>
51
+ <CancelServicesRequest>
52
+ <AgentID>YOUR_AGENT_ID</AgentID>
53
+ <Password>YOUR_AGENT_PASSWORD</Password>
54
+ <BookingId>14226</BookingId>
55
+ <ReturnBooking>Y</ReturnBooking>
56
+ </CancelServicesRequest>
57
+ </Request>
58
+ ```
59
+
60
+ Equivalent curl:
61
+
62
+ ```bash
63
+ curl --location 'https://<HOSTCONNECT_ENDPOINT>/api/hostConnectApi' \
64
+ --header 'Content-Type: application/xml; charset=utf-8' \
65
+ --header 'requestId: <uuid>' \
66
+ --header 'Accept: application/xml' \
67
+ --data '<Request>
68
+ <CancelServicesRequest>
69
+ <AgentID>YOUR_AGENT_ID</AgentID>
70
+ <Password>YOUR_AGENT_PASSWORD</Password>
71
+ <BookingId>14226</BookingId>
72
+ <ReturnBooking>Y</ReturnBooking>
73
+ </CancelServicesRequest>
74
+ </Request>'
75
+ ```
76
+
77
+ ### HostConnect XML Response (example)
78
+
79
+ ```xml
80
+ <?xml version="1.0" encoding="utf-8"?>
81
+ <!DOCTYPE Reply SYSTEM "hostConnect_5_05_010.dtd">
82
+ <Reply>
83
+ <CancelServicesReply>
84
+ <BookingId>14226</BookingId>
85
+ <Ref>A2IN111975</Ref>
86
+ <ServiceStatuses>
87
+ <ServiceStatus>
88
+ <ServiceLineId>61738</ServiceLineId>
89
+ <Date>2026-07-03</Date>
90
+ <SequenceNumber>10</SequenceNumber>
91
+ <Status>XX</Status>
92
+ </ServiceStatus>
93
+ </ServiceStatuses>
94
+ </CancelServicesReply>
95
+ </Reply>
96
+ ```
97
+
98
+ ### Plugin Return Shape
99
+
100
+ The plugin returns both:
101
+
102
+ - `cancelServicesReply`: raw parsed `CancelServicesReply` object
103
+ - `cancellation`: normalized object
104
+ - `id`: from `BookingId`
105
+ - `status`: aggregate over all `ServiceStatus.Status` values:
106
+ - same status on all lines => that status (e.g. `XX`)
107
+ - mixed line statuses => `MIXED`
108
+
109
+ ## Confirm Booking (HostConnect)
110
+
111
+ This plugin converts a quote to a confirmed booking using HostConnect `QuoteToBookRequest`. Inventory is allocated for each service line when the quote is confirmed; the returned `ServiceStatus` values indicate whether allocation succeeded per line.
112
+
113
+ ### HostConnect XML Request
114
+
115
+ ```xml
116
+ <Request>
117
+ <QuoteToBookRequest>
118
+ <AgentID>YOUR_AGENT_ID</AgentID>
119
+ <Password>YOUR_AGENT_PASSWORD</Password>
120
+ <BookingId>14226</BookingId>
121
+ </QuoteToBookRequest>
122
+ </Request>
123
+ ```
124
+
125
+ Equivalent curl:
126
+
127
+ ```bash
128
+ curl --location 'https://<HOSTCONNECT_ENDPOINT>/api/hostConnectApi' \
129
+ --header 'Content-Type: application/xml; charset=utf-8' \
130
+ --header 'requestId: <uuid>' \
131
+ --header 'Accept: application/xml' \
132
+ --data '<Request>
133
+ <QuoteToBookRequest>
134
+ <AgentID>YOUR_AGENT_ID</AgentID>
135
+ <Password>YOUR_AGENT_PASSWORD</Password>
136
+ <BookingId>14226</BookingId>
137
+ </QuoteToBookRequest>
138
+ </Request>'
139
+ ```
140
+
141
+ ### HostConnect XML Response (example)
142
+
143
+ ```xml
144
+ <?xml version="1.0" encoding="utf-8"?>
145
+ <!DOCTYPE Reply SYSTEM "hostConnect_5_05_010.dtd">
146
+ <Reply>
147
+ <QuoteToBookReply>
148
+ <BookingId>14226</BookingId>
149
+ <Ref>A2IN111975</Ref>
150
+ <ServiceStatuses>
151
+ <ServiceStatus>
152
+ <Ref>A2IN111975</Ref>
153
+ <ServiceLineId>61738</ServiceLineId>
154
+ <Date>2026-07-03</Date>
155
+ <SequenceNumber>10</SequenceNumber>
156
+ <Status>OK</Status>
157
+ </ServiceStatus>
158
+ </ServiceStatuses>
159
+ </QuoteToBookReply>
160
+ </Reply>
161
+ ```
162
+
163
+ ### Plugin Return Shape
164
+
165
+ The plugin returns both:
166
+
167
+ - `confirmBookingReply`: raw parsed HostConnect `QuoteToBookReply` object
168
+ - `booking`: normalized object
169
+ - `ref`: from `Ref`
170
+ - `id`: from `BookingId` (or the identifier sent in the request)
171
+ - `status`: aggregate over all `ServiceStatus.Status` values (same rules as cancel), with fallbacks to `BookingStatus`, `Status`, `payload.status`, then `'Confirmed'`
172
+ - `serviceLines`: array of `{ ref, serviceLineId, date, sequenceNumber, status }`
package/index.js CHANGED
@@ -10,6 +10,8 @@ const Normalizer = require('./normalizer');
10
10
 
11
11
  const { searchAvailabilityForItinerary } = require('./availability/itinerary-availability');
12
12
  const { addServiceToItinerary } = require('./itinerary-add-service');
13
+ const { cancelBooking } = require('./itinerary-cancel-booking');
14
+ const { confirmBooking } = require('./itinerary-confirm-booking');
13
15
  const { searchProductsForItinerary } = require('./itinerary-products-search');
14
16
  const { searchItineraries } = require('./itinerary-search');
15
17
  const { hostConnectXmlOptions } = require('./utils');
@@ -679,6 +681,38 @@ class BuyerPlugin {
679
681
  });
680
682
  }
681
683
 
684
+ /**
685
+ * Cancel a booking.
686
+ */
687
+ async cancelBooking({
688
+ axios,
689
+ token,
690
+ payload,
691
+ }) {
692
+ return cancelBooking({
693
+ axios,
694
+ token,
695
+ payload,
696
+ callTourplan: this.callTourplan.bind(this),
697
+ });
698
+ }
699
+
700
+ /**
701
+ * Convert a quote to a confirmed booking.
702
+ */
703
+ async confirmBooking({
704
+ axios,
705
+ token,
706
+ payload,
707
+ }) {
708
+ return confirmBooking({
709
+ axios,
710
+ token,
711
+ payload,
712
+ callTourplan: this.callTourplan.bind(this),
713
+ });
714
+ }
715
+
682
716
  async searchItineraries({
683
717
  axios,
684
718
  typeDefsAndQueries,
package/index.test.js CHANGED
@@ -132,6 +132,306 @@ describe('search tests', () => {
132
132
  }
133
133
  });
134
134
  });
135
+ describe('cancelBooking', () => {
136
+ it('cancels a booking by id', async () => {
137
+ mockCallTourplan.mockImplementationOnce(async () => ({
138
+ CancelServicesReply: {
139
+ BookingId: '316559',
140
+ Ref: 'A2IN111975',
141
+ ServiceStatuses: {
142
+ ServiceStatus: {
143
+ ServiceLineId: '61738',
144
+ Date: '2026-07-03',
145
+ SequenceNumber: '10',
146
+ Status: 'XX',
147
+ },
148
+ },
149
+ },
150
+ }));
151
+ const retVal = await app.cancelBooking({
152
+ axios,
153
+ token,
154
+ payload: {
155
+ id: '316559',
156
+ status: 'Cancelled',
157
+ clicked: 1719571452,
158
+ },
159
+ });
160
+ expect(mockCallTourplan).toHaveBeenNthCalledWith(1, expect.objectContaining({
161
+ model: {
162
+ CancelServicesRequest: expect.objectContaining({
163
+ BookingId: '316559',
164
+ ReturnBooking: 'Y',
165
+ }),
166
+ },
167
+ }));
168
+ expect(retVal).toEqual({
169
+ cancelServicesReply: {
170
+ BookingId: '316559',
171
+ Ref: 'A2IN111975',
172
+ ServiceStatuses: {
173
+ ServiceStatus: {
174
+ ServiceLineId: '61738',
175
+ Date: '2026-07-03',
176
+ SequenceNumber: '10',
177
+ Status: 'XX',
178
+ },
179
+ },
180
+ },
181
+ cancellation: {
182
+ id: '316559',
183
+ status: 'XX',
184
+ },
185
+ });
186
+ });
187
+
188
+ it('cancels a booking by ref', async () => {
189
+ mockCallTourplan.mockImplementationOnce(async () => ({
190
+ CancelServicesReply: {
191
+ BookingId: '316559',
192
+ ServiceStatuses: {
193
+ ServiceStatus: [{
194
+ ServiceLineId: '61738',
195
+ Status: 'XX',
196
+ }],
197
+ },
198
+ },
199
+ }));
200
+ const retVal = await app.cancelBooking({
201
+ axios,
202
+ token,
203
+ payload: {
204
+ ref: 'ALFI393706',
205
+ status: 'Cancelled',
206
+ clicked: 1719571452,
207
+ },
208
+ });
209
+ expect(mockCallTourplan).toHaveBeenNthCalledWith(1, expect.objectContaining({
210
+ model: {
211
+ CancelServicesRequest: expect.objectContaining({
212
+ Ref: 'ALFI393706',
213
+ ReturnBooking: 'Y',
214
+ }),
215
+ },
216
+ }));
217
+ expect(retVal).toEqual({
218
+ cancelServicesReply: {
219
+ BookingId: '316559',
220
+ ServiceStatuses: {
221
+ ServiceStatus: [{
222
+ ServiceLineId: '61738',
223
+ Status: 'XX',
224
+ }],
225
+ },
226
+ },
227
+ cancellation: {
228
+ id: '316559',
229
+ status: 'XX',
230
+ },
231
+ });
232
+ });
233
+
234
+ it('returns MIXED status when service statuses differ', async () => {
235
+ mockCallTourplan.mockImplementationOnce(async () => ({
236
+ CancelServicesReply: {
237
+ BookingId: '316559',
238
+ ServiceStatuses: {
239
+ ServiceStatus: [{
240
+ ServiceLineId: '61738',
241
+ Status: 'XX',
242
+ }, {
243
+ ServiceLineId: '61739',
244
+ Status: 'RQ',
245
+ }],
246
+ },
247
+ },
248
+ }));
249
+ const retVal = await app.cancelBooking({
250
+ axios,
251
+ token,
252
+ payload: {
253
+ bookingId: '316559',
254
+ status: 'Cancelled',
255
+ clicked: 1719571452,
256
+ },
257
+ });
258
+ expect(retVal).toEqual({
259
+ cancelServicesReply: {
260
+ BookingId: '316559',
261
+ ServiceStatuses: {
262
+ ServiceStatus: [{
263
+ ServiceLineId: '61738',
264
+ Status: 'XX',
265
+ }, {
266
+ ServiceLineId: '61739',
267
+ Status: 'RQ',
268
+ }],
269
+ },
270
+ },
271
+ cancellation: {
272
+ id: '316559',
273
+ status: 'MIXED',
274
+ },
275
+ });
276
+ });
277
+
278
+ it('requires a booking id or reference', async () => {
279
+ await expect(app.cancelBooking({
280
+ axios,
281
+ token,
282
+ payload: {},
283
+ })).rejects.toThrow('Must provide booking id or reference for cancellation');
284
+ expect(mockCallTourplan).not.toHaveBeenCalled();
285
+ });
286
+ });
287
+ describe('confirmBooking', () => {
288
+ it('converts a quote to a booking by id', async () => {
289
+ mockCallTourplan.mockImplementationOnce(async () => ({
290
+ QuoteToBookReply: {
291
+ BookingId: '14226',
292
+ Ref: 'A2IN111975',
293
+ ServiceStatuses: {
294
+ ServiceStatus: {
295
+ Ref: 'A2IN111975',
296
+ ServiceLineId: '61738',
297
+ Date: '2026-07-03',
298
+ SequenceNumber: '10',
299
+ Status: 'OK',
300
+ },
301
+ },
302
+ },
303
+ }));
304
+ const retVal = await app.confirmBooking({
305
+ axios,
306
+ token,
307
+ payload: {
308
+ bookingId: '14226',
309
+ },
310
+ });
311
+ expect(mockCallTourplan).toHaveBeenNthCalledWith(1, expect.objectContaining({
312
+ model: {
313
+ QuoteToBookRequest: expect.objectContaining({
314
+ BookingId: '14226',
315
+ }),
316
+ },
317
+ }));
318
+ expect(retVal).toEqual({
319
+ confirmBookingReply: {
320
+ BookingId: '14226',
321
+ Ref: 'A2IN111975',
322
+ ServiceStatuses: {
323
+ ServiceStatus: {
324
+ Ref: 'A2IN111975',
325
+ ServiceLineId: '61738',
326
+ Date: '2026-07-03',
327
+ SequenceNumber: '10',
328
+ Status: 'OK',
329
+ },
330
+ },
331
+ },
332
+ booking: {
333
+ ref: 'A2IN111975',
334
+ id: '14226',
335
+ status: 'OK',
336
+ serviceLines: [{
337
+ ref: 'A2IN111975',
338
+ serviceLineId: '61738',
339
+ date: '2026-07-03',
340
+ sequenceNumber: '10',
341
+ status: 'OK',
342
+ }],
343
+ },
344
+ });
345
+ });
346
+
347
+ it('converts a quote to a booking by ref', async () => {
348
+ mockCallTourplan.mockImplementationOnce(async () => ({
349
+ QuoteToBookReply: {
350
+ BookingId: '14226',
351
+ Ref: 'A2IN111975',
352
+ ServiceStatuses: {
353
+ ServiceStatus: [{
354
+ ServiceLineId: '61738',
355
+ Date: '2026-07-03',
356
+ SequenceNumber: '10',
357
+ Status: 'OK',
358
+ }],
359
+ },
360
+ },
361
+ }));
362
+ const retVal = await app.confirmBooking({
363
+ axios,
364
+ token,
365
+ payload: {
366
+ ref: 'A2IN111975',
367
+ },
368
+ });
369
+ expect(mockCallTourplan).toHaveBeenNthCalledWith(1, expect.objectContaining({
370
+ model: {
371
+ QuoteToBookRequest: expect.objectContaining({
372
+ Ref: 'A2IN111975',
373
+ }),
374
+ },
375
+ }));
376
+ expect(retVal.booking.id).toBe('14226');
377
+ expect(retVal.booking.ref).toBe('A2IN111975');
378
+ expect(retVal.booking.status).toBe('OK');
379
+ });
380
+
381
+ it('returns MIXED status when service line statuses differ', async () => {
382
+ mockCallTourplan.mockImplementationOnce(async () => ({
383
+ QuoteToBookReply: {
384
+ BookingId: '14226',
385
+ Ref: 'A2IN111975',
386
+ ServiceStatuses: {
387
+ ServiceStatus: [{
388
+ ServiceLineId: '61738',
389
+ Status: 'OK',
390
+ }, {
391
+ ServiceLineId: '61739',
392
+ Status: 'RQ',
393
+ }],
394
+ },
395
+ },
396
+ }));
397
+ const retVal = await app.confirmBooking({
398
+ axios,
399
+ token,
400
+ payload: {
401
+ bookingId: '14226',
402
+ },
403
+ });
404
+ expect(retVal.booking.status).toBe('MIXED');
405
+ expect(retVal.booking.serviceLines).toHaveLength(2);
406
+ });
407
+
408
+ it('requires a booking id or reference', async () => {
409
+ await expect(app.confirmBooking({
410
+ axios,
411
+ token,
412
+ payload: {},
413
+ })).rejects.toThrow('Must provide booking id or reference for confirm booking');
414
+ expect(mockCallTourplan).not.toHaveBeenCalled();
415
+ });
416
+
417
+ it('falls back to Confirmed when no service statuses are returned', async () => {
418
+ mockCallTourplan.mockImplementationOnce(async () => ({
419
+ QuoteToBookReply: {
420
+ BookingId: '14226',
421
+ Ref: 'A2IN111975',
422
+ },
423
+ }));
424
+ const retVal = await app.confirmBooking({
425
+ axios,
426
+ token,
427
+ payload: {
428
+ bookingId: '14226',
429
+ },
430
+ });
431
+ expect(retVal.booking.status).toBe('Confirmed');
432
+ expect(retVal.booking.serviceLines).toEqual([]);
433
+ });
434
+ });
135
435
  describe('template tests', () => {
136
436
  let template;
137
437
  it('get the template', async () => {
@@ -0,0 +1,72 @@
1
+ const assert = require('assert');
2
+ const R = require('ramda');
3
+ const {
4
+ hostConnectXmlOptions,
5
+ } = require('./utils');
6
+ const {
7
+ getBookingIdentifier,
8
+ getAggregateServiceStatus,
9
+ } = require('./itinerary-hostconnect-helpers');
10
+
11
+ const extractCancellationReply = replyObj => (
12
+ R.path(['CancelServicesReply'], replyObj)
13
+ || {}
14
+ );
15
+
16
+ const normalizeCancellationResponse = (replyObj, payload, identifier) => {
17
+ const cancellationReply = extractCancellationReply(replyObj);
18
+ const aggregateServiceStatus = getAggregateServiceStatus(cancellationReply);
19
+ return {
20
+ cancelServicesReply: cancellationReply,
21
+ cancellation: {
22
+ id: R.path(['BookingId'], cancellationReply) || identifier.value,
23
+ status: aggregateServiceStatus
24
+ || R.path(['BookingStatus'], cancellationReply)
25
+ || R.path(['Status'], cancellationReply)
26
+ || payload.status
27
+ || 'Cancelled',
28
+ },
29
+ };
30
+ };
31
+
32
+ /**
33
+ * Cancels a booking by id or reference via HostConnect CancelServicesRequest.
34
+ */
35
+ const cancelBooking = async ({
36
+ axios,
37
+ token: {
38
+ hostConnectEndpoint,
39
+ hostConnectAgentID,
40
+ hostConnectAgentPassword,
41
+ },
42
+ payload = {},
43
+ callTourplan,
44
+ }) => {
45
+ assert(hostConnectEndpoint, 'Must provide token.hostConnectEndpoint for booking cancellation');
46
+ assert(hostConnectAgentID, 'Must provide token.hostConnectAgentID for booking cancellation');
47
+ assert(hostConnectAgentPassword, 'Must provide token.hostConnectAgentPassword for booking cancellation');
48
+ const identifier = getBookingIdentifier(payload);
49
+ assert(identifier, 'Must provide booking id or reference for cancellation');
50
+
51
+ const baseRequest = {
52
+ AgentID: hostConnectAgentID,
53
+ Password: hostConnectAgentPassword,
54
+ [identifier.field]: identifier.value,
55
+ };
56
+ const replyObj = await callTourplan({
57
+ model: {
58
+ CancelServicesRequest: {
59
+ ...baseRequest,
60
+ ReturnBooking: 'Y',
61
+ },
62
+ },
63
+ endpoint: hostConnectEndpoint,
64
+ axios,
65
+ xmlOptions: hostConnectXmlOptions,
66
+ });
67
+ return normalizeCancellationResponse(replyObj, payload, identifier);
68
+ };
69
+
70
+ module.exports = {
71
+ cancelBooking,
72
+ };
@@ -0,0 +1,72 @@
1
+ const assert = require('assert');
2
+ const R = require('ramda');
3
+ const { hostConnectXmlOptions } = require('./utils');
4
+ const {
5
+ getBookingIdentifier,
6
+ getAggregateServiceStatus,
7
+ mapServiceStatusLines,
8
+ } = require('./itinerary-hostconnect-helpers');
9
+
10
+ const extractConfirmBookingReply = replyObj => (
11
+ R.path(['QuoteToBookReply'], replyObj)
12
+ || {}
13
+ );
14
+
15
+ const normalizeConfirmBookingResponse = (replyObj, payload, identifier) => {
16
+ const confirmBookingReply = extractConfirmBookingReply(replyObj);
17
+ const aggregateServiceStatus = getAggregateServiceStatus(confirmBookingReply);
18
+ return {
19
+ confirmBookingReply,
20
+ booking: {
21
+ ref: R.path(['Ref'], confirmBookingReply),
22
+ id: R.path(['BookingId'], confirmBookingReply) || identifier.value,
23
+ status: aggregateServiceStatus
24
+ || R.path(['BookingStatus'], confirmBookingReply)
25
+ || R.path(['Status'], confirmBookingReply)
26
+ || payload.status
27
+ || 'Confirmed',
28
+ serviceLines: mapServiceStatusLines(confirmBookingReply),
29
+ },
30
+ };
31
+ };
32
+
33
+ /**
34
+ * Converts a quote to a confirmed booking via HostConnect QuoteToBookRequest.
35
+ * Inventory is allocated for each service line; returned ServiceStatus values
36
+ * indicate whether allocation succeeded per line.
37
+ */
38
+ const confirmBooking = async ({
39
+ axios,
40
+ token: {
41
+ hostConnectEndpoint,
42
+ hostConnectAgentID,
43
+ hostConnectAgentPassword,
44
+ },
45
+ payload = {},
46
+ callTourplan,
47
+ }) => {
48
+ assert(hostConnectEndpoint, 'Must provide token.hostConnectEndpoint for confirm booking');
49
+ assert(hostConnectAgentID, 'Must provide token.hostConnectAgentID for confirm booking');
50
+ assert(hostConnectAgentPassword, 'Must provide token.hostConnectAgentPassword for confirm booking');
51
+ const identifier = getBookingIdentifier(payload);
52
+ assert(identifier, 'Must provide booking id or reference for confirm booking');
53
+
54
+ const baseRequest = {
55
+ AgentID: hostConnectAgentID,
56
+ Password: hostConnectAgentPassword,
57
+ [identifier.field]: identifier.value,
58
+ };
59
+ const replyObj = await callTourplan({
60
+ model: {
61
+ QuoteToBookRequest: baseRequest,
62
+ },
63
+ endpoint: hostConnectEndpoint,
64
+ axios,
65
+ xmlOptions: hostConnectXmlOptions,
66
+ });
67
+ return normalizeConfirmBookingResponse(replyObj, payload, identifier);
68
+ };
69
+
70
+ module.exports = {
71
+ confirmBooking,
72
+ };
@@ -0,0 +1,52 @@
1
+ const R = require('ramda');
2
+ const { escapeInvalidXmlChars } = require('./utils');
3
+
4
+ const getBookingIdentifier = payload => {
5
+ const bookingId = payload.bookingId || payload.id;
6
+ if (bookingId) {
7
+ return {
8
+ field: 'BookingId',
9
+ value: String(bookingId),
10
+ };
11
+ }
12
+ const bookingRef = payload.ref || payload.reference;
13
+ if (bookingRef) {
14
+ return {
15
+ field: 'Ref',
16
+ value: escapeInvalidXmlChars(String(bookingRef)),
17
+ };
18
+ }
19
+ return null;
20
+ };
21
+
22
+ const toServiceStatusArray = reply => {
23
+ let serviceStatuses = R.pathOr([], ['ServiceStatuses', 'ServiceStatus'], reply);
24
+ if (!Array.isArray(serviceStatuses)) serviceStatuses = [serviceStatuses];
25
+ return serviceStatuses.filter(Boolean);
26
+ };
27
+
28
+ const getAggregateServiceStatus = reply => {
29
+ const statuses = toServiceStatusArray(reply)
30
+ .map(serviceStatus => R.path(['Status'], serviceStatus))
31
+ .filter(Boolean)
32
+ .map(status => String(status).toUpperCase());
33
+ if (!statuses.length) return null;
34
+ const uniqueStatuses = [...new Set(statuses)];
35
+ if (uniqueStatuses.length === 1) return uniqueStatuses[0];
36
+ return 'MIXED';
37
+ };
38
+
39
+ const mapServiceStatusLines = reply => toServiceStatusArray(reply).map(serviceStatus => ({
40
+ ref: R.path(['Ref'], serviceStatus),
41
+ serviceLineId: R.path(['ServiceLineId'], serviceStatus),
42
+ date: R.path(['Date'], serviceStatus),
43
+ sequenceNumber: R.path(['SequenceNumber'], serviceStatus),
44
+ status: R.path(['Status'], serviceStatus),
45
+ }));
46
+
47
+ module.exports = {
48
+ getBookingIdentifier,
49
+ toServiceStatusArray,
50
+ getAggregateServiceStatus,
51
+ mapServiceStatusLines,
52
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ti2-tourplan",
3
- "version": "1.0.122",
3
+ "version": "1.0.124",
4
4
  "description": "Tourplan's TI2 Plugin",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -39,7 +39,7 @@
39
39
  "jsonwebtoken": "^8.5.1",
40
40
  "moment": "^2.29.1",
41
41
  "ramda": "^0.27.1",
42
- "ti2": "^1.0.111",
42
+ "ti2": "^1.0.118",
43
43
  "underscore": "^1.13.4",
44
44
  "xml-js": "^1.6.11",
45
45
  "xml2js": "^0.4.23"