public async Task <PriceDataDTO> Calculate(string eventId, [FromBody] CalculateOrderDTO order) { var eventData = await eventsCache.Get(eventId); var price = await orderPriceCalculationFacade.CalculatePriceForOrderAndItems(eventData, order); return(price.TotalPrice); }
private async Task InvalidateDiscountCode(CalculateOrderDTO order) { var result = await discountCodeCollection.FindOneAndUpdateAsync( c => c.Id == order.DiscountCode && c.ClaimedDate == null, Builders <DiscountCode> .Update.Set(c => c.ClaimedDate, DateTime.UtcNow)); if (result == null) { throw new InvalidDiscountCodeException(); } }
private decimal DetermineVat(CalculateOrderDTO order, DateTime now) { if (!string.IsNullOrEmpty(order.BillingAddress.VatNumber)) { // validate VAT if (!vatNumberValidator.IsValidVat(order.BillingAddress)) { throw new InvalidVATException(); } } var vatRate = vatRateProvider.GetVatRate(now, order.BillingAddress); return vatRate; }
public async Task ApplyDiscount(EventDTO eventData, CalculateOrderDTO order, List <PriceDataDTO> orderItemPrices, bool invalidateDiscountCoupon) { // get discount code var discountCode = await discountCodeCollection.FindByIdAsync(order.DiscountCode); if (discountCode == null || discountCode.ExpirationDate < DateTime.UtcNow || discountCode.ClaimedDate != null) { throw new InvalidDiscountCodeException(); } // apply to products for (int i = 0; i < order.OrderItems.Count; i++) { var orderItem = order.OrderItems[i]; var orderItemPrice = orderItemPrices[i]; // try to find an applicable rule var rule = discountCode.Rules.FirstOrDefault(r => r.ApplicableSku.Contains(orderItem.Sku)); if (rule != null) { // apply the rule var applicableAmount = Math.Min(orderItem.Amount, rule.MaxAmount); var discountPrice = CalculateDiscountPrice(rule, orderItemPrice); // add the discount order line order.OrderItems.Add(new CalculateOrderItemDTO() { Sku = Constants.DiscountSku, Amount = applicableAmount }); orderItemPrices.Add(new PriceDataDTO() { BasePrice = -discountPrice, CurrencyCode = orderItemPrice.CurrencyCode, Price = OrderPriceCalculationFacade.Round(-discountPrice * applicableAmount) }); if (invalidateDiscountCoupon) { // claim discount code await InvalidateDiscountCode(order); } return; } } throw new InvalidDiscountCodeException(); }
public async Task Recalculate() { var calculationData = new CalculateOrderDTO() { BillingAddress = new CalculateAddressDTO() { CountryCode = Order.BillingAddress.CountryCode, VatNumber = Order.BillingAddress.VatNumber }, OrderItems = new ObservableCollection <CalculateOrderItemDTO>(Order.OrderItems.Select(i => new CalculateOrderItemDTO() { Amount = 1, Sku = i.Sku })) }; var result = await ordersApi.ApiOrdersCalculateByEventIdPostAsync(EventId, calculationData); TotalPrice = $"{result.Price:n0} {result.CurrencyCode}"; TotalPriceInclVat = $"{result.PriceInclVat:n0} {result.CurrencyCode}"; }
private List<PriceDataDTO> CalculateItemPrices(EventDTO eventData, CalculateOrderDTO order, DateTime now) { var orderItemPrices = new List<PriceDataDTO>(); foreach (var i in order.OrderItems) { var eventPrice = eventData.Prices.SingleOrDefault(p => p.BeginDate <= now && now < p.EndDate && p.Sku == i.Sku); if (eventPrice == null) { throw new InvalidSkuException(); } var orderItemPrice = new PriceDataDTO(); orderItemPrice.BasePrice = (decimal) eventPrice.Price.Value; orderItemPrice.CurrencyCode = eventPrice.CurrencyCode; orderItemPrice.Price = Round(i.Amount * orderItemPrice.BasePrice); orderItemPrices.Add(orderItemPrice); } return orderItemPrices; }
public async Task<CalculateOrderResultDTO> CalculatePriceForOrderAndItems(EventDTO eventData, CalculateOrderDTO order, bool invalidateDiscountCoupon = false) { var now = dateTimeProvider.Now; // calculate prices for order items var orderItemPrices = CalculateItemPrices(eventData, order, now); // validate there is only one currency if (orderItemPrices.Select(p => p.CurrencyCode).Distinct().Count() > 1) { throw new OrderItemsMustUseTheSameCurrencyException(); } // apply discount if (!string.IsNullOrEmpty(order.DiscountCode)) { await orderDiscountFacade.ApplyDiscount(eventData, order, orderItemPrices, invalidateDiscountCoupon); } // get current VAT rate var vatRate = DetermineVat(order, now); // apply VAT ApplyVat(orderItemPrices, vatRate); // calculate total for order var totalPrice = new PriceDataDTO() { BasePrice = Round(orderItemPrices.Sum(p => p.BasePrice)), Price = Round(orderItemPrices.Sum(p => p.Price)), VatRate = vatRate, PriceInclVat = Round(orderItemPrices.Sum(p => p.PriceInclVat)), CurrencyCode = orderItemPrices.First().CurrencyCode }; return new CalculateOrderResultDTO() { TotalPrice = totalPrice, OrderItemPrices = orderItemPrices }; }