//TODO: This should reuse code of LeaseOrderItem protected override async ValueTask BookOrderItems(List <OrderItemContext <FacilityOpportunity> > orderItemContexts, StoreBookingFlowContext flowContext, OrderStateContext stateContext, OrderTransaction databaseTransaction) { // Check that there are no conflicts between the supplied opportunities // Also take into account spaces requested across OrderItems against total spaces in each opportunity foreach (var ctxGroup in orderItemContexts.GroupBy(x => x.RequestBookableOpportunityOfferId)) { // Check that the Opportunity ID and type are as expected for the store if (ctxGroup.Key.OpportunityType != OpportunityType.FacilityUseSlot || !ctxGroup.Key.SlotId.HasValue) { throw new OpenBookingException(new UnableToProcessOrderItemError(), "Opportunity ID and type are as not expected for the FacilityStore, during booking"); } // Attempt to book for those with the same IDs, which is atomic var(result, bookedOrderItemInfos) = await FakeDatabase.BookOrderItemsForFacilitySlot( databaseTransaction.FakeDatabaseTransaction, flowContext.OrderId.ClientId, flowContext.SellerId.SellerIdLong ?? null /* Hack to allow this to work in Single Seller mode too */, flowContext.OrderId.uuid, ctxGroup.Key.SlotId.Value, RenderOpportunityId(ctxGroup.Key), RenderOfferId(ctxGroup.Key), ctxGroup.Count(), false ); switch (result) { case ReserveOrderItemsResult.Success: foreach (var(ctx, bookedOrderItemInfo) in ctxGroup.Zip(bookedOrderItemInfos, (ctx, bookedOrderItemInfo) => (ctx, bookedOrderItemInfo))) { // Set OrderItemId and access properties for each orderItemContext ctx.SetOrderItemId(flowContext, bookedOrderItemInfo.OrderItemId); BookedOrderItemHelper.AddPropertiesToBookedOrderItem(ctx, bookedOrderItemInfo); } break; case ReserveOrderItemsResult.SellerIdMismatch: throw new OpenBookingException(new SellerMismatchError(), "An OrderItem SellerID did not match"); case ReserveOrderItemsResult.OpportunityNotFound: throw new OpenBookingException(new UnableToProcessOrderItemError(), "Opportunity not found"); case ReserveOrderItemsResult.NotEnoughCapacity: throw new OpenBookingException(new OpportunityHasInsufficientCapacityError()); case ReserveOrderItemsResult.OpportunityOfferPairNotBookable: throw new OpenBookingException(new UnableToProcessOrderItemError(), "Opportunity and offer pair were not bookable"); default: throw new OpenBookingException(new OrderCreationFailedError(), "Booking failed for an unexpected reason"); } } }