@vulog/aima-booking 1.2.42 → 1.2.43
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 +109 -2
- package/dist/index.d.cts +147 -1
- package/dist/index.d.mts +147 -1
- package/dist/index.mjs +107 -3
- package/package.json +3 -3
- package/src/createBookingRequest.test.ts +73 -0
- package/src/createBookingRequest.ts +116 -0
- package/src/getAvailableModels.test.ts +88 -0
- package/src/getAvailableModels.ts +47 -0
- package/src/getStationUnavailability.test.ts +79 -0
- package/src/getStationUnavailability.ts +41 -0
- package/src/index.ts +6 -0
- package/src/types.ts +73 -0
package/dist/index.cjs
CHANGED
|
@@ -157,10 +157,10 @@ const getScheduledBookingById = async (client, bookingId) => {
|
|
|
157
157
|
//#endregion
|
|
158
158
|
//#region src/getAvailableVehicles.ts
|
|
159
159
|
/** ISO date-time without milliseconds (e.g. 2025-02-10T12:00:00Z or 2025-02-10T12:00:00+01:00). */
|
|
160
|
-
const isoDateTimeNoMs = zod.z.string().trim().datetime({ precision: 0 });
|
|
160
|
+
const isoDateTimeNoMs$2 = zod.z.string().trim().datetime({ precision: 0 });
|
|
161
161
|
const getAvailableVehiclesSchema = zod.z.object({
|
|
162
162
|
stationId: zod.z.string().trim().min(1),
|
|
163
|
-
startDate: isoDateTimeNoMs
|
|
163
|
+
startDate: isoDateTimeNoMs$2
|
|
164
164
|
});
|
|
165
165
|
const getAvailableVehicles = async (client, stationId, startDate) => {
|
|
166
166
|
const result = getAvailableVehiclesSchema.safeParse({
|
|
@@ -526,11 +526,117 @@ const createSubscription = async (client, body) => {
|
|
|
526
526
|
return client.post(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/subscription/bookingrequests`, result.data).then(({ data }) => data);
|
|
527
527
|
};
|
|
528
528
|
//#endregion
|
|
529
|
+
//#region src/createBookingRequest.ts
|
|
530
|
+
const createBookingRequestBodySchema = zod.z.object({
|
|
531
|
+
startDate: zod.z.string().trim().min(1),
|
|
532
|
+
endDate: zod.z.string().trim().min(1),
|
|
533
|
+
modelId: zod.z.number().int().positive(),
|
|
534
|
+
profileId: zod.z.string().trim().min(1).uuid(),
|
|
535
|
+
serviceId: zod.z.string().trim().min(1).uuid(),
|
|
536
|
+
userId: zod.z.string().uuid().optional(),
|
|
537
|
+
vehicleId: zod.z.string().uuid().optional(),
|
|
538
|
+
station: zod.z.string().optional(),
|
|
539
|
+
latitude: zod.z.number().optional(),
|
|
540
|
+
longitude: zod.z.number().optional(),
|
|
541
|
+
radius: zod.z.number().int().optional(),
|
|
542
|
+
email: zod.z.string().email().optional(),
|
|
543
|
+
notes: zod.z.string().optional(),
|
|
544
|
+
plannedReturnDate: zod.z.string().optional(),
|
|
545
|
+
deliveryAddress: zod.z.string().optional(),
|
|
546
|
+
deliveryAddressAdditionalInfo: zod.z.string().optional(),
|
|
547
|
+
deliveryCity: zod.z.string().optional(),
|
|
548
|
+
deliveryPostalCode: zod.z.string().optional(),
|
|
549
|
+
dropOffStation: zod.z.string().optional(),
|
|
550
|
+
rollingContract: zod.z.boolean().optional(),
|
|
551
|
+
planDurationInMonths: zod.z.number().int().optional(),
|
|
552
|
+
planName: zod.z.string().optional(),
|
|
553
|
+
parentId: zod.z.string().optional(),
|
|
554
|
+
contractType: zod.z.enum(["SVS", "MVS"]).optional(),
|
|
555
|
+
productIds: zod.z.array(zod.z.string()).optional(),
|
|
556
|
+
preallocatedVehicleId: zod.z.string().optional(),
|
|
557
|
+
bookingReferenceId: zod.z.string().optional(),
|
|
558
|
+
providedPricingId: zod.z.string().uuid().optional(),
|
|
559
|
+
preferredPaymentMethods: zod.z.array(zod.z.object({
|
|
560
|
+
pspReference: zod.z.string(),
|
|
561
|
+
amount: zod.z.number()
|
|
562
|
+
})).optional(),
|
|
563
|
+
requiresActionReturnURL: zod.z.string().optional(),
|
|
564
|
+
cityId: zod.z.string().optional()
|
|
565
|
+
});
|
|
566
|
+
/**
|
|
567
|
+
* Create a new booking request.
|
|
568
|
+
*
|
|
569
|
+
* Swagger: `POST /scheduledBooking/fleets/{fleetId}/bookingrequests` (admin-booking).
|
|
570
|
+
*/
|
|
571
|
+
const createBookingRequest = async (client, body, options = {}) => {
|
|
572
|
+
const result = createBookingRequestBodySchema.safeParse(body);
|
|
573
|
+
if (!result.success) throw new TypeError("Invalid args", { cause: result.error.issues });
|
|
574
|
+
const query = options.userStatusCheckRequired !== void 0 ? `?userStatusCheckRequired=${options.userStatusCheckRequired}` : "";
|
|
575
|
+
return client.post(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/bookingrequests${query}`, {
|
|
576
|
+
...result.data,
|
|
577
|
+
fleetId: client.clientOptions.fleetId
|
|
578
|
+
}).then(({ data }) => data);
|
|
579
|
+
};
|
|
580
|
+
//#endregion
|
|
581
|
+
//#region src/getAvailableModels.ts
|
|
582
|
+
/** ISO date-time without milliseconds (e.g. 2020-09-20T00:00:00Z or 2020-09-20T00:00:00+01:00). */
|
|
583
|
+
const isoDateTimeNoMs$1 = zod.z.string().trim().datetime({ precision: 0 });
|
|
584
|
+
const getAvailableModelsSchema = zod.z.object({
|
|
585
|
+
startDate: isoDateTimeNoMs$1,
|
|
586
|
+
endDate: isoDateTimeNoMs$1,
|
|
587
|
+
cityId: zod.z.string().trim().min(1).optional(),
|
|
588
|
+
userId: zod.z.string().uuid().optional(),
|
|
589
|
+
profileId: zod.z.string().uuid().optional(),
|
|
590
|
+
oneWayTrip: zod.z.boolean().optional(),
|
|
591
|
+
showUnavailableModels: zod.z.boolean().optional()
|
|
592
|
+
});
|
|
593
|
+
/**
|
|
594
|
+
* Get available models grouped by station in a given time range.
|
|
595
|
+
*
|
|
596
|
+
* Swagger: `GET /scheduledBooking/fleets/{fleetId}/stations/models` (admin-booking / internal).
|
|
597
|
+
*/
|
|
598
|
+
const getAvailableModels = async (client, params) => {
|
|
599
|
+
const result = getAvailableModelsSchema.safeParse(params);
|
|
600
|
+
if (!result.success) throw new TypeError("Invalid args", { cause: result.error.issues });
|
|
601
|
+
const searchParams = new URLSearchParams();
|
|
602
|
+
for (const [key, value] of Object.entries(result.data)) if (value !== void 0) searchParams.append(key, String(value));
|
|
603
|
+
return client.get(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/stations/models?${searchParams.toString()}`).then(({ data }) => data);
|
|
604
|
+
};
|
|
605
|
+
//#endregion
|
|
606
|
+
//#region src/getStationUnavailability.ts
|
|
607
|
+
/** ISO date-time without milliseconds (e.g. 2021-01-01T00:00:00Z). */
|
|
608
|
+
const isoDateTimeNoMs = zod.z.string().trim().datetime({ precision: 0 });
|
|
609
|
+
const getStationUnavailabilitySchema = zod.z.object({
|
|
610
|
+
stationId: zod.z.string().uuid(),
|
|
611
|
+
from: isoDateTimeNoMs,
|
|
612
|
+
to: isoDateTimeNoMs,
|
|
613
|
+
serviceId: zod.z.string().uuid()
|
|
614
|
+
});
|
|
615
|
+
/**
|
|
616
|
+
* Get the list of vehicle unavailabilities for a given station over a period.
|
|
617
|
+
*
|
|
618
|
+
* Swagger: `GET /fleets/{fleetId}/stations/{stationId}/unavailability` (admin-booking,
|
|
619
|
+
* operationId `getVehicleCalendarForPeriod`).
|
|
620
|
+
*/
|
|
621
|
+
const getStationUnavailability = async (client, params) => {
|
|
622
|
+
const result = getStationUnavailabilitySchema.safeParse(params);
|
|
623
|
+
if (!result.success) throw new TypeError("Invalid args", { cause: result.error.issues });
|
|
624
|
+
const { stationId, from, to, serviceId } = result.data;
|
|
625
|
+
const searchParams = new URLSearchParams({
|
|
626
|
+
from,
|
|
627
|
+
to,
|
|
628
|
+
serviceId
|
|
629
|
+
});
|
|
630
|
+
return client.get(`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/stations/${stationId}/unavailability?${searchParams.toString()}`).then(({ data }) => data);
|
|
631
|
+
};
|
|
632
|
+
//#endregion
|
|
529
633
|
exports.allocateVehicle = allocateVehicle;
|
|
530
634
|
exports.cancelBookingRequest = cancelBookingRequest;
|
|
635
|
+
exports.createBookingRequest = createBookingRequest;
|
|
531
636
|
exports.createSubscription = createSubscription;
|
|
532
637
|
exports.deallocateVehicle = deallocateVehicle;
|
|
533
638
|
exports.getAdditionalDrivers = getAdditionalDrivers;
|
|
639
|
+
exports.getAvailableModels = getAvailableModels;
|
|
534
640
|
exports.getAvailableVehicles = getAvailableVehicles;
|
|
535
641
|
exports.getBookingRequestById = getBookingRequestById;
|
|
536
642
|
exports.getBookingRequestByTrip = getBookingRequestByTrip;
|
|
@@ -542,6 +648,7 @@ exports.getScheduleBookingRequests = getScheduleBookingRequests;
|
|
|
542
648
|
exports.getScheduledBookingById = getScheduledBookingById;
|
|
543
649
|
exports.getSlaves = getSlaves;
|
|
544
650
|
exports.getStationById = getStationById;
|
|
651
|
+
exports.getStationUnavailability = getStationUnavailability;
|
|
545
652
|
exports.getStations = getStations;
|
|
546
653
|
exports.getSubscriptionBookingRequestById = getSubscriptionBookingRequestById;
|
|
547
654
|
exports.getSubscriptionBookingRequests = getSubscriptionBookingRequests;
|
package/dist/index.d.cts
CHANGED
|
@@ -317,6 +317,71 @@ type BookingRequestSlave = {
|
|
|
317
317
|
traveledDistance: number;
|
|
318
318
|
energyLevelEnd: number;
|
|
319
319
|
};
|
|
320
|
+
/** Mileage allowance for an available model (Swagger: `MileageAllowanceDTO`). */
|
|
321
|
+
type MileageAllowance = {
|
|
322
|
+
allowancePerDay?: number;
|
|
323
|
+
totalAllowance?: number;
|
|
324
|
+
pricePerExceedingUnit?: number;
|
|
325
|
+
};
|
|
326
|
+
/** Estimated product embedded in a price breakdown (Swagger: `EstimatedProductDTO`). */
|
|
327
|
+
type EstimatedProduct = {
|
|
328
|
+
productId?: string;
|
|
329
|
+
price?: number;
|
|
330
|
+
};
|
|
331
|
+
/** Price breakdown for an available model (Swagger: `PriceBreakdownDTO`). */
|
|
332
|
+
type PriceBreakdown = {
|
|
333
|
+
tripPrice?: number;
|
|
334
|
+
productsPrice?: number;
|
|
335
|
+
productDetails?: EstimatedProduct[];
|
|
336
|
+
};
|
|
337
|
+
/** Pricing info for an available model (Swagger: `PricingInfo`). */
|
|
338
|
+
type PricingInfo = {
|
|
339
|
+
pricingId?: string;
|
|
340
|
+
type?: string;
|
|
341
|
+
priceBreakdown?: PriceBreakdown;
|
|
342
|
+
};
|
|
343
|
+
/** Available model entry returned by `getAvailableModels` (Swagger: `BookingRequestModelDTO`). */
|
|
344
|
+
type AvailableModel = {
|
|
345
|
+
id: number;
|
|
346
|
+
price?: string;
|
|
347
|
+
prePaymentPrice?: number;
|
|
348
|
+
mileageAllowance?: MileageAllowance;
|
|
349
|
+
pricingInfo?: PricingInfo;
|
|
350
|
+
};
|
|
351
|
+
/** Station entry returned by `getAvailableModels` (Swagger: `StationDTO`). */
|
|
352
|
+
type StationWithAvailableModels = {
|
|
353
|
+
id: string;
|
|
354
|
+
zoneId: string;
|
|
355
|
+
poiId: string;
|
|
356
|
+
models: AvailableModel[];
|
|
357
|
+
taxZoneId?: string;
|
|
358
|
+
cityId?: string;
|
|
359
|
+
serviceId?: string;
|
|
360
|
+
fleetId?: string;
|
|
361
|
+
openTime?: string;
|
|
362
|
+
closeTime?: string;
|
|
363
|
+
};
|
|
364
|
+
/** Single unavailability entry in a station vehicle calendar (Swagger: `UnavailabilityDTO`). */
|
|
365
|
+
type VehicleUnavailability = {
|
|
366
|
+
id?: string;
|
|
367
|
+
vehicleId?: string;
|
|
368
|
+
modelId?: number;
|
|
369
|
+
from?: string;
|
|
370
|
+
to?: string;
|
|
371
|
+
toWithMargin?: string;
|
|
372
|
+
type?: 'BOOKING' | 'MAINTENANCE';
|
|
373
|
+
userId?: string;
|
|
374
|
+
reason?: string;
|
|
375
|
+
serviceId?: string;
|
|
376
|
+
};
|
|
377
|
+
/** Vehicle calendar for a station over a period (Swagger: `VehicleCalendarResponseDTO`). */
|
|
378
|
+
type StationVehicleCalendar = {
|
|
379
|
+
timezone?: string;
|
|
380
|
+
from?: string;
|
|
381
|
+
to?: string;
|
|
382
|
+
vehicleIds?: string[];
|
|
383
|
+
unavailabilities?: VehicleUnavailability[];
|
|
384
|
+
};
|
|
320
385
|
//#endregion
|
|
321
386
|
//#region src/getBookingRequests.d.ts
|
|
322
387
|
declare const BookingRequestStatusSchema: z.ZodEnum<{
|
|
@@ -490,4 +555,85 @@ type CreateSubscriptionBody = {
|
|
|
490
555
|
};
|
|
491
556
|
declare const createSubscription: (client: Client, body: CreateSubscriptionBody) => Promise<BookingRequest>;
|
|
492
557
|
//#endregion
|
|
493
|
-
|
|
558
|
+
//#region src/createBookingRequest.d.ts
|
|
559
|
+
type CreateBookingRequestBody = {
|
|
560
|
+
startDate: string;
|
|
561
|
+
endDate: string;
|
|
562
|
+
modelId: number;
|
|
563
|
+
profileId: string;
|
|
564
|
+
serviceId: string;
|
|
565
|
+
userId?: string;
|
|
566
|
+
vehicleId?: string;
|
|
567
|
+
station?: string;
|
|
568
|
+
latitude?: number;
|
|
569
|
+
longitude?: number;
|
|
570
|
+
radius?: number;
|
|
571
|
+
email?: string;
|
|
572
|
+
notes?: string;
|
|
573
|
+
plannedReturnDate?: string;
|
|
574
|
+
deliveryAddress?: string;
|
|
575
|
+
deliveryAddressAdditionalInfo?: string;
|
|
576
|
+
deliveryCity?: string;
|
|
577
|
+
deliveryPostalCode?: string;
|
|
578
|
+
dropOffStation?: string;
|
|
579
|
+
rollingContract?: boolean;
|
|
580
|
+
planDurationInMonths?: number;
|
|
581
|
+
planName?: string;
|
|
582
|
+
parentId?: string;
|
|
583
|
+
contractType?: 'SVS' | 'MVS';
|
|
584
|
+
productIds?: string[];
|
|
585
|
+
preallocatedVehicleId?: string;
|
|
586
|
+
bookingReferenceId?: string;
|
|
587
|
+
providedPricingId?: string;
|
|
588
|
+
preferredPaymentMethods?: {
|
|
589
|
+
pspReference: string;
|
|
590
|
+
amount: number;
|
|
591
|
+
}[];
|
|
592
|
+
requiresActionReturnURL?: string;
|
|
593
|
+
cityId?: string;
|
|
594
|
+
};
|
|
595
|
+
type CreateBookingRequestOptions = {
|
|
596
|
+
/** When false, bypass the user status check (operator use). Default true server-side. */userStatusCheckRequired?: boolean;
|
|
597
|
+
};
|
|
598
|
+
/**
|
|
599
|
+
* Create a new booking request.
|
|
600
|
+
*
|
|
601
|
+
* Swagger: `POST /scheduledBooking/fleets/{fleetId}/bookingrequests` (admin-booking).
|
|
602
|
+
*/
|
|
603
|
+
declare const createBookingRequest: (client: Client, body: CreateBookingRequestBody, options?: CreateBookingRequestOptions) => Promise<BookingRequest>;
|
|
604
|
+
//#endregion
|
|
605
|
+
//#region src/getAvailableModels.d.ts
|
|
606
|
+
declare const getAvailableModelsSchema: z.ZodObject<{
|
|
607
|
+
startDate: z.ZodString;
|
|
608
|
+
endDate: z.ZodString;
|
|
609
|
+
cityId: z.ZodOptional<z.ZodString>;
|
|
610
|
+
userId: z.ZodOptional<z.ZodString>;
|
|
611
|
+
profileId: z.ZodOptional<z.ZodString>;
|
|
612
|
+
oneWayTrip: z.ZodOptional<z.ZodBoolean>;
|
|
613
|
+
showUnavailableModels: z.ZodOptional<z.ZodBoolean>;
|
|
614
|
+
}, z.core.$strip>;
|
|
615
|
+
type GetAvailableModelsParams = z.infer<typeof getAvailableModelsSchema>;
|
|
616
|
+
/**
|
|
617
|
+
* Get available models grouped by station in a given time range.
|
|
618
|
+
*
|
|
619
|
+
* Swagger: `GET /scheduledBooking/fleets/{fleetId}/stations/models` (admin-booking / internal).
|
|
620
|
+
*/
|
|
621
|
+
declare const getAvailableModels: (client: Client, params: GetAvailableModelsParams) => Promise<StationWithAvailableModels[]>;
|
|
622
|
+
//#endregion
|
|
623
|
+
//#region src/getStationUnavailability.d.ts
|
|
624
|
+
declare const getStationUnavailabilitySchema: z.ZodObject<{
|
|
625
|
+
stationId: z.ZodString;
|
|
626
|
+
from: z.ZodString;
|
|
627
|
+
to: z.ZodString;
|
|
628
|
+
serviceId: z.ZodString;
|
|
629
|
+
}, z.core.$strip>;
|
|
630
|
+
type GetStationUnavailabilityParams = z.infer<typeof getStationUnavailabilitySchema>;
|
|
631
|
+
/**
|
|
632
|
+
* Get the list of vehicle unavailabilities for a given station over a period.
|
|
633
|
+
*
|
|
634
|
+
* Swagger: `GET /fleets/{fleetId}/stations/{stationId}/unavailability` (admin-booking,
|
|
635
|
+
* operationId `getVehicleCalendarForPeriod`).
|
|
636
|
+
*/
|
|
637
|
+
declare const getStationUnavailability: (client: Client, params: GetStationUnavailabilityParams) => Promise<StationVehicleCalendar>;
|
|
638
|
+
//#endregion
|
|
639
|
+
export { AdditionalDriver, AvailableModel, AvailableVehiclesResponse, BRPaymentItem, BaseBookingRequest, BookingCredit, BookingRequest, type BookingRequestFilters, BookingRequestSlave, type BookingRequestStatus, Contract, type CreateBookingRequestBody, type CreateBookingRequestOptions, type CreateSubscriptionBody, CustomPrice, DayOpeningHours, Days, EstimatedProduct, GeoInfo, type GetAvailableModelsParams, type GetStationUnavailabilityParams, IFormatSlave, IFormatSubscription, type Include, type IncludeStation, Master, MileageAllowance, OpeningHours, PaymentReceipts, PreferredPaymentMethod, PriceBreakdown, PricingInfo, SATBookingRequest, type SATBookingRequestStatus, Service, ServiceInfo, type ServiceType, Slave, Station, StationVehicleCalendar, StationWithAvailableModels, Timetable, TriggerBRPaymentResponse, Vehicle, VehicleUnavailability, allocateVehicle, cancelBookingRequest, createBookingRequest, createSubscription, deallocateVehicle, getAdditionalDrivers, getAvailableModels, getAvailableVehicles, getBookingRequestById, getBookingRequestByTrip, getBookingRequests, getBookingRequestsByUserId, getDigitalContracts, getSATBookingRequests, getScheduleBookingRequests, getScheduledBookingById, getSlaves, getStationById, getStationUnavailability, getStations, getSubscriptionBookingRequestById, getSubscriptionBookingRequests, getSubscriptionsByUserId, releaseBRPayment, submitCancellationRequest, triggerBRPayment, updateScheduleBooking };
|
package/dist/index.d.mts
CHANGED
|
@@ -317,6 +317,71 @@ type BookingRequestSlave = {
|
|
|
317
317
|
traveledDistance: number;
|
|
318
318
|
energyLevelEnd: number;
|
|
319
319
|
};
|
|
320
|
+
/** Mileage allowance for an available model (Swagger: `MileageAllowanceDTO`). */
|
|
321
|
+
type MileageAllowance = {
|
|
322
|
+
allowancePerDay?: number;
|
|
323
|
+
totalAllowance?: number;
|
|
324
|
+
pricePerExceedingUnit?: number;
|
|
325
|
+
};
|
|
326
|
+
/** Estimated product embedded in a price breakdown (Swagger: `EstimatedProductDTO`). */
|
|
327
|
+
type EstimatedProduct = {
|
|
328
|
+
productId?: string;
|
|
329
|
+
price?: number;
|
|
330
|
+
};
|
|
331
|
+
/** Price breakdown for an available model (Swagger: `PriceBreakdownDTO`). */
|
|
332
|
+
type PriceBreakdown = {
|
|
333
|
+
tripPrice?: number;
|
|
334
|
+
productsPrice?: number;
|
|
335
|
+
productDetails?: EstimatedProduct[];
|
|
336
|
+
};
|
|
337
|
+
/** Pricing info for an available model (Swagger: `PricingInfo`). */
|
|
338
|
+
type PricingInfo = {
|
|
339
|
+
pricingId?: string;
|
|
340
|
+
type?: string;
|
|
341
|
+
priceBreakdown?: PriceBreakdown;
|
|
342
|
+
};
|
|
343
|
+
/** Available model entry returned by `getAvailableModels` (Swagger: `BookingRequestModelDTO`). */
|
|
344
|
+
type AvailableModel = {
|
|
345
|
+
id: number;
|
|
346
|
+
price?: string;
|
|
347
|
+
prePaymentPrice?: number;
|
|
348
|
+
mileageAllowance?: MileageAllowance;
|
|
349
|
+
pricingInfo?: PricingInfo;
|
|
350
|
+
};
|
|
351
|
+
/** Station entry returned by `getAvailableModels` (Swagger: `StationDTO`). */
|
|
352
|
+
type StationWithAvailableModels = {
|
|
353
|
+
id: string;
|
|
354
|
+
zoneId: string;
|
|
355
|
+
poiId: string;
|
|
356
|
+
models: AvailableModel[];
|
|
357
|
+
taxZoneId?: string;
|
|
358
|
+
cityId?: string;
|
|
359
|
+
serviceId?: string;
|
|
360
|
+
fleetId?: string;
|
|
361
|
+
openTime?: string;
|
|
362
|
+
closeTime?: string;
|
|
363
|
+
};
|
|
364
|
+
/** Single unavailability entry in a station vehicle calendar (Swagger: `UnavailabilityDTO`). */
|
|
365
|
+
type VehicleUnavailability = {
|
|
366
|
+
id?: string;
|
|
367
|
+
vehicleId?: string;
|
|
368
|
+
modelId?: number;
|
|
369
|
+
from?: string;
|
|
370
|
+
to?: string;
|
|
371
|
+
toWithMargin?: string;
|
|
372
|
+
type?: 'BOOKING' | 'MAINTENANCE';
|
|
373
|
+
userId?: string;
|
|
374
|
+
reason?: string;
|
|
375
|
+
serviceId?: string;
|
|
376
|
+
};
|
|
377
|
+
/** Vehicle calendar for a station over a period (Swagger: `VehicleCalendarResponseDTO`). */
|
|
378
|
+
type StationVehicleCalendar = {
|
|
379
|
+
timezone?: string;
|
|
380
|
+
from?: string;
|
|
381
|
+
to?: string;
|
|
382
|
+
vehicleIds?: string[];
|
|
383
|
+
unavailabilities?: VehicleUnavailability[];
|
|
384
|
+
};
|
|
320
385
|
//#endregion
|
|
321
386
|
//#region src/getBookingRequests.d.ts
|
|
322
387
|
declare const BookingRequestStatusSchema: z.ZodEnum<{
|
|
@@ -490,4 +555,85 @@ type CreateSubscriptionBody = {
|
|
|
490
555
|
};
|
|
491
556
|
declare const createSubscription: (client: Client, body: CreateSubscriptionBody) => Promise<BookingRequest>;
|
|
492
557
|
//#endregion
|
|
493
|
-
|
|
558
|
+
//#region src/createBookingRequest.d.ts
|
|
559
|
+
type CreateBookingRequestBody = {
|
|
560
|
+
startDate: string;
|
|
561
|
+
endDate: string;
|
|
562
|
+
modelId: number;
|
|
563
|
+
profileId: string;
|
|
564
|
+
serviceId: string;
|
|
565
|
+
userId?: string;
|
|
566
|
+
vehicleId?: string;
|
|
567
|
+
station?: string;
|
|
568
|
+
latitude?: number;
|
|
569
|
+
longitude?: number;
|
|
570
|
+
radius?: number;
|
|
571
|
+
email?: string;
|
|
572
|
+
notes?: string;
|
|
573
|
+
plannedReturnDate?: string;
|
|
574
|
+
deliveryAddress?: string;
|
|
575
|
+
deliveryAddressAdditionalInfo?: string;
|
|
576
|
+
deliveryCity?: string;
|
|
577
|
+
deliveryPostalCode?: string;
|
|
578
|
+
dropOffStation?: string;
|
|
579
|
+
rollingContract?: boolean;
|
|
580
|
+
planDurationInMonths?: number;
|
|
581
|
+
planName?: string;
|
|
582
|
+
parentId?: string;
|
|
583
|
+
contractType?: 'SVS' | 'MVS';
|
|
584
|
+
productIds?: string[];
|
|
585
|
+
preallocatedVehicleId?: string;
|
|
586
|
+
bookingReferenceId?: string;
|
|
587
|
+
providedPricingId?: string;
|
|
588
|
+
preferredPaymentMethods?: {
|
|
589
|
+
pspReference: string;
|
|
590
|
+
amount: number;
|
|
591
|
+
}[];
|
|
592
|
+
requiresActionReturnURL?: string;
|
|
593
|
+
cityId?: string;
|
|
594
|
+
};
|
|
595
|
+
type CreateBookingRequestOptions = {
|
|
596
|
+
/** When false, bypass the user status check (operator use). Default true server-side. */userStatusCheckRequired?: boolean;
|
|
597
|
+
};
|
|
598
|
+
/**
|
|
599
|
+
* Create a new booking request.
|
|
600
|
+
*
|
|
601
|
+
* Swagger: `POST /scheduledBooking/fleets/{fleetId}/bookingrequests` (admin-booking).
|
|
602
|
+
*/
|
|
603
|
+
declare const createBookingRequest: (client: Client, body: CreateBookingRequestBody, options?: CreateBookingRequestOptions) => Promise<BookingRequest>;
|
|
604
|
+
//#endregion
|
|
605
|
+
//#region src/getAvailableModels.d.ts
|
|
606
|
+
declare const getAvailableModelsSchema: z.ZodObject<{
|
|
607
|
+
startDate: z.ZodString;
|
|
608
|
+
endDate: z.ZodString;
|
|
609
|
+
cityId: z.ZodOptional<z.ZodString>;
|
|
610
|
+
userId: z.ZodOptional<z.ZodString>;
|
|
611
|
+
profileId: z.ZodOptional<z.ZodString>;
|
|
612
|
+
oneWayTrip: z.ZodOptional<z.ZodBoolean>;
|
|
613
|
+
showUnavailableModels: z.ZodOptional<z.ZodBoolean>;
|
|
614
|
+
}, z.core.$strip>;
|
|
615
|
+
type GetAvailableModelsParams = z.infer<typeof getAvailableModelsSchema>;
|
|
616
|
+
/**
|
|
617
|
+
* Get available models grouped by station in a given time range.
|
|
618
|
+
*
|
|
619
|
+
* Swagger: `GET /scheduledBooking/fleets/{fleetId}/stations/models` (admin-booking / internal).
|
|
620
|
+
*/
|
|
621
|
+
declare const getAvailableModels: (client: Client, params: GetAvailableModelsParams) => Promise<StationWithAvailableModels[]>;
|
|
622
|
+
//#endregion
|
|
623
|
+
//#region src/getStationUnavailability.d.ts
|
|
624
|
+
declare const getStationUnavailabilitySchema: z.ZodObject<{
|
|
625
|
+
stationId: z.ZodString;
|
|
626
|
+
from: z.ZodString;
|
|
627
|
+
to: z.ZodString;
|
|
628
|
+
serviceId: z.ZodString;
|
|
629
|
+
}, z.core.$strip>;
|
|
630
|
+
type GetStationUnavailabilityParams = z.infer<typeof getStationUnavailabilitySchema>;
|
|
631
|
+
/**
|
|
632
|
+
* Get the list of vehicle unavailabilities for a given station over a period.
|
|
633
|
+
*
|
|
634
|
+
* Swagger: `GET /fleets/{fleetId}/stations/{stationId}/unavailability` (admin-booking,
|
|
635
|
+
* operationId `getVehicleCalendarForPeriod`).
|
|
636
|
+
*/
|
|
637
|
+
declare const getStationUnavailability: (client: Client, params: GetStationUnavailabilityParams) => Promise<StationVehicleCalendar>;
|
|
638
|
+
//#endregion
|
|
639
|
+
export { AdditionalDriver, AvailableModel, AvailableVehiclesResponse, BRPaymentItem, BaseBookingRequest, BookingCredit, BookingRequest, type BookingRequestFilters, BookingRequestSlave, type BookingRequestStatus, Contract, type CreateBookingRequestBody, type CreateBookingRequestOptions, type CreateSubscriptionBody, CustomPrice, DayOpeningHours, Days, EstimatedProduct, GeoInfo, type GetAvailableModelsParams, type GetStationUnavailabilityParams, IFormatSlave, IFormatSubscription, type Include, type IncludeStation, Master, MileageAllowance, OpeningHours, PaymentReceipts, PreferredPaymentMethod, PriceBreakdown, PricingInfo, SATBookingRequest, type SATBookingRequestStatus, Service, ServiceInfo, type ServiceType, Slave, Station, StationVehicleCalendar, StationWithAvailableModels, Timetable, TriggerBRPaymentResponse, Vehicle, VehicleUnavailability, allocateVehicle, cancelBookingRequest, createBookingRequest, createSubscription, deallocateVehicle, getAdditionalDrivers, getAvailableModels, getAvailableVehicles, getBookingRequestById, getBookingRequestByTrip, getBookingRequests, getBookingRequestsByUserId, getDigitalContracts, getSATBookingRequests, getScheduleBookingRequests, getScheduledBookingById, getSlaves, getStationById, getStationUnavailability, getStations, getSubscriptionBookingRequestById, getSubscriptionBookingRequests, getSubscriptionsByUserId, releaseBRPayment, submitCancellationRequest, triggerBRPayment, updateScheduleBooking };
|
package/dist/index.mjs
CHANGED
|
@@ -156,10 +156,10 @@ const getScheduledBookingById = async (client, bookingId) => {
|
|
|
156
156
|
//#endregion
|
|
157
157
|
//#region src/getAvailableVehicles.ts
|
|
158
158
|
/** ISO date-time without milliseconds (e.g. 2025-02-10T12:00:00Z or 2025-02-10T12:00:00+01:00). */
|
|
159
|
-
const isoDateTimeNoMs = z.string().trim().datetime({ precision: 0 });
|
|
159
|
+
const isoDateTimeNoMs$2 = z.string().trim().datetime({ precision: 0 });
|
|
160
160
|
const getAvailableVehiclesSchema = z.object({
|
|
161
161
|
stationId: z.string().trim().min(1),
|
|
162
|
-
startDate: isoDateTimeNoMs
|
|
162
|
+
startDate: isoDateTimeNoMs$2
|
|
163
163
|
});
|
|
164
164
|
const getAvailableVehicles = async (client, stationId, startDate) => {
|
|
165
165
|
const result = getAvailableVehiclesSchema.safeParse({
|
|
@@ -525,4 +525,108 @@ const createSubscription = async (client, body) => {
|
|
|
525
525
|
return client.post(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/subscription/bookingrequests`, result.data).then(({ data }) => data);
|
|
526
526
|
};
|
|
527
527
|
//#endregion
|
|
528
|
-
|
|
528
|
+
//#region src/createBookingRequest.ts
|
|
529
|
+
const createBookingRequestBodySchema = z.object({
|
|
530
|
+
startDate: z.string().trim().min(1),
|
|
531
|
+
endDate: z.string().trim().min(1),
|
|
532
|
+
modelId: z.number().int().positive(),
|
|
533
|
+
profileId: z.string().trim().min(1).uuid(),
|
|
534
|
+
serviceId: z.string().trim().min(1).uuid(),
|
|
535
|
+
userId: z.string().uuid().optional(),
|
|
536
|
+
vehicleId: z.string().uuid().optional(),
|
|
537
|
+
station: z.string().optional(),
|
|
538
|
+
latitude: z.number().optional(),
|
|
539
|
+
longitude: z.number().optional(),
|
|
540
|
+
radius: z.number().int().optional(),
|
|
541
|
+
email: z.string().email().optional(),
|
|
542
|
+
notes: z.string().optional(),
|
|
543
|
+
plannedReturnDate: z.string().optional(),
|
|
544
|
+
deliveryAddress: z.string().optional(),
|
|
545
|
+
deliveryAddressAdditionalInfo: z.string().optional(),
|
|
546
|
+
deliveryCity: z.string().optional(),
|
|
547
|
+
deliveryPostalCode: z.string().optional(),
|
|
548
|
+
dropOffStation: z.string().optional(),
|
|
549
|
+
rollingContract: z.boolean().optional(),
|
|
550
|
+
planDurationInMonths: z.number().int().optional(),
|
|
551
|
+
planName: z.string().optional(),
|
|
552
|
+
parentId: z.string().optional(),
|
|
553
|
+
contractType: z.enum(["SVS", "MVS"]).optional(),
|
|
554
|
+
productIds: z.array(z.string()).optional(),
|
|
555
|
+
preallocatedVehicleId: z.string().optional(),
|
|
556
|
+
bookingReferenceId: z.string().optional(),
|
|
557
|
+
providedPricingId: z.string().uuid().optional(),
|
|
558
|
+
preferredPaymentMethods: z.array(z.object({
|
|
559
|
+
pspReference: z.string(),
|
|
560
|
+
amount: z.number()
|
|
561
|
+
})).optional(),
|
|
562
|
+
requiresActionReturnURL: z.string().optional(),
|
|
563
|
+
cityId: z.string().optional()
|
|
564
|
+
});
|
|
565
|
+
/**
|
|
566
|
+
* Create a new booking request.
|
|
567
|
+
*
|
|
568
|
+
* Swagger: `POST /scheduledBooking/fleets/{fleetId}/bookingrequests` (admin-booking).
|
|
569
|
+
*/
|
|
570
|
+
const createBookingRequest = async (client, body, options = {}) => {
|
|
571
|
+
const result = createBookingRequestBodySchema.safeParse(body);
|
|
572
|
+
if (!result.success) throw new TypeError("Invalid args", { cause: result.error.issues });
|
|
573
|
+
const query = options.userStatusCheckRequired !== void 0 ? `?userStatusCheckRequired=${options.userStatusCheckRequired}` : "";
|
|
574
|
+
return client.post(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/bookingrequests${query}`, {
|
|
575
|
+
...result.data,
|
|
576
|
+
fleetId: client.clientOptions.fleetId
|
|
577
|
+
}).then(({ data }) => data);
|
|
578
|
+
};
|
|
579
|
+
//#endregion
|
|
580
|
+
//#region src/getAvailableModels.ts
|
|
581
|
+
/** ISO date-time without milliseconds (e.g. 2020-09-20T00:00:00Z or 2020-09-20T00:00:00+01:00). */
|
|
582
|
+
const isoDateTimeNoMs$1 = z.string().trim().datetime({ precision: 0 });
|
|
583
|
+
const getAvailableModelsSchema = z.object({
|
|
584
|
+
startDate: isoDateTimeNoMs$1,
|
|
585
|
+
endDate: isoDateTimeNoMs$1,
|
|
586
|
+
cityId: z.string().trim().min(1).optional(),
|
|
587
|
+
userId: z.string().uuid().optional(),
|
|
588
|
+
profileId: z.string().uuid().optional(),
|
|
589
|
+
oneWayTrip: z.boolean().optional(),
|
|
590
|
+
showUnavailableModels: z.boolean().optional()
|
|
591
|
+
});
|
|
592
|
+
/**
|
|
593
|
+
* Get available models grouped by station in a given time range.
|
|
594
|
+
*
|
|
595
|
+
* Swagger: `GET /scheduledBooking/fleets/{fleetId}/stations/models` (admin-booking / internal).
|
|
596
|
+
*/
|
|
597
|
+
const getAvailableModels = async (client, params) => {
|
|
598
|
+
const result = getAvailableModelsSchema.safeParse(params);
|
|
599
|
+
if (!result.success) throw new TypeError("Invalid args", { cause: result.error.issues });
|
|
600
|
+
const searchParams = new URLSearchParams();
|
|
601
|
+
for (const [key, value] of Object.entries(result.data)) if (value !== void 0) searchParams.append(key, String(value));
|
|
602
|
+
return client.get(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/stations/models?${searchParams.toString()}`).then(({ data }) => data);
|
|
603
|
+
};
|
|
604
|
+
//#endregion
|
|
605
|
+
//#region src/getStationUnavailability.ts
|
|
606
|
+
/** ISO date-time without milliseconds (e.g. 2021-01-01T00:00:00Z). */
|
|
607
|
+
const isoDateTimeNoMs = z.string().trim().datetime({ precision: 0 });
|
|
608
|
+
const getStationUnavailabilitySchema = z.object({
|
|
609
|
+
stationId: z.string().uuid(),
|
|
610
|
+
from: isoDateTimeNoMs,
|
|
611
|
+
to: isoDateTimeNoMs,
|
|
612
|
+
serviceId: z.string().uuid()
|
|
613
|
+
});
|
|
614
|
+
/**
|
|
615
|
+
* Get the list of vehicle unavailabilities for a given station over a period.
|
|
616
|
+
*
|
|
617
|
+
* Swagger: `GET /fleets/{fleetId}/stations/{stationId}/unavailability` (admin-booking,
|
|
618
|
+
* operationId `getVehicleCalendarForPeriod`).
|
|
619
|
+
*/
|
|
620
|
+
const getStationUnavailability = async (client, params) => {
|
|
621
|
+
const result = getStationUnavailabilitySchema.safeParse(params);
|
|
622
|
+
if (!result.success) throw new TypeError("Invalid args", { cause: result.error.issues });
|
|
623
|
+
const { stationId, from, to, serviceId } = result.data;
|
|
624
|
+
const searchParams = new URLSearchParams({
|
|
625
|
+
from,
|
|
626
|
+
to,
|
|
627
|
+
serviceId
|
|
628
|
+
});
|
|
629
|
+
return client.get(`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/stations/${stationId}/unavailability?${searchParams.toString()}`).then(({ data }) => data);
|
|
630
|
+
};
|
|
631
|
+
//#endregion
|
|
632
|
+
export { allocateVehicle, cancelBookingRequest, createBookingRequest, createSubscription, deallocateVehicle, getAdditionalDrivers, getAvailableModels, getAvailableVehicles, getBookingRequestById, getBookingRequestByTrip, getBookingRequests, getBookingRequestsByUserId, getDigitalContracts, getSATBookingRequests, getScheduleBookingRequests, getScheduledBookingById, getSlaves, getStationById, getStationUnavailability, getStations, getSubscriptionBookingRequestById, getSubscriptionBookingRequests, getSubscriptionsByUserId, releaseBRPayment, submitCancellationRequest, triggerBRPayment, updateScheduleBooking };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vulog/aima-booking",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.43",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.cts",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"author": "Vulog",
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@vulog/aima-client": "1.2.
|
|
36
|
-
"@vulog/aima-core": "1.2.
|
|
35
|
+
"@vulog/aima-client": "1.2.43",
|
|
36
|
+
"@vulog/aima-core": "1.2.43"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"es-toolkit": "^1.45.1",
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, test, vi, expect, beforeEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { Client } from '@vulog/aima-client';
|
|
4
|
+
|
|
5
|
+
import { createBookingRequest, CreateBookingRequestBody } from './createBookingRequest';
|
|
6
|
+
|
|
7
|
+
describe('createBookingRequest', () => {
|
|
8
|
+
const postMock = vi.fn();
|
|
9
|
+
const client = {
|
|
10
|
+
post: postMock,
|
|
11
|
+
clientOptions: {
|
|
12
|
+
fleetId: 'VULOG-FRPAR',
|
|
13
|
+
},
|
|
14
|
+
} as unknown as Client;
|
|
15
|
+
|
|
16
|
+
const validBody: CreateBookingRequestBody = {
|
|
17
|
+
startDate: '2026-06-01T10:00:00Z',
|
|
18
|
+
endDate: '2026-06-05T10:00:00Z',
|
|
19
|
+
modelId: 141411,
|
|
20
|
+
profileId: '9f0fd479-28a9-4754-9c77-611ea48bfb8f',
|
|
21
|
+
serviceId: '9ed7d9d4-8c64-43ef-bb3d-e2b271fed682',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
vi.clearAllMocks();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('should throw on invalid args (missing required fields)', async () => {
|
|
29
|
+
const badBody = { startDate: '2026-06-01T10:00:00Z' } as unknown as CreateBookingRequestBody;
|
|
30
|
+
await expect(createBookingRequest(client, badBody)).rejects.toThrow('Invalid args');
|
|
31
|
+
expect(postMock).not.toHaveBeenCalled();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should throw on invalid UUID profileId', async () => {
|
|
35
|
+
await expect(
|
|
36
|
+
createBookingRequest(client, { ...validBody, profileId: 'not-a-uuid' })
|
|
37
|
+
).rejects.toThrow('Invalid args');
|
|
38
|
+
expect(postMock).not.toHaveBeenCalled();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('should post body with fleetId injected and return booking request', async () => {
|
|
42
|
+
const responseBody = {
|
|
43
|
+
id: '0b528336-2624-42ae-8640-59fb663e17f4',
|
|
44
|
+
fleetId: 'VULOG-FRPAR',
|
|
45
|
+
status: 'PENDING',
|
|
46
|
+
};
|
|
47
|
+
postMock.mockResolvedValueOnce({ data: responseBody });
|
|
48
|
+
|
|
49
|
+
const result = await createBookingRequest(client, validBody);
|
|
50
|
+
|
|
51
|
+
expect(postMock).toHaveBeenCalledWith(
|
|
52
|
+
'/boapi/proxy/user/scheduledBooking/fleets/VULOG-FRPAR/bookingrequests',
|
|
53
|
+
{ ...validBody, fleetId: 'VULOG-FRPAR' }
|
|
54
|
+
);
|
|
55
|
+
expect(result).toEqual(responseBody);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('should append userStatusCheckRequired query param when provided', async () => {
|
|
59
|
+
postMock.mockResolvedValueOnce({ data: {} });
|
|
60
|
+
|
|
61
|
+
await createBookingRequest(client, validBody, { userStatusCheckRequired: false });
|
|
62
|
+
|
|
63
|
+
expect(postMock).toHaveBeenCalledWith(
|
|
64
|
+
'/boapi/proxy/user/scheduledBooking/fleets/VULOG-FRPAR/bookingrequests?userStatusCheckRequired=false',
|
|
65
|
+
{ ...validBody, fleetId: 'VULOG-FRPAR' }
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('should propagate client errors', async () => {
|
|
70
|
+
postMock.mockRejectedValueOnce(new Error('network down'));
|
|
71
|
+
await expect(createBookingRequest(client, validBody)).rejects.toThrow('network down');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { BookingRequest } from './types';
|
|
5
|
+
|
|
6
|
+
export type CreateBookingRequestBody = {
|
|
7
|
+
// Required fields (per Swagger BookingRequestDTO)
|
|
8
|
+
startDate: string;
|
|
9
|
+
endDate: string;
|
|
10
|
+
modelId: number;
|
|
11
|
+
profileId: string;
|
|
12
|
+
serviceId: string;
|
|
13
|
+
|
|
14
|
+
// Optional fields
|
|
15
|
+
userId?: string;
|
|
16
|
+
vehicleId?: string;
|
|
17
|
+
station?: string;
|
|
18
|
+
latitude?: number;
|
|
19
|
+
longitude?: number;
|
|
20
|
+
radius?: number;
|
|
21
|
+
email?: string;
|
|
22
|
+
notes?: string;
|
|
23
|
+
plannedReturnDate?: string;
|
|
24
|
+
deliveryAddress?: string;
|
|
25
|
+
deliveryAddressAdditionalInfo?: string;
|
|
26
|
+
deliveryCity?: string;
|
|
27
|
+
deliveryPostalCode?: string;
|
|
28
|
+
dropOffStation?: string;
|
|
29
|
+
rollingContract?: boolean;
|
|
30
|
+
planDurationInMonths?: number;
|
|
31
|
+
planName?: string;
|
|
32
|
+
parentId?: string;
|
|
33
|
+
contractType?: 'SVS' | 'MVS';
|
|
34
|
+
productIds?: string[];
|
|
35
|
+
preallocatedVehicleId?: string;
|
|
36
|
+
bookingReferenceId?: string;
|
|
37
|
+
providedPricingId?: string;
|
|
38
|
+
preferredPaymentMethods?: { pspReference: string; amount: number }[];
|
|
39
|
+
requiresActionReturnURL?: string;
|
|
40
|
+
cityId?: string;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type CreateBookingRequestOptions = {
|
|
44
|
+
/** When false, bypass the user status check (operator use). Default true server-side. */
|
|
45
|
+
userStatusCheckRequired?: boolean;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const createBookingRequestBodySchema = z.object({
|
|
49
|
+
startDate: z.string().trim().min(1),
|
|
50
|
+
endDate: z.string().trim().min(1),
|
|
51
|
+
modelId: z.number().int().positive(),
|
|
52
|
+
profileId: z.string().trim().min(1).uuid(),
|
|
53
|
+
serviceId: z.string().trim().min(1).uuid(),
|
|
54
|
+
|
|
55
|
+
userId: z.string().uuid().optional(),
|
|
56
|
+
vehicleId: z.string().uuid().optional(),
|
|
57
|
+
station: z.string().optional(),
|
|
58
|
+
latitude: z.number().optional(),
|
|
59
|
+
longitude: z.number().optional(),
|
|
60
|
+
radius: z.number().int().optional(),
|
|
61
|
+
email: z.string().email().optional(),
|
|
62
|
+
notes: z.string().optional(),
|
|
63
|
+
plannedReturnDate: z.string().optional(),
|
|
64
|
+
deliveryAddress: z.string().optional(),
|
|
65
|
+
deliveryAddressAdditionalInfo: z.string().optional(),
|
|
66
|
+
deliveryCity: z.string().optional(),
|
|
67
|
+
deliveryPostalCode: z.string().optional(),
|
|
68
|
+
dropOffStation: z.string().optional(),
|
|
69
|
+
rollingContract: z.boolean().optional(),
|
|
70
|
+
planDurationInMonths: z.number().int().optional(),
|
|
71
|
+
planName: z.string().optional(),
|
|
72
|
+
parentId: z.string().optional(),
|
|
73
|
+
contractType: z.enum(['SVS', 'MVS']).optional(),
|
|
74
|
+
productIds: z.array(z.string()).optional(),
|
|
75
|
+
preallocatedVehicleId: z.string().optional(),
|
|
76
|
+
bookingReferenceId: z.string().optional(),
|
|
77
|
+
providedPricingId: z.string().uuid().optional(),
|
|
78
|
+
preferredPaymentMethods: z
|
|
79
|
+
.array(
|
|
80
|
+
z.object({
|
|
81
|
+
pspReference: z.string(),
|
|
82
|
+
amount: z.number(),
|
|
83
|
+
})
|
|
84
|
+
)
|
|
85
|
+
.optional(),
|
|
86
|
+
requiresActionReturnURL: z.string().optional(),
|
|
87
|
+
cityId: z.string().optional(),
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Create a new booking request.
|
|
92
|
+
*
|
|
93
|
+
* Swagger: `POST /scheduledBooking/fleets/{fleetId}/bookingrequests` (admin-booking).
|
|
94
|
+
*/
|
|
95
|
+
export const createBookingRequest = async (
|
|
96
|
+
client: Client,
|
|
97
|
+
body: CreateBookingRequestBody,
|
|
98
|
+
options: CreateBookingRequestOptions = {}
|
|
99
|
+
): Promise<BookingRequest> => {
|
|
100
|
+
const result = createBookingRequestBodySchema.safeParse(body);
|
|
101
|
+
if (!result.success) {
|
|
102
|
+
throw new TypeError('Invalid args', { cause: result.error.issues });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const query =
|
|
106
|
+
options.userStatusCheckRequired !== undefined
|
|
107
|
+
? `?userStatusCheckRequired=${options.userStatusCheckRequired}`
|
|
108
|
+
: '';
|
|
109
|
+
|
|
110
|
+
return client
|
|
111
|
+
.post<BookingRequest>(
|
|
112
|
+
`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/bookingrequests${query}`,
|
|
113
|
+
{ ...result.data, fleetId: client.clientOptions.fleetId }
|
|
114
|
+
)
|
|
115
|
+
.then(({ data }) => data);
|
|
116
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, test, vi, expect, beforeEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { Client } from '@vulog/aima-client';
|
|
4
|
+
|
|
5
|
+
import { getAvailableModels } from './getAvailableModels';
|
|
6
|
+
import { StationWithAvailableModels } from './types';
|
|
7
|
+
|
|
8
|
+
describe('getAvailableModels', () => {
|
|
9
|
+
const getMock = vi.fn();
|
|
10
|
+
const client = {
|
|
11
|
+
get: getMock,
|
|
12
|
+
clientOptions: {
|
|
13
|
+
fleetId: 'VULOG-FRPAR',
|
|
14
|
+
},
|
|
15
|
+
} as unknown as Client;
|
|
16
|
+
|
|
17
|
+
const validParams = {
|
|
18
|
+
startDate: '2026-06-01T00:00:00Z',
|
|
19
|
+
endDate: '2026-06-05T00:00:00Z',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
vi.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('should throw on missing required dates', async () => {
|
|
27
|
+
await expect(
|
|
28
|
+
getAvailableModels(client, { startDate: '2026-06-01T00:00:00Z' } as never)
|
|
29
|
+
).rejects.toThrow('Invalid args');
|
|
30
|
+
expect(getMock).not.toHaveBeenCalled();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('should throw on invalid ISO datetime', async () => {
|
|
34
|
+
await expect(
|
|
35
|
+
getAvailableModels(client, { startDate: 'not-a-date', endDate: validParams.endDate })
|
|
36
|
+
).rejects.toThrow('Invalid args');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('should throw on invalid userId UUID', async () => {
|
|
40
|
+
await expect(
|
|
41
|
+
getAvailableModels(client, { ...validParams, userId: 'not-a-uuid' })
|
|
42
|
+
).rejects.toThrow('Invalid args');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('should call endpoint with required query params and return stations', async () => {
|
|
46
|
+
const mockResponse: StationWithAvailableModels[] = [
|
|
47
|
+
{
|
|
48
|
+
id: 'd63bd962-e846-11ea-adc1-0242ac120002',
|
|
49
|
+
zoneId: 'f99e9a545059439c99eb81a8a8a88f93',
|
|
50
|
+
poiId: 'd2760ed840654f25b2beeb0fc52b6cf7',
|
|
51
|
+
models: [{ id: 141411, price: '120.00', prePaymentPrice: 30 }],
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
getMock.mockResolvedValueOnce({ data: mockResponse });
|
|
55
|
+
|
|
56
|
+
const result = await getAvailableModels(client, validParams);
|
|
57
|
+
|
|
58
|
+
expect(getMock).toHaveBeenCalledWith(
|
|
59
|
+
'/boapi/proxy/user/scheduledBooking/fleets/VULOG-FRPAR/stations/models?startDate=2026-06-01T00%3A00%3A00Z&endDate=2026-06-05T00%3A00%3A00Z'
|
|
60
|
+
);
|
|
61
|
+
expect(result).toEqual(mockResponse);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('should include all optional query params when provided', async () => {
|
|
65
|
+
getMock.mockResolvedValueOnce({ data: [] });
|
|
66
|
+
|
|
67
|
+
await getAvailableModels(client, {
|
|
68
|
+
...validParams,
|
|
69
|
+
cityId: 'PARIS',
|
|
70
|
+
userId: '9f0fd479-28a9-4754-9c77-611ea48bfb8f',
|
|
71
|
+
profileId: '245cb038-0bcd-415f-a3ce-d0a5b2fdb730',
|
|
72
|
+
oneWayTrip: true,
|
|
73
|
+
showUnavailableModels: false,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const url = getMock.mock.calls[0][0] as string;
|
|
77
|
+
expect(url).toContain('cityId=PARIS');
|
|
78
|
+
expect(url).toContain('userId=9f0fd479-28a9-4754-9c77-611ea48bfb8f');
|
|
79
|
+
expect(url).toContain('profileId=245cb038-0bcd-415f-a3ce-d0a5b2fdb730');
|
|
80
|
+
expect(url).toContain('oneWayTrip=true');
|
|
81
|
+
expect(url).toContain('showUnavailableModels=false');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('should propagate client errors', async () => {
|
|
85
|
+
getMock.mockRejectedValueOnce(new Error('network down'));
|
|
86
|
+
await expect(getAvailableModels(client, validParams)).rejects.toThrow('network down');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { StationWithAvailableModels } from './types';
|
|
5
|
+
|
|
6
|
+
/** ISO date-time without milliseconds (e.g. 2020-09-20T00:00:00Z or 2020-09-20T00:00:00+01:00). */
|
|
7
|
+
const isoDateTimeNoMs = z.string().trim().datetime({ precision: 0 });
|
|
8
|
+
|
|
9
|
+
const getAvailableModelsSchema = z.object({
|
|
10
|
+
startDate: isoDateTimeNoMs,
|
|
11
|
+
endDate: isoDateTimeNoMs,
|
|
12
|
+
cityId: z.string().trim().min(1).optional(),
|
|
13
|
+
userId: z.string().uuid().optional(),
|
|
14
|
+
profileId: z.string().uuid().optional(),
|
|
15
|
+
oneWayTrip: z.boolean().optional(),
|
|
16
|
+
showUnavailableModels: z.boolean().optional(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export type GetAvailableModelsParams = z.infer<typeof getAvailableModelsSchema>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get available models grouped by station in a given time range.
|
|
23
|
+
*
|
|
24
|
+
* Swagger: `GET /scheduledBooking/fleets/{fleetId}/stations/models` (admin-booking / internal).
|
|
25
|
+
*/
|
|
26
|
+
export const getAvailableModels = async (
|
|
27
|
+
client: Client,
|
|
28
|
+
params: GetAvailableModelsParams
|
|
29
|
+
): Promise<StationWithAvailableModels[]> => {
|
|
30
|
+
const result = getAvailableModelsSchema.safeParse(params);
|
|
31
|
+
if (!result.success) {
|
|
32
|
+
throw new TypeError('Invalid args', { cause: result.error.issues });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const searchParams = new URLSearchParams();
|
|
36
|
+
for (const [key, value] of Object.entries(result.data)) {
|
|
37
|
+
if (value !== undefined) {
|
|
38
|
+
searchParams.append(key, String(value));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return client
|
|
43
|
+
.get<
|
|
44
|
+
StationWithAvailableModels[]
|
|
45
|
+
>(`/boapi/proxy/user/scheduledBooking/fleets/${client.clientOptions.fleetId}/stations/models?${searchParams.toString()}`)
|
|
46
|
+
.then(({ data }) => data);
|
|
47
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { describe, test, vi, expect, beforeEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { Client } from '@vulog/aima-client';
|
|
4
|
+
|
|
5
|
+
import { getStationUnavailability } from './getStationUnavailability';
|
|
6
|
+
import { StationVehicleCalendar } from './types';
|
|
7
|
+
|
|
8
|
+
describe('getStationUnavailability', () => {
|
|
9
|
+
const getMock = vi.fn();
|
|
10
|
+
const client = {
|
|
11
|
+
get: getMock,
|
|
12
|
+
clientOptions: {
|
|
13
|
+
fleetId: 'VULOG-FRPAR',
|
|
14
|
+
},
|
|
15
|
+
} as unknown as Client;
|
|
16
|
+
|
|
17
|
+
const validParams = {
|
|
18
|
+
stationId: '57e64770-72c8-4256-b3f2-931242fa7d61',
|
|
19
|
+
from: '2026-01-01T00:00:00Z',
|
|
20
|
+
to: '2026-02-01T00:00:00Z',
|
|
21
|
+
serviceId: '14946b6e-caac-4608-ab92-6068cc7363cf',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
vi.clearAllMocks();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('should throw on invalid stationId UUID', async () => {
|
|
29
|
+
await expect(
|
|
30
|
+
getStationUnavailability(client, { ...validParams, stationId: 'not-a-uuid' })
|
|
31
|
+
).rejects.toThrow('Invalid args');
|
|
32
|
+
expect(getMock).not.toHaveBeenCalled();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('should throw on invalid serviceId UUID', async () => {
|
|
36
|
+
await expect(
|
|
37
|
+
getStationUnavailability(client, { ...validParams, serviceId: 'not-a-uuid' })
|
|
38
|
+
).rejects.toThrow('Invalid args');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('should throw on invalid ISO date', async () => {
|
|
42
|
+
await expect(
|
|
43
|
+
getStationUnavailability(client, { ...validParams, from: 'not-a-date' })
|
|
44
|
+
).rejects.toThrow('Invalid args');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('should call endpoint with required query params and return calendar', async () => {
|
|
48
|
+
const mockResponse: StationVehicleCalendar = {
|
|
49
|
+
timezone: 'Europe/Paris',
|
|
50
|
+
from: validParams.from,
|
|
51
|
+
to: validParams.to,
|
|
52
|
+
vehicleIds: ['veh-1', 'veh-2'],
|
|
53
|
+
unavailabilities: [
|
|
54
|
+
{
|
|
55
|
+
id: 'u-1',
|
|
56
|
+
vehicleId: 'veh-1',
|
|
57
|
+
modelId: 141411,
|
|
58
|
+
from: '2026-01-10T08:00:00Z',
|
|
59
|
+
to: '2026-01-12T18:00:00Z',
|
|
60
|
+
type: 'BOOKING',
|
|
61
|
+
serviceId: validParams.serviceId,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
getMock.mockResolvedValueOnce({ data: mockResponse });
|
|
66
|
+
|
|
67
|
+
const result = await getStationUnavailability(client, validParams);
|
|
68
|
+
|
|
69
|
+
expect(getMock).toHaveBeenCalledWith(
|
|
70
|
+
`/boapi/proxy/user/fleets/VULOG-FRPAR/stations/${validParams.stationId}/unavailability?from=2026-01-01T00%3A00%3A00Z&to=2026-02-01T00%3A00%3A00Z&serviceId=${validParams.serviceId}`
|
|
71
|
+
);
|
|
72
|
+
expect(result).toEqual(mockResponse);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('should propagate client errors', async () => {
|
|
76
|
+
getMock.mockRejectedValueOnce(new Error('network down'));
|
|
77
|
+
await expect(getStationUnavailability(client, validParams)).rejects.toThrow('network down');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { StationVehicleCalendar } from './types';
|
|
5
|
+
|
|
6
|
+
/** ISO date-time without milliseconds (e.g. 2021-01-01T00:00:00Z). */
|
|
7
|
+
const isoDateTimeNoMs = z.string().trim().datetime({ precision: 0 });
|
|
8
|
+
|
|
9
|
+
const getStationUnavailabilitySchema = z.object({
|
|
10
|
+
stationId: z.string().uuid(),
|
|
11
|
+
from: isoDateTimeNoMs,
|
|
12
|
+
to: isoDateTimeNoMs,
|
|
13
|
+
serviceId: z.string().uuid(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export type GetStationUnavailabilityParams = z.infer<typeof getStationUnavailabilitySchema>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get the list of vehicle unavailabilities for a given station over a period.
|
|
20
|
+
*
|
|
21
|
+
* Swagger: `GET /fleets/{fleetId}/stations/{stationId}/unavailability` (admin-booking,
|
|
22
|
+
* operationId `getVehicleCalendarForPeriod`).
|
|
23
|
+
*/
|
|
24
|
+
export const getStationUnavailability = async (
|
|
25
|
+
client: Client,
|
|
26
|
+
params: GetStationUnavailabilityParams
|
|
27
|
+
): Promise<StationVehicleCalendar> => {
|
|
28
|
+
const result = getStationUnavailabilitySchema.safeParse(params);
|
|
29
|
+
if (!result.success) {
|
|
30
|
+
throw new TypeError('Invalid args', { cause: result.error.issues });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const { stationId, from, to, serviceId } = result.data;
|
|
34
|
+
const searchParams = new URLSearchParams({ from, to, serviceId });
|
|
35
|
+
|
|
36
|
+
return client
|
|
37
|
+
.get<StationVehicleCalendar>(
|
|
38
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/stations/${stationId}/unavailability?${searchParams.toString()}`
|
|
39
|
+
)
|
|
40
|
+
.then(({ data }) => data);
|
|
41
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -28,3 +28,9 @@ export { getSubscriptionsByUserId } from './getSubscriptionsByUserId';
|
|
|
28
28
|
export { submitCancellationRequest } from './submitCancellationRequest';
|
|
29
29
|
export { createSubscription } from './createSubscription';
|
|
30
30
|
export type { CreateSubscriptionBody } from './createSubscription';
|
|
31
|
+
export { createBookingRequest } from './createBookingRequest';
|
|
32
|
+
export type { CreateBookingRequestBody, CreateBookingRequestOptions } from './createBookingRequest';
|
|
33
|
+
export { getAvailableModels } from './getAvailableModels';
|
|
34
|
+
export type { GetAvailableModelsParams } from './getAvailableModels';
|
|
35
|
+
export { getStationUnavailability } from './getStationUnavailability';
|
|
36
|
+
export type { GetStationUnavailabilityParams } from './getStationUnavailability';
|
package/src/types.ts
CHANGED
|
@@ -342,3 +342,76 @@ export type BookingRequestSlave = {
|
|
|
342
342
|
traveledDistance: number;
|
|
343
343
|
energyLevelEnd: number;
|
|
344
344
|
};
|
|
345
|
+
|
|
346
|
+
/** Mileage allowance for an available model (Swagger: `MileageAllowanceDTO`). */
|
|
347
|
+
export type MileageAllowance = {
|
|
348
|
+
allowancePerDay?: number;
|
|
349
|
+
totalAllowance?: number;
|
|
350
|
+
pricePerExceedingUnit?: number;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
/** Estimated product embedded in a price breakdown (Swagger: `EstimatedProductDTO`). */
|
|
354
|
+
export type EstimatedProduct = {
|
|
355
|
+
productId?: string;
|
|
356
|
+
price?: number;
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
/** Price breakdown for an available model (Swagger: `PriceBreakdownDTO`). */
|
|
360
|
+
export type PriceBreakdown = {
|
|
361
|
+
tripPrice?: number;
|
|
362
|
+
productsPrice?: number;
|
|
363
|
+
productDetails?: EstimatedProduct[];
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
/** Pricing info for an available model (Swagger: `PricingInfo`). */
|
|
367
|
+
export type PricingInfo = {
|
|
368
|
+
pricingId?: string;
|
|
369
|
+
type?: string;
|
|
370
|
+
priceBreakdown?: PriceBreakdown;
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
/** Available model entry returned by `getAvailableModels` (Swagger: `BookingRequestModelDTO`). */
|
|
374
|
+
export type AvailableModel = {
|
|
375
|
+
id: number;
|
|
376
|
+
price?: string;
|
|
377
|
+
prePaymentPrice?: number;
|
|
378
|
+
mileageAllowance?: MileageAllowance;
|
|
379
|
+
pricingInfo?: PricingInfo;
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
/** Station entry returned by `getAvailableModels` (Swagger: `StationDTO`). */
|
|
383
|
+
export type StationWithAvailableModels = {
|
|
384
|
+
id: string;
|
|
385
|
+
zoneId: string;
|
|
386
|
+
poiId: string;
|
|
387
|
+
models: AvailableModel[];
|
|
388
|
+
taxZoneId?: string;
|
|
389
|
+
cityId?: string;
|
|
390
|
+
serviceId?: string;
|
|
391
|
+
fleetId?: string;
|
|
392
|
+
openTime?: string;
|
|
393
|
+
closeTime?: string;
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
/** Single unavailability entry in a station vehicle calendar (Swagger: `UnavailabilityDTO`). */
|
|
397
|
+
export type VehicleUnavailability = {
|
|
398
|
+
id?: string;
|
|
399
|
+
vehicleId?: string;
|
|
400
|
+
modelId?: number;
|
|
401
|
+
from?: string;
|
|
402
|
+
to?: string;
|
|
403
|
+
toWithMargin?: string;
|
|
404
|
+
type?: 'BOOKING' | 'MAINTENANCE';
|
|
405
|
+
userId?: string;
|
|
406
|
+
reason?: string;
|
|
407
|
+
serviceId?: string;
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
/** Vehicle calendar for a station over a period (Swagger: `VehicleCalendarResponseDTO`). */
|
|
411
|
+
export type StationVehicleCalendar = {
|
|
412
|
+
timezone?: string;
|
|
413
|
+
from?: string;
|
|
414
|
+
to?: string;
|
|
415
|
+
vehicleIds?: string[];
|
|
416
|
+
unavailabilities?: VehicleUnavailability[];
|
|
417
|
+
};
|