public async Task <OrderDetailsModel> PrepareOrderDetailsModelAsync(Order order) { Guard.NotNull(order, nameof(order)); var settingFactory = _services.SettingFactory; var store = await _db.Stores.FindByIdAsync(order.StoreId, false) ?? _services.StoreContext.CurrentStore; var language = _services.WorkContext.WorkingLanguage; var orderSettings = await settingFactory.LoadSettingsAsync <OrderSettings>(store.Id); var catalogSettings = await settingFactory.LoadSettingsAsync <CatalogSettings>(store.Id); var taxSettings = await settingFactory.LoadSettingsAsync <TaxSettings>(store.Id); var pdfSettings = await settingFactory.LoadSettingsAsync <PdfSettings>(store.Id); var addressSettings = await settingFactory.LoadSettingsAsync <AddressSettings>(store.Id); var companyInfoSettings = await settingFactory.LoadSettingsAsync <CompanyInformationSettings>(store.Id); var shoppingCartSettings = await settingFactory.LoadSettingsAsync <ShoppingCartSettings>(store.Id); var mediaSettings = await settingFactory.LoadSettingsAsync <MediaSettings>(store.Id); var model = new OrderDetailsModel { Id = order.Id, StoreId = order.StoreId, CustomerLanguageId = order.CustomerLanguageId, CustomerComment = order.CustomerOrderComment, OrderNumber = order.GetOrderNumber(), CreatedOn = _dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc), OrderStatus = await _services.Localization.GetLocalizedEnumAsync(order.OrderStatus), IsReOrderAllowed = orderSettings.IsReOrderAllowed, IsReturnRequestAllowed = _orderProcessingService.IsReturnRequestAllowed(order), DisplayPdfInvoice = pdfSettings.Enabled, RenderOrderNotes = pdfSettings.RenderOrderNotes, // Shipping info. ShippingStatus = await _services.Localization.GetLocalizedEnumAsync(order.ShippingStatus) }; // TODO: refactor modelling for multi-order processing. var companyCountry = await _db.Countries.FindByIdAsync(companyInfoSettings.CountryId, false); model.MerchantCompanyInfo = companyInfoSettings; model.MerchantCompanyCountryName = companyCountry?.GetLocalized(x => x.Name); if (order.ShippingStatus != ShippingStatus.ShippingNotRequired) { model.IsShippable = true; await MapperFactory.MapAsync(order.ShippingAddress, model.ShippingAddress); model.ShippingMethod = order.ShippingMethod; // Shipments (only already shipped). var shipments = order.Shipments.Where(x => x.ShippedDateUtc.HasValue).OrderBy(x => x.CreatedOnUtc).ToList(); foreach (var shipment in shipments) { var shipmentModel = new OrderDetailsModel.ShipmentBriefModel { Id = shipment.Id, TrackingNumber = shipment.TrackingNumber, }; if (shipment.ShippedDateUtc.HasValue) { shipmentModel.ShippedDate = _dateTimeHelper.ConvertToUserTime(shipment.ShippedDateUtc.Value, DateTimeKind.Utc); } if (shipment.DeliveryDateUtc.HasValue) { shipmentModel.DeliveryDate = _dateTimeHelper.ConvertToUserTime(shipment.DeliveryDateUtc.Value, DateTimeKind.Utc); } model.Shipments.Add(shipmentModel); } } await MapperFactory.MapAsync(order.BillingAddress, model.BillingAddress); model.VatNumber = order.VatNumber; // Payment method. var paymentMethod = await _paymentService.LoadPaymentMethodBySystemNameAsync(order.PaymentMethodSystemName); model.PaymentMethodSystemName = order.PaymentMethodSystemName; // TODO: (mh) (core) //model.PaymentMethod = paymentMethod != null ? _pluginMediator.GetLocalizedFriendlyName(paymentMethod.Metadata) : order.PaymentMethodSystemName; model.PaymentMethod = order.PaymentMethodSystemName; model.CanRePostProcessPayment = await _paymentService.CanRePostProcessPaymentAsync(order); // Purchase order number (we have to find a better to inject this information because it's related to a certain plugin). if (paymentMethod != null && paymentMethod.Metadata.SystemName.Equals("Smartstore.PurchaseOrderNumber", StringComparison.InvariantCultureIgnoreCase)) { model.DisplayPurchaseOrderNumber = true; model.PurchaseOrderNumber = order.PurchaseOrderNumber; } if (order.AllowStoringCreditCardNumber) { model.CardNumber = _encryptor.DecryptText(order.CardNumber); model.MaskedCreditCardNumber = _encryptor.DecryptText(order.MaskedCreditCardNumber); model.CardCvv2 = _encryptor.DecryptText(order.CardCvv2); model.CardExpirationMonth = _encryptor.DecryptText(order.CardExpirationMonth); model.CardExpirationYear = _encryptor.DecryptText(order.CardExpirationYear); } if (order.AllowStoringDirectDebit) { model.DirectDebitAccountHolder = _encryptor.DecryptText(order.DirectDebitAccountHolder); model.DirectDebitAccountNumber = _encryptor.DecryptText(order.DirectDebitAccountNumber); model.DirectDebitBankCode = _encryptor.DecryptText(order.DirectDebitBankCode); model.DirectDebitBankName = _encryptor.DecryptText(order.DirectDebitBankName); model.DirectDebitBIC = _encryptor.DecryptText(order.DirectDebitBIC); model.DirectDebitCountry = _encryptor.DecryptText(order.DirectDebitCountry); model.DirectDebitIban = _encryptor.DecryptText(order.DirectDebitIban); } // TODO: (mh) (core) Reimplement when pricing is ready. // Totals. var customerCurrency = await _db.Currencies .AsNoTracking() .Where(x => x.CurrencyCode == order.CustomerCurrencyCode) .FirstOrDefaultAsync(); switch (order.CustomerTaxDisplayType) { case TaxDisplayType.ExcludingTax: { // Order subtotal. var orderSubtotalExclTax = _currencyService.ConvertToExchangeRate(order.OrderSubtotalExclTax, order.CurrencyRate, customerCurrency); model.OrderSubtotal = orderSubtotalExclTax.ToString(); // Discount (applied to order subtotal). var orderSubTotalDiscountExclTax = _currencyService.ConvertToExchangeRate(order.OrderSubTotalDiscountExclTax, order.CurrencyRate, customerCurrency); if (orderSubTotalDiscountExclTax > 0) { model.OrderSubTotalDiscount = (orderSubTotalDiscountExclTax * -1).ToString(); } // Order shipping. var orderShippingExclTax = _currencyService.ConvertToExchangeRate(order.OrderShippingExclTax, order.CurrencyRate, customerCurrency); model.OrderShipping = orderShippingExclTax.ToString(); // Payment method additional fee. var paymentMethodAdditionalFeeExclTax = _currencyService.ConvertToExchangeRate(order.PaymentMethodAdditionalFeeExclTax, order.CurrencyRate, customerCurrency); if (paymentMethodAdditionalFeeExclTax != 0) { model.PaymentMethodAdditionalFee = paymentMethodAdditionalFeeExclTax.ToString(); } } break; case TaxDisplayType.IncludingTax: { // Order subtotal. var orderSubtotalInclTax = _currencyService.ConvertToExchangeRate(order.OrderSubtotalInclTax, order.CurrencyRate, customerCurrency); model.OrderSubtotal = orderSubtotalInclTax.ToString(); // Discount (applied to order subtotal). var orderSubTotalDiscountInclTax = _currencyService.ConvertToExchangeRate(order.OrderSubTotalDiscountInclTax, order.CurrencyRate, customerCurrency); if (orderSubTotalDiscountInclTax > 0) { model.OrderSubTotalDiscount = (orderSubTotalDiscountInclTax * -1).ToString(); } // Order shipping. var orderShippingInclTax = _currencyService.ConvertToExchangeRate(order.OrderShippingInclTax, order.CurrencyRate, customerCurrency); model.OrderShipping = orderShippingInclTax.ToString(); // Payment method additional fee. var paymentMethodAdditionalFeeInclTax = _currencyService.ConvertToExchangeRate(order.PaymentMethodAdditionalFeeInclTax, order.CurrencyRate, customerCurrency); if (paymentMethodAdditionalFeeInclTax != 0) { model.PaymentMethodAdditionalFee = paymentMethodAdditionalFeeInclTax.ToString(); } } break; } // Tax. var displayTax = true; var displayTaxRates = true; if (taxSettings.HideTaxInOrderSummary && order.CustomerTaxDisplayType == TaxDisplayType.IncludingTax) { displayTax = false; displayTaxRates = false; } else { if (order.OrderTax == 0 && taxSettings.HideZeroTax) { displayTax = false; displayTaxRates = false; } else { displayTaxRates = taxSettings.DisplayTaxRates && order.TaxRatesDictionary.Count > 0; displayTax = !displayTaxRates; var orderTaxInCustomerCurrency = _currencyService.ConvertToExchangeRate(order.OrderTax, order.CurrencyRate, customerCurrency); model.Tax = orderTaxInCustomerCurrency.ToString(); foreach (var tr in order.TaxRatesDictionary) { var rate = _taxService.FormatTaxRate(tr.Key); var labelKey = _services.WorkContext.TaxDisplayType == TaxDisplayType.IncludingTax ? "ShoppingCart.Totals.TaxRateLineIncl" : "ShoppingCart.Totals.TaxRateLineExcl"; model.TaxRates.Add(new OrderDetailsModel.TaxRate { Rate = rate, Label = T(labelKey, rate), Value = _currencyService.ConvertToExchangeRate(tr.Value, order.CurrencyRate, customerCurrency).ToString() }); } } } model.DisplayTaxRates = displayTaxRates; model.DisplayTax = displayTax; // Discount (applied to order total). var orderDiscountInCustomerCurrency = _currencyService.ConvertToExchangeRate(order.OrderDiscount, order.CurrencyRate, customerCurrency); if (orderDiscountInCustomerCurrency > 0) { model.OrderTotalDiscount = (orderDiscountInCustomerCurrency * -1).ToString(); } // Gift cards. foreach (var gcuh in order.GiftCardUsageHistory) { var remainingAmountBase = _giftCardService.GetRemainingAmount(gcuh.GiftCard); var remainingAmount = _currencyService.ConvertToExchangeRate(remainingAmountBase.Amount, order.CurrencyRate, customerCurrency); var usedAmount = _currencyService.ConvertToExchangeRate(gcuh.UsedValue, order.CurrencyRate, customerCurrency); var gcModel = new OrderDetailsModel.GiftCard { CouponCode = gcuh.GiftCard.GiftCardCouponCode, Amount = (usedAmount * -1).ToString(), Remaining = remainingAmount.ToString() }; model.GiftCards.Add(gcModel); } // Reward points . if (order.RedeemedRewardPointsEntry != null) { var usedAmount = _currencyService.ConvertToExchangeRate(order.RedeemedRewardPointsEntry.UsedAmount, order.CurrencyRate, customerCurrency); model.RedeemedRewardPoints = -order.RedeemedRewardPointsEntry.Points; model.RedeemedRewardPointsAmount = (usedAmount * -1).ToString(); } // Credit balance. if (order.CreditBalance > 0) { var convertedCreditBalance = _currencyService.ConvertToExchangeRate(order.CreditBalance, order.CurrencyRate, customerCurrency); model.CreditBalance = (convertedCreditBalance * -1).ToString(); } // Total. (var orderTotal, var roundingAmount) = await _orderService.GetOrderTotalInCustomerCurrencyAsync(order, customerCurrency); model.OrderTotal = orderTotal.ToString(); if (roundingAmount != 0) { model.OrderTotalRounding = roundingAmount.ToString(); } // Checkout attributes. model.CheckoutAttributeInfo = HtmlUtils.ConvertPlainTextToTable(HtmlUtils.ConvertHtmlToPlainText(order.CheckoutAttributeDescription)); // Order notes. await _db.LoadCollectionAsync(order, x => x.OrderNotes); var orderNotes = order.OrderNotes .Where(x => x.DisplayToCustomer) .OrderByDescending(x => x.CreatedOnUtc) .ToList(); foreach (var orderNote in orderNotes) { var createdOn = _dateTimeHelper.ConvertToUserTime(orderNote.CreatedOnUtc, DateTimeKind.Utc); model.OrderNotes.Add(new OrderDetailsModel.OrderNote { Note = orderNote.FormatOrderNoteText(), CreatedOn = createdOn, FriendlyCreatedOn = orderNote.CreatedOnUtc.Humanize() }); } // Purchased products. model.ShowSku = catalogSettings.ShowProductSku; model.ShowProductImages = shoppingCartSettings.ShowProductImagesOnShoppingCart; model.ShowProductBundleImages = shoppingCartSettings.ShowProductBundleImagesOnShoppingCart; model.BundleThumbSize = mediaSettings.CartThumbBundleItemPictureSize; await _db.LoadCollectionAsync(order, x => x.OrderItems, false, q => q.Include(x => x.Product)); foreach (var orderItem in order.OrderItems) { var orderItemModel = await PrepareOrderItemModelAsync(order, orderItem, catalogSettings, shoppingCartSettings, mediaSettings, customerCurrency); model.Items.Add(orderItemModel); } return(model); }