@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 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
- export { }
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
- export { }
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vulog/aima-booking",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -17,7 +17,6 @@ describe('getBookingRequests', () => {
17
17
  });
18
18
 
19
19
  afterEach(() => {
20
- // restoring date after each test run
21
20
  vi.useRealTimers();
22
21
  });
23
22
 
@@ -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';