@vulog/aima-booking 1.2.34 → 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/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,23 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { type AdditionalDriver } from './types';
|
|
5
|
+
|
|
6
|
+
const schema = z.object({
|
|
7
|
+
parentId: z.string().trim().min(1),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const getAdditionalDrivers = async (client: Client, parentId: string): Promise<AdditionalDriver[]> => {
|
|
11
|
+
const result = schema.safeParse({ parentId });
|
|
12
|
+
if (!result.success) {
|
|
13
|
+
throw new TypeError('Invalid parentId', {
|
|
14
|
+
cause: result.error.issues,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return client
|
|
19
|
+
.get<
|
|
20
|
+
AdditionalDriver[]
|
|
21
|
+
>(`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/bookingrequests/${parentId}/additionalDrivers`)
|
|
22
|
+
.then(({ data }) => data);
|
|
23
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, test, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { Client } from '@vulog/aima-client';
|
|
3
|
+
import { getAvailableVehicles } from './getAvailableVehicles';
|
|
4
|
+
|
|
5
|
+
describe('getAvailableVehicles', () => {
|
|
6
|
+
const getMock = vi.fn();
|
|
7
|
+
const client = {
|
|
8
|
+
get: getMock,
|
|
9
|
+
clientOptions: {
|
|
10
|
+
fleetId: 'FLEET_ID',
|
|
11
|
+
},
|
|
12
|
+
} as unknown as Client;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
getMock.mockReset();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('throws Invalid args when stationId is empty', async () => {
|
|
19
|
+
await expect(
|
|
20
|
+
getAvailableVehicles(client, '', '2025-02-10T12:00:00Z')
|
|
21
|
+
).rejects.toThrow(TypeError);
|
|
22
|
+
await expect(
|
|
23
|
+
getAvailableVehicles(client, '', '2025-02-10T12:00:00Z')
|
|
24
|
+
).rejects.toMatchObject({ message: 'Invalid args' });
|
|
25
|
+
expect(getMock).not.toHaveBeenCalled();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('throws Invalid args when startDate is invalid datetime', async () => {
|
|
29
|
+
await expect(
|
|
30
|
+
getAvailableVehicles(client, 'station-123', 'not-a-date')
|
|
31
|
+
).rejects.toThrow(TypeError);
|
|
32
|
+
expect(getMock).not.toHaveBeenCalled();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('calls GET with correct URL and returns available vehicles response', async () => {
|
|
36
|
+
const stationId = 'ded03b86-fa3f-4d79-80fa-191b2ec13b5e';
|
|
37
|
+
const startDate = '2025-02-10T12:00:00Z';
|
|
38
|
+
const response = {
|
|
39
|
+
stationId,
|
|
40
|
+
vehicles: [{ vehicleId: 'vehicle-1' }, { vehicleId: 'vehicle-2' }],
|
|
41
|
+
};
|
|
42
|
+
getMock.mockResolvedValueOnce({ data: response });
|
|
43
|
+
|
|
44
|
+
const result = await getAvailableVehicles(client, stationId, startDate);
|
|
45
|
+
|
|
46
|
+
expect(getMock).toHaveBeenCalledTimes(1);
|
|
47
|
+
expect(getMock).toHaveBeenCalledWith(
|
|
48
|
+
`/boapi/proxy/user/scheduledBooking/fleets/FLEET_ID/subscription/stations/${stationId}/vehicles/available?startDate=${startDate}`
|
|
49
|
+
);
|
|
50
|
+
expect(result).toEqual(response);
|
|
51
|
+
expect(result.vehicles).toHaveLength(2);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { describe, test, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getBookingRequestById,
|
|
4
|
+
getBookingRequestByTrip,
|
|
5
|
+
getSubscriptionBookingRequestById,
|
|
6
|
+
getScheduledBookingById,
|
|
7
|
+
} from './getBookingRequest';
|
|
3
8
|
import { Client } from '@vulog/aima-client';
|
|
4
9
|
import { randomUUID } from 'crypto';
|
|
5
10
|
import { PaymentReceipts } from './types';
|
|
@@ -436,3 +441,69 @@ describe('getsubscriptionBookingRequestByID', () => {
|
|
|
436
441
|
expect(result.station).toEqual(data.stationId);
|
|
437
442
|
});
|
|
438
443
|
});
|
|
444
|
+
|
|
445
|
+
describe('getScheduledBookingById', () => {
|
|
446
|
+
const getMock = vi.fn();
|
|
447
|
+
const client = {
|
|
448
|
+
get: getMock,
|
|
449
|
+
clientOptions: {
|
|
450
|
+
fleetId: 'FLEET_ID',
|
|
451
|
+
},
|
|
452
|
+
} as unknown as Client;
|
|
453
|
+
|
|
454
|
+
beforeEach(() => {
|
|
455
|
+
getMock.mockReset();
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
test('throws Invalid bookingId when bookingId is not a valid UUID', async () => {
|
|
459
|
+
await expect(getScheduledBookingById(client, 'not-a-uuid')).rejects.toThrow(TypeError);
|
|
460
|
+
await expect(getScheduledBookingById(client, 'not-a-uuid')).rejects.toMatchObject({
|
|
461
|
+
message: 'Invalid bookingId',
|
|
462
|
+
});
|
|
463
|
+
expect(getMock).not.toHaveBeenCalled();
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
test('throws Invalid bookingId when bookingId is empty', async () => {
|
|
467
|
+
await expect(getScheduledBookingById(client, '')).rejects.toThrow(TypeError);
|
|
468
|
+
expect(getMock).not.toHaveBeenCalled();
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
test('calls GET with by-service URL and returns SATBookingRequest', async () => {
|
|
472
|
+
const bookingId = randomUUID();
|
|
473
|
+
const data = {
|
|
474
|
+
id: bookingId,
|
|
475
|
+
startDate: '2026-03-03T10:00:00Z',
|
|
476
|
+
endDate: '2026-06-03T09:00:00Z',
|
|
477
|
+
returnedDate: null,
|
|
478
|
+
profileId: '76175b0c-7e39-41ad-a338-914df3a5fdf6',
|
|
479
|
+
vehicleId: null,
|
|
480
|
+
modelId: null,
|
|
481
|
+
journeyId: 'BEBD00056A9A16103D418CC36D940E26',
|
|
482
|
+
station: 'ded03b86-fa3f-4d79-80fa-191b2ec13b5e',
|
|
483
|
+
status: 'CONFIRMED',
|
|
484
|
+
creationDate: '2026-03-03T09:29:45Z',
|
|
485
|
+
fleetId: 'FLEET_ID',
|
|
486
|
+
userId: '20fb98a3-b60d-491a-9359-62e55f51fcb9',
|
|
487
|
+
serviceId: 'f49080b0-66bc-45e9-8e84-0dfb57bb8f92',
|
|
488
|
+
productIds: [],
|
|
489
|
+
pricingDetails: [],
|
|
490
|
+
completed: true,
|
|
491
|
+
rollingContract: true,
|
|
492
|
+
planDurationInMonths: 3,
|
|
493
|
+
planName: '3 mois',
|
|
494
|
+
contractType: 'SVS',
|
|
495
|
+
bookingReferenceId: 'q93UCF',
|
|
496
|
+
};
|
|
497
|
+
getMock.mockResolvedValueOnce({ data });
|
|
498
|
+
|
|
499
|
+
const result = await getScheduledBookingById(client, bookingId);
|
|
500
|
+
|
|
501
|
+
expect(getMock).toHaveBeenCalledTimes(1);
|
|
502
|
+
expect(getMock).toHaveBeenCalledWith(
|
|
503
|
+
`/boapi/proxy/user/scheduledBooking/by-service/fleets/FLEET_ID/bookingrequests/${bookingId}`
|
|
504
|
+
);
|
|
505
|
+
expect(result).toEqual(data);
|
|
506
|
+
expect(result.id).toBe(bookingId);
|
|
507
|
+
expect(result.status).toBe('CONFIRMED');
|
|
508
|
+
});
|
|
509
|
+
});
|
package/src/getBookingRequest.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Client } from '@vulog/aima-client';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
|
-
import { BookingRequest } from './types';
|
|
4
|
+
import { BookingRequest, SATBookingRequest } from './types';
|
|
5
5
|
|
|
6
6
|
export const getBookingRequestById = async (client: Client, id: string): Promise<BookingRequest> => {
|
|
7
7
|
const result = z.string().trim().min(1).uuid().safeParse(id);
|
|
@@ -46,3 +46,17 @@ export const getSubscriptionBookingRequestById = async (client: Client, id: stri
|
|
|
46
46
|
)
|
|
47
47
|
.then(({ data: { stationId, ...data } }) => ({ station: stationId, ...data }) as BookingRequest);
|
|
48
48
|
};
|
|
49
|
+
|
|
50
|
+
export const getScheduledBookingById = async (client: Client, bookingId: string): Promise<SATBookingRequest> => {
|
|
51
|
+
const result = z.string().trim().min(1).uuid().safeParse(bookingId);
|
|
52
|
+
if (!result.success) {
|
|
53
|
+
throw new TypeError('Invalid bookingId', {
|
|
54
|
+
cause: result.error.issues,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return client
|
|
58
|
+
.get<SATBookingRequest>(
|
|
59
|
+
`/boapi/proxy/user/scheduledBooking/by-service/fleets/${client.clientOptions.fleetId}/bookingrequests/${bookingId}`
|
|
60
|
+
)
|
|
61
|
+
.then(({ data }) => data);
|
|
62
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, test, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { Client } from '@vulog/aima-client';
|
|
3
|
+
import { getDigitalContracts } from './getDigitalContracts';
|
|
4
|
+
import type { Contract } from './types';
|
|
5
|
+
|
|
6
|
+
describe('getDigitalContracts', () => {
|
|
7
|
+
const getMock = vi.fn();
|
|
8
|
+
const client = {
|
|
9
|
+
get: getMock,
|
|
10
|
+
clientOptions: {
|
|
11
|
+
fleetId: 'FLEET_ID',
|
|
12
|
+
},
|
|
13
|
+
} as unknown as Client;
|
|
14
|
+
|
|
15
|
+
const mockContracts: Contract[] = [
|
|
16
|
+
{
|
|
17
|
+
id: 'contract-1',
|
|
18
|
+
status: 'SIGNED',
|
|
19
|
+
provider: 'DOCUSIGN',
|
|
20
|
+
creationDate: '2026-03-03T10:00:00Z',
|
|
21
|
+
profileId: '76175b0c-7e39-41ad-a338-914df3a5fdf6',
|
|
22
|
+
externalContractId: 'ext-1',
|
|
23
|
+
type: 'RENTAL',
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
getMock.mockReset();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('throws Invalid args when bookingId is empty', async () => {
|
|
32
|
+
await expect(getDigitalContracts(client, '')).rejects.toThrow(TypeError);
|
|
33
|
+
await expect(getDigitalContracts(client, '')).rejects.toMatchObject({
|
|
34
|
+
message: 'Invalid args',
|
|
35
|
+
});
|
|
36
|
+
expect(getMock).not.toHaveBeenCalled();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('calls GET with default status SIGNED and returns contracts', async () => {
|
|
40
|
+
const bookingId = '66bcbd77-37ef-47bd-b9af-877e5d213b8f';
|
|
41
|
+
getMock.mockResolvedValueOnce({ data: mockContracts });
|
|
42
|
+
|
|
43
|
+
const result = await getDigitalContracts(client, bookingId);
|
|
44
|
+
|
|
45
|
+
expect(getMock).toHaveBeenCalledTimes(1);
|
|
46
|
+
expect(getMock).toHaveBeenCalledWith(
|
|
47
|
+
`/boapi/proxy/user/scheduledBooking/fleets/FLEET_ID/subscription/bookingrequests/${bookingId}/digitalContracts?status=SIGNED`
|
|
48
|
+
);
|
|
49
|
+
expect(result).toEqual(mockContracts);
|
|
50
|
+
expect(result[0].status).toBe('SIGNED');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('calls GET with custom status when provided', async () => {
|
|
54
|
+
const bookingId = '66bcbd77-37ef-47bd-b9af-877e5d213b8f';
|
|
55
|
+
getMock.mockResolvedValueOnce({ data: [] });
|
|
56
|
+
|
|
57
|
+
await getDigitalContracts(client, bookingId, 'PENDING');
|
|
58
|
+
|
|
59
|
+
expect(getMock).toHaveBeenCalledWith(
|
|
60
|
+
`/boapi/proxy/user/scheduledBooking/fleets/FLEET_ID/subscription/bookingrequests/${bookingId}/digitalContracts?status=PENDING`
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('returns empty array when no contracts', async () => {
|
|
65
|
+
const bookingId = 'some-booking-id';
|
|
66
|
+
getMock.mockResolvedValueOnce({ data: [] });
|
|
67
|
+
|
|
68
|
+
const result = await getDigitalContracts(client, bookingId);
|
|
69
|
+
|
|
70
|
+
expect(result).toEqual([]);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { Contract } from './types';
|
|
5
|
+
|
|
6
|
+
const schema = z.object({
|
|
7
|
+
bookingId: z.string().trim().min(1),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const getDigitalContracts = async (
|
|
11
|
+
client: Client,
|
|
12
|
+
bookingId: string,
|
|
13
|
+
status = 'SIGNED'
|
|
14
|
+
): Promise<Contract[]> => {
|
|
15
|
+
const result = schema.safeParse({ bookingId });
|
|
16
|
+
if (!result.success) {
|
|
17
|
+
throw new TypeError('Invalid args', {
|
|
18
|
+
cause: result.error.issues,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return client
|
|
22
|
+
.get<
|
|
23
|
+
Contract[]
|
|
24
|
+
>(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/subscription/bookingrequests/${result.data.bookingId}/digitalContracts?status=${encodeURIComponent(status)}`)
|
|
25
|
+
.then(({ data }) => data);
|
|
26
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, test, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { Client } from '@vulog/aima-client';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
import { getSlaves } from './getSlaves';
|
|
5
|
+
import type { BookingRequestSlave } from './types';
|
|
6
|
+
|
|
7
|
+
describe('getSlaves', () => {
|
|
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 bookingId when parentId is empty', async () => {
|
|
21
|
+
await expect(getSlaves(client, '', 'UPCOMING')).rejects.toThrow(TypeError);
|
|
22
|
+
await expect(getSlaves(client, '', 'UPCOMING')).rejects.toMatchObject({
|
|
23
|
+
message: 'Invalid bookingId',
|
|
24
|
+
});
|
|
25
|
+
expect(getMock).not.toHaveBeenCalled();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('throws when status is not in enum', async () => {
|
|
29
|
+
const parentId = randomUUID();
|
|
30
|
+
await expect(getSlaves(client, parentId, 'INVALID_STATUS')).rejects.toThrow(TypeError);
|
|
31
|
+
expect(getMock).not.toHaveBeenCalled();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('calls GET with correct URL for UPCOMING and returns slaves', async () => {
|
|
35
|
+
const parentId = randomUUID();
|
|
36
|
+
const slaves: BookingRequestSlave[] = [
|
|
37
|
+
{
|
|
38
|
+
id: randomUUID(),
|
|
39
|
+
vehicleId: randomUUID(),
|
|
40
|
+
modelId: 2597,
|
|
41
|
+
startDate: '2026-03-03T10:00:00Z',
|
|
42
|
+
endDate: '2026-03-06T09:00:00Z',
|
|
43
|
+
tripId: 'BEBD00056A9A16103D418CC36D940E26',
|
|
44
|
+
parentId,
|
|
45
|
+
traveledDistance: 120,
|
|
46
|
+
energyLevelEnd: 80,
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
getMock.mockResolvedValueOnce({ data: slaves });
|
|
50
|
+
|
|
51
|
+
const result = await getSlaves(client, parentId, 'UPCOMING');
|
|
52
|
+
|
|
53
|
+
expect(getMock).toHaveBeenCalledTimes(1);
|
|
54
|
+
expect(getMock).toHaveBeenCalledWith(
|
|
55
|
+
`/boapi/proxy/user/scheduledBooking/fleets/FLEET_ID/subscription/bookingRequests/${parentId}/bookingRequestsSlave?bookingStatus=UPCOMING`
|
|
56
|
+
);
|
|
57
|
+
expect(result).toEqual(slaves);
|
|
58
|
+
expect(result).toHaveLength(1);
|
|
59
|
+
});
|
|
60
|
+
});
|
package/src/getSlaves.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { BookingRequestSlave } from './types';
|
|
5
|
+
|
|
6
|
+
const schema = z.object({
|
|
7
|
+
parentId: z.string().trim().min(1),
|
|
8
|
+
status: z.enum(['ONGOING, COMPLETED', 'UPCOMING']),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const getSlaves = async (client: Client, parentId: string, status: string): Promise<BookingRequestSlave[]> => {
|
|
12
|
+
const result = schema.safeParse({ parentId, status });
|
|
13
|
+
if (!result.success) {
|
|
14
|
+
throw new TypeError('Invalid bookingId', {
|
|
15
|
+
cause: result.error.issues,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return client
|
|
20
|
+
.get<
|
|
21
|
+
BookingRequestSlave[]
|
|
22
|
+
>(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/subscription/bookingRequests/${parentId}/bookingRequestsSlave?bookingStatus=${status}`)
|
|
23
|
+
.then(({ data }) => data);
|
|
24
|
+
};
|
|
@@ -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
|
+
};
|