The problem
There was nothing online. Bookings arrived by phone and by email, an agent would call or write to ask what was still available, and somebody in the office would check and reply. That worked until the business outgrew it. Every booking cost a member of staff a conversation, and eventually there were more bookings coming in than there were hours to answer them in.
Two separate problems came out of that. Agents needed to book seats themselves instead of waiting on someone to get back to them. The operator needed one place where every booking lived, rather than each one sitting in whichever inbox or phone call it happened to arrive through.
A tour operator selling through travel agents also has a different commerce problem from one selling to the public. Agents log in, see prices that are specific to their agreement, and book on behalf of someone else. The public catalogue and the agent catalogue are the same inventory with different rules on top.
What I built
Two sites with different jobs. The international incoming site, aimed at travellers coming to Romania, is a presentation frontend and sells nothing. The agent platform is Magento 2, customised until it fitted a business Magento was not written for.
- Agent accounts as Magento customers, so every partner is a customer record and the operator can see that partner's reservations and their numbers without any of it being built from scratch
- Trips as products, so a departure is the record that carries price and availability
- Room types and their prices as custom options, so the choices that change what a booking costs sit on the trip itself
- Coach diagrams, so a seat is chosen off a plan of the vehicle rather than picked as a number off a list
- Name reservations, since a seat is held against the passenger who will sit in it, not against the agent booking it
Decisions and tradeoffs
A trip is a Magento product, and the room types with their prices are custom options on it. That much Magento does well, and it is why the catalogue, the partner accounts and the admin screens did not have to be built. Reusing the customer entity for partners is what gives the operator per-partner reservation history and figures without a line of reporting code.
What Magento could not represent is the booking. A reservation is not a quantity of a thing, it is named people in specific seats on one departure, so reservations and coach types became models of their own. The consequence is that this platform has no checkout. An agent fills in a custom form and the reservation is written straight to its own model, and Magento's cart and checkout are not part of the flow at all.
Access falls out of the same customer records. An administrator sees every reservation, and a partner sees only their own.
What I got wrong
If I did this again I would not build it on Magento. The problem is not quality, because Magento is a strong framework. The problem is fit. It was more than this job needed, and what I ended up using was the catalogue, the custom options, the customer accounts and the admin, while I wrote the booking myself regardless.
I would still start from a platform rather than from nothing, but Laravel suits this better. It is more work up front, since none of the catalogue or account scaffolding is there to inherit. What you get back is room to configure and extend later, instead of working around decisions the platform has already made for you.
Where it stands
It is in production, and I still maintain the B2B and international sides of the platform.
The agent platform sits behind a login and holds live commercial data, so there are no screenshots on this page.