Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Booking system with CS #871

Open
cahueya opened this issue May 2, 2024 · 10 comments
Open

Booking system with CS #871

cahueya opened this issue May 2, 2024 · 10 comments

Comments

@cahueya
Copy link
Contributor

cahueya commented May 2, 2024

Hello peeps,

I have a request to implement a booking system for a small guesthouse and I would like to do that with CommunityStore, because I love it :-)

I'm here to spin ideas and/or experiences.

What I THINK to do it bulk-produce a bunch of products for each room ("room1, room2") where each product has a date attribute which is the date of check-in.

So when a customer select their stay, an bunch of products (room1_day1, room1_day2, room1_day3) is selected and then purchased.

In that case, I only have to build a custom product list block to display/select in a proper way and everything else would be standard CommunityStore functionality.

What do you think about that? Or has any of you fine people done a similar thing?

Thanks!

@Mesuva
Copy link
Collaborator

Mesuva commented May 3, 2024

I've done a bit to do with linking event tickets, but not so much for accommodation.

The way I think I'd approach is:

  • treat different rates or levels of accommodation as different products, and use a product's quantity as the number of days someone is booking for. Or, if there are discounts for the number of days, I'd use product variations.
  • I'd have a checkin(and and maybe checkout date) field on each product
  • pretty much ignore the standard mechanisms of adding to the cart, and build my old calendar/process
  • selecting one or more dates and then hitting some button to select it would programatically add the product to the cart, with the right number of days, populating the checkin (and checkout) day fields. Things would be locked so all they could do is remove it from the cart.

Then when an order is placed, I think an event hook may then need to be used to look at the order, work out the product, the number of dates and the dates involved, and then programatically adjust the calendar to block out that period. This bit is perhaps the hardest bit involved, as it would need to handle cancellations, holiday periods, etc.

Anything with dates and booking can get very complicated, very quickly, with lots of little considerations and exception cases. Personally I'd be very hesitant to build something myself - I'd make sure that you check out lots of the third-party platforms for guesthouses/B&Bs, as there's lots to chose from - and they've been built to handle all the complexity. The cost to develop something, versus the ongoing third-party cost would be worth weighing up.

@cahueya
Copy link
Contributor Author

cahueya commented May 3, 2024

Thanks for the thinking!

What do you think about the suggestion above? With the ability to import a product by CSV, I can easily build 365 products for each room type where each product represents one day at one room type. Quantity is always just 1.

Each product contains a attribute that contains the check-in date (03-05-2024) with which I can build hook into a calendar display.

This way, the "difficult part" of blocking availability is gone and all I need to customize is the "how to book a room"-display.

So for this small place (12) rooms, it is 365 * 12 products per year with all-predefined description and attributes through CSV.

@cahueya
Copy link
Contributor Author

cahueya commented May 3, 2024

The problem with the third-party options is, that they do not hook easily into all the other custom stuff we already have available through concreteCMS. So I can either focus on customizing the third-party integration OR I can focus on making bookings through CommunityStore working and enjoy all the other things we already have available :-)

@Mesuva
Copy link
Collaborator

Mesuva commented May 3, 2024

I've actually built a booking add-on for Concrete, one that we've used for booking training sessions (and doing thing like reserving squash courts). It's not related to Community Store, but it uses a similar sort of mechanism to what you've described.

  • we define the session times, what days of the week, etc, and there's an automated job that pre-populates the timeslots. Then if someone picks one, that gets marked as used.
  • The automated job creates them up to, say, 365 days ahead, on a rolling basis
  • There's a job to clean up unused sessions that pass, just so we don't end up with a growing database of unneeded records

Now this add-on isn't really going to work for accommodation, as it's very much about booking one session/timeslot at a time, but it works well from a management point of view.

I think what you've described could work, having a few thousand products in there shouldn't really break anything as such. The bit that doesn't feel right to me though is that creating a new product, just for the purpose of restricting it, seems like it's the wrong place to handle it. It also would make reporting much more difficult as well (whereas if you have one or two products, you can easily count the quantity sold over a period of time to work out how many nights have been sold).

I reckon if you're going to be building something to handle the calendar display and selection, you probably should just build some sort of basic calendar storage, where you import the CSV of room availability and populate a custom database table.

Each room/date entry could then map against a product, with that in the CSV really just being the product ID.

It also mean you can do things like change the rates easily, without having to remove and re-create a whole number of products.

@cahueya
Copy link
Contributor Author

cahueya commented May 3, 2024

Yeah, sounds good too. Well, creating 12 products for 12 rooms really isnt the way to go, more like "2 products for 2 room categories" and the Quantity of each product represents the quantity of availability for that given day. So in this case it would be 2 products with Quantity of 6 each for each day of the year, which makes the reporting display much more useful...

and isn't the pDateAvailableEnd exactly the field that represents the checkout date so pDateAvailableEnd -1 would be the checkin date... So in theory I would build a job that clears out all products after where pDateAvailableEnd < today?

