@vulog/aima-booking 1.0.0 → 1.0.2
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 +22 -0
- package/dist/index.d.mts +117 -1
- package/dist/index.d.ts +117 -1
- package/dist/index.js +216 -0
- package/dist/index.mjs +187 -0
- package/package.json +1 -1
- package/src/getBookingRequests.test.ts +0 -1
- package/src/getBookingRequests.ts +33 -0
- package/src/getStations.test.ts +419 -0
- package/src/getStations.ts +166 -0
- package/src/index.ts +4 -0
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# @vulog/aima-booking
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
npm i @vulog/aima-client @vulog/aima-core @vulog/aima-booking
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
import { getClient } from '@vulog/aima-client';
|
|
9
|
+
import { getBookingRequests } from '@vulog/aima-booking';
|
|
10
|
+
|
|
11
|
+
const client = getClient({
|
|
12
|
+
apiKey: '...',
|
|
13
|
+
baseUrl: '...',
|
|
14
|
+
clientId: '...',
|
|
15
|
+
clientSecret: '...',
|
|
16
|
+
fleetId: '...',
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const response = await getBookingRequests(client, 'ONGOING');
|
|
20
|
+
|
|
21
|
+
const station = await getStations(client, ['OPEN_HOUR', 'INFO']);
|
|
22
|
+
```
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,118 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { PaginableOptions, PaginableResponse } from '@vulog/aima-core';
|
|
3
|
+
import { z } from 'zod';
|
|
1
4
|
|
|
2
|
-
|
|
5
|
+
declare const BookingRequestStatusSchema: z.ZodEnum<["ALERT", "UPCOMING", "ONGOING", "COMPLETED", "CANCELLED", "PENDING_APPROVAL"]>;
|
|
6
|
+
type BookingRequestStatus = z.infer<typeof BookingRequestStatusSchema>;
|
|
7
|
+
declare const ServiceTypeSchema: z.ZodEnum<["SUBSCRIPTION", "ROUND_TRIP_BOOKING", "SCHEDULED_BOOKING_STATION"]>;
|
|
8
|
+
type ServiceType = z.infer<typeof ServiceTypeSchema>;
|
|
9
|
+
type SpecificBookingRequestFilters = {
|
|
10
|
+
serviceIds?: string[];
|
|
11
|
+
userId?: string;
|
|
12
|
+
modelId?: number;
|
|
13
|
+
vehicleId?: string;
|
|
14
|
+
stationId?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Format: yyyy-MM-dd
|
|
17
|
+
*/
|
|
18
|
+
creationDate?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Format: yyyy-MM-dd'T'HH:mm:ssZ
|
|
21
|
+
* default now plus 2 months
|
|
22
|
+
*/
|
|
23
|
+
startDate?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Format: yyyy-MM-dd'T'HH:mm:ssZ
|
|
26
|
+
* default now plus 2 months
|
|
27
|
+
*/
|
|
28
|
+
endDate?: string;
|
|
29
|
+
};
|
|
30
|
+
type BookingRequestFilters = SpecificBookingRequestFilters & {
|
|
31
|
+
serviceTypes?: ServiceType[];
|
|
32
|
+
};
|
|
33
|
+
type BookingRequest = {
|
|
34
|
+
id: string;
|
|
35
|
+
startDate: string;
|
|
36
|
+
endDate: string;
|
|
37
|
+
returnedDate?: string;
|
|
38
|
+
profileId: string;
|
|
39
|
+
vehicleId?: string;
|
|
40
|
+
modelId: 1647;
|
|
41
|
+
journeyId?: string;
|
|
42
|
+
station: string;
|
|
43
|
+
profileType: 'Single' | 'Business';
|
|
44
|
+
entityName?: string;
|
|
45
|
+
status: string;
|
|
46
|
+
creationDate: string;
|
|
47
|
+
realStartDate?: string;
|
|
48
|
+
cancellationDate?: string;
|
|
49
|
+
cancelledBy?: string;
|
|
50
|
+
userId: string;
|
|
51
|
+
serviceId: string;
|
|
52
|
+
cityId: string;
|
|
53
|
+
deliveryAddress?: string;
|
|
54
|
+
deliveryAddressAdditionalInfo?: string;
|
|
55
|
+
deliveryCity?: string;
|
|
56
|
+
deliveryPostalCode?: string;
|
|
57
|
+
rollingContract: string;
|
|
58
|
+
planDurationInMonths?: number;
|
|
59
|
+
contractType?: string;
|
|
60
|
+
productIds: string[];
|
|
61
|
+
bookingReferenceId?: string;
|
|
62
|
+
pricingDetails: {
|
|
63
|
+
pricingId: string;
|
|
64
|
+
providerType: string;
|
|
65
|
+
}[];
|
|
66
|
+
completed: boolean;
|
|
67
|
+
[key: string]: any;
|
|
68
|
+
};
|
|
69
|
+
declare const getBookingRequests: (client: Client, status: BookingRequestStatus, options?: PaginableOptions<BookingRequestFilters>) => Promise<PaginableResponse<BookingRequest>>;
|
|
70
|
+
declare const getScheduleBookingRequests: (client: Client, status: BookingRequestStatus, options?: PaginableOptions<SpecificBookingRequestFilters>) => Promise<PaginableResponse<BookingRequest>>;
|
|
71
|
+
declare const getSubscriptionBookingRequests: (client: Client, status: BookingRequestStatus, options?: PaginableOptions<SpecificBookingRequestFilters>) => Promise<PaginableResponse<BookingRequest>>;
|
|
72
|
+
|
|
73
|
+
declare const IncludeSchema: z.ZodEnum<["INFO", "OPEN_HOUR", "SERVICES"]>;
|
|
74
|
+
type Include = z.infer<typeof IncludeSchema>;
|
|
75
|
+
type Days = 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY' | 'SUNDAY';
|
|
76
|
+
type DayOpeningHours = {
|
|
77
|
+
id: number;
|
|
78
|
+
closed: boolean;
|
|
79
|
+
openAt: string;
|
|
80
|
+
closeAt: string;
|
|
81
|
+
};
|
|
82
|
+
type Timetable = Record<Days, DayOpeningHours[]>;
|
|
83
|
+
type OpeningHours = {
|
|
84
|
+
alwaysOpen: boolean;
|
|
85
|
+
timetable: Timetable;
|
|
86
|
+
};
|
|
87
|
+
type GeoInfo = {
|
|
88
|
+
name: string;
|
|
89
|
+
coordinates: {
|
|
90
|
+
latitude: number;
|
|
91
|
+
longitude: number;
|
|
92
|
+
};
|
|
93
|
+
geoProperties: {
|
|
94
|
+
[key: string]: any;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
type Service = {
|
|
98
|
+
id: string;
|
|
99
|
+
models: {
|
|
100
|
+
id: number;
|
|
101
|
+
vehicles: string[];
|
|
102
|
+
}[];
|
|
103
|
+
};
|
|
104
|
+
type ServiceInfo = {
|
|
105
|
+
services: Service[];
|
|
106
|
+
};
|
|
107
|
+
type Station = Partial<GeoInfo> & Partial<ServiceInfo> & {
|
|
108
|
+
id: string;
|
|
109
|
+
zoneId: string;
|
|
110
|
+
poiId: string;
|
|
111
|
+
modificationDate: string;
|
|
112
|
+
fleetId: string;
|
|
113
|
+
openingHours?: OpeningHours;
|
|
114
|
+
[key: string]: any;
|
|
115
|
+
};
|
|
116
|
+
declare const getStations: (client: Client, includes?: Include[]) => Promise<Station[]>;
|
|
117
|
+
|
|
118
|
+
export { type BookingRequest, type BookingRequestFilters, type BookingRequestStatus, type DayOpeningHours, type Days, type Include, type OpeningHours, type ServiceType, type Station, type Timetable, getBookingRequests, getScheduleBookingRequests, getStations, getSubscriptionBookingRequests };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,118 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { PaginableOptions, PaginableResponse } from '@vulog/aima-core';
|
|
3
|
+
import { z } from 'zod';
|
|
1
4
|
|
|
2
|
-
|
|
5
|
+
declare const BookingRequestStatusSchema: z.ZodEnum<["ALERT", "UPCOMING", "ONGOING", "COMPLETED", "CANCELLED", "PENDING_APPROVAL"]>;
|
|
6
|
+
type BookingRequestStatus = z.infer<typeof BookingRequestStatusSchema>;
|
|
7
|
+
declare const ServiceTypeSchema: z.ZodEnum<["SUBSCRIPTION", "ROUND_TRIP_BOOKING", "SCHEDULED_BOOKING_STATION"]>;
|
|
8
|
+
type ServiceType = z.infer<typeof ServiceTypeSchema>;
|
|
9
|
+
type SpecificBookingRequestFilters = {
|
|
10
|
+
serviceIds?: string[];
|
|
11
|
+
userId?: string;
|
|
12
|
+
modelId?: number;
|
|
13
|
+
vehicleId?: string;
|
|
14
|
+
stationId?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Format: yyyy-MM-dd
|
|
17
|
+
*/
|
|
18
|
+
creationDate?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Format: yyyy-MM-dd'T'HH:mm:ssZ
|
|
21
|
+
* default now plus 2 months
|
|
22
|
+
*/
|
|
23
|
+
startDate?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Format: yyyy-MM-dd'T'HH:mm:ssZ
|
|
26
|
+
* default now plus 2 months
|
|
27
|
+
*/
|
|
28
|
+
endDate?: string;
|
|
29
|
+
};
|
|
30
|
+
type BookingRequestFilters = SpecificBookingRequestFilters & {
|
|
31
|
+
serviceTypes?: ServiceType[];
|
|
32
|
+
};
|
|
33
|
+
type BookingRequest = {
|
|
34
|
+
id: string;
|
|
35
|
+
startDate: string;
|
|
36
|
+
endDate: string;
|
|
37
|
+
returnedDate?: string;
|
|
38
|
+
profileId: string;
|
|
39
|
+
vehicleId?: string;
|
|
40
|
+
modelId: 1647;
|
|
41
|
+
journeyId?: string;
|
|
42
|
+
station: string;
|
|
43
|
+
profileType: 'Single' | 'Business';
|
|
44
|
+
entityName?: string;
|
|
45
|
+
status: string;
|
|
46
|
+
creationDate: string;
|
|
47
|
+
realStartDate?: string;
|
|
48
|
+
cancellationDate?: string;
|
|
49
|
+
cancelledBy?: string;
|
|
50
|
+
userId: string;
|
|
51
|
+
serviceId: string;
|
|
52
|
+
cityId: string;
|
|
53
|
+
deliveryAddress?: string;
|
|
54
|
+
deliveryAddressAdditionalInfo?: string;
|
|
55
|
+
deliveryCity?: string;
|
|
56
|
+
deliveryPostalCode?: string;
|
|
57
|
+
rollingContract: string;
|
|
58
|
+
planDurationInMonths?: number;
|
|
59
|
+
contractType?: string;
|
|
60
|
+
productIds: string[];
|
|
61
|
+
bookingReferenceId?: string;
|
|
62
|
+
pricingDetails: {
|
|
63
|
+
pricingId: string;
|
|
64
|
+
providerType: string;
|
|
65
|
+
}[];
|
|
66
|
+
completed: boolean;
|
|
67
|
+
[key: string]: any;
|
|
68
|
+
};
|
|
69
|
+
declare const getBookingRequests: (client: Client, status: BookingRequestStatus, options?: PaginableOptions<BookingRequestFilters>) => Promise<PaginableResponse<BookingRequest>>;
|
|
70
|
+
declare const getScheduleBookingRequests: (client: Client, status: BookingRequestStatus, options?: PaginableOptions<SpecificBookingRequestFilters>) => Promise<PaginableResponse<BookingRequest>>;
|
|
71
|
+
declare const getSubscriptionBookingRequests: (client: Client, status: BookingRequestStatus, options?: PaginableOptions<SpecificBookingRequestFilters>) => Promise<PaginableResponse<BookingRequest>>;
|
|
72
|
+
|
|
73
|
+
declare const IncludeSchema: z.ZodEnum<["INFO", "OPEN_HOUR", "SERVICES"]>;
|
|
74
|
+
type Include = z.infer<typeof IncludeSchema>;
|
|
75
|
+
type Days = 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY' | 'SUNDAY';
|
|
76
|
+
type DayOpeningHours = {
|
|
77
|
+
id: number;
|
|
78
|
+
closed: boolean;
|
|
79
|
+
openAt: string;
|
|
80
|
+
closeAt: string;
|
|
81
|
+
};
|
|
82
|
+
type Timetable = Record<Days, DayOpeningHours[]>;
|
|
83
|
+
type OpeningHours = {
|
|
84
|
+
alwaysOpen: boolean;
|
|
85
|
+
timetable: Timetable;
|
|
86
|
+
};
|
|
87
|
+
type GeoInfo = {
|
|
88
|
+
name: string;
|
|
89
|
+
coordinates: {
|
|
90
|
+
latitude: number;
|
|
91
|
+
longitude: number;
|
|
92
|
+
};
|
|
93
|
+
geoProperties: {
|
|
94
|
+
[key: string]: any;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
type Service = {
|
|
98
|
+
id: string;
|
|
99
|
+
models: {
|
|
100
|
+
id: number;
|
|
101
|
+
vehicles: string[];
|
|
102
|
+
}[];
|
|
103
|
+
};
|
|
104
|
+
type ServiceInfo = {
|
|
105
|
+
services: Service[];
|
|
106
|
+
};
|
|
107
|
+
type Station = Partial<GeoInfo> & Partial<ServiceInfo> & {
|
|
108
|
+
id: string;
|
|
109
|
+
zoneId: string;
|
|
110
|
+
poiId: string;
|
|
111
|
+
modificationDate: string;
|
|
112
|
+
fleetId: string;
|
|
113
|
+
openingHours?: OpeningHours;
|
|
114
|
+
[key: string]: any;
|
|
115
|
+
};
|
|
116
|
+
declare const getStations: (client: Client, includes?: Include[]) => Promise<Station[]>;
|
|
117
|
+
|
|
118
|
+
export { type BookingRequest, type BookingRequestFilters, type BookingRequestStatus, type DayOpeningHours, type Days, type Include, type OpeningHours, type ServiceType, type Station, type Timetable, getBookingRequests, getScheduleBookingRequests, getStations, getSubscriptionBookingRequests };
|
package/dist/index.js
CHANGED
|
@@ -1 +1,217 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
getBookingRequests: () => getBookingRequests,
|
|
24
|
+
getScheduleBookingRequests: () => getScheduleBookingRequests,
|
|
25
|
+
getStations: () => getStations,
|
|
26
|
+
getSubscriptionBookingRequests: () => getSubscriptionBookingRequests
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(src_exports);
|
|
29
|
+
|
|
30
|
+
// src/getBookingRequests.ts
|
|
31
|
+
var import_aima_core = require("@vulog/aima-core");
|
|
32
|
+
var import_lodash = require("lodash");
|
|
33
|
+
var import_zod = require("zod");
|
|
34
|
+
var BookingRequestStatusSchema = import_zod.z.enum([
|
|
35
|
+
"ALERT",
|
|
36
|
+
"UPCOMING",
|
|
37
|
+
"ONGOING",
|
|
38
|
+
"COMPLETED",
|
|
39
|
+
"CANCELLED",
|
|
40
|
+
"PENDING_APPROVAL"
|
|
41
|
+
]);
|
|
42
|
+
var ServiceTypeSchema = import_zod.z.enum(["SUBSCRIPTION", "ROUND_TRIP_BOOKING", "SCHEDULED_BOOKING_STATION"]);
|
|
43
|
+
var getBookingRequests = async (client, status, options) => {
|
|
44
|
+
const resultStatus = BookingRequestStatusSchema.safeParse(status);
|
|
45
|
+
if (!resultStatus.success) {
|
|
46
|
+
throw new TypeError("Invalid status", {
|
|
47
|
+
cause: resultStatus.error.issues
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const date = /* @__PURE__ */ new Date();
|
|
51
|
+
date.setMilliseconds(0);
|
|
52
|
+
const startDate = date.toISOString().replace(".000Z", "Z");
|
|
53
|
+
date.setMonth(date.getMonth() + 2);
|
|
54
|
+
const endDate = date.toISOString().replace(".000Z", "Z");
|
|
55
|
+
const BookingRequestFiltersSchema = import_zod.z.object({
|
|
56
|
+
serviceTypes: import_zod.z.array(ServiceTypeSchema).optional(),
|
|
57
|
+
serviceIds: import_zod.z.array(import_zod.z.string().uuid()).optional(),
|
|
58
|
+
userId: import_zod.z.string().uuid().optional(),
|
|
59
|
+
modelId: import_zod.z.number().positive().optional(),
|
|
60
|
+
vehicleId: import_zod.z.string().uuid().optional(),
|
|
61
|
+
stationId: import_zod.z.string().uuid().optional(),
|
|
62
|
+
creationDate: import_zod.z.string().date().optional(),
|
|
63
|
+
startDate: import_zod.z.string().datetime({ offset: false, precision: 0 }).default(startDate),
|
|
64
|
+
endDate: import_zod.z.string().datetime({ offset: false, precision: 0 }).default(endDate)
|
|
65
|
+
});
|
|
66
|
+
const PaginableOptionsSchema = (0, import_aima_core.createPaginableOptionsSchema)(BookingRequestFiltersSchema).default({});
|
|
67
|
+
const resultOptions = PaginableOptionsSchema.safeParse(options);
|
|
68
|
+
if (!resultOptions.success) {
|
|
69
|
+
throw new TypeError("Invalid options", {
|
|
70
|
+
cause: resultOptions.error.issues
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const finalOptions = resultOptions.data;
|
|
74
|
+
const searchParams = new URLSearchParams();
|
|
75
|
+
searchParams.append("page", finalOptions.page.toString());
|
|
76
|
+
searchParams.append("pageSize", finalOptions.pageSize.toString());
|
|
77
|
+
Object.entries(finalOptions.filters).forEach(([key, value]) => {
|
|
78
|
+
if (value === void 0) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
82
|
+
searchParams.append(key, value.join(","));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if ((0, import_lodash.isNumber)(value)) {
|
|
86
|
+
searchParams.append(key, value.toString());
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
searchParams.append(key, value);
|
|
90
|
+
});
|
|
91
|
+
return client.get(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/bookingrequests/status/${status}/filters?${searchParams.toString()}`).then(({ data, headers }) => {
|
|
92
|
+
return {
|
|
93
|
+
data,
|
|
94
|
+
page: headers.number,
|
|
95
|
+
pageSize: headers.size,
|
|
96
|
+
total: headers.totalelements,
|
|
97
|
+
totalPages: headers.totalpages
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
var getScheduleBookingRequests = async (client, status, options) => {
|
|
102
|
+
return getBookingRequests(client, status, {
|
|
103
|
+
...options,
|
|
104
|
+
filters: {
|
|
105
|
+
...options?.filters,
|
|
106
|
+
serviceTypes: ["ROUND_TRIP_BOOKING", "SCHEDULED_BOOKING_STATION"]
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
var getSubscriptionBookingRequests = async (client, status, options) => {
|
|
111
|
+
return getBookingRequests(client, status, {
|
|
112
|
+
...options,
|
|
113
|
+
filters: {
|
|
114
|
+
...options?.filters,
|
|
115
|
+
serviceTypes: ["SUBSCRIPTION"]
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// src/getStations.ts
|
|
121
|
+
var import_zod2 = require("zod");
|
|
122
|
+
var IncludeSchema = import_zod2.z.enum(["INFO", "OPEN_HOUR", "SERVICES"]);
|
|
123
|
+
var IncludesSchema = import_zod2.z.array(IncludeSchema);
|
|
124
|
+
var getStations = async (client, includes = []) => {
|
|
125
|
+
const resultIncludes = IncludesSchema.safeParse(includes);
|
|
126
|
+
if (!resultIncludes.success) {
|
|
127
|
+
throw new TypeError("Invalid includes", {
|
|
128
|
+
cause: resultIncludes.error.issues
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const searchParams = new URLSearchParams();
|
|
132
|
+
if (includes.includes("OPEN_HOUR")) {
|
|
133
|
+
searchParams.append("showTimetable", "true");
|
|
134
|
+
}
|
|
135
|
+
const stations = await client.get(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/stations${searchParams.size > 0 ? `?${searchParams.toString()}` : ""}`).then(
|
|
136
|
+
({ data }) => data.map(
|
|
137
|
+
(station) => Object.keys(station).reduce((acc, key) => {
|
|
138
|
+
if (key === "stationTimetableDTO") {
|
|
139
|
+
if (station.stationTimetableDTO?.stationId) {
|
|
140
|
+
acc.openingHours = {
|
|
141
|
+
alwaysOpen: station.stationTimetableDTO.alwaysOpen,
|
|
142
|
+
timetable: Object.keys(station.stationTimetableDTO.timetable).reduce(
|
|
143
|
+
(timetable, val) => {
|
|
144
|
+
timetable[val] = station.stationTimetableDTO.timetable[val].map(
|
|
145
|
+
(day) => ({
|
|
146
|
+
id: day.id,
|
|
147
|
+
closed: day.closed,
|
|
148
|
+
openAt: day.openAt,
|
|
149
|
+
closeAt: day.closeAt
|
|
150
|
+
})
|
|
151
|
+
);
|
|
152
|
+
return timetable;
|
|
153
|
+
},
|
|
154
|
+
{}
|
|
155
|
+
)
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return acc;
|
|
159
|
+
}
|
|
160
|
+
acc[key] = station[key];
|
|
161
|
+
return acc;
|
|
162
|
+
}, {})
|
|
163
|
+
)
|
|
164
|
+
);
|
|
165
|
+
if (includes.includes("INFO")) {
|
|
166
|
+
const pois = await client.get(`/boapi/proxy/geoloc/fleets/${client.clientOptions.fleetId}/pois`, {
|
|
167
|
+
headers: { accept: "application/vnd.geo+json" }
|
|
168
|
+
}).then(
|
|
169
|
+
({ data }) => data.features.reduce((acc, poi) => {
|
|
170
|
+
const {
|
|
171
|
+
geometry: {
|
|
172
|
+
coordinates: [longitude, latitude]
|
|
173
|
+
},
|
|
174
|
+
properties
|
|
175
|
+
} = poi;
|
|
176
|
+
acc[properties.poiId] = {
|
|
177
|
+
name: properties.name,
|
|
178
|
+
coordinates: { latitude, longitude },
|
|
179
|
+
geoProperties: properties
|
|
180
|
+
};
|
|
181
|
+
return acc;
|
|
182
|
+
}, {})
|
|
183
|
+
);
|
|
184
|
+
stations.forEach((station) => {
|
|
185
|
+
if (station.poiId && pois[station.poiId]) {
|
|
186
|
+
Object.assign(station, pois[station.poiId]);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
if (includes.includes("SERVICES")) {
|
|
191
|
+
const services = await client.get(`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/stations/details?size=1000`).then(
|
|
192
|
+
({ data }) => data.stations.reduce((acc, service) => {
|
|
193
|
+
if (!acc[service.station.id]) {
|
|
194
|
+
acc[service.station.id] = { services: [] };
|
|
195
|
+
}
|
|
196
|
+
acc[service.station.id].services.push({
|
|
197
|
+
id: service.serviceId,
|
|
198
|
+
models: service.models
|
|
199
|
+
});
|
|
200
|
+
return acc;
|
|
201
|
+
}, {})
|
|
202
|
+
);
|
|
203
|
+
stations.forEach((station) => {
|
|
204
|
+
if (services[station.id]) {
|
|
205
|
+
Object.assign(station, services[station.poiId]);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return stations;
|
|
210
|
+
};
|
|
211
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
212
|
+
0 && (module.exports = {
|
|
213
|
+
getBookingRequests,
|
|
214
|
+
getScheduleBookingRequests,
|
|
215
|
+
getStations,
|
|
216
|
+
getSubscriptionBookingRequests
|
|
217
|
+
});
|
package/dist/index.mjs
CHANGED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// src/getBookingRequests.ts
|
|
2
|
+
import { createPaginableOptionsSchema } from "@vulog/aima-core";
|
|
3
|
+
import { isNumber } from "lodash";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
var BookingRequestStatusSchema = z.enum([
|
|
6
|
+
"ALERT",
|
|
7
|
+
"UPCOMING",
|
|
8
|
+
"ONGOING",
|
|
9
|
+
"COMPLETED",
|
|
10
|
+
"CANCELLED",
|
|
11
|
+
"PENDING_APPROVAL"
|
|
12
|
+
]);
|
|
13
|
+
var ServiceTypeSchema = z.enum(["SUBSCRIPTION", "ROUND_TRIP_BOOKING", "SCHEDULED_BOOKING_STATION"]);
|
|
14
|
+
var getBookingRequests = async (client, status, options) => {
|
|
15
|
+
const resultStatus = BookingRequestStatusSchema.safeParse(status);
|
|
16
|
+
if (!resultStatus.success) {
|
|
17
|
+
throw new TypeError("Invalid status", {
|
|
18
|
+
cause: resultStatus.error.issues
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
const date = /* @__PURE__ */ new Date();
|
|
22
|
+
date.setMilliseconds(0);
|
|
23
|
+
const startDate = date.toISOString().replace(".000Z", "Z");
|
|
24
|
+
date.setMonth(date.getMonth() + 2);
|
|
25
|
+
const endDate = date.toISOString().replace(".000Z", "Z");
|
|
26
|
+
const BookingRequestFiltersSchema = z.object({
|
|
27
|
+
serviceTypes: z.array(ServiceTypeSchema).optional(),
|
|
28
|
+
serviceIds: z.array(z.string().uuid()).optional(),
|
|
29
|
+
userId: z.string().uuid().optional(),
|
|
30
|
+
modelId: z.number().positive().optional(),
|
|
31
|
+
vehicleId: z.string().uuid().optional(),
|
|
32
|
+
stationId: z.string().uuid().optional(),
|
|
33
|
+
creationDate: z.string().date().optional(),
|
|
34
|
+
startDate: z.string().datetime({ offset: false, precision: 0 }).default(startDate),
|
|
35
|
+
endDate: z.string().datetime({ offset: false, precision: 0 }).default(endDate)
|
|
36
|
+
});
|
|
37
|
+
const PaginableOptionsSchema = createPaginableOptionsSchema(BookingRequestFiltersSchema).default({});
|
|
38
|
+
const resultOptions = PaginableOptionsSchema.safeParse(options);
|
|
39
|
+
if (!resultOptions.success) {
|
|
40
|
+
throw new TypeError("Invalid options", {
|
|
41
|
+
cause: resultOptions.error.issues
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const finalOptions = resultOptions.data;
|
|
45
|
+
const searchParams = new URLSearchParams();
|
|
46
|
+
searchParams.append("page", finalOptions.page.toString());
|
|
47
|
+
searchParams.append("pageSize", finalOptions.pageSize.toString());
|
|
48
|
+
Object.entries(finalOptions.filters).forEach(([key, value]) => {
|
|
49
|
+
if (value === void 0) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
53
|
+
searchParams.append(key, value.join(","));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (isNumber(value)) {
|
|
57
|
+
searchParams.append(key, value.toString());
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
searchParams.append(key, value);
|
|
61
|
+
});
|
|
62
|
+
return client.get(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/bookingrequests/status/${status}/filters?${searchParams.toString()}`).then(({ data, headers }) => {
|
|
63
|
+
return {
|
|
64
|
+
data,
|
|
65
|
+
page: headers.number,
|
|
66
|
+
pageSize: headers.size,
|
|
67
|
+
total: headers.totalelements,
|
|
68
|
+
totalPages: headers.totalpages
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
var getScheduleBookingRequests = async (client, status, options) => {
|
|
73
|
+
return getBookingRequests(client, status, {
|
|
74
|
+
...options,
|
|
75
|
+
filters: {
|
|
76
|
+
...options?.filters,
|
|
77
|
+
serviceTypes: ["ROUND_TRIP_BOOKING", "SCHEDULED_BOOKING_STATION"]
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
var getSubscriptionBookingRequests = async (client, status, options) => {
|
|
82
|
+
return getBookingRequests(client, status, {
|
|
83
|
+
...options,
|
|
84
|
+
filters: {
|
|
85
|
+
...options?.filters,
|
|
86
|
+
serviceTypes: ["SUBSCRIPTION"]
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// src/getStations.ts
|
|
92
|
+
import { z as z2 } from "zod";
|
|
93
|
+
var IncludeSchema = z2.enum(["INFO", "OPEN_HOUR", "SERVICES"]);
|
|
94
|
+
var IncludesSchema = z2.array(IncludeSchema);
|
|
95
|
+
var getStations = async (client, includes = []) => {
|
|
96
|
+
const resultIncludes = IncludesSchema.safeParse(includes);
|
|
97
|
+
if (!resultIncludes.success) {
|
|
98
|
+
throw new TypeError("Invalid includes", {
|
|
99
|
+
cause: resultIncludes.error.issues
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const searchParams = new URLSearchParams();
|
|
103
|
+
if (includes.includes("OPEN_HOUR")) {
|
|
104
|
+
searchParams.append("showTimetable", "true");
|
|
105
|
+
}
|
|
106
|
+
const stations = await client.get(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/stations${searchParams.size > 0 ? `?${searchParams.toString()}` : ""}`).then(
|
|
107
|
+
({ data }) => data.map(
|
|
108
|
+
(station) => Object.keys(station).reduce((acc, key) => {
|
|
109
|
+
if (key === "stationTimetableDTO") {
|
|
110
|
+
if (station.stationTimetableDTO?.stationId) {
|
|
111
|
+
acc.openingHours = {
|
|
112
|
+
alwaysOpen: station.stationTimetableDTO.alwaysOpen,
|
|
113
|
+
timetable: Object.keys(station.stationTimetableDTO.timetable).reduce(
|
|
114
|
+
(timetable, val) => {
|
|
115
|
+
timetable[val] = station.stationTimetableDTO.timetable[val].map(
|
|
116
|
+
(day) => ({
|
|
117
|
+
id: day.id,
|
|
118
|
+
closed: day.closed,
|
|
119
|
+
openAt: day.openAt,
|
|
120
|
+
closeAt: day.closeAt
|
|
121
|
+
})
|
|
122
|
+
);
|
|
123
|
+
return timetable;
|
|
124
|
+
},
|
|
125
|
+
{}
|
|
126
|
+
)
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return acc;
|
|
130
|
+
}
|
|
131
|
+
acc[key] = station[key];
|
|
132
|
+
return acc;
|
|
133
|
+
}, {})
|
|
134
|
+
)
|
|
135
|
+
);
|
|
136
|
+
if (includes.includes("INFO")) {
|
|
137
|
+
const pois = await client.get(`/boapi/proxy/geoloc/fleets/${client.clientOptions.fleetId}/pois`, {
|
|
138
|
+
headers: { accept: "application/vnd.geo+json" }
|
|
139
|
+
}).then(
|
|
140
|
+
({ data }) => data.features.reduce((acc, poi) => {
|
|
141
|
+
const {
|
|
142
|
+
geometry: {
|
|
143
|
+
coordinates: [longitude, latitude]
|
|
144
|
+
},
|
|
145
|
+
properties
|
|
146
|
+
} = poi;
|
|
147
|
+
acc[properties.poiId] = {
|
|
148
|
+
name: properties.name,
|
|
149
|
+
coordinates: { latitude, longitude },
|
|
150
|
+
geoProperties: properties
|
|
151
|
+
};
|
|
152
|
+
return acc;
|
|
153
|
+
}, {})
|
|
154
|
+
);
|
|
155
|
+
stations.forEach((station) => {
|
|
156
|
+
if (station.poiId && pois[station.poiId]) {
|
|
157
|
+
Object.assign(station, pois[station.poiId]);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (includes.includes("SERVICES")) {
|
|
162
|
+
const services = await client.get(`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/stations/details?size=1000`).then(
|
|
163
|
+
({ data }) => data.stations.reduce((acc, service) => {
|
|
164
|
+
if (!acc[service.station.id]) {
|
|
165
|
+
acc[service.station.id] = { services: [] };
|
|
166
|
+
}
|
|
167
|
+
acc[service.station.id].services.push({
|
|
168
|
+
id: service.serviceId,
|
|
169
|
+
models: service.models
|
|
170
|
+
});
|
|
171
|
+
return acc;
|
|
172
|
+
}, {})
|
|
173
|
+
);
|
|
174
|
+
stations.forEach((station) => {
|
|
175
|
+
if (services[station.id]) {
|
|
176
|
+
Object.assign(station, services[station.poiId]);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return stations;
|
|
181
|
+
};
|
|
182
|
+
export {
|
|
183
|
+
getBookingRequests,
|
|
184
|
+
getScheduleBookingRequests,
|
|
185
|
+
getStations,
|
|
186
|
+
getSubscriptionBookingRequests
|
|
187
|
+
};
|
package/package.json
CHANGED
|
@@ -42,6 +42,39 @@ export type BookingRequestFilters = SpecificBookingRequestFilters & {
|
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
export type BookingRequest = {
|
|
45
|
+
id: string;
|
|
46
|
+
startDate: string;
|
|
47
|
+
endDate: string;
|
|
48
|
+
returnedDate?: string;
|
|
49
|
+
profileId: string;
|
|
50
|
+
vehicleId?: string;
|
|
51
|
+
modelId: 1647;
|
|
52
|
+
journeyId?: string;
|
|
53
|
+
station: string;
|
|
54
|
+
profileType: 'Single' | 'Business';
|
|
55
|
+
entityName?: string;
|
|
56
|
+
status: string;
|
|
57
|
+
creationDate: string;
|
|
58
|
+
realStartDate?: string;
|
|
59
|
+
cancellationDate?: string;
|
|
60
|
+
cancelledBy?: string;
|
|
61
|
+
userId: string;
|
|
62
|
+
serviceId: string;
|
|
63
|
+
cityId: string;
|
|
64
|
+
deliveryAddress?: string;
|
|
65
|
+
deliveryAddressAdditionalInfo?: string;
|
|
66
|
+
deliveryCity?: string;
|
|
67
|
+
deliveryPostalCode?: string;
|
|
68
|
+
rollingContract: string;
|
|
69
|
+
planDurationInMonths?: number;
|
|
70
|
+
contractType?: string;
|
|
71
|
+
productIds: string[];
|
|
72
|
+
bookingReferenceId?: string;
|
|
73
|
+
pricingDetails: {
|
|
74
|
+
pricingId: string;
|
|
75
|
+
providerType: string;
|
|
76
|
+
}[];
|
|
77
|
+
completed: boolean;
|
|
45
78
|
[key: string]: any;
|
|
46
79
|
};
|
|
47
80
|
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import { describe, test, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { Client } from '@vulog/aima-client';
|
|
3
|
+
import { getStations } from './getStations';
|
|
4
|
+
import { features } from 'process';
|
|
5
|
+
|
|
6
|
+
describe('getStations', () => {
|
|
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
|
+
beforeEach(() => {
|
|
16
|
+
getMock.mockReset();
|
|
17
|
+
vi.useFakeTimers({ now: new Date('2025-01-12T13:35:50.123Z') });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
vi.useRealTimers();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('Fake includes', async () => {
|
|
25
|
+
const rejects = await expect(() => getStations(client, 'FAKE' as any)).rejects;
|
|
26
|
+
rejects.toThrowError('Invalid includes');
|
|
27
|
+
rejects.toSatisfy((error: any) => {
|
|
28
|
+
expect(error).toHaveProperty('cause');
|
|
29
|
+
expect(error.cause).toHaveLength(1);
|
|
30
|
+
expect(error.cause[0]).toHaveProperty('code');
|
|
31
|
+
expect(error.cause[0].code).toBe('invalid_type');
|
|
32
|
+
return true;
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('Fake includes', async () => {
|
|
37
|
+
const rejects = await expect(() => getStations(client, ['FAKE'] as any)).rejects;
|
|
38
|
+
rejects.toThrowError('Invalid includes');
|
|
39
|
+
rejects.toSatisfy((error: any) => {
|
|
40
|
+
expect(error).toHaveProperty('cause');
|
|
41
|
+
expect(error.cause).toHaveLength(1);
|
|
42
|
+
expect(error.cause[0]).toHaveProperty('received');
|
|
43
|
+
expect(error.cause[0]).toHaveProperty('code');
|
|
44
|
+
expect(error.cause[0].received).toBe('FAKE');
|
|
45
|
+
expect(error.cause[0].code).toBe('invalid_enum_value');
|
|
46
|
+
return true;
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('call Base', async () => {
|
|
51
|
+
getMock.mockResolvedValueOnce({
|
|
52
|
+
data: [],
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const stations = await getStations(client);
|
|
56
|
+
expect(getMock).toBeCalled();
|
|
57
|
+
expect(getMock).toBeCalledWith('/boapi/proxy/user/scheduledBooking/fleets/FLEET_ID/stations');
|
|
58
|
+
expect(stations).toEqual([]);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('call Base', async () => {
|
|
62
|
+
const data = {
|
|
63
|
+
id: '009fb49d-ee9c-4df5-92a7-cae77e135499',
|
|
64
|
+
zoneId: 'c67da400508f42449c2115bc513365eb',
|
|
65
|
+
taxZoneId: null,
|
|
66
|
+
poiId: '27d538b15f3d4915b103bf05d7470835',
|
|
67
|
+
modificationDate: '2024-06-20T14:26:39Z',
|
|
68
|
+
fleetId: 'PFSDE-DESTR',
|
|
69
|
+
openTime: '08:00:00',
|
|
70
|
+
closeTime: '18:00:00',
|
|
71
|
+
stationTimetableDTO: {
|
|
72
|
+
stationId: null,
|
|
73
|
+
fleetId: null,
|
|
74
|
+
alwaysOpen: null,
|
|
75
|
+
timetable: null,
|
|
76
|
+
},
|
|
77
|
+
description: {
|
|
78
|
+
fleetId: null,
|
|
79
|
+
stationId: null,
|
|
80
|
+
infos: [],
|
|
81
|
+
},
|
|
82
|
+
maxAvailableSpots: 0,
|
|
83
|
+
};
|
|
84
|
+
getMock.mockResolvedValueOnce({
|
|
85
|
+
data: [data],
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const stations = await getStations(client);
|
|
89
|
+
expect(getMock).toBeCalled();
|
|
90
|
+
expect(getMock).toBeCalledWith('/boapi/proxy/user/scheduledBooking/fleets/FLEET_ID/stations');
|
|
91
|
+
expect(stations.length).toEqual(1);
|
|
92
|
+
expect(stations[0].id).toEqual(data.id);
|
|
93
|
+
expect(stations[0].openingHours).toBeUndefined();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('call includes OPEN_HOUR', async () => {
|
|
97
|
+
const data = {
|
|
98
|
+
id: '009fb49d-ee9c-4df5-92a7-cae77e135499',
|
|
99
|
+
zoneId: 'c67da400508f42449c2115bc513365eb',
|
|
100
|
+
taxZoneId: null,
|
|
101
|
+
poiId: '27d538b15f3d4915b103bf05d7470835',
|
|
102
|
+
modificationDate: '2024-06-20T14:26:39Z',
|
|
103
|
+
fleetId: 'PFSDE-DESTR',
|
|
104
|
+
openTime: '08:00:00',
|
|
105
|
+
closeTime: '18:00:00',
|
|
106
|
+
stationTimetableDTO: {
|
|
107
|
+
stationId: '009fb49d-ee9c-4df5-92a7-cae77e135499',
|
|
108
|
+
fleetId: 'PFSDE-DESTR',
|
|
109
|
+
alwaysOpen: false,
|
|
110
|
+
timetable: {
|
|
111
|
+
MONDAY: [
|
|
112
|
+
{
|
|
113
|
+
id: 3851,
|
|
114
|
+
openAt: '00:00',
|
|
115
|
+
closeAt: '23:59',
|
|
116
|
+
closed: false,
|
|
117
|
+
weekDay: 'MONDAY',
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
TUESDAY: [
|
|
121
|
+
{
|
|
122
|
+
id: 3854,
|
|
123
|
+
openAt: '00:00',
|
|
124
|
+
closeAt: '23:59',
|
|
125
|
+
closed: false,
|
|
126
|
+
weekDay: 'TUESDAY',
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
WEDNESDAY: [
|
|
130
|
+
{
|
|
131
|
+
id: 3857,
|
|
132
|
+
openAt: '00:00',
|
|
133
|
+
closeAt: '23:59',
|
|
134
|
+
closed: false,
|
|
135
|
+
weekDay: 'WEDNESDAY',
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
THURSDAY: [
|
|
139
|
+
{
|
|
140
|
+
id: 3860,
|
|
141
|
+
openAt: '00:00',
|
|
142
|
+
closeAt: '23:59',
|
|
143
|
+
closed: false,
|
|
144
|
+
weekDay: 'THURSDAY',
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
FRIDAY: [
|
|
148
|
+
{
|
|
149
|
+
id: 3863,
|
|
150
|
+
openAt: '00:00',
|
|
151
|
+
closeAt: '23:59',
|
|
152
|
+
closed: false,
|
|
153
|
+
weekDay: 'FRIDAY',
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
SATURDAY: [
|
|
157
|
+
{
|
|
158
|
+
id: 3866,
|
|
159
|
+
openAt: '00:00',
|
|
160
|
+
closeAt: '23:59',
|
|
161
|
+
closed: false,
|
|
162
|
+
weekDay: 'SATURDAY',
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
SUNDAY: [
|
|
166
|
+
{
|
|
167
|
+
id: 3869,
|
|
168
|
+
openAt: '00:00',
|
|
169
|
+
closeAt: '23:59',
|
|
170
|
+
closed: false,
|
|
171
|
+
weekDay: 'SUNDAY',
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
description: {
|
|
177
|
+
fleetId: null,
|
|
178
|
+
stationId: null,
|
|
179
|
+
infos: [],
|
|
180
|
+
},
|
|
181
|
+
maxAvailableSpots: 0,
|
|
182
|
+
};
|
|
183
|
+
getMock.mockResolvedValueOnce({
|
|
184
|
+
data: [data],
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const stations = await getStations(client, ['OPEN_HOUR']);
|
|
188
|
+
expect(getMock).toBeCalled();
|
|
189
|
+
expect(getMock).toBeCalledWith(
|
|
190
|
+
'/boapi/proxy/user/scheduledBooking/fleets/FLEET_ID/stations?showTimetable=true'
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
expect(stations[0].id).toEqual(data.id);
|
|
194
|
+
expect(stations[0].openingHours).not.toBeUndefined();
|
|
195
|
+
const { openingHours } = stations[0];
|
|
196
|
+
expect(openingHours!.alwaysOpen).toEqual(false);
|
|
197
|
+
expect(openingHours!.timetable.FRIDAY.length).toEqual(1);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('call includes OPEN_HOUR, INFO', async () => {
|
|
201
|
+
const data = {
|
|
202
|
+
id: '009fb49d-ee9c-4df5-92a7-cae77e135499',
|
|
203
|
+
zoneId: 'c67da400508f42449c2115bc513365eb',
|
|
204
|
+
taxZoneId: null,
|
|
205
|
+
poiId: '27d538b15f3d4915b103bf05d7470835',
|
|
206
|
+
modificationDate: '2024-06-20T14:26:39Z',
|
|
207
|
+
fleetId: 'PFSDE-DESTR',
|
|
208
|
+
openTime: '08:00:00',
|
|
209
|
+
closeTime: '18:00:00',
|
|
210
|
+
stationTimetableDTO: {
|
|
211
|
+
stationId: '009fb49d-ee9c-4df5-92a7-cae77e135499',
|
|
212
|
+
fleetId: 'PFSDE-DESTR',
|
|
213
|
+
alwaysOpen: false,
|
|
214
|
+
timetable: {
|
|
215
|
+
MONDAY: [
|
|
216
|
+
{
|
|
217
|
+
id: 3851,
|
|
218
|
+
openAt: '00:00',
|
|
219
|
+
closeAt: '23:59',
|
|
220
|
+
closed: false,
|
|
221
|
+
weekDay: 'MONDAY',
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
TUESDAY: [
|
|
225
|
+
{
|
|
226
|
+
id: 3854,
|
|
227
|
+
openAt: '00:00',
|
|
228
|
+
closeAt: '23:59',
|
|
229
|
+
closed: false,
|
|
230
|
+
weekDay: 'TUESDAY',
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
WEDNESDAY: [
|
|
234
|
+
{
|
|
235
|
+
id: 3857,
|
|
236
|
+
openAt: '00:00',
|
|
237
|
+
closeAt: '23:59',
|
|
238
|
+
closed: false,
|
|
239
|
+
weekDay: 'WEDNESDAY',
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
THURSDAY: [
|
|
243
|
+
{
|
|
244
|
+
id: 3860,
|
|
245
|
+
openAt: '00:00',
|
|
246
|
+
closeAt: '23:59',
|
|
247
|
+
closed: false,
|
|
248
|
+
weekDay: 'THURSDAY',
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
FRIDAY: [
|
|
252
|
+
{
|
|
253
|
+
id: 3863,
|
|
254
|
+
openAt: '00:00',
|
|
255
|
+
closeAt: '23:59',
|
|
256
|
+
closed: false,
|
|
257
|
+
weekDay: 'FRIDAY',
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
SATURDAY: [
|
|
261
|
+
{
|
|
262
|
+
id: 3866,
|
|
263
|
+
openAt: '00:00',
|
|
264
|
+
closeAt: '23:59',
|
|
265
|
+
closed: false,
|
|
266
|
+
weekDay: 'SATURDAY',
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
SUNDAY: [
|
|
270
|
+
{
|
|
271
|
+
id: 3869,
|
|
272
|
+
openAt: '00:00',
|
|
273
|
+
closeAt: '23:59',
|
|
274
|
+
closed: false,
|
|
275
|
+
weekDay: 'SUNDAY',
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
description: {
|
|
281
|
+
fleetId: null,
|
|
282
|
+
stationId: null,
|
|
283
|
+
infos: [],
|
|
284
|
+
},
|
|
285
|
+
maxAvailableSpots: 0,
|
|
286
|
+
};
|
|
287
|
+
getMock
|
|
288
|
+
.mockResolvedValueOnce({
|
|
289
|
+
data: [data],
|
|
290
|
+
})
|
|
291
|
+
.mockResolvedValueOnce({
|
|
292
|
+
data: { features: [] },
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const stations = await getStations(client, ['OPEN_HOUR', 'INFO']);
|
|
296
|
+
expect(stations.length).toEqual(1);
|
|
297
|
+
expect(getMock).toBeCalled();
|
|
298
|
+
expect(getMock).toBeCalledWith(
|
|
299
|
+
'/boapi/proxy/user/scheduledBooking/fleets/FLEET_ID/stations?showTimetable=true'
|
|
300
|
+
);
|
|
301
|
+
expect(getMock).toBeCalledWith('/boapi/proxy/geoloc/fleets/FLEET_ID/pois', {
|
|
302
|
+
headers: {
|
|
303
|
+
accept: 'application/vnd.geo+json',
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test('call includes OPEN_HOUR, INFO, SERVICES', async () => {
|
|
309
|
+
const data = {
|
|
310
|
+
id: '009fb49d-ee9c-4df5-92a7-cae77e135499',
|
|
311
|
+
zoneId: 'c67da400508f42449c2115bc513365eb',
|
|
312
|
+
taxZoneId: null,
|
|
313
|
+
poiId: '27d538b15f3d4915b103bf05d7470835',
|
|
314
|
+
modificationDate: '2024-06-20T14:26:39Z',
|
|
315
|
+
fleetId: 'PFSDE-DESTR',
|
|
316
|
+
openTime: '08:00:00',
|
|
317
|
+
closeTime: '18:00:00',
|
|
318
|
+
stationTimetableDTO: {
|
|
319
|
+
stationId: '009fb49d-ee9c-4df5-92a7-cae77e135499',
|
|
320
|
+
fleetId: 'PFSDE-DESTR',
|
|
321
|
+
alwaysOpen: false,
|
|
322
|
+
timetable: {
|
|
323
|
+
MONDAY: [
|
|
324
|
+
{
|
|
325
|
+
id: 3851,
|
|
326
|
+
openAt: '00:00',
|
|
327
|
+
closeAt: '23:59',
|
|
328
|
+
closed: false,
|
|
329
|
+
weekDay: 'MONDAY',
|
|
330
|
+
},
|
|
331
|
+
],
|
|
332
|
+
TUESDAY: [
|
|
333
|
+
{
|
|
334
|
+
id: 3854,
|
|
335
|
+
openAt: '00:00',
|
|
336
|
+
closeAt: '23:59',
|
|
337
|
+
closed: false,
|
|
338
|
+
weekDay: 'TUESDAY',
|
|
339
|
+
},
|
|
340
|
+
],
|
|
341
|
+
WEDNESDAY: [
|
|
342
|
+
{
|
|
343
|
+
id: 3857,
|
|
344
|
+
openAt: '00:00',
|
|
345
|
+
closeAt: '23:59',
|
|
346
|
+
closed: false,
|
|
347
|
+
weekDay: 'WEDNESDAY',
|
|
348
|
+
},
|
|
349
|
+
],
|
|
350
|
+
THURSDAY: [
|
|
351
|
+
{
|
|
352
|
+
id: 3860,
|
|
353
|
+
openAt: '00:00',
|
|
354
|
+
closeAt: '23:59',
|
|
355
|
+
closed: false,
|
|
356
|
+
weekDay: 'THURSDAY',
|
|
357
|
+
},
|
|
358
|
+
],
|
|
359
|
+
FRIDAY: [
|
|
360
|
+
{
|
|
361
|
+
id: 3863,
|
|
362
|
+
openAt: '00:00',
|
|
363
|
+
closeAt: '23:59',
|
|
364
|
+
closed: false,
|
|
365
|
+
weekDay: 'FRIDAY',
|
|
366
|
+
},
|
|
367
|
+
],
|
|
368
|
+
SATURDAY: [
|
|
369
|
+
{
|
|
370
|
+
id: 3866,
|
|
371
|
+
openAt: '00:00',
|
|
372
|
+
closeAt: '23:59',
|
|
373
|
+
closed: false,
|
|
374
|
+
weekDay: 'SATURDAY',
|
|
375
|
+
},
|
|
376
|
+
],
|
|
377
|
+
SUNDAY: [
|
|
378
|
+
{
|
|
379
|
+
id: 3869,
|
|
380
|
+
openAt: '00:00',
|
|
381
|
+
closeAt: '23:59',
|
|
382
|
+
closed: false,
|
|
383
|
+
weekDay: 'SUNDAY',
|
|
384
|
+
},
|
|
385
|
+
],
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
description: {
|
|
389
|
+
fleetId: null,
|
|
390
|
+
stationId: null,
|
|
391
|
+
infos: [],
|
|
392
|
+
},
|
|
393
|
+
maxAvailableSpots: 0,
|
|
394
|
+
};
|
|
395
|
+
getMock
|
|
396
|
+
.mockResolvedValueOnce({
|
|
397
|
+
data: [data],
|
|
398
|
+
})
|
|
399
|
+
.mockResolvedValueOnce({
|
|
400
|
+
data: { features: [] },
|
|
401
|
+
})
|
|
402
|
+
.mockResolvedValueOnce({
|
|
403
|
+
data: { stations: [] },
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
const stations = await getStations(client, ['OPEN_HOUR', 'INFO', 'SERVICES']);
|
|
407
|
+
expect(stations.length).toEqual(1);
|
|
408
|
+
expect(getMock).toBeCalled();
|
|
409
|
+
expect(getMock).toBeCalledWith(
|
|
410
|
+
'/boapi/proxy/user/scheduledBooking/fleets/FLEET_ID/stations?showTimetable=true'
|
|
411
|
+
);
|
|
412
|
+
expect(getMock).toBeCalledWith('/boapi/proxy/geoloc/fleets/FLEET_ID/pois', {
|
|
413
|
+
headers: {
|
|
414
|
+
accept: 'application/vnd.geo+json',
|
|
415
|
+
},
|
|
416
|
+
});
|
|
417
|
+
expect(getMock).toBeCalledWith('/boapi/proxy/user/fleets/FLEET_ID/stations/details?size=1000');
|
|
418
|
+
});
|
|
419
|
+
});
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
const IncludeSchema = z.enum(['INFO', 'OPEN_HOUR', 'SERVICES']);
|
|
5
|
+
const IncludesSchema = z.array(IncludeSchema);
|
|
6
|
+
export type Include = z.infer<typeof IncludeSchema>;
|
|
7
|
+
|
|
8
|
+
export type Days = 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY' | 'SUNDAY';
|
|
9
|
+
|
|
10
|
+
export type DayOpeningHours = {
|
|
11
|
+
id: number;
|
|
12
|
+
closed: boolean;
|
|
13
|
+
openAt: string;
|
|
14
|
+
closeAt: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type Timetable = Record<Days, DayOpeningHours[]>;
|
|
18
|
+
|
|
19
|
+
export type OpeningHours = {
|
|
20
|
+
alwaysOpen: boolean;
|
|
21
|
+
timetable: Timetable;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type GeoInfo = {
|
|
25
|
+
name: string;
|
|
26
|
+
coordinates: {
|
|
27
|
+
latitude: number;
|
|
28
|
+
longitude: number;
|
|
29
|
+
};
|
|
30
|
+
geoProperties: { [key: string]: any };
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type Service = {
|
|
34
|
+
id: string;
|
|
35
|
+
models: {
|
|
36
|
+
id: number;
|
|
37
|
+
vehicles: string[];
|
|
38
|
+
}[];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
type ServiceInfo = {
|
|
42
|
+
services: Service[];
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type Station = Partial<GeoInfo> &
|
|
46
|
+
Partial<ServiceInfo> & {
|
|
47
|
+
id: string;
|
|
48
|
+
zoneId: string;
|
|
49
|
+
poiId: string;
|
|
50
|
+
modificationDate: string;
|
|
51
|
+
fleetId: string;
|
|
52
|
+
openingHours?: OpeningHours;
|
|
53
|
+
// description: {
|
|
54
|
+
// fleetId: null;
|
|
55
|
+
// stationId: null;
|
|
56
|
+
// infos: [];
|
|
57
|
+
// };
|
|
58
|
+
[key: string]: any;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const getStations = async (client: Client, includes: Include[] = []): Promise<Station[]> => {
|
|
62
|
+
const resultIncludes = IncludesSchema.safeParse(includes);
|
|
63
|
+
if (!resultIncludes.success) {
|
|
64
|
+
throw new TypeError('Invalid includes', {
|
|
65
|
+
cause: resultIncludes.error.issues,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const searchParams = new URLSearchParams();
|
|
70
|
+
if (includes.includes('OPEN_HOUR')) {
|
|
71
|
+
searchParams.append('showTimetable', 'true');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const stations = await client
|
|
75
|
+
.get<
|
|
76
|
+
any[]
|
|
77
|
+
>(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/stations${searchParams.size > 0 ? `?${searchParams.toString()}` : ''}`)
|
|
78
|
+
.then(({ data }) =>
|
|
79
|
+
data.map(
|
|
80
|
+
(station: any) =>
|
|
81
|
+
Object.keys(station).reduce<{ [key: string]: any }>((acc, key) => {
|
|
82
|
+
if (key === 'stationTimetableDTO') {
|
|
83
|
+
if (station.stationTimetableDTO?.stationId) {
|
|
84
|
+
acc.openingHours = {
|
|
85
|
+
alwaysOpen: station.stationTimetableDTO.alwaysOpen,
|
|
86
|
+
timetable: Object.keys(station.stationTimetableDTO.timetable).reduce<Timetable>(
|
|
87
|
+
(timetable, val) => {
|
|
88
|
+
// eslint-disable-next-line no-param-reassign
|
|
89
|
+
timetable[val as Days] = station.stationTimetableDTO.timetable[val].map(
|
|
90
|
+
(day: any) => ({
|
|
91
|
+
id: day.id,
|
|
92
|
+
closed: day.closed,
|
|
93
|
+
openAt: day.openAt,
|
|
94
|
+
closeAt: day.closeAt,
|
|
95
|
+
})
|
|
96
|
+
);
|
|
97
|
+
return timetable;
|
|
98
|
+
},
|
|
99
|
+
{} as Timetable
|
|
100
|
+
),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return acc;
|
|
104
|
+
}
|
|
105
|
+
acc[key] = station[key];
|
|
106
|
+
return acc;
|
|
107
|
+
}, {}) as Station
|
|
108
|
+
)
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
if (includes.includes('INFO')) {
|
|
112
|
+
const pois = await client
|
|
113
|
+
.get<{ features: any[] }>(`/boapi/proxy/geoloc/fleets/${client.clientOptions.fleetId}/pois`, {
|
|
114
|
+
headers: { accept: 'application/vnd.geo+json' },
|
|
115
|
+
})
|
|
116
|
+
.then(({ data }) =>
|
|
117
|
+
data.features.reduce<{ [key: string]: GeoInfo }>((acc, poi) => {
|
|
118
|
+
const {
|
|
119
|
+
geometry: {
|
|
120
|
+
coordinates: [longitude, latitude],
|
|
121
|
+
},
|
|
122
|
+
properties,
|
|
123
|
+
} = poi;
|
|
124
|
+
acc[properties.poiId] = {
|
|
125
|
+
name: properties.name,
|
|
126
|
+
coordinates: { latitude, longitude },
|
|
127
|
+
geoProperties: properties,
|
|
128
|
+
};
|
|
129
|
+
return acc;
|
|
130
|
+
}, {})
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
stations.forEach((station) => {
|
|
134
|
+
if (station.poiId && pois[station.poiId]) {
|
|
135
|
+
Object.assign(station, pois[station.poiId]);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (includes.includes('SERVICES')) {
|
|
141
|
+
const services = await client
|
|
142
|
+
.get<{
|
|
143
|
+
stations: any[];
|
|
144
|
+
}>(`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/stations/details?size=1000`)
|
|
145
|
+
.then(({ data }) =>
|
|
146
|
+
data.stations.reduce<{ [key: string]: ServiceInfo }>((acc, service) => {
|
|
147
|
+
if (!acc[service.station.id]) {
|
|
148
|
+
acc[service.station.id] = { services: [] };
|
|
149
|
+
}
|
|
150
|
+
acc[service.station.id].services.push({
|
|
151
|
+
id: service.serviceId,
|
|
152
|
+
models: service.models,
|
|
153
|
+
});
|
|
154
|
+
return acc;
|
|
155
|
+
}, {})
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
stations.forEach((station) => {
|
|
159
|
+
if (services[station.id]) {
|
|
160
|
+
Object.assign(station, services[station.poiId]);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return stations;
|
|
166
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { getBookingRequests, getScheduleBookingRequests, getSubscriptionBookingRequests } from './getBookingRequests';
|
|
2
|
+
export type { BookingRequest, BookingRequestStatus, ServiceType, BookingRequestFilters } from './getBookingRequests';
|
|
3
|
+
export { getStations } from './getStations';
|
|
4
|
+
export type { Station, Include, Days, DayOpeningHours, Timetable, OpeningHours } from './getStations';
|