mirror of
https://github.com/tomru/pfadi-bussle.git
synced 2026-03-03 22:47:15 +01:00
It also brings the problem of consolidating bookers over multiple bookings. The amount of data is not justifying having it in an own entity
148 lines
4.0 KiB
TypeScript
148 lines
4.0 KiB
TypeScript
import * as mongoose from 'mongoose'
|
|
import { v4 as uuidv4 } from 'uuid'
|
|
import { dateFormatBackend, getDays, nowInTz } from '../helpers/date'
|
|
|
|
import { Bill } from './bill'
|
|
import { BOOKING_STATUS, VALIDATION_ERRORS } from './enums'
|
|
import { getBookedDays } from './index'
|
|
|
|
export type Booking = {
|
|
uuid: string
|
|
name: string
|
|
email: string
|
|
phone: string
|
|
street: string
|
|
zip: string
|
|
city: string
|
|
bill?: Bill
|
|
startDate: string
|
|
endDate: string
|
|
status?: BOOKING_STATUS
|
|
purpose?: string
|
|
org?: string
|
|
destination?: string
|
|
days?: string[]
|
|
}
|
|
|
|
export type BookingDocument = Booking &
|
|
mongoose.Document &
|
|
mongoose.SchemaTimestampsConfig
|
|
|
|
export type BookingModel = mongoose.Model<BookingDocument> & {
|
|
findBookedDays(uuidsToIngore?: string[]): Promise<string[]>
|
|
}
|
|
|
|
const BookingSchema = new mongoose.Schema<BookingDocument>(
|
|
{
|
|
// need a seperate uuid to be able to target a booking anonimously
|
|
uuid: {
|
|
type: String,
|
|
default: uuidv4,
|
|
index: true,
|
|
},
|
|
name: { type: String, required: true },
|
|
email: { type: String, required: true, minlength: 5 },
|
|
phone: { type: String, required: false },
|
|
street: { type: String, required: true },
|
|
zip: { type: String, required: true },
|
|
city: { type: String, required: true },
|
|
bill: {
|
|
type: mongoose.Schema.Types.ObjectId,
|
|
ref: 'Bill',
|
|
required: false,
|
|
},
|
|
startDate: {
|
|
type: Date,
|
|
required: true,
|
|
get: dateFormatBackend,
|
|
validate: {
|
|
validator: function (v: Date): boolean {
|
|
return v >= nowInTz()
|
|
},
|
|
message: (props: { value: Date }): string =>
|
|
`${props.value} is in the past`,
|
|
},
|
|
},
|
|
endDate: {
|
|
type: Date,
|
|
required: false,
|
|
get: dateFormatBackend,
|
|
validate: {
|
|
validator: function (v: Date): boolean {
|
|
return v >= nowInTz()
|
|
},
|
|
message: (props: { value: Date }): string =>
|
|
`${props.value} is in the past`,
|
|
},
|
|
},
|
|
days: {
|
|
type: [String],
|
|
required: true,
|
|
validate: {
|
|
validator: async function (days: string[]): Promise<boolean> {
|
|
const booking = this as Booking
|
|
const uuid = booking.uuid && [booking.uuid]
|
|
const bookedDays = await getBookedDays(uuid)
|
|
|
|
const doubleBookedDays = days.filter((day: string): boolean =>
|
|
bookedDays.includes(day)
|
|
)
|
|
return doubleBookedDays.length === 0
|
|
},
|
|
message: (props: { value: string[] }): string =>
|
|
`At least one day is of ${props.value.join(',')} is already booked`,
|
|
type: VALIDATION_ERRORS.AT_LEAST_ONE_DAY_BOOKED,
|
|
},
|
|
},
|
|
status: {
|
|
type: String,
|
|
enum: Object.values(BOOKING_STATUS),
|
|
required: true,
|
|
default: 'requested',
|
|
},
|
|
purpose: { type: String, required: false },
|
|
org: { type: String, required: false },
|
|
destination: { type: String, required: false },
|
|
},
|
|
{
|
|
timestamps: true,
|
|
toJSON: { virtuals: true, getters: true },
|
|
toObject: { virtuals: true, getters: true },
|
|
}
|
|
)
|
|
|
|
BookingSchema.pre('validate', function (next: () => void): void {
|
|
const booking = this as BookingDocument
|
|
booking.days = getDays({
|
|
startDate: new Date(booking.startDate),
|
|
endDate: new Date(booking.endDate),
|
|
})
|
|
next()
|
|
})
|
|
|
|
BookingSchema.static('findBookedDays', async function (
|
|
uuidsToIngore: string[] = []
|
|
): Promise<string[]> {
|
|
const model = this as BookingModel
|
|
const now = nowInTz()
|
|
const bookedDays = await model
|
|
.find(
|
|
{
|
|
status: { $in: [BOOKING_STATUS.REQUESTED, BOOKING_STATUS.CONFIRMED] },
|
|
uuid: { $nin: uuidsToIngore },
|
|
// dateFormatBackend uses YYYY-MM-DD, which is startOfDay anyway
|
|
endDate: { $gt: dateFormatBackend(now) },
|
|
},
|
|
'days'
|
|
)
|
|
.exec()
|
|
|
|
return bookedDays
|
|
.map((b) => b.days)
|
|
.flat()
|
|
.sort()
|
|
})
|
|
|
|
export default <BookingModel>mongoose.models.Booking ||
|
|
mongoose.model<BookingDocument, BookingModel>('Booking', BookingSchema)
|