It looks like most of what needs to be there is already available in the products table.

I have to think about the differences of your last suggestion, which is adding more complexity/fragility or which is too limiting. I would love to keep the customization at the display level but maybe I'm thinking too simplistic.

@cahueya
Copy link
Contributor Author

cahueya commented May 13, 2024

Alright, I want to keep you up to date in the process and maybe get feedback or warnings about my thought process.

I did some playing with the CSV Import to products and it works fine and with a little customisation does exactly what I need it for.

It's also working well for updating products in bulk. If the SKU already exists, it just updates the attributes and that's it. So my customer will just have CSV template for every room type with all the dates and values and can use that to create update sheets.

So I will stick with the plan to create a product for each room category for each day of the year. I just like the idea of using all the functionality that already comes with the Product Class.

I will use the SKU and endDateAvailable field to identify the Rooms (SKU: DATE-ROOMTYPE e.g. 05132024-A, 13052024-A ).

On the frontend, I want to use https://lopezb.com/hoteldatepicker/ because it looks amazing and does exactly what I need.
I'm still struggling with getting it to work, but that's because I'm the Jon Snow of Javascript, I know nuthin about it.

The hoteldatepicker will (once working) return an array of dates to the controller of my custom block. With those dates I will run a query through the Products table and return arrays for each day, holding all the available room types of those days.

So if the customer selects array(05-10-2024, 05-11-2024, 05-12-2024),

I want to grab those dates and run a foreach loop:

foreach $dates as $date {
modifiedbookingdate('Y-m-d', strtotime($date. ' + 1 day')); $bookingdate=SELECT * FROM Products WHERE endDateAvailable=$modifiedbookingdate}

I shift the requested date to match the endDateAvailable, where a room is no more available the day after its availability.

This should give me an array with available Rooms/Products for each of the requested days

array{
    05-10-2024{
        05102024-A, 
        05102024-B
    }
    05-11-2024{
        05112024-A, 
        05112024-B, 
        05112024-C
    }
    05-12-2024{
        05122024-A, 
        05122024-B
        }
    }

I haven't thought much further but then I want to show the room types to the customer, and only those room types that are available on all the selected dates, and then they choose one and I have to figure out how to "bulk-add-to-cart" the items but I think well do that along the way.

Somewhere before that I also need to ask of course how many beds are needed and each room-product contains the number available for that specific roomtype and we'll filter through that too.

Am I somewhere completely wrong in my thinking? Please tell me if I am :-)

@cahueya
Copy link
Contributor Author

cahueya commented May 20, 2024

Ok, I have the whole display and filtering going to the point where the controller returns an array of $pID that match the critera like daterange, numerofpeople and roomcategory.

Now while working on submitting that to the Cart, I've realized that I don't see how that is working and if it would be possible to submit an array of products.

I see the form that includes that $pID but I didnt find where it submits to and what the rules are here. Can you help with that, @Mesuva ?

Basically my plan is to merge all matching products into $booking_products arrays where each Item contains the $pID of all the daterange and bedspace matching products and the various arrays are differentiated by the room types, which I have set as product groups.

So in the end there would be a list of booking_products where each booking_product contains an array of all the daterange matching products. The submit button stays with each booking_product and will submit the array of $pID to the cart.

But is it possible or do I need to loop through?

Thanks for hints!

@Mesuva
Copy link
Collaborator

Mesuva commented May 20, 2024

The normal add-to-cart process calls a URL mapped to this function:
https://github.com/concretecms-community-store/community_store/blob/master/controllers/single_page/cart.php#L150

But it's the StoreCart::add($data) call that actually does the work of adding the product to the cart session:
https://github.com/concretecms-community-store/community_store/blob/master/src/CommunityStore/Cart/Cart.php#L254

In $data (which is just the POST array), it's expecting a pID value, a quantity value as a minimum. Then you can also pass it other attributes (if the product has options).

So in your case, you're effectively wanting to call StoreCart::add($data) multiple times, looping through the products you're POST-ing.

What I'd suggest is in your own package, create an endpoint similar to /cart/add, that can receive POST data with multiple products and quantities, loop through it there, passing it through to StoreCart::add. What is perhaps the fiddliest bit is deciding what then happens - you might want to show your own custom popup/cart, showing what has happened, or do something like redirect to the /cart page.

@cahueya
Copy link
Contributor Author

cahueya commented May 20, 2024

Aaaah great thank you!
Yeah, the plan is to show the cart with each single day shown and then just submit the order.

Next step will be a custom singlepage for a Reports view with the booking shown in a booking table. But submission first. Thank you so much!

@cahueya
Copy link
Contributor Author

cahueya commented May 21, 2024

Nice, the logic works. Now I'll fiddle with the display and some extra attributes and report-singlepages. So basically it works as a filtering interface for the products and helps bulk-adding them to the Cart.

Once done, I'll push it to Github for the world to critisize :-D

Thank you for that well-structured, easy extendable code!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants