private CitationSeverity CalculateSeverity(ITrafficState trafficState, ILegalEntity citee) { int speedDiff = trafficState.IncidentSpeed - trafficState.SpeedLimit; // If it's the citee's birthday, knock 5 MPH off of their speed diff. if (citee.BirthDate.Month == _calendar.CurrentDate.Month && citee.BirthDate.Day == _calendar.CurrentDate.Day) { speedDiff -= 5; } CitationSeverity severity; if (speedDiff > 25) { severity = CitationSeverity.Large; } else if (speedDiff > 10) { severity = CitationSeverity.Medium; } else if (speedDiff > 0) { severity = CitationSeverity.Small; } else { severity = CitationSeverity.None; } return(severity); }
public override IProduct CloneForNewOwner(ILegalEntity owner) { if (!base.Template) { throw new ProductUseException("Owners are not allowed to materialize Products out of nothing!"); } return(new Drink(this, owner)); }
public SpeedingCitation(ICalendarProvider calendar, ITicketer issuer, ILegalEntity citee, CitationSeverity severity) { _calendar = calendar ?? throw new ArgumentNullException(nameof(calendar)); Issuer = issuer ?? throw new ArgumentNullException(nameof(issuer)); Citee = citee ?? throw new ArgumentNullException(nameof(citee)); Severity = severity; CitationDate = _calendar.CurrentDate; }
public IEnumerable <ICitation> IssueCitations(ITrafficState trafficState, ILegalEntity citee) { List <ICitation> citations; citations = TrafficLaws .Where(x => x.ShouldIssueCitation(trafficState, citee)) .Select(x => x.CreateCitation(trafficState, citee, this)) .ToList(); return(citations); }
//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 IEnumerable <IProduct> PackageProductFor(ILegalEntity customer, uint quantity) { var products = new List <IProduct>(); if (quantity > Quantity) { throw new ArgumentOutOfRangeException("You don't have that many stocked!"); } Quantity -= quantity; for (int i = 0; i < quantity; i++) { products.Add(Product.CloneForNewOwner(customer)); } return(products); }
// Note that the order of "Organization, Person" must match the generated properties that accept ILegalEntity public static SingleValues <Organization, Person> GetSingleValues(this ILegalEntity legalEntity) { switch (legalEntity) { case Organization organization: return(organization); case Person person: return(person); case null: return(default); default: throw new InvalidCastException($"Supplied ILegalEntity is of unknown type {legalEntity.GetType().ToString()}"); } }
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); }
//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 Drink(Drink drink, ILegalEntity owner) : base((Product)drink, owner) { }
public abstract IProduct CloneForNewOwner(ILegalEntity owner);
protected Product(Product product, ILegalEntity owner) : this(product.Name, product.Description, product.ManufacturingCost, product.Servings, product.VAT, product.ExtraStoreMarkupFactor, owner) { Template = false; }
public abstract Task <Order> ProcessOrderCreationFromOrderProposal(OrderIdComponents orderId, OrderIdTemplate orderIdTemplate, ILegalEntity seller, SellerIdComponents sellerId, Order order);
public bool ShouldIssueCitation(ITrafficState trafficState, ILegalEntity citee) { var severity = CalculateSeverity(trafficState, citee); return(severity != CitationSeverity.None); }
protected abstract Task <Order> ProcessGetOrderStatus(OrderIdComponents orderId, SellerIdComponents sellerId, ILegalEntity seller);
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); }
public ICitation CreateCitation(ITrafficState trafficState, ILegalEntity citee, ITicketer issuer) { return(new SpeedingCitation(_calendar, issuer, citee, CalculateSeverity(trafficState, citee))); }