Day 5: Leases and Booking
Objective for Day 5
Implement leasing and booking.
Rationale
With the details of the opportunities and the majority of the response collated in Day 4, Day 5 is about ensuring that leasing and booking actually occurs.
Step 1: Ensure your database has a compatible schema
The Open Booking API includes concepts that likely map onto your existing schema, however your database schema may require slight adjustment in order to be compatible.

Entity
Description
Order
A table representing the atomic successfully created Order which is the result of B. A lease flag can also be added to this table to allow it to also represent a leased OrderQuote (for C1 and C2) or a separate table may be used for this purpose. This table likely also includes the booker (customer) details. This table is important as it is used to generate the Orders feed (see Day 6 for more information).
OrderItem
A table representing an individual booking of an Opportunity within an Order. This table likely also includes the guest checkout attendee details if these are supported. Existing "booking" or "attendee" tables may serve this purpose. Each OrderItem represents a booked space of a 'bookable' Opportunity and Offer pair.
Opportunity
One or many tables that represent the different types of opportunity, some of which may be bookable.
Offer
A table or other data structure that represents the available Offers within each Opportunity
Seller
A table that represents Sellers, organizations or individuals who organize the events or provide the facilities. Existing "organisation" tables may serve this purpose. This is only required if the booking system is multi-tenancy within the same database (i.e. it supports multiple Sellers).
AuthToken
This is likely to be managed by the authentication library, e.g. as JWT. See Day 8 for more information.
Booking Partner
This is likely to be managed by the authentication library, e.g. as a table of OAuth Clients. See Day 8 for more information.
Step 2: Understand the StoreBookingEngine booking flow
The StoreBookingEngine handles creation of the overall Lease or Order, as well as the booking of each OrderItem, within a transaction.
The diagram below illustrates the abstract methods that are called by the StoreBookingEngine, noting that:
The
OpportunityStoreused for calls toGetOrderItems,LeaseOrderItemsandBookOrderItemsfor the set ofOrderItems of each opportunity type is based on theOpportunityStoreRoutingconfigured in Day 3.The same
OrderItemContextis passed untouched fromGetOrderItemsto eitherLeaseOrderItemsorBookOrderItems, which allows logic to be executed inside or outside of the transaction as required.If an exception occurs after
BeginOrderTransaction,IDatabaseTransaction.Rollback()is called.

Step 3: Implement OrderStore
Create a new OrderStore implementation with stub methods.
Note that all methods except for CustomerCancelOrderItems will be implemented by the end this Day 5.
Configure the OrderStore setting of StoreBookingEngineSettings within EngineConfig.cs to use this new implementation of SellerStore:
Step 4: Implement Transactions
The OrderStore generic type has a parameter for a custom database transaction class, which can be used to wrap an existing transaction type (such as DbContextTransaction within entity framework), depending on your ORM or database.
Implement a new IDatabaseTransaction class, ensuring that the class is sealed, and that Dispose() is implemented correctly.
Within your new OrderStore, implement BeginOrderTransaction to return this new class.
Entity Framework Example
Step 5: Implement Leasing

