Skip to content
This repository has been archived by the owner on Feb 16, 2022. It is now read-only.

Availability documentation #48

Closed
baj84 opened this issue Sep 28, 2020 · 5 comments
Closed

Availability documentation #48

baj84 opened this issue Sep 28, 2020 · 5 comments

Comments

@baj84
Copy link

baj84 commented Sep 28, 2020

I understand the documentation isn't complete, but could someone help me by explaining how you can create availabilities and check for clashes in dates?

Thanks!

@l4nos
Copy link

l4nos commented Feb 15, 2021

I agree, this is an important feature that is needed.

"Get me all available slots for Wednesday for this room" is such an important feature especially if you are wanting to build a customer facing appointment system (like calendly)

To have a ->getAvailability($date) command against the model would be a game changer.

@kingkarki
Copy link

I agree. That is the most important thing.

@hmaldonadoi
Copy link

As we see in dosc we don'ts use default booking duration time, i think that this is because you can extends many models to be booked.

I think that we should create duration constant for every model that we need, and in some cases, the user can choose their custom duration time.

Based on that, i think that we need to use the custom documented function bookingsStartsBetween to create custom own function (or service) to get available datas, looping the result of:

$room->bookingsStartsBetween('2017-06-21 19:28:51', '2017-07-01 12:00:00')->get(); // Get bookings starts between the given dates

And, making our custom logic depending of duration of service, (1, 5, 7, 15 minutes i need in this case?).

So, to understand it better, i think that doesnt exist any "virtual calendar mind" available to work, so we need to get "used dates" to get our "available calendar" and show it.

Another option is to work directly on Eloquent models with dates, and date parts.

$eloquent->selectRaw(DATEPART ...)->WHERE NOT IN (SELECT DATE FROM BOOKED);

I hope this helps.

@vesper8
Copy link

vesper8 commented Jul 31, 2021

I also noticed that there isn't any built-in collision check to prevent double bookings.. seems like a big omission

I've added this additional scope which I use to make sure there aren't any existing bookings prior to making a new booking.

I don't think it's perfect and I had to use a bit of a hack with addSeconds / subSeconds. But so far it works for me.


    /**
     * Get bookings between given start and end dates inclusively.
     * 
     * - Check for two things - 
     * Either starts_at or ends_at falling into any of the already existing booking intervals; 
     * or starts_at before and ends_at after those of an existing booking 
     * (because you can’t make a new booking from 9am to 14am, if one from 10am to 11am already exists.)
     *
     * @param string $startsAt
     * @param string $endsAt
     *
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
     */
    public function bookingsBetween(string $startsAt, string $endsAt): MorphMany
    {
        return $this->bookings()
            ->whereNull('canceled_at')
            ->where(
                fn ($q) => $q->whereBetween('starts_at', [(new Carbon($startsAt)), (new Carbon($endsAt))->subSeconds(1)])
                    ->orWhereBetween('ends_at', [(new Carbon($startsAt))->addSeconds(1), (new Carbon($endsAt))])
                    ->orWhere(
                        fn ($q) => $q->where('starts_at', '<', (new Carbon($startsAt)))
                            ->where('ends_at', '>', (new Carbon($endsAt)))
                    )
            );
    }

And a little test

        $user = User::first();

        Booking::truncate();

        $room = Room::first();

        $bookingsTimes = [
            [Carbon::today()->addHours(12)->addMinutes(0), Carbon::today()->addHours(14)->addMinutes(0)], // ok
            [Carbon::today()->addHours(13)->addMinutes(0), Carbon::today()->addHours(14)->addMinutes(0)], // fail
            [Carbon::today()->addHours(14)->addMinutes(0), Carbon::today()->addHours(15)->addMinutes(0)], // ok
            [Carbon::today()->addHours(12)->addMinutes(30), Carbon::today()->addHours(14)->addMinutes(30)], // fail
            [Carbon::today()->addHours(11)->addMinutes(0), Carbon::today()->addHours(11)->addMinutes(30)], // ok
            [Carbon::today()->addHours(11)->addMinutes(30), Carbon::today()->addHours(11)->addMinutes(60)], // ok
        ];

        foreach ($bookingsTimes as $bookingsTime) {
            $start = $bookingsTime[0];
            $end = $bookingsTime[1];

            $existingBookings = $room->bookingsBetween($start, $end)->get();

            if ($existingBookings->count()) {
                $this->warn(sprintf('There is already a booking in room %s between %s and %s', $room->name, $start, $end));
            } else {
                $this->info(sprintf('Succesfully booked room %s between %s and %s', $room->name, $start, $end));
                $user->newBooking($room, $start, $end);
            }
        }

        $this->line('');
        $this->line(sprintf('Room %s has %d bookings', $room->name, $room->bookings->count()));

@Omranic
Copy link
Member

Omranic commented Sep 28, 2021

Thank you for your patience. The availability features implementation wasn't completed in the perfect possible way, so I'd expect some edge cases, and possibly odd behavior. I'd bee happy to consider any PRs that consolidate this feature. All PRs are welcome 😉

Added to the readme roadmap
https://github.com/rinvex/laravel-bookings/blob/develop/README.md#roadmap

@Omranic Omranic closed this as completed Sep 28, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants