/// <summary> /// Update order totals /// </summary> /// <param name="updateOrderParameters">Parameters for the updating order</param> public virtual void UpdateOrderTotals(UpdateOrderParameters updateOrderParameters) { if (!_orderSettings.AutoUpdateOrderTotalsOnEditingOrder) return; var updatedOrder = updateOrderParameters.UpdatedOrder; var updatedOrderItem = updateOrderParameters.UpdatedOrderItem; //restore shopping cart from order items var restoredCart = updatedOrder.OrderItems.Select(orderItem => new ShoppingCartItem { Id = orderItem.Id, AttributesXml = orderItem.AttributesXml, Customer = updatedOrder.Customer, Product = orderItem.Product, Quantity = orderItem.Id == updatedOrderItem.Id ? updateOrderParameters.Quantity : orderItem.Quantity, RentalEndDateUtc = orderItem.RentalEndDateUtc, RentalStartDateUtc = orderItem.RentalStartDateUtc, ShoppingCartType = ShoppingCartType.ShoppingCart, StoreId = updatedOrder.StoreId }).ToList(); //get shopping cart item which has been updated var updatedShoppingCartItem = restoredCart.FirstOrDefault(shoppingCartItem => shoppingCartItem.Id == updatedOrderItem.Id); var itemDeleted = updatedShoppingCartItem == null; //validate shopping cart for warnings updateOrderParameters.Warnings.AddRange(_shoppingCartService.GetShoppingCartWarnings(restoredCart, string.Empty, false)); if (!itemDeleted) updateOrderParameters.Warnings.AddRange(_shoppingCartService.GetShoppingCartItemWarnings(updatedOrder.Customer, updatedShoppingCartItem.ShoppingCartType, updatedShoppingCartItem.Product, updatedOrder.StoreId, updatedShoppingCartItem.AttributesXml, updatedShoppingCartItem.CustomerEnteredPrice, updatedShoppingCartItem.RentalStartDateUtc, updatedShoppingCartItem.RentalEndDateUtc, updatedShoppingCartItem.Quantity, false)); _orderTotalCalculationService.UpdateOrderTotals(updateOrderParameters, restoredCart); if (updateOrderParameters.PickupPoint != null) { updatedOrder.PickUpInStore = true; updatedOrder.PickupAddress = new Address { Address1 = updateOrderParameters.PickupPoint.Address, City = updateOrderParameters.PickupPoint.City, Country = _countryService.GetCountryByTwoLetterIsoCode(updateOrderParameters.PickupPoint.CountryCode), ZipPostalCode = updateOrderParameters.PickupPoint.ZipPostalCode, CreatedOnUtc = DateTime.UtcNow, }; updatedOrder.ShippingMethod = string.Format(_localizationService.GetResource("Checkout.PickupPoints.Name"), updateOrderParameters.PickupPoint.Name); updatedOrder.ShippingRateComputationMethodSystemName = updateOrderParameters.PickupPoint.ProviderSystemName; } if (!itemDeleted) { updatedOrderItem.ItemWeight = _shippingService.GetShoppingCartItemWeight(updatedShoppingCartItem); updatedOrderItem.OriginalProductCost = _priceCalculationService.GetProductCost(updatedShoppingCartItem.Product, updatedShoppingCartItem.AttributesXml); updatedOrderItem.AttributeDescription = _productAttributeFormatter.FormatAttributes(updatedShoppingCartItem.Product, updatedShoppingCartItem.AttributesXml, updatedOrder.Customer); //gift cards if (updatedShoppingCartItem.Product.IsGiftCard) { string giftCardRecipientName; string giftCardRecipientEmail; string giftCardSenderName; string giftCardSenderEmail; string giftCardMessage; _productAttributeParser.GetGiftCardAttribute(updatedShoppingCartItem.AttributesXml, out giftCardRecipientName, out giftCardRecipientEmail, out giftCardSenderName, out giftCardSenderEmail, out giftCardMessage); for (var i = 0; i < updatedShoppingCartItem.Quantity; i++) { _giftCardService.InsertGiftCard(new GiftCard { GiftCardType = updatedShoppingCartItem.Product.GiftCardType, PurchasedWithOrderItem = updatedOrderItem, Amount = updatedShoppingCartItem.Product.OverriddenGiftCardAmount.HasValue ? updatedShoppingCartItem.Product.OverriddenGiftCardAmount.Value : updatedOrderItem.UnitPriceExclTax, IsGiftCardActivated = false, GiftCardCouponCode = _giftCardService.GenerateGiftCardCode(), RecipientName = giftCardRecipientName, RecipientEmail = giftCardRecipientEmail, SenderName = giftCardSenderName, SenderEmail = giftCardSenderEmail, Message = giftCardMessage, IsRecipientNotified = false, CreatedOnUtc = DateTime.UtcNow }); } } } _orderService.UpdateOrder(updatedOrder); //discount usage history var discountUsageHistoryForOrder = _discountService.GetAllDiscountUsageHistory(null, updatedOrder.Customer.Id, updatedOrder.Id); foreach (var discount in updateOrderParameters.AppliedDiscounts) { if (!discountUsageHistoryForOrder.Where(history => history.DiscountId == discount.Id).Any()) _discountService.InsertDiscountUsageHistory(new DiscountUsageHistory { Discount = discount, Order = updatedOrder, CreatedOnUtc = DateTime.UtcNow }); } CheckOrderStatus(updatedOrder); }
public ActionResult AddProductToOrderDetails(int orderId, int productId, FormCollection form) { if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) return AccessDeniedView(); //a vendor does not have access to this functionality if (_workContext.CurrentVendor != null) return RedirectToAction("Edit", "Order", new { id = orderId }); var order = _orderService.GetOrderById(orderId); var product = _productService.GetProductById(productId); //save order item //basic properties decimal unitPriceInclTax; decimal.TryParse(form["UnitPriceInclTax"], out unitPriceInclTax); decimal unitPriceExclTax; decimal.TryParse(form["UnitPriceExclTax"], out unitPriceExclTax); int quantity; int.TryParse(form["Quantity"], out quantity); decimal priceInclTax; decimal.TryParse(form["SubTotalInclTax"], out priceInclTax); decimal priceExclTax; decimal.TryParse(form["SubTotalExclTax"], out priceExclTax); //warnings var warnings = new List<string>(); //attributes var attributesXml = ParseProductAttributes(product, form); #region Gift cards string recipientName = ""; string recipientEmail = ""; string senderName = ""; string senderEmail = ""; string giftCardMessage = ""; if (product.IsGiftCard) { foreach (string formKey in form.AllKeys) { if (formKey.Equals("giftcard.RecipientName", StringComparison.InvariantCultureIgnoreCase)) { recipientName = form[formKey]; continue; } if (formKey.Equals("giftcard.RecipientEmail", StringComparison.InvariantCultureIgnoreCase)) { recipientEmail = form[formKey]; continue; } if (formKey.Equals("giftcard.SenderName", StringComparison.InvariantCultureIgnoreCase)) { senderName = form[formKey]; continue; } if (formKey.Equals("giftcard.SenderEmail", StringComparison.InvariantCultureIgnoreCase)) { senderEmail = form[formKey]; continue; } if (formKey.Equals("giftcard.Message", StringComparison.InvariantCultureIgnoreCase)) { giftCardMessage = form[formKey]; continue; } } attributesXml = _productAttributeParser.AddGiftCardAttribute(attributesXml, recipientName, recipientEmail, senderName, senderEmail, giftCardMessage); } #endregion #region Rental product DateTime? rentalStartDate = null; DateTime? rentalEndDate = null; if (product.IsRental) { ParseRentalDates(form, out rentalStartDate, out rentalEndDate); } #endregion //warnings warnings.AddRange(_shoppingCartService.GetShoppingCartItemAttributeWarnings(order.Customer, ShoppingCartType.ShoppingCart, product, quantity, attributesXml)); warnings.AddRange(_shoppingCartService.GetShoppingCartItemGiftCardWarnings(ShoppingCartType.ShoppingCart, product, attributesXml)); warnings.AddRange(_shoppingCartService.GetRentalProductWarnings(product, rentalStartDate, rentalEndDate)); if (!warnings.Any()) { //no errors //attributes var attributeDescription = _productAttributeFormatter.FormatAttributes(product, attributesXml, order.Customer); //save item var orderItem = new OrderItem { OrderItemGuid = Guid.NewGuid(), Order = order, ProductId = product.Id, UnitPriceInclTax = unitPriceInclTax, UnitPriceExclTax = unitPriceExclTax, PriceInclTax = priceInclTax, PriceExclTax = priceExclTax, OriginalProductCost = _priceCalculationService.GetProductCost(product, attributesXml), AttributeDescription = attributeDescription, AttributesXml = attributesXml, Quantity = quantity, DiscountAmountInclTax = decimal.Zero, DiscountAmountExclTax = decimal.Zero, DownloadCount = 0, IsDownloadActivated = false, LicenseDownloadId = 0, RentalStartDateUtc = rentalStartDate, RentalEndDateUtc = rentalEndDate }; order.OrderItems.Add(orderItem); _orderService.UpdateOrder(order); //adjust inventory _productService.AdjustInventory(orderItem.Product, -orderItem.Quantity, orderItem.AttributesXml); //update order totals var updateOrderParameters = new UpdateOrderParameters { UpdatedOrder = order, UpdatedOrderItem = orderItem, PriceInclTax = unitPriceInclTax, PriceExclTax = unitPriceExclTax, SubTotalInclTax = priceInclTax, SubTotalExclTax = priceExclTax, Quantity = quantity }; _orderProcessingService.UpdateOrderTotals(updateOrderParameters); //add a note order.OrderNotes.Add(new OrderNote { Note = "A new order item has been added", DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); _orderService.UpdateOrder(order); LogEditOrder(order.Id); //gift cards if (product.IsGiftCard) { for (int i = 0; i < orderItem.Quantity; i++) { var gc = new GiftCard { GiftCardType = product.GiftCardType, PurchasedWithOrderItem = orderItem, Amount = unitPriceExclTax, IsGiftCardActivated = false, GiftCardCouponCode = _giftCardService.GenerateGiftCardCode(), RecipientName = recipientName, RecipientEmail = recipientEmail, SenderName = senderName, SenderEmail = senderEmail, Message = giftCardMessage, IsRecipientNotified = false, CreatedOnUtc = DateTime.UtcNow }; _giftCardService.InsertGiftCard(gc); } } //redirect to order details page TempData["nop.admin.order.warnings"] = updateOrderParameters.Warnings; return RedirectToAction("Edit", "Order", new { id = order.Id }); } //errors var model = PrepareAddProductToOrderModel(order.Id, product.Id); model.Warnings.AddRange(warnings); return View(model); }
public ActionResult DeleteOrderItem(int id, FormCollection form) { if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) return AccessDeniedView(); var order = _orderService.GetOrderById(id); if (order == null) //No order found with the specified id return RedirectToAction("List"); //a vendor does not have access to this functionality if (_workContext.CurrentVendor != null) return RedirectToAction("Edit", "Order", new { id = id }); //get order item identifier int orderItemId = 0; foreach (var formValue in form.AllKeys) if (formValue.StartsWith("btnDeleteOrderItem", StringComparison.InvariantCultureIgnoreCase)) orderItemId = Convert.ToInt32(formValue.Substring("btnDeleteOrderItem".Length)); var orderItem = order.OrderItems.FirstOrDefault(x => x.Id == orderItemId); if (orderItem == null) throw new ArgumentException("No order item found with the specified id"); if (_giftCardService.GetGiftCardsByPurchasedWithOrderItemId(orderItem.Id).Any()) { //we cannot delete an order item with associated gift cards //a store owner should delete them first var model = new OrderModel(); PrepareOrderDetailsModel(model, order); ErrorNotification("This order item has an associated gift card record. Please delete it first.", false); //selected tab SaveSelectedTabName(persistForTheNextRequest: false); return View(model); } else { //adjust inventory _productService.AdjustInventory(orderItem.Product, orderItem.Quantity, orderItem.AttributesXml); //delete item _orderService.DeleteOrderItem(orderItem); //update order totals var updateOrderParameters = new UpdateOrderParameters { UpdatedOrder = order, UpdatedOrderItem = orderItem }; _orderProcessingService.UpdateOrderTotals(updateOrderParameters); //add a note order.OrderNotes.Add(new OrderNote { Note = "Order item has been deleted", DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); _orderService.UpdateOrder(order); LogEditOrder(order.Id); var model = new OrderModel(); PrepareOrderDetailsModel(model, order); model.Warnings = updateOrderParameters.Warnings; //selected tab SaveSelectedTabName(persistForTheNextRequest: false); return View(model); } }
public ActionResult EditOrderItem(int id, FormCollection form) { if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders)) return AccessDeniedView(); var order = _orderService.GetOrderById(id); if (order == null) //No order found with the specified id return RedirectToAction("List"); //a vendor does not have access to this functionality if (_workContext.CurrentVendor != null) return RedirectToAction("Edit", "Order", new { id = id }); //get order item identifier int orderItemId = 0; foreach (var formValue in form.AllKeys) if (formValue.StartsWith("btnSaveOrderItem", StringComparison.InvariantCultureIgnoreCase)) orderItemId = Convert.ToInt32(formValue.Substring("btnSaveOrderItem".Length)); var orderItem = order.OrderItems.FirstOrDefault(x => x.Id == orderItemId); if (orderItem == null) throw new ArgumentException("No order item found with the specified id"); decimal unitPriceInclTax, unitPriceExclTax, discountInclTax, discountExclTax,priceInclTax,priceExclTax; int quantity; if (!decimal.TryParse(form["pvUnitPriceInclTax" + orderItemId], out unitPriceInclTax)) unitPriceInclTax = orderItem.UnitPriceInclTax; if (!decimal.TryParse(form["pvUnitPriceExclTax" + orderItemId], out unitPriceExclTax)) unitPriceExclTax = orderItem.UnitPriceExclTax; if (!int.TryParse(form["pvQuantity" + orderItemId], out quantity)) quantity = orderItem.Quantity; if (!decimal.TryParse(form["pvDiscountInclTax" + orderItemId], out discountInclTax)) discountInclTax = orderItem.DiscountAmountInclTax; if (!decimal.TryParse(form["pvDiscountExclTax" + orderItemId], out discountExclTax)) discountExclTax = orderItem.DiscountAmountExclTax; if (!decimal.TryParse(form["pvPriceInclTax" + orderItemId], out priceInclTax)) priceInclTax = orderItem.PriceInclTax; if (!decimal.TryParse(form["pvPriceExclTax" + orderItemId], out priceExclTax)) priceExclTax = orderItem.PriceExclTax; if (quantity > 0) { int qtyDifference = orderItem.Quantity - quantity; if (!_orderSettings.AutoUpdateOrderTotalsOnEditingOrder) { orderItem.UnitPriceInclTax = unitPriceInclTax; orderItem.UnitPriceExclTax = unitPriceExclTax; orderItem.Quantity = quantity; orderItem.DiscountAmountInclTax = discountInclTax; orderItem.DiscountAmountExclTax = discountExclTax; orderItem.PriceInclTax = priceInclTax; orderItem.PriceExclTax = priceExclTax; _orderService.UpdateOrder(order); } //adjust inventory _productService.AdjustInventory(orderItem.Product, qtyDifference, orderItem.AttributesXml); } else { //adjust inventory _productService.AdjustInventory(orderItem.Product, orderItem.Quantity, orderItem.AttributesXml); //delete item _orderService.DeleteOrderItem(orderItem); } //update order totals var updateOrderParameters = new UpdateOrderParameters { UpdatedOrder = order, UpdatedOrderItem = orderItem, PriceInclTax = unitPriceInclTax, PriceExclTax = unitPriceExclTax, DiscountAmountInclTax = discountInclTax, DiscountAmountExclTax = discountExclTax, SubTotalInclTax = priceInclTax, SubTotalExclTax = priceExclTax, Quantity = quantity }; _orderProcessingService.UpdateOrderTotals(updateOrderParameters); //add a note order.OrderNotes.Add(new OrderNote { Note = "Order item has been edited", DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); _orderService.UpdateOrder(order); LogEditOrder(order.Id); var model = new OrderModel(); PrepareOrderDetailsModel(model, order); model.Warnings = updateOrderParameters.Warnings; //selected tab SaveSelectedTabName(persistForTheNextRequest: false); return View(model); }
/// <summary> /// Update order totals /// </summary> /// <param name="updateOrderParameters">Parameters for the updating order</param> /// <param name="restoredCart">Shopping cart</param> public virtual void UpdateOrderTotals(UpdateOrderParameters updateOrderParameters, IList<ShoppingCartItem> restoredCart) { var updatedOrder = updateOrderParameters.UpdatedOrder; var updatedOrderItem = updateOrderParameters.UpdatedOrderItem; //get the customer var customer = restoredCart.GetCustomer(); #region Sub total var subTotalExclTax = decimal.Zero; var subTotalInclTax = decimal.Zero; var subTotalTaxRates = new SortedDictionary<decimal, decimal>(); foreach (var shoppingCartItem in restoredCart) { var itemSubTotalExclTax = decimal.Zero; var itemSubTotalInclTax = decimal.Zero; var taxRate = decimal.Zero; var itemDiscounts = new List<Discount>(); //calculate subtotal for the updated order item if (shoppingCartItem.Id == updatedOrderItem.Id) { //update order item updatedOrderItem.UnitPriceExclTax = updateOrderParameters.PriceExclTax; updatedOrderItem.UnitPriceInclTax = updateOrderParameters.PriceInclTax; updatedOrderItem.DiscountAmountExclTax = updateOrderParameters.DiscountAmountExclTax; updatedOrderItem.DiscountAmountInclTax = updateOrderParameters.DiscountAmountInclTax; updatedOrderItem.PriceExclTax = itemSubTotalExclTax = updateOrderParameters.SubTotalExclTax; updatedOrderItem.PriceInclTax = itemSubTotalInclTax = updateOrderParameters.SubTotalInclTax; updatedOrderItem.Quantity = shoppingCartItem.Quantity; taxRate = Math.Round((100 * (itemSubTotalInclTax - itemSubTotalExclTax)) / itemSubTotalExclTax, 3); } else { //get the already calculated subtotal from the order item itemSubTotalExclTax = updatedOrder.OrderItems.FirstOrDefault(item => item.Id == shoppingCartItem.Id).PriceExclTax; itemSubTotalInclTax = updatedOrder.OrderItems.FirstOrDefault(item => item.Id == shoppingCartItem.Id).PriceInclTax; taxRate = Math.Round((100 * (itemSubTotalInclTax - itemSubTotalExclTax)) / itemSubTotalExclTax, 3); } foreach (var discount in itemDiscounts) if (!updateOrderParameters.AppliedDiscounts.ContainsDiscount(discount)) updateOrderParameters.AppliedDiscounts.Add(discount); subTotalExclTax += itemSubTotalExclTax; subTotalInclTax += itemSubTotalInclTax; //tax rates var itemTaxValue = itemSubTotalInclTax - itemSubTotalExclTax; if (taxRate > decimal.Zero && itemTaxValue > decimal.Zero) { if (!subTotalTaxRates.ContainsKey(taxRate)) subTotalTaxRates.Add(taxRate, itemTaxValue); else subTotalTaxRates[taxRate] = subTotalTaxRates[taxRate] + itemTaxValue; } } if (subTotalExclTax < decimal.Zero) subTotalExclTax = decimal.Zero; if (subTotalInclTax < decimal.Zero) subTotalInclTax = decimal.Zero; //We calculate discount amount on order subtotal excl tax (discount first) //calculate discount amount ('Applied to order subtotal' discount) List<Discount> subTotalDiscounts; var discountAmountExclTax = GetOrderSubtotalDiscount(customer, subTotalExclTax, out subTotalDiscounts); if (subTotalExclTax < discountAmountExclTax) discountAmountExclTax = subTotalExclTax; var discountAmountInclTax = discountAmountExclTax; //add tax for shopping items var tempTaxRates = new Dictionary<decimal, decimal>(subTotalTaxRates); foreach (var kvp in tempTaxRates) { if (kvp.Value != decimal.Zero && subTotalExclTax > decimal.Zero) { var discountTaxValue = kvp.Value * (discountAmountExclTax / subTotalExclTax); discountAmountInclTax += discountTaxValue; subTotalTaxRates[kvp.Key] = kvp.Value - discountTaxValue; } } //rounding if (_shoppingCartSettings.RoundPricesDuringCalculation) { subTotalExclTax = RoundingHelper.RoundPrice(subTotalExclTax); subTotalInclTax = RoundingHelper.RoundPrice(subTotalInclTax); discountAmountExclTax = RoundingHelper.RoundPrice(discountAmountExclTax); discountAmountInclTax = RoundingHelper.RoundPrice(discountAmountInclTax); } updatedOrder.OrderSubtotalExclTax = subTotalExclTax; updatedOrder.OrderSubtotalInclTax = subTotalInclTax; updatedOrder.OrderSubTotalDiscountExclTax = discountAmountExclTax; updatedOrder.OrderSubTotalDiscountInclTax = discountAmountInclTax; foreach (var discount in subTotalDiscounts) if (!updateOrderParameters.AppliedDiscounts.ContainsDiscount(discount)) updateOrderParameters.AppliedDiscounts.Add(discount); #endregion #region Shipping var shippingTotalExclTax = decimal.Zero; var shippingTotalInclTax = decimal.Zero; var shippingTaxRate = decimal.Zero; if (restoredCart.RequiresShipping()) { if (!IsFreeShipping(restoredCart, _shippingSettings.FreeShippingOverXIncludingTax ? subTotalInclTax : subTotalExclTax)) { var shippingTotal = decimal.Zero; if (!string.IsNullOrEmpty(updatedOrder.ShippingRateComputationMethodSystemName)) { //in the updated order were shipping items if (updatedOrder.PickUpInStore) { //customer chose pickup in store method, try to get chosen pickup point if (_shippingSettings.AllowPickUpInStore) { var pickupPointsResponse = _shippingService.GetPickupPoints(updatedOrder.BillingAddress, updatedOrder.ShippingRateComputationMethodSystemName, _storeContext.CurrentStore.Id); if (pickupPointsResponse.Success) { var selectedPickupPoint = pickupPointsResponse.PickupPoints.FirstOrDefault(point => updatedOrder.ShippingMethod.Contains(point.Name)); if (selectedPickupPoint != null) shippingTotal = selectedPickupPoint.PickupFee; else updateOrderParameters.Warnings.Add(string.Format("Shipping method {0} could not be loaded", updatedOrder.ShippingMethod)); } else updateOrderParameters.Warnings.AddRange(pickupPointsResponse.Errors); } else updateOrderParameters.Warnings.Add("Pick up in store is not available"); } else { //customer chose shipping to address, try to get chosen shipping option var shippingOptionsResponse = _shippingService.GetShippingOptions(restoredCart, updatedOrder.ShippingAddress, updatedOrder.ShippingRateComputationMethodSystemName, _storeContext.CurrentStore.Id); if (shippingOptionsResponse.Success) { var shippingOption = shippingOptionsResponse.ShippingOptions.FirstOrDefault(option => updatedOrder.ShippingMethod.Contains(option.Name)); if (shippingOption != null) shippingTotal = shippingOption.Rate; else updateOrderParameters.Warnings.Add(string.Format("Shipping method {0} could not be loaded", updatedOrder.ShippingMethod)); } else updateOrderParameters.Warnings.AddRange(shippingOptionsResponse.Errors); } } else { //before updating order was without shipping if (_shippingSettings.AllowPickUpInStore) { //try to get the cheapest pickup point var pickupPointsResponse = _shippingService.GetPickupPoints(updatedOrder.BillingAddress, null, _storeContext.CurrentStore.Id); if (pickupPointsResponse.Success) { updateOrderParameters.PickupPoint = pickupPointsResponse.PickupPoints.OrderBy(point => point.PickupFee).First(); shippingTotal = updateOrderParameters.PickupPoint.PickupFee; } else updateOrderParameters.Warnings.AddRange(pickupPointsResponse.Errors); } else updateOrderParameters.Warnings.Add("Pick up in store is not available"); if (updateOrderParameters.PickupPoint == null) { //or try to get the cheapest shipping option for the shipping to the customer address var shippingRateComputationMethods = _shippingService.LoadActiveShippingRateComputationMethods(_storeContext.CurrentStore.Id); if (shippingRateComputationMethods.Any()) { var shippingOptionsResponse = _shippingService.GetShippingOptions(restoredCart, customer.ShippingAddress, null, _storeContext.CurrentStore.Id); if (shippingOptionsResponse.Success) { var shippingOption = shippingOptionsResponse.ShippingOptions.OrderBy(option => option.Rate).First(); updatedOrder.ShippingRateComputationMethodSystemName = shippingOption.ShippingRateComputationMethodSystemName; updatedOrder.ShippingMethod = shippingOption.Name; updatedOrder.ShippingAddress = (Address)customer.ShippingAddress.Clone(); shippingTotal = shippingOption.Rate; } else updateOrderParameters.Warnings.AddRange(shippingOptionsResponse.Errors); } else updateOrderParameters.Warnings.Add("Shipping rate computation method could not be loaded"); } } //additional shipping charge shippingTotal += restoredCart.Where(item => item.IsShipEnabled && !item.IsFreeShipping).Sum(item => item.Product.AdditionalShippingCharge); //shipping discounts List<Discount> shippingTotalDiscounts; shippingTotal -= GetShippingDiscount(customer, shippingTotal, out shippingTotalDiscounts); if (shippingTotal < decimal.Zero) shippingTotal = decimal.Zero; shippingTotalExclTax = _taxService.GetShippingPrice(shippingTotal, false, customer); shippingTotalInclTax = _taxService.GetShippingPrice(shippingTotal, true, customer, out shippingTaxRate); //rounding if (_shoppingCartSettings.RoundPricesDuringCalculation) { shippingTotalExclTax = RoundingHelper.RoundPrice(shippingTotalExclTax); shippingTotalInclTax = RoundingHelper.RoundPrice(shippingTotalInclTax); } //change shipping status if (updatedOrder.ShippingStatus == ShippingStatus.ShippingNotRequired || updatedOrder.ShippingStatus == ShippingStatus.NotYetShipped) updatedOrder.ShippingStatus = ShippingStatus.NotYetShipped; else updatedOrder.ShippingStatus = ShippingStatus.PartiallyShipped; foreach (var discount in shippingTotalDiscounts) if (!updateOrderParameters.AppliedDiscounts.ContainsDiscount(discount)) updateOrderParameters.AppliedDiscounts.Add(discount); } } else updatedOrder.ShippingStatus = ShippingStatus.ShippingNotRequired; updatedOrder.OrderShippingExclTax = shippingTotalExclTax; updatedOrder.OrderShippingInclTax = shippingTotalInclTax; #endregion #region Tax rates var taxRates = new SortedDictionary<decimal, decimal>(); //order subtotal taxes var subTotalTax = decimal.Zero; foreach (var kvp in subTotalTaxRates) { subTotalTax += kvp.Value; if (kvp.Key > decimal.Zero && kvp.Value > decimal.Zero) { if (!taxRates.ContainsKey(kvp.Key)) taxRates.Add(kvp.Key, kvp.Value); else taxRates[kvp.Key] = taxRates[kvp.Key] + kvp.Value; } } //shipping taxes var shippingTax = decimal.Zero; if (_taxSettings.ShippingIsTaxable) { shippingTax = shippingTotalInclTax - shippingTotalExclTax; if (shippingTax < decimal.Zero) shippingTax = decimal.Zero; if (shippingTaxRate > decimal.Zero && shippingTax > decimal.Zero) { if (!taxRates.ContainsKey(shippingTaxRate)) taxRates.Add(shippingTaxRate, shippingTax); else taxRates[shippingTaxRate] = taxRates[shippingTaxRate] + shippingTax; } } //payment method additional fee tax var paymentMethodAdditionalFeeTax = decimal.Zero; if (_taxSettings.PaymentMethodAdditionalFeeIsTaxable) { paymentMethodAdditionalFeeTax = updatedOrder.PaymentMethodAdditionalFeeInclTax - updatedOrder.PaymentMethodAdditionalFeeExclTax; if (paymentMethodAdditionalFeeTax < decimal.Zero) paymentMethodAdditionalFeeTax = decimal.Zero; if (updatedOrder.PaymentMethodAdditionalFeeExclTax > decimal.Zero) { var paymentTaxRate = Math.Round(100 * paymentMethodAdditionalFeeTax / updatedOrder.PaymentMethodAdditionalFeeExclTax, 3); if (paymentTaxRate > decimal.Zero && paymentMethodAdditionalFeeTax > decimal.Zero) { if (!taxRates.ContainsKey(paymentTaxRate)) taxRates.Add(paymentTaxRate, paymentMethodAdditionalFeeTax); else taxRates[paymentTaxRate] = taxRates[paymentTaxRate] + paymentMethodAdditionalFeeTax; } } } //add at least one tax rate (0%) if (!taxRates.Any()) taxRates.Add(decimal.Zero, decimal.Zero); //summarize taxes var taxTotal = subTotalTax + shippingTax + paymentMethodAdditionalFeeTax; if (taxTotal < decimal.Zero) taxTotal = decimal.Zero; //round tax if (_shoppingCartSettings.RoundPricesDuringCalculation) taxTotal = RoundingHelper.RoundPrice(taxTotal); updatedOrder.OrderTax = taxTotal; updatedOrder.TaxRates = taxRates.Aggregate(string.Empty, (current, next) => string.Format("{0}{1}:{2}; ", current, next.Key.ToString(CultureInfo.InvariantCulture), next.Value.ToString(CultureInfo.InvariantCulture))); #endregion #region Total var total = (subTotalExclTax - discountAmountExclTax) + shippingTotalExclTax + updatedOrder.PaymentMethodAdditionalFeeExclTax + taxTotal; //get discounts for the order total List<Discount> orderAppliedDiscounts; var discountAmountTotal = GetOrderTotalDiscount(customer, total, out orderAppliedDiscounts); if (total < discountAmountTotal) discountAmountTotal = total; total -= discountAmountTotal; //applied giftcards foreach (var giftCard in _giftCardService.GetAllGiftCards(usedWithOrderId: updatedOrder.Id)) { if (total > decimal.Zero) { var remainingAmount = giftCard.GiftCardUsageHistory.Where(history => history.UsedWithOrderId == updatedOrder.Id).Sum(history => history.UsedValue); var amountCanBeUsed = total > remainingAmount ? remainingAmount : total; total -= amountCanBeUsed; } } //reward points var rewardPointsOfOrder = _rewardPointService.GetRewardPointsHistory(customer.Id, true).FirstOrDefault(history => history.UsedWithOrder == updatedOrder); if (rewardPointsOfOrder != null) { var rewardPoints = -rewardPointsOfOrder.Points; var rewardPointsAmount = ConvertRewardPointsToAmount(rewardPoints); if (total < rewardPointsAmount) { rewardPoints = ConvertAmountToRewardPoints(total); rewardPointsAmount = total; } if (total > decimal.Zero) total -= rewardPointsAmount; //uncomment here for the return unused reward points if new order total less redeemed reward points amount //if (rewardPoints < -rewardPointsOfOrder.Points) // _rewardPointService.AddRewardPointsHistoryEntry(customer, -rewardPointsOfOrder.Points - rewardPoints, _storeContext.CurrentStore.Id, "Return unused reward points"); if (rewardPointsAmount != rewardPointsOfOrder.UsedAmount) { rewardPointsOfOrder.UsedAmount = rewardPointsAmount; rewardPointsOfOrder.Points = -rewardPoints; _rewardPointService.UpdateRewardPointsHistoryEntry(rewardPointsOfOrder); } } //rounding if (total < decimal.Zero) total = decimal.Zero; if (_shoppingCartSettings.RoundPricesDuringCalculation) total = RoundingHelper.RoundPrice(total); updatedOrder.OrderDiscount = discountAmountTotal; updatedOrder.OrderTotal = total; foreach (var discount in orderAppliedDiscounts) if (!updateOrderParameters.AppliedDiscounts.ContainsDiscount(discount)) updateOrderParameters.AppliedDiscounts.Add(discount); #endregion }
/// <summary> /// Update order totals /// </summary> /// <param name="updateOrderParameters">Parameters for the updating order</param> /// <param name="restoredCart">Shopping cart</param> public virtual void UpdateOrderTotals(UpdateOrderParameters updateOrderParameters, IList <ShoppingCartItem> restoredCart) { var updatedOrder = updateOrderParameters.UpdatedOrder; var updatedOrderItem = updateOrderParameters.UpdatedOrderItem; //get the customer var customer = restoredCart.GetCustomer(); #region Sub total var subTotalExclTax = decimal.Zero; var subTotalInclTax = decimal.Zero; var subTotalTaxRates = new SortedDictionary <decimal, decimal>(); foreach (var shoppingCartItem in restoredCart) { var itemSubTotalExclTax = decimal.Zero; var itemSubTotalInclTax = decimal.Zero; var taxRate = decimal.Zero; var itemDiscounts = new List <DiscountForCaching>(); //calculate subtotal for the updated order item if (shoppingCartItem.Id == updatedOrderItem.Id) { //update order item updatedOrderItem.UnitPriceExclTax = updateOrderParameters.PriceExclTax; updatedOrderItem.UnitPriceInclTax = updateOrderParameters.PriceInclTax; updatedOrderItem.DiscountAmountExclTax = updateOrderParameters.DiscountAmountExclTax; updatedOrderItem.DiscountAmountInclTax = updateOrderParameters.DiscountAmountInclTax; updatedOrderItem.PriceExclTax = itemSubTotalExclTax = updateOrderParameters.SubTotalExclTax; updatedOrderItem.PriceInclTax = itemSubTotalInclTax = updateOrderParameters.SubTotalInclTax; updatedOrderItem.Quantity = shoppingCartItem.Quantity; taxRate = Math.Round((100 * (itemSubTotalInclTax - itemSubTotalExclTax)) / itemSubTotalExclTax, 3); } else { //get the already calculated subtotal from the order item itemSubTotalExclTax = updatedOrder.OrderItems.FirstOrDefault(item => item.Id == shoppingCartItem.Id).PriceExclTax; itemSubTotalInclTax = updatedOrder.OrderItems.FirstOrDefault(item => item.Id == shoppingCartItem.Id).PriceInclTax; taxRate = Math.Round((100 * (itemSubTotalInclTax - itemSubTotalExclTax)) / itemSubTotalExclTax, 3); } foreach (var discount in itemDiscounts) { if (!updateOrderParameters.AppliedDiscounts.ContainsDiscount(discount)) { updateOrderParameters.AppliedDiscounts.Add(discount); } } subTotalExclTax += itemSubTotalExclTax; subTotalInclTax += itemSubTotalInclTax; //tax rates var itemTaxValue = itemSubTotalInclTax - itemSubTotalExclTax; if (taxRate > decimal.Zero && itemTaxValue > decimal.Zero) { if (!subTotalTaxRates.ContainsKey(taxRate)) { subTotalTaxRates.Add(taxRate, itemTaxValue); } else { subTotalTaxRates[taxRate] = subTotalTaxRates[taxRate] + itemTaxValue; } } } if (subTotalExclTax < decimal.Zero) { subTotalExclTax = decimal.Zero; } if (subTotalInclTax < decimal.Zero) { subTotalInclTax = decimal.Zero; } //We calculate discount amount on order subtotal excl tax (discount first) //calculate discount amount ('Applied to order subtotal' discount) List <DiscountForCaching> subTotalDiscounts; var discountAmountExclTax = GetOrderSubtotalDiscount(customer, subTotalExclTax, out subTotalDiscounts); if (subTotalExclTax < discountAmountExclTax) { discountAmountExclTax = subTotalExclTax; } var discountAmountInclTax = discountAmountExclTax; //add tax for shopping items var tempTaxRates = new Dictionary <decimal, decimal>(subTotalTaxRates); foreach (var kvp in tempTaxRates) { if (kvp.Value != decimal.Zero && subTotalExclTax > decimal.Zero) { var discountTaxValue = kvp.Value * (discountAmountExclTax / subTotalExclTax); discountAmountInclTax += discountTaxValue; subTotalTaxRates[kvp.Key] = kvp.Value - discountTaxValue; } } //rounding if (_shoppingCartSettings.RoundPricesDuringCalculation) { subTotalExclTax = RoundingHelper.RoundPrice(subTotalExclTax); subTotalInclTax = RoundingHelper.RoundPrice(subTotalInclTax); discountAmountExclTax = RoundingHelper.RoundPrice(discountAmountExclTax); discountAmountInclTax = RoundingHelper.RoundPrice(discountAmountInclTax); } updatedOrder.OrderSubtotalExclTax = subTotalExclTax; updatedOrder.OrderSubtotalInclTax = subTotalInclTax; updatedOrder.OrderSubTotalDiscountExclTax = discountAmountExclTax; updatedOrder.OrderSubTotalDiscountInclTax = discountAmountInclTax; foreach (var discount in subTotalDiscounts) { if (!updateOrderParameters.AppliedDiscounts.ContainsDiscount(discount)) { updateOrderParameters.AppliedDiscounts.Add(discount); } } #endregion #region Tax rates var taxRates = new SortedDictionary <decimal, decimal>(); //order subtotal taxes var subTotalTax = decimal.Zero; foreach (var kvp in subTotalTaxRates) { subTotalTax += kvp.Value; if (kvp.Key > decimal.Zero && kvp.Value > decimal.Zero) { if (!taxRates.ContainsKey(kvp.Key)) { taxRates.Add(kvp.Key, kvp.Value); } else { taxRates[kvp.Key] = taxRates[kvp.Key] + kvp.Value; } } } //payment method additional fee tax var paymentMethodAdditionalFeeTax = decimal.Zero; if (_taxSettings.PaymentMethodAdditionalFeeIsTaxable) { paymentMethodAdditionalFeeTax = updatedOrder.PaymentMethodAdditionalFeeInclTax - updatedOrder.PaymentMethodAdditionalFeeExclTax; if (paymentMethodAdditionalFeeTax < decimal.Zero) { paymentMethodAdditionalFeeTax = decimal.Zero; } if (updatedOrder.PaymentMethodAdditionalFeeExclTax > decimal.Zero) { var paymentTaxRate = Math.Round(100 * paymentMethodAdditionalFeeTax / updatedOrder.PaymentMethodAdditionalFeeExclTax, 3); if (paymentTaxRate > decimal.Zero && paymentMethodAdditionalFeeTax > decimal.Zero) { if (!taxRates.ContainsKey(paymentTaxRate)) { taxRates.Add(paymentTaxRate, paymentMethodAdditionalFeeTax); } else { taxRates[paymentTaxRate] = taxRates[paymentTaxRate] + paymentMethodAdditionalFeeTax; } } } } //add at least one tax rate (0%) if (!taxRates.Any()) { taxRates.Add(decimal.Zero, decimal.Zero); } //summarize taxes var taxTotal = subTotalTax + paymentMethodAdditionalFeeTax; if (taxTotal < decimal.Zero) { taxTotal = decimal.Zero; } //round tax if (_shoppingCartSettings.RoundPricesDuringCalculation) { taxTotal = RoundingHelper.RoundPrice(taxTotal); } updatedOrder.OrderTax = taxTotal; updatedOrder.TaxRates = taxRates.Aggregate(string.Empty, (current, next) => string.Format("{0}{1}:{2}; ", current, next.Key.ToString(CultureInfo.InvariantCulture), next.Value.ToString(CultureInfo.InvariantCulture))); #endregion #region Total var total = (subTotalExclTax - discountAmountExclTax) + updatedOrder.PaymentMethodAdditionalFeeExclTax + taxTotal; //get discounts for the order total List <DiscountForCaching> orderAppliedDiscounts; var discountAmountTotal = GetOrderTotalDiscount(customer, total, out orderAppliedDiscounts); if (total < discountAmountTotal) { discountAmountTotal = total; } total -= discountAmountTotal; //reward points var rewardPointsOfOrder = _rewardPointService.GetRewardPointsHistory(customer.Id, true).FirstOrDefault(history => history.UsedWithOrder == updatedOrder); if (rewardPointsOfOrder != null) { var rewardPoints = -rewardPointsOfOrder.Points; var rewardPointsAmount = ConvertRewardPointsToAmount(rewardPoints); if (total < rewardPointsAmount) { rewardPoints = ConvertAmountToRewardPoints(total); rewardPointsAmount = total; } if (total > decimal.Zero) { total -= rewardPointsAmount; } //uncomment here for the return unused reward points if new order total less redeemed reward points amount //if (rewardPoints < -rewardPointsOfOrder.Points) // _rewardPointService.AddRewardPointsHistoryEntry(customer, -rewardPointsOfOrder.Points - rewardPoints, _storeContext.CurrentStore.Id, "Return unused reward points"); if (rewardPointsAmount != rewardPointsOfOrder.UsedAmount) { rewardPointsOfOrder.UsedAmount = rewardPointsAmount; rewardPointsOfOrder.Points = -rewardPoints; _rewardPointService.UpdateRewardPointsHistoryEntry(rewardPointsOfOrder); } } //rounding if (total < decimal.Zero) { total = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { total = RoundingHelper.RoundPrice(total); } updatedOrder.OrderDiscount = discountAmountTotal; updatedOrder.OrderTotal = total; foreach (var discount in orderAppliedDiscounts) { if (!updateOrderParameters.AppliedDiscounts.ContainsDiscount(discount)) { updateOrderParameters.AppliedDiscounts.Add(discount); } } #endregion }