The objective of this step is to implement CreateLease , LeaseOrderItems, and DeleteLease, while updating BeginOrderTransaction if necessary.
Use CreateLease to create an overall lease "container" for a collection of opportunities, if required by your system. CreateLease receives an immutable flowContext, which contains useful properties about the lease, and should contain enough data to satisfy most requirements for persisting a lease in a database. A Lease must be returned by CreateLease in order for LeaseOrderItems to be called.
To cater for edge cases: CreateLease also receives a mutable responseOrderQuote, which is the full OrderQuote response created so far. Note that the OrderItems will be overwritten by LeaseOrderItems, but all other properties may be updated if required, or can be read if useful when creating the lease "container" in the database.
Note that leases are time-bound, and so must be cleaned up if they expire (e.g. on a schedule). This must be handled outside of the StoreBookingEngine.
Use LeaseOrderItems to lease the individual opportunities. LeaseOrderItems follows a similar pattern to GetOrderItems, using lists of mutable OrderItemContext as described in Day 4. Note that as per the Open Booking API specification lease errors must not generate exceptions; instead AddError is useful here, as in Day 4, for adding any OrderItem level leasing errors to the response.
OrderStore.DeleteLease is called by the OrderQuote Deletion endpoint.
The Open Booking API specification provides several options for leasing an opportunity to a customer so that it cannot be booked by anyone else while the customer is completing their booking journey. The implementation of each is supported by the StoreBookingEngine through varying implementations of BeginOrderTransaction, CreateLease and DeleteLease, as described below.
Option 1: Disable leasing
Ensure that
BeginOrderTransactionreturnsnull, forFlowStage.C1andFlowStage.C2.Ensure
CreateLeasealways returnsnull, which will preventLeaseOrderItemsbeing triggered.LeaseOrderItemscan throwNotImplementedException.Implement
DeleteLeaseto do nothing (as the specification requires a positive response for OrderQuote Deletion, even if no lease exists).
Option 2: Named leasing - lease at C2 only
Use conditional logic to return null from BeginOrderTransaction and CreateLease at FlowStage.C1.
Implement CreateLease to create a new lease in your database against the flowContext.OrderId.uuid.
Implement LeaseOrderItems for each OpportunityStore to add the provided list of OrderItemContext identified by their RequestBookableOpportunityOfferId to the lease identified by flowContext.OrderId.uuid.
Implement DeleteLease to delete the lease based on the provided orderId.uuid, whilst always ensuring a positive response for OrderQuote Deletion, even if no lease exists.
Note that a Lease object must be returned from CreateLease in order for the LeaseOrderItems within each OpportunityStore implementation to be executed.
Option 3: Anonymous leasing - lease at C1 and C2
Same as Option 2, without the conditional logic.
Step 6: Run Test Suite for Leases
The appropriate lease tests should pass for C1 and C2.
Anonymous leasing (C1)
The anonymous-leasing feature within the openactive-integration-tests test suite should pass, if anonymous leasing has been implemented.
Run this test in isolation as follows:
Named leasing (C2)
The named-leasing feature within the openactive-integration-tests test suite should pass, if anonymous leasing or named leasing has been implemented.
Run this test in isolation as follows:
Step 7: Implement Booking

The objective of this step is to implement CreateOrder , BookOrderItems, and DeleteOrder, storing at least enough data to construct an Orders feed entry.
Use CreateOrder to create the Order that will feature in your Orders feed. CreateOrder receives an immutable flowContext, which contains useful properties about the Order, and should contain enough data to satisfy most requirements for persisting an Order in a database.
To cater for edge cases: CreateOrder also receives a mutable responseOrder, which is the full Order response created so far. Note that the OrderItems will be overwritten by BookOrderItems, but all other properties may be updated if required, or can be read if useful when creating the Order in the database.
Use BookOrderItems to book the individual opportunities. BookOrderItems follows a similar pattern to GetOrderItems, using lists of mutable OrderItemContext as described in Day 4. Note that to conform with the Open Booking API specification all booking errors must generate an exception; so do not use AddError. For errors relating to capacity throw OpenBookingException with OpportunityHasInsufficientCapacityError or OpportunityCapacityIsReservedByLeaseError as appropriate, or for other errors in BookOrderItems throw OpenBookingException with UnableToProcessOrderItemError.
OrderItemContext includes a method SetOrderItemId which must be used within BookOrderItems to set the OrderItem Id based on any completed bookings.
OrderStore.DeleteOrder is called by the Order Deletion endpoint, and must soft-delete the Order (such that it appears as "deleted" within the Orders feed).
Finally, when concurrent transactions are used to write to tables that power RPDE feeds, there is a risk of a delayed item interleaving race condition occurring. Ensure your Orders table updates (and Orders RPDE query in Day 6) implement the prevention strategies outlined here.
Step 8: Run Test Suite for Booking
The free-opportunities and non-free-opportunities features within the openactive-integration-tests test suite should pass.
Run these tests in isolation as follows:
Last updated
Was this helpful?