157 lines
6.3 KiB
TypeScript
157 lines
6.3 KiB
TypeScript
import { EngineModel } from '@seed/engine/EngineModel';
|
|
import { BaseGraphModel } from '@seed/graphql/BaseGraphModel';
|
|
import { newError } from '@seed/helpers/Error';
|
|
import { converDateRangeToDateTime, isTimeSlotInDates, slotToDatesRange } from '@seed/helpers/Utils.dates';
|
|
import { checkIfDatesAreInAvailabilities } from '@seed/helpers/Utils.dates.intervals';
|
|
import { StatusEnum } from '@seed/interfaces/components';
|
|
import { AvailabilityComponent, DateRangeComponent, SlotComponent } from '@seed/interfaces/components.dates';
|
|
import { ApolloContext } from '@seed/interfaces/context';
|
|
import { baseSearchFunction } from '@seed/services/database/DBRequestService';
|
|
import { CheckoutEngineInput } from '@services/module-payments/functions/orders/schemas/order.schema.input';
|
|
import { BookingArgsSchema, BookingNewInputSchema } from '@src/bookings/schemas/bookings.input';
|
|
import { BookingSchema, BookingDBInterfaceSchema } from '@src/bookings/schemas/bookings.schema';
|
|
import { BookingsRessourceEnum } from '@src/__components/components';
|
|
import _ from 'lodash';
|
|
import { concat } from 'lodash';
|
|
import { DateTime } from 'luxon';
|
|
import { DurationTypeEnum } from '../components';
|
|
import BookingModel from './bookings.engine.model';
|
|
|
|
export interface NewOneBookingInterface<T> {
|
|
model: T;
|
|
input: BookingNewInputSchema;
|
|
status: StatusEnum;
|
|
availabilities?: AvailabilityComponent;
|
|
ctx: ApolloContext;
|
|
}
|
|
|
|
export interface SaveOneBookingInterface<T> extends NewOneBookingInterface<T> {
|
|
ressourceModel: BookingsRessourceEnum;
|
|
ressourceId: string;
|
|
rest: {
|
|
capacity: number;
|
|
comments?: string | undefined;
|
|
checkoutInfo?: CheckoutEngineInput | undefined;
|
|
durationType: DurationTypeEnum;
|
|
startToEnd?: DateRangeComponent | undefined;
|
|
slot?: SlotComponent | undefined;
|
|
};
|
|
permissions: any;
|
|
}
|
|
|
|
export class BookingService {
|
|
async getBookings(args: BookingArgsSchema, ctx?: ApolloContext | null): Promise<BookingSchema[]> {
|
|
const insi: any = {
|
|
model: new BookingModel() as any,
|
|
engine: true,
|
|
query: args,
|
|
ctx: ctx,
|
|
};
|
|
|
|
if (args.pagination) insi.pagination = args.pagination;
|
|
else insi.all = true;
|
|
|
|
return baseSearchFunction(insi);
|
|
}
|
|
|
|
async getBookingsToFilter(ressourceType: BookingsRessourceEnum, args: SlotComponent): Promise<string[]> {
|
|
const idsToOmit: string[] = [];
|
|
|
|
const bookings = await this.getBookings({
|
|
dateRange: {
|
|
startDate: DateTime.fromJSDate(args.startDate).startOf('day').toJSDate(),
|
|
endDate: DateTime.fromJSDate(args.endDate).endOf('day').toJSDate(),
|
|
},
|
|
});
|
|
|
|
if (bookings && bookings.length > 0) {
|
|
// Get the booking that are in those specifiq hours
|
|
bookings.forEach((element) => {
|
|
const bookingDates = converDateRangeToDateTime(element.dates);
|
|
if (isTimeSlotInDates(bookingDates, args.startTime || '00:00', args.endTime || '23:59')) {
|
|
const pIndex = _.findIndex(element.paths, { ressourceModel: ressourceType });
|
|
if (pIndex !== -1) idsToOmit.push(element.paths[pIndex].ressourceId);
|
|
}
|
|
});
|
|
}
|
|
|
|
return _.uniq(idsToOmit);
|
|
}
|
|
|
|
async createOneBookingWithEngine<T extends EngineModel<any, any, any>>(data: NewOneBookingInterface<T>): Promise<BookingSchema> {
|
|
const { model, status, ctx, input, availabilities } = data;
|
|
const { ressourceModel, ressourceId, ...rest } = input;
|
|
|
|
const permissions: any = {
|
|
r: [ctx.ctx.user._id, ...model.permissions.r],
|
|
w: [ctx.ctx.user._id, ...model.permissions.w],
|
|
d: [ctx.ctx.user._id, ...model.permissions.d],
|
|
};
|
|
|
|
return await this.saveBooking<T>({ input, ressourceModel, ressourceId, rest, status, model, ctx, permissions, availabilities });
|
|
}
|
|
|
|
async createOneBookingWithModel<T extends BaseGraphModel>(data: NewOneBookingInterface<T>): Promise<BookingSchema> {
|
|
const { model, status, ctx, input, availabilities } = data;
|
|
const { ressourceModel, ressourceId, ...rest } = input;
|
|
|
|
_.remove(model.r, function(n) { return n == "public";})
|
|
_.remove(model.w, function(n) { return n == "public";})
|
|
_.remove(model.d, function(n) { return n == "public";})
|
|
|
|
const permissions: any = {
|
|
r: [ctx.ctx.user._id, ...model.r],
|
|
w: [ctx.ctx.user._id, ...model.w],
|
|
d: [ctx.ctx.user._id, ...model.d],
|
|
};
|
|
|
|
|
|
|
|
return await this.saveBooking<T>({ input, ressourceModel, ressourceId, rest, status, model, ctx, permissions, availabilities });
|
|
}
|
|
|
|
async saveBooking<T extends EngineModel<any, any, any> | BaseGraphModel>(data: SaveOneBookingInterface<T>) {
|
|
const { ressourceModel, ressourceId, rest, status, model, ctx, permissions, input, availabilities } = data;
|
|
|
|
const zone = process.env.TIMEZONE || 'utc';
|
|
|
|
const dates: DateRangeComponent[] = [];
|
|
let ressourceIdsToOmit: string[] = [];
|
|
|
|
// (1) First check, in the bookings already made
|
|
|
|
if (input.durationType == DurationTypeEnum.startToEnd && input.startToEnd) dates.push(input.startToEnd);
|
|
else if (input.durationType == DurationTypeEnum.slot && input.slot) dates.push(...slotToDatesRange(input.slot));
|
|
|
|
if (dates.length == 0) throw newError(7001);
|
|
|
|
// (1) First check, in the availabilities
|
|
if (availabilities) {
|
|
const inAvailability = checkIfDatesAreInAvailabilities(converDateRangeToDateTime(dates, { zone }), availabilities);
|
|
if (!inAvailability) throw newError(7002);
|
|
}
|
|
|
|
// (2) Second check
|
|
// Verify if no overlaps with others
|
|
if (input.slot) ressourceIdsToOmit = await this.getBookingsToFilter(ressourceModel, input.slot);
|
|
// Check if overlap
|
|
if (ressourceIdsToOmit.includes(ressourceId)) throw newError(7000);
|
|
|
|
const newData: BookingDBInterfaceSchema = {
|
|
...rest,
|
|
status,
|
|
dates,
|
|
paths: concat((model as any).getPath()),
|
|
ownerId: ctx.ctx.user._id,
|
|
};
|
|
|
|
return await new BookingModel(newData).saveOne({
|
|
additionnalData: {
|
|
paths: concat((model as any).getPath()),
|
|
permissions,
|
|
},
|
|
ctx,
|
|
});
|
|
}
|
|
}
|