public void SellerIdComponents_Null_Equality()
        {
            SellerIdComponents x = null;
            SellerIdComponents y = null;

            Assert.True(x == y);
            Assert.False(x != y);
        }
Ejemplo n.º 2
0
 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());
        }
Ejemplo n.º 8
0
 // 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);
         }
     }
 }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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);
Ejemplo n.º 12
0
        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);
Ejemplo n.º 16
0
 /// <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));
 }
Ejemplo n.º 17
0
 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 */);
 }
Ejemplo n.º 18
0
 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);
 }
Ejemplo n.º 19
0
        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}");
            }
        }
Ejemplo n.º 20
0
        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());
            }
        }
Ejemplo n.º 21
0
 protected abstract Task <DeleteOrderResult> ProcessOrderDeletion(OrderIdComponents orderId, SellerIdComponents sellerId);
Ejemplo n.º 22
0
 protected abstract Task <Order> ProcessGetOrderStatus(OrderIdComponents orderId, SellerIdComponents sellerId, ILegalEntity seller);
Ejemplo n.º 23
0
 /// <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);
     }
 }
Ejemplo n.º 24
0
        //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
            });
        }
Ejemplo n.º 25
0
        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");
            }
        }
Ejemplo n.º 26
0
 public abstract Task <Order> ProcessOrderCreationFromOrderProposal(OrderIdComponents orderId, OrderIdTemplate orderIdTemplate, ILegalEntity seller, SellerIdComponents sellerId, Order order);
Ejemplo n.º 27
0
 public abstract Task ProcessOrderProposalCustomerRejection(OrderIdComponents orderId, SellerIdComponents sellerId, OrderIdTemplate orderIdTemplate);
Ejemplo n.º 28
0
        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);
        }
Ejemplo n.º 29
0
 protected abstract Task <Event> InsertTestOpportunity(string testDatasetIdentifier, OpportunityType opportunityType, TestOpportunityCriteriaEnumeration criteria, TestOpenBookingFlowEnumeration openBookingFlow, SellerIdComponents seller);
Ejemplo n.º 30
0
 /// <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));
 }