@vulog/aima-booking 1.2.33 → 1.2.35
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 +103 -0
- package/dist/index.cjs +82 -6
- package/dist/index.d.cts +125 -1
- package/dist/index.d.mts +125 -1
- package/dist/index.mjs +77 -7
- package/package.json +3 -3
- package/src/getAdditionalDrivers.test.ts +61 -0
- package/src/getAdditionalDrivers.ts +23 -0
- package/src/getAvailableVehicles.test.ts +53 -0
- package/src/getBookingRequest.test.ts +72 -1
- package/src/getBookingRequest.ts +15 -1
- package/src/getDigitalContracts.test.ts +72 -0
- package/src/getDigitalContracts.ts +26 -0
- package/src/getSlaves.test.ts +60 -0
- package/src/getSlaves.ts +24 -0
- package/src/getSubscriptionsByUserId.test.ts +96 -0
- package/src/getSubscriptionsByUserId.ts +27 -0
- package/src/index.ts +11 -1
- package/src/submitCancellationRequest.test.ts +81 -0
- package/src/submitCancellationRequest.ts +38 -0
- package/src/types.ts +117 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, test, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { Client } from '@vulog/aima-client';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
import { getSubscriptionsByUserId } from './getSubscriptionsByUserId';
|
|
5
|
+
import type { Master } from './types';
|
|
6
|
+
|
|
7
|
+
describe('getSubscriptionsByUserId', () => {
|
|
8
|
+
const getMock = vi.fn();
|
|
9
|
+
const client = {
|
|
10
|
+
get: getMock,
|
|
11
|
+
clientOptions: {
|
|
12
|
+
fleetId: 'FLEET_ID',
|
|
13
|
+
},
|
|
14
|
+
} as unknown as Client;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
getMock.mockReset();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('throws Invalid userId when userId is not a valid UUID', async () => {
|
|
21
|
+
await expect(getSubscriptionsByUserId(client, 'not-a-uuid')).rejects.toThrow(TypeError);
|
|
22
|
+
await expect(getSubscriptionsByUserId(client, 'not-a-uuid')).rejects.toMatchObject({
|
|
23
|
+
message: 'Invalid userId',
|
|
24
|
+
});
|
|
25
|
+
expect(getMock).not.toHaveBeenCalled();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('calls GET with active path by default and returns masters', async () => {
|
|
29
|
+
const userId = randomUUID();
|
|
30
|
+
const masters: Master[] = [
|
|
31
|
+
{
|
|
32
|
+
id: randomUUID(),
|
|
33
|
+
fleetId: 'FLEET_ID',
|
|
34
|
+
userId,
|
|
35
|
+
bookingReferenceId: 'q93UCF',
|
|
36
|
+
startDate: '2026-03-03T10:00:00Z',
|
|
37
|
+
endDate: '2026-06-03T09:00:00Z',
|
|
38
|
+
creationDate: '2026-03-03T09:29:45Z',
|
|
39
|
+
status: 'CONFIRMED',
|
|
40
|
+
contractType: 'SVS',
|
|
41
|
+
station: 'ded03b86-fa3f-4d79-80fa-191b2ec13b5e',
|
|
42
|
+
vehicleId: randomUUID(),
|
|
43
|
+
modelId: 2597,
|
|
44
|
+
journeyId: 'BEBD00056A9A16103D418CC36D940E26',
|
|
45
|
+
profileId: randomUUID(),
|
|
46
|
+
serviceId: randomUUID(),
|
|
47
|
+
planDurationInMonths: 3,
|
|
48
|
+
planName: '3 mois',
|
|
49
|
+
rollingContract: true,
|
|
50
|
+
returnedDate: null,
|
|
51
|
+
cancellationDate: null,
|
|
52
|
+
cityId: null,
|
|
53
|
+
customPrice: null,
|
|
54
|
+
deliveryAddress: null,
|
|
55
|
+
deliveryAddressAdditionalInfo: null,
|
|
56
|
+
deliveryCity: null,
|
|
57
|
+
deliveryPostalCode: null,
|
|
58
|
+
plannedReturnDate: null,
|
|
59
|
+
parentId: randomUUID(),
|
|
60
|
+
previous: null,
|
|
61
|
+
pricingId: null,
|
|
62
|
+
products: [],
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
getMock.mockResolvedValueOnce({ data: masters });
|
|
66
|
+
|
|
67
|
+
const result = await getSubscriptionsByUserId(client, userId);
|
|
68
|
+
|
|
69
|
+
expect(getMock).toHaveBeenCalledTimes(1);
|
|
70
|
+
expect(getMock).toHaveBeenCalledWith(
|
|
71
|
+
`/boapi/proxy/user/scheduledBooking/fleets/FLEET_ID/subscription/users/${userId}/active`
|
|
72
|
+
);
|
|
73
|
+
expect(result).toEqual(masters);
|
|
74
|
+
expect(result).toHaveLength(1);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('calls GET with past path when active is false', async () => {
|
|
78
|
+
const userId = randomUUID();
|
|
79
|
+
getMock.mockResolvedValueOnce({ data: [] });
|
|
80
|
+
|
|
81
|
+
await getSubscriptionsByUserId(client, userId, false);
|
|
82
|
+
|
|
83
|
+
expect(getMock).toHaveBeenCalledWith(
|
|
84
|
+
`/boapi/proxy/user/scheduledBooking/fleets/FLEET_ID/subscription/users/${userId}/past`
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('returns empty array when no subscriptions', async () => {
|
|
89
|
+
const userId = randomUUID();
|
|
90
|
+
getMock.mockResolvedValueOnce({ data: [] });
|
|
91
|
+
|
|
92
|
+
const result = await getSubscriptionsByUserId(client, userId);
|
|
93
|
+
|
|
94
|
+
expect(result).toEqual([]);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { Master } from './types';
|
|
5
|
+
|
|
6
|
+
const schema = z.object({
|
|
7
|
+
userId: z.string().trim().min(1).uuid(),
|
|
8
|
+
active: z.boolean().optional().default(true),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const getSubscriptionsByUserId = async (
|
|
12
|
+
client: Client,
|
|
13
|
+
userId: string,
|
|
14
|
+
active: boolean = true
|
|
15
|
+
): Promise<Master[]> => {
|
|
16
|
+
const result = schema.safeParse({ userId, active });
|
|
17
|
+
if (!result.success) {
|
|
18
|
+
throw new TypeError('Invalid userId', {
|
|
19
|
+
cause: result.error.issues,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return client
|
|
23
|
+
.get<
|
|
24
|
+
Master[]
|
|
25
|
+
>(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/subscription/users/${userId}/${active ? 'active' : 'past'}`)
|
|
26
|
+
.then(({ data }) => data);
|
|
27
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export { getBookingRequests, getScheduleBookingRequests, getSubscriptionBookingRequests } from './getBookingRequests';
|
|
2
2
|
export { getSATBookingRequests } from './getSATBookingRequests';
|
|
3
|
-
export {
|
|
3
|
+
export {
|
|
4
|
+
getBookingRequestById,
|
|
5
|
+
getBookingRequestByTrip,
|
|
6
|
+
getSubscriptionBookingRequestById,
|
|
7
|
+
getScheduledBookingById,
|
|
8
|
+
} from './getBookingRequest';
|
|
4
9
|
export * from './types';
|
|
5
10
|
export type { BookingRequestStatus, ServiceType, BookingRequestFilters } from './getBookingRequests';
|
|
6
11
|
export type { SATBookingRequestStatus } from './getSATBookingRequests';
|
|
@@ -16,5 +21,10 @@ export { triggerBRPayment } from './triggerBRPayment';
|
|
|
16
21
|
export { getBookingRequestsByUserId } from './getBookingRequestsByUserId';
|
|
17
22
|
export { releaseBRPayment } from './releaseBRPayment';
|
|
18
23
|
export { cancelBookingRequest } from './cancelBookingRequest';
|
|
24
|
+
export { getDigitalContracts } from './getDigitalContracts';
|
|
25
|
+
export { getAdditionalDrivers } from './getAdditionalDrivers';
|
|
26
|
+
export { getSlaves } from './getSlaves';
|
|
27
|
+
export { getSubscriptionsByUserId } from './getSubscriptionsByUserId';
|
|
28
|
+
export { submitCancellationRequest } from './submitCancellationRequest';
|
|
19
29
|
export { createSubscription } from './createSubscription';
|
|
20
30
|
export type { CreateSubscriptionBody } from './createSubscription';
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, test, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { Client } from '@vulog/aima-client';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
import { submitCancellationRequest } from './submitCancellationRequest';
|
|
5
|
+
import type { SATBookingRequest } from './types';
|
|
6
|
+
|
|
7
|
+
describe('submitCancellationRequest', () => {
|
|
8
|
+
const postMock = vi.fn();
|
|
9
|
+
const client = {
|
|
10
|
+
post: postMock,
|
|
11
|
+
clientOptions: {
|
|
12
|
+
fleetId: 'FLEET_ID',
|
|
13
|
+
},
|
|
14
|
+
} as unknown as Client;
|
|
15
|
+
|
|
16
|
+
const minimalResponse = {
|
|
17
|
+
id: randomUUID(),
|
|
18
|
+
status: 'PENDING',
|
|
19
|
+
startDate: '2026-03-03T10:00:00Z',
|
|
20
|
+
endDate: '2026-06-03T09:00:00Z',
|
|
21
|
+
fleetId: 'FLEET_ID',
|
|
22
|
+
userId: randomUUID(),
|
|
23
|
+
profileId: randomUUID(),
|
|
24
|
+
serviceId: randomUUID(),
|
|
25
|
+
creationDate: '2026-03-03T09:29:45Z',
|
|
26
|
+
productIds: [],
|
|
27
|
+
pricingDetails: [],
|
|
28
|
+
completed: false,
|
|
29
|
+
rollingContract: true,
|
|
30
|
+
contractType: 'SVS',
|
|
31
|
+
notes: '',
|
|
32
|
+
} as unknown as SATBookingRequest;
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
postMock.mockReset();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('throws Invalid args when bookingRequestId is not a valid UUID', async () => {
|
|
39
|
+
const userId = randomUUID();
|
|
40
|
+
await expect(
|
|
41
|
+
submitCancellationRequest(client, 'not-a-uuid', userId)
|
|
42
|
+
).rejects.toThrow(TypeError);
|
|
43
|
+
await expect(
|
|
44
|
+
submitCancellationRequest(client, 'not-a-uuid', userId)
|
|
45
|
+
).rejects.toMatchObject({ message: 'Invalid args' });
|
|
46
|
+
expect(postMock).not.toHaveBeenCalled();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('calls POST with correct URL and body and returns SATBookingRequest', async () => {
|
|
50
|
+
const bookingRequestId = randomUUID();
|
|
51
|
+
const userId = randomUUID();
|
|
52
|
+
postMock.mockResolvedValueOnce({ data: minimalResponse });
|
|
53
|
+
|
|
54
|
+
const result = await submitCancellationRequest(client, bookingRequestId, userId);
|
|
55
|
+
|
|
56
|
+
expect(postMock).toHaveBeenCalledTimes(1);
|
|
57
|
+
expect(postMock).toHaveBeenCalledWith(
|
|
58
|
+
`/boapi/proxy/user/fleets/FLEET_ID/bookingrequests/${bookingRequestId}/actions`,
|
|
59
|
+
{
|
|
60
|
+
action: 'EARLIER_CANCELLATION_REQUEST',
|
|
61
|
+
bookingStatusBO: 'ONGOING',
|
|
62
|
+
status: 'PENDING',
|
|
63
|
+
userId,
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
expect(result).toEqual(minimalResponse);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('throws when request fails', async () => {
|
|
70
|
+
const bookingRequestId = randomUUID();
|
|
71
|
+
const userId = randomUUID();
|
|
72
|
+
const networkError = new Error('Network error');
|
|
73
|
+
postMock.mockRejectedValueOnce(networkError);
|
|
74
|
+
|
|
75
|
+
await expect(
|
|
76
|
+
submitCancellationRequest(client, bookingRequestId, userId)
|
|
77
|
+
).rejects.toMatchObject({
|
|
78
|
+
message: 'Failed to submit cancellation request',
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { SATBookingRequest } from './types';
|
|
5
|
+
|
|
6
|
+
const schema = z.object({
|
|
7
|
+
bookingRequestId: z.string().uuid(),
|
|
8
|
+
userId: z.string().uuid(),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const submitCancellationRequest = async (
|
|
12
|
+
client: Client,
|
|
13
|
+
bookingRequestId: string,
|
|
14
|
+
userId: string
|
|
15
|
+
): Promise<SATBookingRequest> => {
|
|
16
|
+
const result = schema.safeParse({ bookingRequestId, userId });
|
|
17
|
+
if (!result.success) {
|
|
18
|
+
throw new TypeError('Invalid args', {
|
|
19
|
+
cause: result.error.issues,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return client
|
|
23
|
+
.post<SATBookingRequest>(
|
|
24
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/bookingrequests/${bookingRequestId}/actions`,
|
|
25
|
+
{
|
|
26
|
+
action: 'EARLIER_CANCELLATION_REQUEST',
|
|
27
|
+
bookingStatusBO: 'ONGOING',
|
|
28
|
+
status: 'PENDING',
|
|
29
|
+
userId,
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
.then(({ data }) => data)
|
|
33
|
+
.catch((error) => {
|
|
34
|
+
throw new TypeError('Failed to submit cancellation request', {
|
|
35
|
+
cause: error,
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -225,3 +225,120 @@ export type AvailableVehiclesResponse = {
|
|
|
225
225
|
stationId: string;
|
|
226
226
|
vehicles: Vehicle[];
|
|
227
227
|
};
|
|
228
|
+
|
|
229
|
+
export type Slave = {
|
|
230
|
+
previous: string | null;
|
|
231
|
+
compositeStatus: string;
|
|
232
|
+
id: string;
|
|
233
|
+
startDate: string;
|
|
234
|
+
endDate: string;
|
|
235
|
+
profileId: string;
|
|
236
|
+
vehicleId: string;
|
|
237
|
+
modelId: number;
|
|
238
|
+
journeyId: string;
|
|
239
|
+
station: string;
|
|
240
|
+
status: string;
|
|
241
|
+
creationDate: string;
|
|
242
|
+
returnedDate: null;
|
|
243
|
+
serviceId: string;
|
|
244
|
+
pricingId: null;
|
|
245
|
+
plannedReturnDate: string | null;
|
|
246
|
+
cancellationDate: string | null;
|
|
247
|
+
rollingContract: boolean;
|
|
248
|
+
planDurationInMonths: number;
|
|
249
|
+
planName: string | null;
|
|
250
|
+
contractType: 'MVS' | 'SVS';
|
|
251
|
+
bookingReferenceId: string;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
export interface IFormatSlave extends Slave {
|
|
255
|
+
traveledDistance: number | null;
|
|
256
|
+
realStartDate?: string | null;
|
|
257
|
+
cancellationRequestOutDTO?: {
|
|
258
|
+
status: string;
|
|
259
|
+
action: string;
|
|
260
|
+
};
|
|
261
|
+
manualApproval:
|
|
262
|
+
| {
|
|
263
|
+
status: string;
|
|
264
|
+
action: string;
|
|
265
|
+
}
|
|
266
|
+
| undefined;
|
|
267
|
+
from: 'ONGOING' | 'UPCOMING' | 'COMPLETED';
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export type Master = {
|
|
271
|
+
bookingReferenceId: string;
|
|
272
|
+
cancellationDate: string | null;
|
|
273
|
+
cityId: string | null;
|
|
274
|
+
contractType: 'MVS' | 'SVS';
|
|
275
|
+
creationDate: string;
|
|
276
|
+
customPrice: number | null;
|
|
277
|
+
deliveryAddress: string | null;
|
|
278
|
+
deliveryAddressAdditionalInfo: string | null;
|
|
279
|
+
deliveryCity: string | null;
|
|
280
|
+
deliveryPostalCode: string | null;
|
|
281
|
+
endDate: string;
|
|
282
|
+
fleetId: string;
|
|
283
|
+
id: string;
|
|
284
|
+
journeyId: string;
|
|
285
|
+
modelId: number;
|
|
286
|
+
parentId: string;
|
|
287
|
+
planDurationInMonths: number;
|
|
288
|
+
planName: string;
|
|
289
|
+
plannedReturnDate: string | null;
|
|
290
|
+
pricingId: string | null;
|
|
291
|
+
previous: string | null;
|
|
292
|
+
products: string[];
|
|
293
|
+
profileId: string;
|
|
294
|
+
returnedDate: string | null;
|
|
295
|
+
rollingContract: boolean;
|
|
296
|
+
serviceId: string;
|
|
297
|
+
startDate: string;
|
|
298
|
+
station: string;
|
|
299
|
+
status: string;
|
|
300
|
+
vehicleId: string;
|
|
301
|
+
userId: string;
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
export interface IFormatSubscription extends Master {
|
|
305
|
+
slaves: {
|
|
306
|
+
ongoing: IFormatSlave[];
|
|
307
|
+
upcoming: IFormatSlave[];
|
|
308
|
+
completed: IFormatSlave[];
|
|
309
|
+
};
|
|
310
|
+
cancellationRequestStatus?: string;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export type Contract = {
|
|
314
|
+
id: string;
|
|
315
|
+
status: 'SIGNED';
|
|
316
|
+
provider: 'DOCUSIGN';
|
|
317
|
+
creationDate: string;
|
|
318
|
+
profileId: string;
|
|
319
|
+
externalContractId: string;
|
|
320
|
+
type: string;
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
export type AdditionalDriver = {
|
|
324
|
+
id: string;
|
|
325
|
+
fleetId: string;
|
|
326
|
+
bookingRequestId: string;
|
|
327
|
+
profileId: string;
|
|
328
|
+
updateDate: string;
|
|
329
|
+
invitationEmail: string;
|
|
330
|
+
profileStatus: string;
|
|
331
|
+
userId: string;
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
export type BookingRequestSlave = {
|
|
335
|
+
id: string;
|
|
336
|
+
vehicleId: string;
|
|
337
|
+
modelId: number;
|
|
338
|
+
startDate: string;
|
|
339
|
+
endDate: string;
|
|
340
|
+
tripId: string;
|
|
341
|
+
parentId: string;
|
|
342
|
+
traveledDistance: number;
|
|
343
|
+
energyLevelEnd: number;
|
|
344
|
+
};
|