public void SellerIdComponents_Null_Equality() { SellerIdComponents x = null; SellerIdComponents y = null; Assert.True(x == y); Assert.False(x != y); }
public override async Task DeleteLease(OrderIdComponents orderId, SellerIdComponents sellerId) { // Note if no lease support, simply do nothing here await FakeBookingSystem.Database.DeleteLease( orderId.ClientId, orderId.uuid, sellerId.SellerIdLong ?? null /* Hack to allow this to work in Single Seller mode too */ ); }
public void SellerIdComponents_Null_Inequality() { SellerIdComponents x = new SellerIdComponents { SellerIdString = "abc" }; SellerIdComponents y = null; Assert.False(x == y); Assert.True(x != y); }
public void SellerIdComponents_String_Inequality() { var x = new SellerIdComponents { SellerIdString = "abc" }; var y = new SellerIdComponents { SellerIdString = "def" }; Assert.False(x == y); Assert.True(x != y); }
public void SellerIdComponents_Long_Equality() { var x = new SellerIdComponents { SellerIdLong = 0 }; var y = new SellerIdComponents { SellerIdLong = 0 }; Assert.True(x == y); Assert.False(x != y); }
//TODO: Should we move Seller into the Abstract level? Perhaps too much complexity private O ValidateFlowRequest <O>(string clientId, Uri authenticationSellerId, FlowStage stage, string uuid, OrderType orderType, O orderQuote) where O : Order, new() { var orderId = new OrderIdComponents { ClientId = clientId, uuid = uuid, OrderType = orderType }; // TODO: Add more request validation rules here SellerIdComponents sellerIdComponents = GetSellerIdComponentsFromApiKey(authenticationSellerId); ILegalEntity seller = settings.SellerStore.GetSellerById(sellerIdComponents); if (seller == null) { throw new OpenBookingException(new SellerNotFoundError()); } if (orderQuote?.Seller?.Id != null && seller?.Id != orderQuote?.Seller?.Id) { throw new OpenBookingException(new SellerMismatchError()); } // Check that taxMode is set in Seller if (!(seller?.TaxMode == TaxMode.TaxGross || seller?.TaxMode == TaxMode.TaxNet)) { throw new EngineConfigurationException("taxMode must always be set in the Seller"); } // Default to BusinessToConsumer if no customer provided TaxPayeeRelationship taxPayeeRelationship = orderQuote.Customer == null ? TaxPayeeRelationship.BusinessToConsumer : orderQuote.BrokerRole == BrokerType.ResellerBroker || orderQuote.Customer.IsOrganization ? TaxPayeeRelationship.BusinessToBusiness : TaxPayeeRelationship.BusinessToConsumer; var payer = orderQuote.BrokerRole == BrokerType.ResellerBroker ? orderQuote.Broker : orderQuote.Customer; return(ProcessFlowRequest <O>(new BookingFlowContext { Stage = stage, OrderId = orderId, OrderIdTemplate = settings.OrderIdTemplate, Seller = seller, SellerId = sellerIdComponents, TaxPayeeRelationship = taxPayeeRelationship, Payer = payer }, orderQuote)); }
public ResponseContent ProcessOrderUpdate(string clientId, Uri sellerId, string uuid, string orderJson) { Order order = OpenActiveSerializer.Deserialize <Order>(orderJson); SellerIdComponents sellerIdComponents = GetSellerIdComponentsFromApiKey(sellerId); // Check for PatchContainsExcessiveProperties Order orderWithOnlyAllowedProperties = new Order { OrderedItem = order.OrderedItem.Select(x => new OrderItem { Id = x.Id, OrderItemStatus = x.OrderItemStatus }).ToList() }; if (OpenActiveSerializer.Serialize <Order>(order) != OpenActiveSerializer.Serialize <Order>(orderWithOnlyAllowedProperties)) { throw new OpenBookingException(new PatchContainsExcessivePropertiesError()); } // Check for PatchNotAllowedOnProperty if (!order.OrderedItem.TrueForAll(x => x.OrderItemStatus == OrderItemStatus.CustomerCancelled)) { throw new OpenBookingException(new PatchNotAllowedOnPropertyError(), "Only 'https://openactive.io/CustomerCancelled' is permitted for this property."); } var orderItemIds = order.OrderedItem.Select(x => settings.OrderIdTemplate.GetOrderItemIdComponents(clientId, x.Id)).ToList(); // Check for mismatching UUIDs if (!orderItemIds.TrueForAll(x => x != null)) { throw new OpenBookingException(new OrderItemIdInvalidError()); } // Check for mismatching UUIDs if (!orderItemIds.TrueForAll(x => x.OrderType == OrderType.Order && x.uuid == uuid)) { throw new OpenBookingException(new OrderItemNotWithinOrderError()); } ProcessCustomerCancellation(new OrderIdComponents { ClientId = clientId, OrderType = OrderType.Order, uuid = uuid }, sellerIdComponents, settings.OrderIdTemplate, orderItemIds); return(ResponseContent.OpenBookingNoContentResponse()); }
// If the Seller is not found, simply return null to generate the correct Open Booking error protected override ILegalEntity GetSeller(SellerIdComponents sellerIdComponents) { // Note both examples are shown below to demonstrate options available. Only one block of the if statement below is required. if (sellerIdComponents.SellerIdLong == null && sellerIdComponents.SellerIdString == null) { // For Single Seller booking systems, no ID will be available from sellerIdComponents, and this data should instead come from your configuration table return(new Organization { Id = this.RenderSingleSellerId(), Name = "Test Seller", TaxMode = TaxMode.TaxGross }); } else { // Otherwise it may be looked up based on supplied sellerIdComponents which are extacted from the sellerId. var seller = FakeBookingSystem.Database.Sellers.SingleOrDefault(x => x.Id == sellerIdComponents.SellerIdLong); if (seller != null) { return(seller.IsIndividual ? (ILegalEntity) new Person { Id = this.RenderSellerId(new SellerIdComponents { SellerIdLong = seller.Id }), Name = seller.Name, TaxMode = TaxMode.TaxGross } : (ILegalEntity) new Organization { Id = this.RenderSellerId(new SellerIdComponents { SellerIdLong = seller.Id }), Name = seller.Name, TaxMode = TaxMode.TaxGross }); } else { return(null); } } }
private async Task <(OrderIdComponents orderId, SellerIdComponents sellerIdComponents, ILegalEntity seller)> ConstructIdsFromRequest(string clientId, Uri authenticationSellerId, string uuidString, OrderType orderType) { var orderId = new OrderIdComponents { ClientId = clientId, uuid = ConvertToGuid(uuidString), OrderType = orderType }; // TODO: Add more request validation rules here SellerIdComponents sellerIdComponents = GetSellerIdComponentsFromApiKey(authenticationSellerId); ILegalEntity seller = await settings.SellerStore.GetSellerById(sellerIdComponents); if (seller == null) { throw new OpenBookingException(new SellerNotFoundError()); } return(orderId, sellerIdComponents, seller); }
public async Task <ResponseContent> ProcessOrderProposalUpdate(string clientId, Uri sellerId, string uuidString, string orderProposalJson) { var orderId = new OrderIdComponents { ClientId = clientId, OrderType = OrderType.OrderProposal, uuid = ConvertToGuid(uuidString) }; using (await asyncDuplicateLock.LockAsync(GetParallelLockKey(orderId))) { OrderProposal orderProposal = OpenActiveSerializer.Deserialize <OrderProposal>(orderProposalJson); SellerIdComponents sellerIdComponents = GetSellerIdComponentsFromApiKey(sellerId); if (orderProposal == null || orderProposal.GetType() != typeof(Order)) { throw new OpenBookingException(new UnexpectedOrderTypeError(), "OrderProposal is required for Order Cancellation"); } // Check for PatchContainsExcessiveProperties OrderProposal orderProposalWithOnlyAllowedProperties = new OrderProposal { OrderProposalStatus = orderProposal.OrderProposalStatus, OrderCustomerNote = orderProposal.OrderCustomerNote }; if (OpenActiveSerializer.Serialize <OrderProposal>(orderProposal) != OpenActiveSerializer.Serialize <OrderProposal>(orderProposalWithOnlyAllowedProperties)) { throw new OpenBookingException(new PatchContainsExcessivePropertiesError()); } // Check for PatchNotAllowedOnProperty if (orderProposal.OrderProposalStatus != OrderProposalStatus.CustomerRejected) { throw new OpenBookingException(new PatchNotAllowedOnPropertyError(), "Only 'https://openactive.io/CustomerRejected' is permitted for this property."); } await ProcessOrderProposalCustomerRejection(orderId, sellerIdComponents, settings.OrderIdTemplate); return(ResponseContent.OpenBookingNoContentResponse()); } }
public abstract void ProcessCustomerCancellation(OrderIdComponents orderId, SellerIdComponents sellerId, OrderIdTemplate orderIdTemplate, List <OrderIdComponents> orderItemIds);
public override async Task <DeleteOrderResult> DeleteOrder(OrderIdComponents orderId, SellerIdComponents sellerId) { var result = await FakeBookingSystem.Database.DeleteOrder( orderId.ClientId, orderId.uuid, sellerId.SellerIdLong ?? null /* Small hack to allow use of FakeDatabase when in Single Seller mode */); switch (result) { case FakeDatabaseDeleteOrderResult.OrderSuccessfullyDeleted: // "OrderWasAlreadyDeleted" is being treated as a success because the order did // exist - This maintains idempotency as requests that follow a successful request // will still return a 2xx. case FakeDatabaseDeleteOrderResult.OrderWasAlreadyDeleted: return(DeleteOrderResult.OrderSuccessfullyDeleted); case FakeDatabaseDeleteOrderResult.OrderWasNotFound: return(DeleteOrderResult.OrderDidNotExist); default: throw new OpenBookingException(new OpenBookingError(), $"Unexpected FakeDatabaseDeleteOrderResult: {result}"); } }
protected abstract void ProcessOrderQuoteDeletion(OrderIdComponents orderId, SellerIdComponents sellerId);
public abstract void DeleteLease(OrderIdComponents orderId, SellerIdComponents sellerId);
public abstract bool CustomerCancelOrderItems(OrderIdComponents orderId, SellerIdComponents sellerId, OrderIdTemplate orderIdTemplate, List <OrderIdComponents> orderItemIds);
/// <summary> /// Reject specified OrderProposal /// Note sellerId will always be null in Single Seller mode /// </summary> /// <returns>True if OrderProposal found, False if OrderProposal not found</returns> public override async Task <bool> CustomerRejectOrderProposal(OrderIdComponents orderId, SellerIdComponents sellerId) { return(await FakeBookingSystem.Database.RejectOrderProposal(orderId.ClientId, sellerId.SellerIdLong ?? null /* Hack to allow this to work in Single Seller mode too */, orderId.uuid, true)); }
public override void DeleteOrder(OrderIdComponents orderId, SellerIdComponents sellerId) { FakeBookingSystem.Database.DeleteOrder(orderId.ClientId, orderId.uuid, sellerId.SellerIdLong ?? null /* Small hack to allow use of FakeDatabase when in Single Seller mode */); }
public override void DeleteLease(OrderIdComponents orderId, SellerIdComponents sellerId) { // Note if no lease support, simply do nothing here FakeBookingSystem.Database.DeleteLease(orderId.ClientId, orderId.uuid, sellerId.SellerIdLong.Value); }
public override async Task <bool> CreateOrderFromOrderProposal(OrderIdComponents orderId, SellerIdComponents sellerId, Uri orderProposalVersion, Order order) { // TODO more elegantly extract version UUID from orderProposalVersion (probably much further up the stack?) var version = new Guid(orderProposalVersion.ToString().Split('/').Last()); var result = await FakeBookingSystem.Database.BookOrderProposal( orderId.ClientId, sellerId.SellerIdLong ?? null /* Hack to allow this to work in Single Seller mode too */, orderId.uuid, version); // TODO return enum to allow errors cases to be handled in the engine switch (result) { case FakeDatabaseBookOrderProposalResult.OrderSuccessfullyBooked: return(true); case FakeDatabaseBookOrderProposalResult.OrderProposalVersionOutdated: return(false); case FakeDatabaseBookOrderProposalResult.OrderProposalNotAccepted: throw new OpenBookingException(new OrderCreationFailedError(), "OrderProposal has not been accepted by the Seller"); case FakeDatabaseBookOrderProposalResult.OrderWasNotFound: throw new OpenBookingException(new UnknownOrderError()); default: throw new OpenBookingException(new OpenBookingError(), $"Unexpected FakeDatabaseDeleteOrderResult: {result}"); } }
public async Task <ResponseContent> ProcessOrderUpdate(string clientId, Uri sellerId, string uuidString, string orderJson) { var orderId = new OrderIdComponents { ClientId = clientId, OrderType = OrderType.Order, uuid = ConvertToGuid(uuidString) }; using (await asyncDuplicateLock.LockAsync(GetParallelLockKey(orderId))) { Order order = OpenActiveSerializer.Deserialize <Order>(orderJson); SellerIdComponents sellerIdComponents = GetSellerIdComponentsFromApiKey(sellerId); if (order == null || order.GetType() != typeof(Order)) { throw new OpenBookingException(new UnexpectedOrderTypeError(), "Order is required for Order Cancellation"); } // Check for PatchContainsExcessiveProperties Order orderWithOnlyAllowedProperties = new Order { OrderedItem = order.OrderedItem.Select(x => new OrderItem { Id = x.Id, OrderItemStatus = x.OrderItemStatus }).ToList() }; if (OpenActiveSerializer.Serialize <Order>(order) != OpenActiveSerializer.Serialize <Order>(orderWithOnlyAllowedProperties)) { throw new OpenBookingException(new PatchContainsExcessivePropertiesError()); } // Check for PatchNotAllowedOnProperty if (!order.OrderedItem.TrueForAll(x => x.OrderItemStatus == OrderItemStatus.CustomerCancelled)) { throw new OpenBookingException(new PatchNotAllowedOnPropertyError(), "Only 'https://openactive.io/CustomerCancelled' is permitted for this property."); } List <OrderIdComponents> orderItemIds; try { orderItemIds = order.OrderedItem.Select(x => settings.OrderIdTemplate.GetOrderItemIdComponents(clientId, x.Id)).ToList(); } catch (ComponentFailedToParseException) { throw new OpenBookingException(new OrderItemIdInvalidError()); } // Check for mismatching UUIDs if (!orderItemIds.TrueForAll(x => x != null)) { throw new OpenBookingException(new OrderItemIdInvalidError()); } // Check for mismatching UUIDs if (!orderItemIds.TrueForAll(x => x.OrderType == OrderType.Order && x.uuid == orderId.uuid)) { throw new OpenBookingException(new OrderItemNotWithinOrderError()); } await ProcessCustomerCancellation(orderId, sellerIdComponents, settings.OrderIdTemplate, orderItemIds); return(ResponseContent.OpenBookingNoContentResponse()); } }
protected abstract Task <DeleteOrderResult> ProcessOrderDeletion(OrderIdComponents orderId, SellerIdComponents sellerId);
protected abstract Task <Order> ProcessGetOrderStatus(OrderIdComponents orderId, SellerIdComponents sellerId, ILegalEntity seller);
/// <summary> /// Initiate customer cancellation for the specified OrderItems /// Note sellerId will always be null in Single Seller mode /// </summary> /// <returns>True if Order found, False if Order not found</returns> public override async Task <bool> CustomerCancelOrderItems(OrderIdComponents orderId, SellerIdComponents sellerId, List <OrderIdComponents> orderItemIds) { try { return(await FakeBookingSystem.Database.CancelOrderItems( orderId.ClientId, sellerId.SellerIdLong ?? null /* Hack to allow this to work in Single Seller mode too */, orderId.uuid, orderItemIds.Where(x => x.OrderItemIdLong.HasValue).Select(x => x.OrderItemIdLong.Value).ToList(), true)); } catch (InvalidOperationException ex) { throw new OpenBookingException(new CancellationNotPermittedError(), ex.Message); } }
//TODO: Should we move Seller into the Abstract level? Perhaps too much complexity protected BookingFlowContext ValidateFlowRequest <TOrder>(OrderIdComponents orderId, SellerIdComponents sellerIdComponents, ILegalEntity seller, FlowStage stage, TOrder order) where TOrder : Order, new() { // If being called from Order Status then expect Seller to already be a full object var sellerIdFromOrder = stage == FlowStage.OrderStatus ? order?.Seller.Object?.Id : order?.Seller.IdReference; if (sellerIdFromOrder == null) { throw new OpenBookingException(new SellerMismatchError()); } if (seller?.Id != sellerIdFromOrder) { throw new OpenBookingException(new InvalidAuthorizationDetailsError()); } // Check that taxMode is set in Seller if (!(seller?.TaxMode == TaxMode.TaxGross || seller?.TaxMode == TaxMode.TaxNet)) { throw new InternalOpenBookingException(new InternalLibraryConfigurationError(), "taxMode must always be set in the Seller"); } // Default to BusinessToConsumer if no customer provided TaxPayeeRelationship taxPayeeRelationship = order.Customer == null ? TaxPayeeRelationship.BusinessToConsumer : order.BrokerRole == BrokerType.ResellerBroker || order.Customer.IsOrganization ? TaxPayeeRelationship.BusinessToBusiness : TaxPayeeRelationship.BusinessToConsumer; if (order.BrokerRole == null) { throw new OpenBookingException(new IncompleteBrokerDetailsError()); } if (order.BrokerRole == BrokerType.NoBroker && order.Broker != null) { throw new OpenBookingException(new IncompleteBrokerDetailsError()); // TODO: Placeholder for https://github.com/openactive/open-booking-api/issues/167 } // Throw error on incomplete customer details if C2, P or B if Broker type is not ResellerBroker if (order.BrokerRole != BrokerType.ResellerBroker) { if (stage != FlowStage.C1 && (order.Customer == null || string.IsNullOrWhiteSpace(order.Customer.Email))) { throw new OpenBookingException(new IncompleteCustomerDetailsError()); } } // Throw error on incomplete broker details if (order.BrokerRole != BrokerType.NoBroker && (order.Broker == null || string.IsNullOrWhiteSpace(order.Broker.Name))) { throw new OpenBookingException(new IncompleteBrokerDetailsError()); } // Throw error if TotalPaymentDue is not specified at B or P if (order.TotalPaymentDue?.Price.HasValue != true && (stage == FlowStage.B || stage == FlowStage.P)) { // TODO replace this with a more specific error throw new OpenBookingException(new OpenBookingError(), "TotalPaymentDue must have a price set"); } var payer = order.BrokerRole == BrokerType.ResellerBroker ? order.Broker : order.Customer; return(new BookingFlowContext { Stage = stage, OrderId = orderId, OrderIdTemplate = settings.OrderIdTemplate, Seller = seller, SellerId = sellerIdComponents, TaxPayeeRelationship = taxPayeeRelationship, Payer = payer }); }
protected override async Task <FacilityOpportunity> CreateOpportunityWithinTestDataset( string testDatasetIdentifier, OpportunityType opportunityType, TestOpportunityCriteriaEnumeration criteria, TestOpenBookingFlowEnumeration openBookingFlow, SellerIdComponents seller) { if (!_appSettings.FeatureFlags.SingleSeller && !seller.SellerIdLong.HasValue) { throw new OpenBookingException(new OpenBookingError(), "Seller must have an ID in Multiple Seller Mode"); } long?sellerId = _appSettings.FeatureFlags.SingleSeller ? null : seller.SellerIdLong; var requiresApproval = openBookingFlow == TestOpenBookingFlowEnumeration.OpenBookingApprovalFlow; switch (opportunityType) { case OpportunityType.FacilityUseSlot: int facilityId, slotId; switch (criteria) { case TestOpportunityCriteriaEnumeration.TestOpportunityBookable: case TestOpportunityCriteriaEnumeration.TestOpportunityOfflineBookable: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Facility", rnd.Next(2) == 0? 0M : 14.99M, 10, requiresApproval); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableCancellable: case TestOpportunityCriteriaEnumeration.TestOpportunityBookableNonFree: case TestOpportunityCriteriaEnumeration.TestOpportunityBookableUsingPayment: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Paid Facility", 14.99M, 10, requiresApproval); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableFree: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Free Facility", 0M, 10, requiresApproval); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableWithinValidFromBeforeStartDate: case TestOpportunityCriteriaEnumeration.TestOpportunityBookableOutsideValidFromBeforeStartDate: { var isValid = criteria == TestOpportunityCriteriaEnumeration.TestOpportunityBookableWithinValidFromBeforeStartDate; (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, $"[OPEN BOOKING API TEST INTERFACE] Bookable Paid Facility {(isValid ? "Within" : "Outside")} Window", 14.99M, 10, requiresApproval, validFromStartDate : isValid); } break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableCancellableWithinWindow: case TestOpportunityCriteriaEnumeration.TestOpportunityBookableCancellableOutsideWindow: { var isValid = criteria == TestOpportunityCriteriaEnumeration.TestOpportunityBookableCancellableWithinWindow; (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, $"[OPEN BOOKING API TEST INTERFACE] Bookable Paid Facility {(isValid ? "Within" : "Outside")} Cancellation Window", 14.99M, 10, requiresApproval, latestCancellationBeforeStartDate : isValid); } break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableNonFreePrepaymentOptional: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Paid Facility Prepayment Optional", 14.99M, 10, requiresApproval, prepayment : RequiredStatusType.Optional); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableNonFreePrepaymentUnavailable: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Paid Facility Prepayment Unavailable", 14.99M, 10, requiresApproval, prepayment : RequiredStatusType.Unavailable); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableNonFreePrepaymentRequired: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Paid Facility Prepayment Required", 14.99M, 10, requiresApproval, prepayment : RequiredStatusType.Required); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableNoSpaces: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Free Facility No Spaces", 14.99M, 0, requiresApproval); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableFiveSpaces: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Free Facility Five Spaces", 14.99M, 5, requiresApproval); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableOneSpace: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Free Facility One Space", 14.99M, 1, requiresApproval); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableNonFreeTaxNet: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, 2, "[OPEN BOOKING API TEST INTERFACE] Bookable Paid Facility Tax Net", 14.99M, 10, requiresApproval); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableNonFreeTaxGross: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, 1, "[OPEN BOOKING API TEST INTERFACE] Bookable Paid Facility Tax Gross", 14.99M, 10, requiresApproval); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableSellerTermsOfService: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, 1, "[OPEN BOOKING API TEST INTERFACE] Bookable Facility With Seller Terms Of Service", 14.99M, 10, requiresApproval); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableAttendeeDetails: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, 1, "[OPEN BOOKING API TEST INTERFACE] Bookable Facility That Requires Attendee Details", 14.99M, 10, requiresApproval, requiresAttendeeValidation : true); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableAdditionalDetails: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Paid Facility That Requires Additional Details", 10M, 10, requiresApproval, requiresAdditionalDetails : true); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableWithNegotiation: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Paid Facility That Allows Proposal Amendment", 10M, 10, requiresApproval, allowProposalAmendment : true); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableNotCancellable: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Facility Paid That Does Not Allow Full Refund", 10M, 10, requiresApproval, allowCustomerCancellationFullRefund : false); break; case TestOpportunityCriteriaEnumeration.TestOpportunityBookableInPast: (facilityId, slotId) = await FakeBookingSystem.Database.AddFacility( testDatasetIdentifier, sellerId, "[OPEN BOOKING API TEST INTERFACE] Bookable Facility in the Past", 10M, 10, requiresApproval, allowCustomerCancellationFullRefund : false, inPast : true); break; default: throw new OpenBookingException(new OpenBookingError(), "testOpportunityCriteria value not supported"); } return(new FacilityOpportunity { OpportunityType = opportunityType, FacilityUseId = facilityId, SlotId = slotId }); default: throw new OpenBookingException(new OpenBookingError(), "Opportunity Type not supported"); } }
public abstract Task <Order> ProcessOrderCreationFromOrderProposal(OrderIdComponents orderId, OrderIdTemplate orderIdTemplate, ILegalEntity seller, SellerIdComponents sellerId, Order order);
public abstract Task ProcessOrderProposalCustomerRejection(OrderIdComponents orderId, SellerIdComponents sellerId, OrderIdTemplate orderIdTemplate);
public override async Task <Order> GetOrderStatus(OrderIdComponents orderId, SellerIdComponents sellerId, ILegalEntity seller) { var(getOrderResult, dbOrder, dbOrderItems) = await FakeBookingSystem.Database.GetOrderAndOrderItems( orderId.ClientId, sellerId.SellerIdLong ?? null /* Hack to allow this to work in Single Seller mode too */, orderId.uuid); if (getOrderResult == FakeDatabaseGetOrderResult.OrderWasNotFound) { throw new OpenBookingException(new UnknownOrderError()); } var orderIdUri = RenderOrderId(dbOrder.OrderMode == OrderMode.Proposal ? OrderType.OrderProposal : dbOrder.OrderMode == OrderMode.Lease ? OrderType.OrderQuote : OrderType.Order, new Guid(dbOrder.OrderId)); var orderItems = dbOrderItems.Select((orderItem) => new OrderItem { Id = dbOrder.OrderMode != OrderMode.Lease ? RenderOrderItemId(OrderType.Order, new Guid(dbOrder.OrderId), orderItem.Id) : null, AcceptedOffer = new Offer { Id = orderItem.OfferJsonLdId, Price = orderItem.Price }, OrderedItem = orderItem.OpportunityJsonLdId, OrderItemStatus = orderItem.Status == BookingStatus.Confirmed ? OrderItemStatus.OrderItemConfirmed : orderItem.Status == BookingStatus.CustomerCancelled ? OrderItemStatus.CustomerCancelled : orderItem.Status == BookingStatus.SellerCancelled ? OrderItemStatus.SellerCancelled : orderItem.Status == BookingStatus.Attended ? OrderItemStatus.AttendeeAttended : orderItem.Status == BookingStatus.Absent ? OrderItemStatus.AttendeeAbsent : (OrderItemStatus?)null }).ToList(); var order = RenderOrderFromDatabaseResult(orderIdUri, dbOrder, orderItems); // Map AcceptedOffer from object to IdReference var mappedOrderItems = order.OrderedItem.Select((orderItem) => new OrderItem { Id = orderItem.Id, AcceptedOffer = orderItem.AcceptedOffer.Object.Id, OrderedItem = orderItem.OrderedItem, OrderItemStatus = orderItem.OrderItemStatus }).ToList(); order.OrderedItem = mappedOrderItems; // These additional properties that are only available in the Order Status endpoint or B after P+A order.Seller = new ReferenceValue <ILegalEntity>(seller); order.BrokerRole = BrokerRoleToBrokerType(dbOrder.BrokerRole); order.Broker = order.BrokerRole == BrokerType.NoBroker ? null : new Organization { Name = dbOrder.BrokerName, Url = dbOrder.BrokerUrl, Telephone = dbOrder.BrokerTelephone }; order.BrokerRole = BrokerRoleToBrokerType(dbOrder.BrokerRole); if (dbOrder.CustomerType == CustomerType.Organization) { order.Customer = new Organization { Email = dbOrder.CustomerEmail, Name = dbOrder.CustomerOrganizationName, }; } else if (dbOrder.CustomerType == CustomerType.Person) { order.Customer = new Person { Email = dbOrder.CustomerEmail, Identifier = dbOrder.CustomerIdentifier, GivenName = dbOrder.CustomerGivenName, FamilyName = dbOrder.CustomerFamilyName, Telephone = dbOrder.CustomerTelephone, }; } // Payment Identifier is mandatory for non-free sessions if (dbOrder.PaymentIdentifier != null) { order.Payment = new Payment { Identifier = dbOrder.PaymentIdentifier, PaymentProviderId = dbOrder.PaymentProviderId, AccountId = dbOrder.PaymentAccountId, Name = dbOrder.PaymentName }; } return(order); }
protected abstract Task <Event> InsertTestOpportunity(string testDatasetIdentifier, OpportunityType opportunityType, TestOpportunityCriteriaEnumeration criteria, TestOpenBookingFlowEnumeration openBookingFlow, SellerIdComponents seller);
/// <summary> /// Initiate customer cancellation for the specified OrderItems /// Note sellerId will always be null in Single Seller mode /// </summary> /// <returns>True if Order found, False if Order not found</returns> public override bool CustomerCancelOrderItems(OrderIdComponents orderId, SellerIdComponents sellerId, OrderIdTemplate orderIdTemplate, List <OrderIdComponents> orderItemIds) { //throw new OpenBookingException(new CancellationNotPermittedError()); return(FakeBookingSystem.Database.CancelOrderItem(orderId.ClientId, sellerId.SellerIdLong ?? null /* Hack to allow this to work in Single Seller mode too */, orderId.uuid, orderItemIds.Select(x => x.OrderItemIdLong.Value).ToList(), true)); }