예제 #1
0
        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);
        }
예제 #2
0
        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;
        }
예제 #4
0
        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();
        }
예제 #5
0
        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
            };
        }