/// <summary> /// Post process payment (used by payment gateways that require redirecting to a third-party URL) /// </summary> /// <param name="postProcessPaymentRequest">Payment info required for an order processing</param> public void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest) { var builder = new StringBuilder(); builder.Append(GetPaypalUrl()); var cmd = _paypalStandardPaymentSettings.PassProductNamesAndTotals ? "_cart" : "_xclick"; builder.AppendFormat("?cmd={0}&business={1}", cmd, HttpUtility.UrlEncode(_paypalStandardPaymentSettings.BusinessEmail)); if (_paypalStandardPaymentSettings.PassProductNamesAndTotals) { builder.AppendFormat("&upload=1"); //get the items in the cart decimal cartTotal = decimal.Zero; var cartItems = postProcessPaymentRequest.Order.OrderItems; int x = 1; foreach (var item in cartItems) { var unitPriceExclTax = item.UnitPriceExclTax; var priceExclTax = item.PriceExclTax; //round var unitPriceExclTaxRounded = Math.Round(unitPriceExclTax, 2); builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(item.Product.Name)); builder.AppendFormat("&amount_" + x + "={0}", unitPriceExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); builder.AppendFormat("&quantity_" + x + "={0}", item.Quantity); x++; cartTotal += priceExclTax; } //the checkout attributes that have a dollar value and send them to Paypal as items to be paid for var attributeValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(postProcessPaymentRequest.Order.CheckoutAttributesXml); foreach (var val in attributeValues) { var attPrice = _taxService.GetCheckoutAttributePrice(val, false, postProcessPaymentRequest.Order.Customer); //round var attPriceRounded = Math.Round(attPrice, 2); if (attPrice > decimal.Zero) //if it has a price { var attribute = val.CheckoutAttribute; if (attribute != null) { var attName = attribute.Name; //set the name builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(attName)); //name builder.AppendFormat("&amount_" + x + "={0}", attPriceRounded.ToString("0.00", CultureInfo.InvariantCulture)); //amount builder.AppendFormat("&quantity_" + x + "={0}", 1); //quantity x++; cartTotal += attPrice; } } } //order totals //shipping var orderShippingExclTax = postProcessPaymentRequest.Order.OrderShippingExclTax; var orderShippingExclTaxRounded = Math.Round(orderShippingExclTax, 2); if (orderShippingExclTax > decimal.Zero) { builder.AppendFormat("&item_name_" + x + "={0}", "Shipping fee"); builder.AppendFormat("&amount_" + x + "={0}", orderShippingExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); builder.AppendFormat("&quantity_" + x + "={0}", 1); x++; cartTotal += orderShippingExclTax; } //payment method additional fee var paymentMethodAdditionalFeeExclTax = postProcessPaymentRequest.Order.PaymentMethodAdditionalFeeExclTax; var paymentMethodAdditionalFeeExclTaxRounded = Math.Round(paymentMethodAdditionalFeeExclTax, 2); if (paymentMethodAdditionalFeeExclTax > decimal.Zero) { builder.AppendFormat("&item_name_" + x + "={0}", "Payment method fee"); builder.AppendFormat("&amount_" + x + "={0}", paymentMethodAdditionalFeeExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); builder.AppendFormat("&quantity_" + x + "={0}", 1); x++; cartTotal += paymentMethodAdditionalFeeExclTax; } //tax var orderTax = postProcessPaymentRequest.Order.OrderTax; var orderTaxRounded = Math.Round(orderTax, 2); if (orderTax > decimal.Zero) { //builder.AppendFormat("&tax_1={0}", orderTax.ToString("0.00", CultureInfo.InvariantCulture)); //add tax as item builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode("Sales Tax")); //name builder.AppendFormat("&amount_" + x + "={0}", orderTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); //amount builder.AppendFormat("&quantity_" + x + "={0}", 1); //quantity cartTotal += orderTax; x++; } if (cartTotal > postProcessPaymentRequest.Order.OrderTotal) { /* Take the difference between what the order total is and what it should be and use that as the "discount". * The difference equals the amount of the gift card and/or reward points used. */ decimal discountTotal = cartTotal - postProcessPaymentRequest.Order.OrderTotal; discountTotal = Math.Round(discountTotal, 2); //gift card or rewared point amount applied to cart in nopCommerce - shows in Paypal as "discount" builder.AppendFormat("&discount_amount_cart={0}", discountTotal.ToString("0.00", CultureInfo.InvariantCulture)); } } else { //pass order total builder.AppendFormat("&item_name=Order Number {0}", postProcessPaymentRequest.Order.Id); var orderTotal = Math.Round(postProcessPaymentRequest.Order.OrderTotal, 2); builder.AppendFormat("&amount={0}", orderTotal.ToString("0.00", CultureInfo.InvariantCulture)); } builder.AppendFormat("&custom={0}", postProcessPaymentRequest.Order.OrderGuid); builder.AppendFormat("&charset={0}", "utf-8"); builder.Append(string.Format("&no_note=1¤cy_code={0}", HttpUtility.UrlEncode(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode))); builder.AppendFormat("&invoice={0}", postProcessPaymentRequest.Order.Id); builder.AppendFormat("&rm=2", new object[0]); if (postProcessPaymentRequest.Order.ShippingStatus != ShippingStatus.ShippingNotRequired) { builder.AppendFormat("&no_shipping=2", new object[0]); } else { builder.AppendFormat("&no_shipping=1", new object[0]); } string returnUrl = _webHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalStandard/PDTHandler"; string cancelReturnUrl = _webHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalStandard/CancelOrder"; builder.AppendFormat("&return={0}&cancel_return={1}", HttpUtility.UrlEncode(returnUrl), HttpUtility.UrlEncode(cancelReturnUrl)); //Instant Payment Notification (server to server message) if (_paypalStandardPaymentSettings.EnableIpn) { string ipnUrl; if (String.IsNullOrWhiteSpace(_paypalStandardPaymentSettings.IpnUrl)) { ipnUrl = _webHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalStandard/IPNHandler"; } else { ipnUrl = _paypalStandardPaymentSettings.IpnUrl; } builder.AppendFormat("¬ify_url={0}", ipnUrl); } //address builder.AppendFormat("&address_override={0}", _paypalStandardPaymentSettings.AddressOverride ? "1" : "0"); builder.AppendFormat("&first_name={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.FirstName)); builder.AppendFormat("&last_name={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.LastName)); builder.AppendFormat("&address1={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.Address1)); builder.AppendFormat("&address2={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.Address2)); builder.AppendFormat("&city={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.City)); //if (!String.IsNullOrEmpty(postProcessPaymentRequest.Order.BillingAddress.PhoneNumber)) //{ // //strip out all non-digit characters from phone number; // string billingPhoneNumber = System.Text.RegularExpressions.Regex.Replace(postProcessPaymentRequest.Order.BillingAddress.PhoneNumber, @"\D", string.Empty); // if (billingPhoneNumber.Length >= 10) // { // builder.AppendFormat("&night_phone_a={0}", HttpUtility.UrlEncode(billingPhoneNumber.Substring(0, 3))); // builder.AppendFormat("&night_phone_b={0}", HttpUtility.UrlEncode(billingPhoneNumber.Substring(3, 3))); // builder.AppendFormat("&night_phone_c={0}", HttpUtility.UrlEncode(billingPhoneNumber.Substring(6, 4))); // } //} if (postProcessPaymentRequest.Order.BillingAddress.StateProvince != null) { builder.AppendFormat("&state={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.StateProvince.Abbreviation)); } else { builder.AppendFormat("&state={0}", ""); } if (postProcessPaymentRequest.Order.BillingAddress.Country != null) { builder.AppendFormat("&country={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.Country.TwoLetterIsoCode)); } else { builder.AppendFormat("&country={0}", ""); } builder.AppendFormat("&zip={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.ZipPostalCode)); builder.AppendFormat("&email={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.Email)); _httpContext.Response.Redirect(builder.ToString()); }
/// <summary> /// Add order items to the request query parameters /// </summary> /// <param name="parameters">Query parameters</param> /// <param name="postProcessPaymentRequest">Payment info required for an order processing</param> private void AddItemsParameters(IDictionary <string, string> parameters, PostProcessPaymentRequest postProcessPaymentRequest) { //upload order items parameters.Add("cmd", "_cart"); parameters.Add("upload", "1"); var cartTotal = decimal.Zero; var roundedCartTotal = decimal.Zero; var itemCount = 1; //add shopping cart items foreach (var item in postProcessPaymentRequest.Order.OrderItems) { var product = _productService.GetProductById(item.ProductId); var roundedItemPrice = Math.Round(item.UnitPriceExclTax, 2); //add query parameters parameters.Add($"item_name_{itemCount}", product.Name); parameters.Add($"amount_{itemCount}", roundedItemPrice.ToString("0.00", CultureInfo.InvariantCulture)); parameters.Add($"quantity_{itemCount}", item.Quantity.ToString()); cartTotal += item.PriceExclTax; roundedCartTotal += roundedItemPrice * item.Quantity; itemCount++; } //add checkout attributes as order items var checkoutAttributeValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(postProcessPaymentRequest.Order.CheckoutAttributesXml); var customer = EngineContext.Current.Resolve <ICustomerService>().GetCustomerById(postProcessPaymentRequest.Order.CustomerId); foreach (var attributeValue in checkoutAttributeValues) { var attributePrice = _taxService.GetCheckoutAttributePrice(attributeValue, false, customer); if (attributePrice > 0) { var roundedAttributePrice = Math.Round(attributePrice, 2); //add query parameters var attribute = EngineContext.Current.Resolve <ICheckoutAttributeService>().GetCheckoutAttributeById(attributeValue.CheckoutAttributeId); if (attribute != null) { parameters.Add($"item_name_{itemCount}", attribute.Name); parameters.Add($"amount_{itemCount}", roundedAttributePrice.ToString("0.00", CultureInfo.InvariantCulture)); parameters.Add($"quantity_{itemCount}", "1"); cartTotal += attributePrice; roundedCartTotal += roundedAttributePrice; itemCount++; } } } //add shipping fee as a separate order item, if it has price var roundedShippingPrice = Math.Round(postProcessPaymentRequest.Order.OrderShippingExclTax, 2); if (roundedShippingPrice > decimal.Zero) { parameters.Add($"item_name_{itemCount}", "Shipping fee"); parameters.Add($"amount_{itemCount}", roundedShippingPrice.ToString("0.00", CultureInfo.InvariantCulture)); parameters.Add($"quantity_{itemCount}", "1"); cartTotal += postProcessPaymentRequest.Order.OrderShippingExclTax; roundedCartTotal += roundedShippingPrice; itemCount++; } //add payment method additional fee as a separate order item, if it has price var roundedPaymentMethodPrice = Math.Round(postProcessPaymentRequest.Order.PaymentMethodAdditionalFeeExclTax, 2); if (roundedPaymentMethodPrice > decimal.Zero) { parameters.Add($"item_name_{itemCount}", "Payment method fee"); parameters.Add($"amount_{itemCount}", roundedPaymentMethodPrice.ToString("0.00", CultureInfo.InvariantCulture)); parameters.Add($"quantity_{itemCount}", "1"); cartTotal += postProcessPaymentRequest.Order.PaymentMethodAdditionalFeeExclTax; roundedCartTotal += roundedPaymentMethodPrice; itemCount++; } //add tax as a separate order item, if it has positive amount var roundedTaxAmount = Math.Round(postProcessPaymentRequest.Order.OrderTax, 2); if (roundedTaxAmount > decimal.Zero) { parameters.Add($"item_name_{itemCount}", "Tax amount"); parameters.Add($"amount_{itemCount}", roundedTaxAmount.ToString("0.00", CultureInfo.InvariantCulture)); parameters.Add($"quantity_{itemCount}", "1"); cartTotal += postProcessPaymentRequest.Order.OrderTax; roundedCartTotal += roundedTaxAmount; itemCount++; } if (cartTotal > postProcessPaymentRequest.Order.OrderTotal) { //get the difference between what the order total is and what it should be and use that as the "discount" var discountTotal = Math.Round(cartTotal - postProcessPaymentRequest.Order.OrderTotal, 2); roundedCartTotal -= discountTotal; //gift card or rewarded point amount applied to cart in nopCommerce - shows in PayPal as "discount" parameters.Add("discount_amount_cart", discountTotal.ToString("0.00", CultureInfo.InvariantCulture)); } //save order total that actually sent to PayPal (used for PDT order total validation) _genericAttributeService.SaveAttribute(postProcessPaymentRequest.Order, PaypalHelper.OrderTotalSentToPayPal, roundedCartTotal); }
GetShoppingCartSubTotal(IList <ShoppingCartItem> cart, bool includingTax) { var discountAmount = decimal.Zero; var appliedDiscounts = new List <ApplyDiscount>(); var subTotalWithoutDiscount = decimal.Zero; var subTotalWithDiscount = decimal.Zero; var taxRates = new SortedDictionary <decimal, decimal>(); if (!cart.Any()) { return(discountAmount, appliedDiscounts, subTotalWithoutDiscount, subTotalWithDiscount, taxRates); } //get the customer Customer customer = _workContext.CurrentCustomer; //sub totals decimal subTotalExclTaxWithoutDiscount = decimal.Zero; decimal subTotalInclTaxWithoutDiscount = decimal.Zero; foreach (var shoppingCartItem in cart) { var product = await _productService.GetProductById(shoppingCartItem.ProductId); if (product == null) { continue; } var subtotal = await _pricingService.GetSubTotal(shoppingCartItem, product); decimal sciSubTotal = subtotal.subTotal; decimal taxRate; var pricesExcl = await _taxService.GetProductPrice(product, sciSubTotal, false, customer); decimal sciExclTax = pricesExcl.productprice; var pricesIncl = await _taxService.GetProductPrice(product, sciSubTotal, true, customer); decimal sciInclTax = pricesIncl.productprice; taxRate = pricesIncl.taxRate; subTotalExclTaxWithoutDiscount += sciExclTax; subTotalInclTaxWithoutDiscount += sciInclTax; //tax rates decimal sciTax = sciInclTax - sciExclTax; if (taxRate > decimal.Zero && sciTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, sciTax); } else { taxRates[taxRate] = taxRates[taxRate] + sciTax; } } } //checkout attributes if (customer != null) { var checkoutAttributes = customer.GetUserFieldFromEntity <List <CustomAttribute> >(SystemCustomerFieldNames.CheckoutAttributes, _workContext.CurrentStore.Id); var attributeValues = await _checkoutAttributeParser.ParseCheckoutAttributeValue(checkoutAttributes); foreach (var attributeValue in attributeValues) { decimal taxRate; var checkoutAttributePriceExclTax = await _taxService.GetCheckoutAttributePrice(attributeValue.ca, attributeValue.cav, false, customer); decimal caExclTax = await _currencyService.ConvertFromPrimaryStoreCurrency(checkoutAttributePriceExclTax.checkoutPrice, _workContext.WorkingCurrency); var checkoutAttributePriceInclTax = await _taxService.GetCheckoutAttributePrice(attributeValue.ca, attributeValue.cav, true, customer); decimal caInclTax = await _currencyService.ConvertFromPrimaryStoreCurrency(checkoutAttributePriceInclTax.checkoutPrice, _workContext.WorkingCurrency); taxRate = checkoutAttributePriceInclTax.taxRate; subTotalExclTaxWithoutDiscount += caExclTax; subTotalInclTaxWithoutDiscount += caInclTax; //tax rates decimal caTax = caInclTax - caExclTax; if (taxRate > decimal.Zero && caTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, caTax); } else { taxRates[taxRate] = taxRates[taxRate] + caTax; } } } } //subtotal without discount subTotalWithoutDiscount = includingTax ? subTotalInclTaxWithoutDiscount : subTotalExclTaxWithoutDiscount; if (subTotalWithoutDiscount < decimal.Zero) { subTotalWithoutDiscount = decimal.Zero; } if (_shoppingCartSettings.RoundPrices) { subTotalWithoutDiscount = RoundingHelper.RoundPrice(subTotalWithoutDiscount, _workContext.WorkingCurrency); } //We calculate discount amount on order subtotal excl tax (discount first) //calculate discount amount ('Applied to order subtotal' discount) var orderSubtotalDiscount = await GetOrderSubtotalDiscount(customer, _workContext.WorkingCurrency, subTotalExclTaxWithoutDiscount); decimal discountAmountExclTax = orderSubtotalDiscount.ordersubtotaldiscount; appliedDiscounts = orderSubtotalDiscount.appliedDiscounts; if (subTotalExclTaxWithoutDiscount < discountAmountExclTax) { discountAmountExclTax = subTotalExclTaxWithoutDiscount; } decimal discountAmountInclTax = discountAmountExclTax; //subtotal with discount (excl tax) decimal subTotalExclTaxWithDiscount = subTotalExclTaxWithoutDiscount - discountAmountExclTax; decimal subTotalInclTaxWithDiscount = subTotalExclTaxWithDiscount; //add tax for shopping items & checkout attributes var tempTaxRates = new Dictionary <decimal, decimal>(taxRates); foreach (KeyValuePair <decimal, decimal> kvp in tempTaxRates) { decimal taxRate = kvp.Key; decimal taxValue = kvp.Value; if (taxValue != decimal.Zero) { //discount the tax amount that applies to subtotal items if (subTotalExclTaxWithoutDiscount > decimal.Zero) { decimal discountTax = taxRates[taxRate] * (discountAmountExclTax / subTotalExclTaxWithoutDiscount); discountAmountInclTax += discountTax; taxValue = taxRates[taxRate] - discountTax; if (_shoppingCartSettings.RoundPrices) { taxValue = RoundingHelper.RoundPrice(taxValue, _workContext.WorkingCurrency); } taxRates[taxRate] = taxValue; } //subtotal with discount (incl tax) subTotalInclTaxWithDiscount += taxValue; } } if (_shoppingCartSettings.RoundPrices) { discountAmountInclTax = RoundingHelper.RoundPrice(discountAmountInclTax, _workContext.WorkingCurrency); discountAmountExclTax = RoundingHelper.RoundPrice(discountAmountExclTax, _workContext.WorkingCurrency); } if (includingTax) { subTotalWithDiscount = subTotalInclTaxWithDiscount; discountAmount = discountAmountInclTax; } else { subTotalWithDiscount = subTotalExclTaxWithDiscount; discountAmount = discountAmountExclTax; } if (subTotalWithDiscount < decimal.Zero) { subTotalWithDiscount = decimal.Zero; } if (_shoppingCartSettings.RoundPrices) { subTotalWithDiscount = RoundingHelper.RoundPrice(subTotalWithDiscount, _workContext.WorkingCurrency); } return(discountAmount, appliedDiscounts, subTotalWithoutDiscount, subTotalWithDiscount, taxRates); }
private void AddOrderLines(PayexInterface payex, string orderRef, Order order) { //get the items in the cart decimal cartTotal = decimal.Zero; var cartItems = order.OrderItems; int itemIndex = 1; foreach (var item in cartItems) { AddOrderLine( payex, orderRef, item.Product.Sku ?? string.Format("{0}", itemIndex++), item.Product.Name, item.Quantity, item.PriceInclTax) .GetAwaiter().GetResult(); cartTotal += item.PriceInclTax; } //the checkout attributes that have a value and send them to PayEx as items to be paid for var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(order.CheckoutAttributesXml); foreach (var val in caValues) { var caPriceInclTax = _taxService.GetCheckoutAttributePrice(val, true, order.Customer); CheckoutAttribute ca = val.CheckoutAttribute; if (caPriceInclTax > decimal.Zero && ca != null) //if it has a price { AddOrderLine(payex, orderRef, string.Format("{0}", itemIndex++), ca.Name, 1, caPriceInclTax) .GetAwaiter().GetResult(); cartTotal += caPriceInclTax; } } //order totals //shipping var orderShippingInclTax = order.OrderShippingInclTax; if (orderShippingInclTax > decimal.Zero) { AddOrderLine( payex, orderRef, string.Format("{0}", itemIndex++), _localizationService.GetResource("Order.Shipping"), 1, orderShippingInclTax) .GetAwaiter().GetResult(); cartTotal += orderShippingInclTax; } //payment method additional fee var paymentMethodAdditionalFeeInclTax = order.PaymentMethodAdditionalFeeInclTax; if (paymentMethodAdditionalFeeInclTax > decimal.Zero) { AddOrderLine( payex, orderRef, string.Format("{0}", itemIndex++), _localizationService.GetResource("Order.PaymentMethodAdditionalFee"), 1, paymentMethodAdditionalFeeInclTax) .GetAwaiter().GetResult(); cartTotal += paymentMethodAdditionalFeeInclTax; } if (cartTotal > order.OrderTotal) { /* Take the difference between what the order total is and what it should be and use that as the "discount". * The difference equals the amount of the gift card and/or reward points used. */ decimal discountTotal = cartTotal - order.OrderTotal; //gift card or rewared point amount applied to cart in nopCommerce AddOrderLine( payex, orderRef, string.Format("{0}", itemIndex++), _localizationService.GetResource("Admin.Orders.Products.Discount"), 1, -discountTotal) .GetAwaiter().GetResult(); } }
/// <summary> /// Add order items to the request request metadata /// </summary> /// <param name="parameters">Query parameters</param> /// <param name="postProcessPaymentRequest">Payment info required for an order processing</param> private void AddOrderItemsMetaData(TransactionInitializeRequest request, PostProcessPaymentRequest postProcessPaymentRequest) { //upload order items var cartTotal = decimal.Zero; var roundedCartTotal = decimal.Zero; var itemCount = 1; //add shopping cart items foreach (var item in postProcessPaymentRequest.Order.OrderItems) { var roundedItemPrice = Math.Round(item.UnitPriceExclTax, 2); //add query parameters request.MetadataObject[$"item_name_{itemCount}"] = item.Product.Name; request.MetadataObject[$"amount_{itemCount}"] = roundedItemPrice.ToString("0.00", CultureInfo.InvariantCulture); request.MetadataObject[$"quantity_{itemCount}"] = item.Quantity.ToString(); cartTotal += item.PriceExclTax; roundedCartTotal += roundedItemPrice * item.Quantity; itemCount++; } //add checkout attributes as order items var checkoutAttributeValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(postProcessPaymentRequest.Order.CheckoutAttributesXml); foreach (var attributeValue in checkoutAttributeValues) { var attributePrice = _taxService.GetCheckoutAttributePrice(attributeValue, false, postProcessPaymentRequest.Order.Customer); var roundedAttributePrice = Math.Round(attributePrice, 2); //add query parameters if (attributeValue.CheckoutAttribute == null) { continue; } request.MetadataObject[$"item_name_{itemCount}"] = attributeValue.CheckoutAttribute.Name; request.MetadataObject[$"amount_{itemCount}"] = roundedAttributePrice.ToString("0.00", CultureInfo.InvariantCulture); request.MetadataObject[$"quantity_{itemCount}"] = "1"; cartTotal += attributePrice; roundedCartTotal += roundedAttributePrice; itemCount++; } //add shipping fee as a separate order item, if it has price var roundedShippingPrice = Math.Round(postProcessPaymentRequest.Order.OrderShippingExclTax, 2); if (roundedShippingPrice > decimal.Zero) { request.MetadataObject[$"item_name_{itemCount}"] = "Shipping fee"; request.MetadataObject[$"amount_{itemCount}"] = roundedShippingPrice.ToString("0.00", CultureInfo.InvariantCulture); request.MetadataObject[$"quantity_{itemCount}"] = "1"; cartTotal += postProcessPaymentRequest.Order.OrderShippingExclTax; roundedCartTotal += roundedShippingPrice; itemCount++; } //add payment method additional fee as a separate order item, if it has price var roundedPaymentMethodPrice = Math.Round(postProcessPaymentRequest.Order.PaymentMethodAdditionalFeeExclTax, 2); if (roundedPaymentMethodPrice > decimal.Zero) { request.MetadataObject[$"item_name_{itemCount}"] = "Payment method fee"; request.MetadataObject[$"amount_{itemCount}"] = roundedPaymentMethodPrice.ToString("0.00", CultureInfo.InvariantCulture); request.MetadataObject[$"quantity_{itemCount}"] = "1"; cartTotal += postProcessPaymentRequest.Order.PaymentMethodAdditionalFeeExclTax; roundedCartTotal += roundedPaymentMethodPrice; itemCount++; } //add tax as a separate order item, if it has positive amount var roundedTaxAmount = Math.Round(postProcessPaymentRequest.Order.OrderTax, 2); if (roundedTaxAmount > decimal.Zero) { request.MetadataObject[$"item_name_{itemCount}"] = "Tax amount"; request.MetadataObject[$"amount_{itemCount}"] = roundedTaxAmount.ToString("0.00", CultureInfo.InvariantCulture); request.MetadataObject[$"quantity_{itemCount}"] = "1"; cartTotal += postProcessPaymentRequest.Order.OrderTax; roundedCartTotal += roundedTaxAmount; } if (cartTotal > postProcessPaymentRequest.Order.OrderTotal) { //get the difference between what the order total is and what it should be and use that as the "discount" var discountTotal = Math.Round(cartTotal - postProcessPaymentRequest.Order.OrderTotal, 2); roundedCartTotal -= discountTotal; //gift card or rewarded point amount applied to cart in nopCommerce - shows in Paystack as "discount" request.MetadataObject["discount_amount_cart"] = discountTotal.ToString("0.00", CultureInfo.InvariantCulture); } //save order total that actually sent to Paystack (used for PDT order total validation) _genericAttributeService.SaveAttribute(postProcessPaymentRequest.Order, PaystackHelper.OrderTotalSentToPaystack, roundedCartTotal); }
/// <summary> /// Formats attributes /// </summary> /// <param name="attributesXml">Attributes in XML format</param> /// <param name="customer">Customer</param> /// <param name="separator">Separator</param> /// <param name="htmlEncode">A value indicating whether to encode (HTML) values</param> /// <param name="renderPrices">A value indicating whether to render prices</param> /// <param name="allowHyperlinks">A value indicating whether to HTML hyperlink tags could be rendered (if required)</param> /// <returns>Attributes</returns> public virtual string FormatAttributes(string attributesXml, Customer customer, string separator = "<br />", bool htmlEncode = true, bool renderPrices = true, bool allowHyperlinks = true) { var result = new StringBuilder(); var attributes = _checkoutAttributeParser.ParseCheckoutAttributes(attributesXml); for (var i = 0; i < attributes.Count; i++) { var attribute = attributes[i]; var valuesStr = _checkoutAttributeParser.ParseValues(attributesXml, attribute.Id); for (var j = 0; j < valuesStr.Count; j++) { var valueStr = valuesStr[j]; var formattedAttribute = string.Empty; if (!attribute.ShouldHaveValues()) { //no values if (attribute.AttributeControlType == AttributeControlType.MultilineTextbox) { //multiline textbox var attributeName = _localizationService.GetLocalized(attribute, a => a.Name, _workContext.WorkingLanguage.Id); //encode (if required) if (htmlEncode) { attributeName = WebUtility.HtmlEncode(attributeName); } formattedAttribute = $"{attributeName}: {HtmlHelper.FormatText(valueStr, false, true, false, false, false, false)}"; //we never encode multiline textbox input } else if (attribute.AttributeControlType == AttributeControlType.FileUpload) { //file upload Guid.TryParse(valueStr, out var downloadGuid); var download = _downloadService.GetDownloadByGuid(downloadGuid); if (download != null) { //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) string attributeText; var fileName = $"{download.Filename ?? download.DownloadGuid.ToString()}{download.Extension}"; //encode (if required) if (htmlEncode) { fileName = WebUtility.HtmlEncode(fileName); } if (allowHyperlinks) { //hyperlinks are allowed var downloadLink = $"{_webHelper.GetStoreLocation(false)}download/getfileupload/?downloadId={download.DownloadGuid}"; attributeText = $"<a href=\"{downloadLink}\" class=\"fileuploadattribute\">{fileName}</a>"; } else { //hyperlinks aren't allowed attributeText = fileName; } var attributeName = _localizationService.GetLocalized(attribute, a => a.Name, _workContext.WorkingLanguage.Id); //encode (if required) if (htmlEncode) { attributeName = WebUtility.HtmlEncode(attributeName); } formattedAttribute = $"{attributeName}: {attributeText}"; } } else { //other attributes (textbox, datepicker) formattedAttribute = $"{_localizationService.GetLocalized(attribute, a => a.Name, _workContext.WorkingLanguage.Id)}: {valueStr}"; //encode (if required) if (htmlEncode) { formattedAttribute = WebUtility.HtmlEncode(formattedAttribute); } } } else { if (int.TryParse(valueStr, out var attributeValueId)) { var attributeValue = _checkoutAttributeService.GetCheckoutAttributeValueById(attributeValueId); if (attributeValue != null) { formattedAttribute = $"{_localizationService.GetLocalized(attribute, a => a.Name, _workContext.WorkingLanguage.Id)}: {_localizationService.GetLocalized(attributeValue, a => a.Name, _workContext.WorkingLanguage.Id)}"; if (renderPrices) { var priceAdjustmentBase = _taxService.GetCheckoutAttributePrice(attribute, attributeValue, customer); var priceAdjustment = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency); if (priceAdjustmentBase > 0) { formattedAttribute += string.Format( _localizationService.GetResource("FormattedAttributes.PriceAdjustment"), "+", _priceFormatter.FormatPrice(priceAdjustment), string.Empty); } } } //encode (if required) if (htmlEncode) { formattedAttribute = WebUtility.HtmlEncode(formattedAttribute); } } } if (string.IsNullOrEmpty(formattedAttribute)) { continue; } if (i != 0 || j != 0) { result.Append(separator); } result.Append(formattedAttribute); } } return(result.ToString()); }
/// <summary> /// Gets shopping cart subtotal /// </summary> /// <param name="cart">Cart</param> /// <param name="includingTax">A value indicating whether calculated price should include tax</param> /// <param name="discountAmount">Applied discount amount</param> /// <param name="appliedDiscount">Applied discount</param> /// <param name="subTotalWithoutDiscount">Sub total (without discount)</param> /// <param name="subTotalWithDiscount">Sub total (with discount)</param> /// <param name="taxRates">Tax rates (of order sub total)</param> public virtual void GetShoppingCartSubTotal(IList <ShoppingCartItem> cart, bool includingTax, out decimal discountAmount, out List <Discount> appliedDiscounts, out decimal subTotalWithoutDiscount, out decimal subTotalWithDiscount, out SortedDictionary <decimal, decimal> taxRates) { discountAmount = decimal.Zero; appliedDiscounts = new List <Discount>(); subTotalWithoutDiscount = decimal.Zero; subTotalWithDiscount = decimal.Zero; taxRates = new SortedDictionary <decimal, decimal>(); if (!cart.Any()) { return; } //get the customer Customer customer = cart.GetCustomer(); //sub totals decimal subTotalExclTaxWithoutDiscount = decimal.Zero; decimal subTotalInclTaxWithoutDiscount = decimal.Zero; var productService = EngineContextExperimental.Current.Resolve <IProductService>(); foreach (var shoppingCartItem in cart) { decimal sciSubTotal = _priceCalculationService.GetSubTotal(shoppingCartItem); var product = productService.GetProductById(shoppingCartItem.ProductId); decimal taxRate; decimal sciExclTax = _taxService.GetProductPrice(product, sciSubTotal, false, customer, out taxRate); decimal sciInclTax = _taxService.GetProductPrice(product, sciSubTotal, true, customer, out taxRate); subTotalExclTaxWithoutDiscount += sciExclTax; subTotalInclTaxWithoutDiscount += sciInclTax; //tax rates decimal sciTax = sciInclTax - sciExclTax; if (taxRate > decimal.Zero && sciTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, sciTax); } else { taxRates[taxRate] = taxRates[taxRate] + sciTax; } } } //checkout attributes if (customer != null) { var checkoutAttributesXml = customer.GetAttribute <string>(SystemCustomerAttributeNames.CheckoutAttributes, _storeContext.CurrentStore.Id); var attributeValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(checkoutAttributesXml); if (attributeValues != null) { foreach (var attributeValue in attributeValues) { decimal taxRate; decimal caExclTax = _taxService.GetCheckoutAttributePrice(attributeValue, false, customer, out taxRate); decimal caInclTax = _taxService.GetCheckoutAttributePrice(attributeValue, true, customer, out taxRate); subTotalExclTaxWithoutDiscount += caExclTax; subTotalInclTaxWithoutDiscount += caInclTax; //tax rates decimal caTax = caInclTax - caExclTax; if (taxRate > decimal.Zero && caTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, caTax); } else { taxRates[taxRate] = taxRates[taxRate] + caTax; } } } } } //subtotal without discount subTotalWithoutDiscount = includingTax ? subTotalInclTaxWithoutDiscount : subTotalExclTaxWithoutDiscount; if (subTotalWithoutDiscount < decimal.Zero) { subTotalWithoutDiscount = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { subTotalWithoutDiscount = RoundingHelper.RoundPrice(subTotalWithoutDiscount); } //We calculate discount amount on order subtotal excl tax (discount first) //calculate discount amount ('Applied to order subtotal' discount) decimal discountAmountExclTax = GetOrderSubtotalDiscount(customer, subTotalExclTaxWithoutDiscount, out appliedDiscounts); if (subTotalExclTaxWithoutDiscount < discountAmountExclTax) { discountAmountExclTax = subTotalExclTaxWithoutDiscount; } decimal discountAmountInclTax = discountAmountExclTax; //subtotal with discount (excl tax) decimal subTotalExclTaxWithDiscount = subTotalExclTaxWithoutDiscount - discountAmountExclTax; decimal subTotalInclTaxWithDiscount = subTotalExclTaxWithDiscount; //add tax for shopping items & checkout attributes var tempTaxRates = new Dictionary <decimal, decimal>(taxRates); foreach (KeyValuePair <decimal, decimal> kvp in tempTaxRates) { decimal taxRate = kvp.Key; decimal taxValue = kvp.Value; if (taxValue != decimal.Zero) { //discount the tax amount that applies to subtotal items if (subTotalExclTaxWithoutDiscount > decimal.Zero) { decimal discountTax = taxRates[taxRate] * (discountAmountExclTax / subTotalExclTaxWithoutDiscount); discountAmountInclTax += discountTax; taxValue = taxRates[taxRate] - discountTax; if (_shoppingCartSettings.RoundPricesDuringCalculation) { taxValue = RoundingHelper.RoundPrice(taxValue); } taxRates[taxRate] = taxValue; } //subtotal with discount (incl tax) subTotalInclTaxWithDiscount += taxValue; } } if (_shoppingCartSettings.RoundPricesDuringCalculation) { discountAmountInclTax = RoundingHelper.RoundPrice(discountAmountInclTax); discountAmountExclTax = RoundingHelper.RoundPrice(discountAmountExclTax); } if (includingTax) { subTotalWithDiscount = subTotalInclTaxWithDiscount; discountAmount = discountAmountInclTax; } else { subTotalWithDiscount = subTotalExclTaxWithDiscount; discountAmount = discountAmountExclTax; } if (subTotalWithDiscount < decimal.Zero) { subTotalWithDiscount = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { subTotalWithDiscount = RoundingHelper.RoundPrice(subTotalWithDiscount); } }
private async Task PrepareCheckoutAttributes(ShoppingCartModel model, GetShoppingCart request) { #region Checkout attributes var checkoutAttributes = await _checkoutAttributeService.GetAllCheckoutAttributes(request.Store.Id, !request.Cart.RequiresShipping()); foreach (var attribute in checkoutAttributes) { var attributeModel = new ShoppingCartModel.CheckoutAttributeModel { Id = attribute.Id, Name = attribute.GetLocalized(x => x.Name, request.Language.Id), TextPrompt = attribute.GetLocalized(x => x.TextPrompt, request.Language.Id), IsRequired = attribute.IsRequired, AttributeControlType = attribute.AttributeControlType, DefaultValue = attribute.DefaultValue }; if (!String.IsNullOrEmpty(attribute.ValidationFileAllowedExtensions)) { attributeModel.AllowedFileExtensions = attribute.ValidationFileAllowedExtensions .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToList(); } if (attribute.ShouldHaveValues()) { //values var attributeValues = attribute.CheckoutAttributeValues; foreach (var attributeValue in attributeValues) { var attributeValueModel = new ShoppingCartModel.CheckoutAttributeValueModel { Id = attributeValue.Id, Name = attributeValue.GetLocalized(x => x.Name, request.Language.Id), ColorSquaresRgb = attributeValue.ColorSquaresRgb, IsPreSelected = attributeValue.IsPreSelected, }; attributeModel.Values.Add(attributeValueModel); //display price if allowed if (await _permissionService.Authorize(StandardPermissionProvider.DisplayPrices)) { decimal priceAdjustmentBase = (await _taxService.GetCheckoutAttributePrice(attribute, attributeValue)).checkoutPrice; decimal priceAdjustment = await _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, request.Currency); if (priceAdjustmentBase > decimal.Zero) { attributeValueModel.PriceAdjustment = "+" + _priceFormatter.FormatPrice(priceAdjustment); } else if (priceAdjustmentBase < decimal.Zero) { attributeValueModel.PriceAdjustment = "-" + _priceFormatter.FormatPrice(-priceAdjustment); } } } } //set already selected attributes var selectedCheckoutAttributes = request.Customer.GetAttributeFromEntity <string>(SystemCustomerAttributeNames.CheckoutAttributes, request.Store.Id); switch (attribute.AttributeControlType) { case AttributeControlType.DropdownList: case AttributeControlType.RadioList: case AttributeControlType.Checkboxes: case AttributeControlType.ColorSquares: case AttributeControlType.ImageSquares: { if (!String.IsNullOrEmpty(selectedCheckoutAttributes)) { //clear default selection foreach (var item in attributeModel.Values) { item.IsPreSelected = false; } //select new values var selectedValues = await _checkoutAttributeParser.ParseCheckoutAttributeValues(selectedCheckoutAttributes); foreach (var attributeValue in selectedValues) { if (attributeModel.Id == attributeValue.CheckoutAttributeId) { foreach (var item in attributeModel.Values) { if (attributeValue.Id == item.Id) { item.IsPreSelected = true; } } } } } } break; case AttributeControlType.ReadonlyCheckboxes: { //do nothing //values are already pre-set } break; case AttributeControlType.TextBox: case AttributeControlType.MultilineTextbox: { if (!String.IsNullOrEmpty(selectedCheckoutAttributes)) { var enteredText = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id); if (enteredText.Any()) { attributeModel.DefaultValue = enteredText[0]; } } } break; case AttributeControlType.Datepicker: { //keep in mind my that the code below works only in the current culture var selectedDateStr = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id); if (selectedDateStr.Any()) { DateTime selectedDate; if (DateTime.TryParseExact(selectedDateStr[0], "D", CultureInfo.CurrentCulture, DateTimeStyles.None, out selectedDate)) { //successfully parsed attributeModel.SelectedDay = selectedDate.Day; attributeModel.SelectedMonth = selectedDate.Month; attributeModel.SelectedYear = selectedDate.Year; } } } break; case AttributeControlType.FileUpload: { if (!String.IsNullOrEmpty(selectedCheckoutAttributes)) { var downloadGuidStr = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id).FirstOrDefault(); Guid downloadGuid; Guid.TryParse(downloadGuidStr, out downloadGuid); var download = await _downloadService.GetDownloadByGuid(downloadGuid); if (download != null) { attributeModel.DefaultValue = download.DownloadGuid.ToString(); } } } break; default: break; } model.CheckoutAttributes.Add(attributeModel); } #endregion }
/// <summary> /// Generate string (URL) for redirection /// </summary> /// <param name="postProcessPaymentRequest">Payment info required for an order processing</param> /// <param name="passProductNamesAndTotals">A value indicating whether to pass product names and totals</param> private string GenerationCallBackUrl(PostProcessPaymentRequest postProcessPaymentRequest, bool passProductNamesAndTotals) { var builder = new StringBuilder(); builder.Append(_webHelper.GetStoreLocation(false) + "Plugins/PaymentMellatBank/PDTHandler"); var cmd = passProductNamesAndTotals ? "_cart" : "_xclick"; builder.AppendFormat("?cmd={0}", cmd); if (passProductNamesAndTotals) { builder.AppendFormat("&upload=1"); //get the items in the cart decimal cartTotal = decimal.Zero; var cartTotalRounded = decimal.Zero; var cartItems = postProcessPaymentRequest.Order.OrderItems; int x = 1; foreach (var item in cartItems) { var unitPriceExclTax = item.UnitPriceExclTax; var priceExclTax = item.PriceExclTax; //round var unitPriceExclTaxRounded = Math.Round(unitPriceExclTax, 2); builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(item.Product.Name)); builder.AppendFormat("&amount_" + x + "={0}", unitPriceExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); builder.AppendFormat("&quantity_" + x + "={0}", item.Quantity); x++; cartTotal += priceExclTax; cartTotalRounded += unitPriceExclTaxRounded * item.Quantity; } //the checkout attributes that have a cost value and send them to MellatBank as items to be paid for var attributeValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(postProcessPaymentRequest.Order.CheckoutAttributesXml); foreach (var val in attributeValues) { var attPrice = _taxService.GetCheckoutAttributePrice(val, false, postProcessPaymentRequest.Order.Customer); //round var attPriceRounded = Math.Round(attPrice, 2); if (attPrice > decimal.Zero) //if it has a price { var attribute = val.CheckoutAttribute; if (attribute != null) { var attName = attribute.Name; //set the name builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(attName)); //name builder.AppendFormat("&amount_" + x + "={0}", attPriceRounded.ToString("0.00", CultureInfo.InvariantCulture)); //amount builder.AppendFormat("&quantity_" + x + "={0}", 1); //quantity x++; cartTotal += attPrice; cartTotalRounded += attPriceRounded; } } } //order totals //shipping var orderShippingExclTax = postProcessPaymentRequest.Order.OrderShippingExclTax; var orderShippingExclTaxRounded = Math.Round(orderShippingExclTax, 2); if (orderShippingExclTax > decimal.Zero) { builder.AppendFormat("&item_name_" + x + "={0}", "Shipping fee"); builder.AppendFormat("&amount_" + x + "={0}", orderShippingExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); builder.AppendFormat("&quantity_" + x + "={0}", 1); x++; cartTotal += orderShippingExclTax; cartTotalRounded += orderShippingExclTaxRounded; } //payment method additional fee var paymentMethodAdditionalFeeExclTax = postProcessPaymentRequest.Order.PaymentMethodAdditionalFeeExclTax; var paymentMethodAdditionalFeeExclTaxRounded = Math.Round(paymentMethodAdditionalFeeExclTax, 2); if (paymentMethodAdditionalFeeExclTax > decimal.Zero) { builder.AppendFormat("&item_name_" + x + "={0}", "Payment method fee"); builder.AppendFormat("&amount_" + x + "={0}", paymentMethodAdditionalFeeExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); builder.AppendFormat("&quantity_" + x + "={0}", 1); x++; cartTotal += paymentMethodAdditionalFeeExclTax; cartTotalRounded += paymentMethodAdditionalFeeExclTaxRounded; } //tax var orderTax = postProcessPaymentRequest.Order.OrderTax; var orderTaxRounded = Math.Round(orderTax, 2); if (orderTax > decimal.Zero) { //builder.AppendFormat("&tax_1={0}", orderTax.ToString("0.00", CultureInfo.InvariantCulture)); //add tax as item builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode("Sales Tax")); //name builder.AppendFormat("&amount_" + x + "={0}", orderTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); //amount builder.AppendFormat("&quantity_" + x + "={0}", 1); //quantity cartTotal += orderTax; cartTotalRounded += orderTaxRounded; x++; } if (cartTotal > postProcessPaymentRequest.Order.OrderTotal) { /* Take the difference between what the order total is and what it should be and use that as the "discount". * The difference equals the amount of the gift card and/or reward points used. */ decimal discountTotal = cartTotal - postProcessPaymentRequest.Order.OrderTotal; discountTotal = Math.Round(discountTotal, 2); cartTotalRounded -= discountTotal; //gift card or rewared point amount applied to cart in nopCommerce - shows in MellatBank as "discount" builder.AppendFormat("&discount_amount_cart={0}", discountTotal.ToString("0.00", CultureInfo.InvariantCulture)); } //save order total that actually sent to MellatBank (used for PDT order total validation) _genericAttributeService.SaveAttribute(postProcessPaymentRequest.Order, "OrderMellatBankSaleReferenceId", cartTotalRounded); } else { //pass order total builder.AppendFormat("&item_name=Order Number {0}", postProcessPaymentRequest.Order.Id); var orderTotal = Math.Round(postProcessPaymentRequest.Order.OrderTotal, 2); builder.AppendFormat("&amount={0}", orderTotal.ToString("0.00", CultureInfo.InvariantCulture)); //save order total that actually sent to MellatBank (used for PDT order total validation) _genericAttributeService.SaveAttribute(postProcessPaymentRequest.Order, "OrderMellatBankSaleReferenceId", orderTotal); } builder.AppendFormat("&custom={0}", postProcessPaymentRequest.Order.OrderGuid); builder.AppendFormat("&charset={0}", "utf-8"); builder.AppendFormat("&bn={0}", BN_CODE); builder.Append(string.Format("&no_note=1¤cy_code={0}", HttpUtility.UrlEncode(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode))); builder.AppendFormat("&invoice={0}", postProcessPaymentRequest.Order.Id); builder.AppendFormat("&rm=2", new object[0]); if (postProcessPaymentRequest.Order.ShippingStatus != ShippingStatus.ShippingNotRequired) { builder.AppendFormat("&no_shipping=2", new object[0]); } else { builder.AppendFormat("&no_shipping=1", new object[0]); } return(builder.ToString()); }
public virtual void PrepareShoppingCartModel(ShoppingCartModel model, IList <ShoppingCartItem> cart, bool isEditable = true, bool validateCheckoutAttributes = false, bool prepareEstimateShippingIfEnabled = true, bool setEstimateShippingDefaultAddress = true, bool prepareAndDisplayOrderReviewData = false) { if (cart == null) { throw new ArgumentNullException("cart"); } if (model == null) { throw new ArgumentNullException("model"); } model.OnePageCheckoutEnabled = _orderSettings.OnePageCheckoutEnabled; if (cart.Count == 0) { return; } #region Simple properties model.IsEditable = isEditable; model.ShowProductImages = _shoppingCartSettings.ShowProductImagesOnShoppingCart; model.ShowSku = _catalogSettings.ShowProductSku; var checkoutAttributesXml = _workContext.CurrentCustomer.GetAttribute <string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService, _storeContext.CurrentStore.Id); model.CheckoutAttributeInfo = _checkoutAttributeFormatter.FormatAttributes(checkoutAttributesXml, _workContext.CurrentCustomer); bool minOrderSubtotalAmountOk = _orderProcessingService.ValidateMinOrderSubtotalAmount(cart); if (!minOrderSubtotalAmountOk) { decimal minOrderSubtotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderSubtotalAmount, _workContext.WorkingCurrency); model.MinOrderSubtotalWarning = string.Format(_localizationService.GetResource("Checkout.MinOrderSubtotalAmount"), _priceFormatter.FormatPrice(minOrderSubtotalAmount, true, false)); } model.TermsOfServiceOnShoppingCartPage = _orderSettings.TermsOfServiceOnShoppingCartPage; model.TermsOfServiceOnOrderConfirmPage = _orderSettings.TermsOfServiceOnOrderConfirmPage; //gift card and gift card boxes model.DiscountBox.Display = _shoppingCartSettings.ShowDiscountBox; var discountCouponCode = _workContext.CurrentCustomer.GetAttribute <string>(SystemCustomerAttributeNames.DiscountCouponCode); var discount = _discountService.GetDiscountByCouponCode(discountCouponCode); if (discount != null && discount.RequiresCouponCode && _discountService.IsDiscountValid(discount, _workContext.CurrentCustomer)) { model.DiscountBox.CurrentCode = discount.CouponCode; } model.GiftCardBox.Display = _shoppingCartSettings.ShowGiftCardBox; //cart warnings var cartWarnings = _shoppingCartService.GetShoppingCartWarnings(cart, checkoutAttributesXml, validateCheckoutAttributes); foreach (var warning in cartWarnings) { model.Warnings.Add(warning); } #endregion #region Checkout attributes var checkoutAttributes = _checkoutAttributeService.GetAllCheckoutAttributes(_storeContext.CurrentStore.Id, !cart.RequiresShipping()); foreach (var attribute in checkoutAttributes) { var attributeModel = new ShoppingCartModel.CheckoutAttributeModel { Id = attribute.Id, Name = attribute.GetLocalized(x => x.Name), TextPrompt = attribute.GetLocalized(x => x.TextPrompt), IsRequired = attribute.IsRequired, AttributeControlType = attribute.AttributeControlType, DefaultValue = attribute.DefaultValue }; if (!String.IsNullOrEmpty(attribute.ValidationFileAllowedExtensions)) { attributeModel.AllowedFileExtensions = attribute.ValidationFileAllowedExtensions .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToList(); } if (attribute.ShouldHaveValues()) { //values var attributeValues = _checkoutAttributeService.GetCheckoutAttributeValues(attribute.Id); foreach (var attributeValue in attributeValues) { var attributeValueModel = new ShoppingCartModel.CheckoutAttributeValueModel { Id = attributeValue.Id, Name = attributeValue.GetLocalized(x => x.Name), ColorSquaresRgb = attributeValue.ColorSquaresRgb, IsPreSelected = attributeValue.IsPreSelected, }; attributeModel.Values.Add(attributeValueModel); //display price if allowed if (_permissionService.Authorize(StandardPermissionProvider.DisplayPrices)) { decimal priceAdjustmentBase = _taxService.GetCheckoutAttributePrice(attributeValue); decimal priceAdjustment = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency); if (priceAdjustmentBase > decimal.Zero) { attributeValueModel.PriceAdjustment = "+" + _priceFormatter.FormatPrice(priceAdjustment); } else if (priceAdjustmentBase < decimal.Zero) { attributeValueModel.PriceAdjustment = "-" + _priceFormatter.FormatPrice(-priceAdjustment); } } } } //set already selected attributes var selectedCheckoutAttributes = _workContext.CurrentCustomer.GetAttribute <string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService, _storeContext.CurrentStore.Id); switch (attribute.AttributeControlType) { case AttributeControlType.DropdownList: case AttributeControlType.RadioList: case AttributeControlType.Checkboxes: case AttributeControlType.ColorSquares: { if (!String.IsNullOrEmpty(selectedCheckoutAttributes)) { //clear default selection foreach (var item in attributeModel.Values) { item.IsPreSelected = false; } //select new values var selectedValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(selectedCheckoutAttributes); foreach (var attributeValue in selectedValues) { foreach (var item in attributeModel.Values) { if (attributeValue.Id == item.Id) { item.IsPreSelected = true; } } } } } break; case AttributeControlType.ReadonlyCheckboxes: { //do nothing //values are already pre-set } break; case AttributeControlType.TextBox: case AttributeControlType.MultilineTextbox: { if (!String.IsNullOrEmpty(selectedCheckoutAttributes)) { var enteredText = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id); if (enteredText.Count > 0) { attributeModel.DefaultValue = enteredText[0]; } } } break; case AttributeControlType.Datepicker: { //keep in mind my that the code below works only in the current culture var selectedDateStr = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id); if (selectedDateStr.Count > 0) { DateTime selectedDate; if (DateTime.TryParseExact(selectedDateStr[0], "D", CultureInfo.CurrentCulture, DateTimeStyles.None, out selectedDate)) { //successfully parsed attributeModel.SelectedDay = selectedDate.Day; attributeModel.SelectedMonth = selectedDate.Month; attributeModel.SelectedYear = selectedDate.Year; } } } break; default: break; } model.CheckoutAttributes.Add(attributeModel); } #endregion #region Estimate shipping if (prepareEstimateShippingIfEnabled) { model.EstimateShipping.Enabled = cart.Count > 0 && cart.RequiresShipping() && _shippingSettings.EstimateShippingEnabled; if (model.EstimateShipping.Enabled) { //countries int?defaultEstimateCountryId = (setEstimateShippingDefaultAddress && _workContext.CurrentCustomer.ShippingAddress != null) ? _workContext.CurrentCustomer.ShippingAddress.CountryId : model.EstimateShipping.CountryId; model.EstimateShipping.AvailableCountries.Add(new SelectListItem { Text = _localizationService.GetResource("Address.SelectCountry"), Value = "0" }); foreach (var c in _countryService.GetAllCountriesForShipping()) { model.EstimateShipping.AvailableCountries.Add(new SelectListItem { Text = c.GetLocalized(x => x.Name), Value = c.Id.ToString(), Selected = c.Id == defaultEstimateCountryId }); } //states int?defaultEstimateStateId = (setEstimateShippingDefaultAddress && _workContext.CurrentCustomer.ShippingAddress != null) ? _workContext.CurrentCustomer.ShippingAddress.StateProvinceId : model.EstimateShipping.StateProvinceId; var states = defaultEstimateCountryId.HasValue ? _stateProvinceService.GetStateProvincesByCountryId(defaultEstimateCountryId.Value).ToList() : new List <StateProvince>(); if (states.Count > 0) { foreach (var s in states) { model.EstimateShipping.AvailableStates.Add(new SelectListItem { Text = s.GetLocalized(x => x.Name), Value = s.Id.ToString(), Selected = s.Id == defaultEstimateStateId }); } } else { model.EstimateShipping.AvailableStates.Add(new SelectListItem { Text = _localizationService.GetResource("Address.OtherNonUS"), Value = "0" }); } if (setEstimateShippingDefaultAddress && _workContext.CurrentCustomer.ShippingAddress != null) { model.EstimateShipping.ZipPostalCode = _workContext.CurrentCustomer.ShippingAddress.ZipPostalCode; } } } #endregion #region Cart items foreach (var sci in cart) { var cartItemModel = new ShoppingCartModel.ShoppingCartItemModel { Id = sci.Id, Sku = sci.Product.FormatSku(sci.AttributesXml, _productAttributeParser), ProductId = sci.Product.Id, ProductName = sci.Product.GetLocalized(x => x.Name), ProductSeName = sci.Product.GetSeName(), Quantity = sci.Quantity, AttributeInfo = _productAttributeFormatter.FormatAttributes(sci.Product, sci.AttributesXml), }; //allow editing? //1. setting enabled? //2. simple product? //3. has attribute or gift card? //4. visible individually? cartItemModel.AllowItemEditing = _shoppingCartSettings.AllowCartItemEditing && sci.Product.ProductType == ProductType.SimpleProduct && (!String.IsNullOrEmpty(cartItemModel.AttributeInfo) || sci.Product.IsGiftCard) && sci.Product.VisibleIndividually; //allowed quantities var allowedQuantities = sci.Product.ParseAllowedQuatities(); foreach (var qty in allowedQuantities) { cartItemModel.AllowedQuantities.Add(new SelectListItem { Text = qty.ToString(), Value = qty.ToString(), Selected = sci.Quantity == qty }); } //recurring info if (sci.Product.IsRecurring) { cartItemModel.RecurringInfo = string.Format(_localizationService.GetResource("ShoppingCart.RecurringPeriod"), sci.Product.RecurringCycleLength, sci.Product.RecurringCyclePeriod.GetLocalizedEnum(_localizationService, _workContext)); } //rental info if (sci.Product.IsRental) { var rentalStartDate = sci.RentalStartDateUtc.HasValue ? sci.Product.FormatRentalDate(sci.RentalStartDateUtc.Value) : ""; var rentalEndDate = sci.RentalEndDateUtc.HasValue ? sci.Product.FormatRentalDate(sci.RentalEndDateUtc.Value) : ""; cartItemModel.RentalInfo = string.Format(_localizationService.GetResource("ShoppingCart.Rental.FormattedDate"), rentalStartDate, rentalEndDate); } //unit prices if (sci.Product.CallForPrice) { cartItemModel.UnitPrice = _localizationService.GetResource("Products.CallForPrice"); } else { decimal taxRate; decimal shoppingCartUnitPriceWithDiscountBase = _taxService.GetProductPrice(sci.Product, _priceCalculationService.GetUnitPrice(sci), out taxRate); decimal shoppingCartUnitPriceWithDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartUnitPriceWithDiscountBase, _workContext.WorkingCurrency); cartItemModel.UnitPrice = _priceFormatter.FormatPrice(shoppingCartUnitPriceWithDiscount); } //subtotal, discount if (sci.Product.CallForPrice) { cartItemModel.SubTotal = _localizationService.GetResource("Products.CallForPrice"); } else { //sub total Discount scDiscount; decimal shoppingCartItemDiscountBase; decimal taxRate; decimal shoppingCartItemSubTotalWithDiscountBase = _taxService.GetProductPrice(sci.Product, _priceCalculationService.GetSubTotal(sci, true, out shoppingCartItemDiscountBase, out scDiscount), out taxRate); decimal shoppingCartItemSubTotalWithDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartItemSubTotalWithDiscountBase, _workContext.WorkingCurrency); cartItemModel.SubTotal = _priceFormatter.FormatPrice(shoppingCartItemSubTotalWithDiscount); //display an applied discount amount if (scDiscount != null) { shoppingCartItemDiscountBase = _taxService.GetProductPrice(sci.Product, shoppingCartItemDiscountBase, out taxRate); if (shoppingCartItemDiscountBase > decimal.Zero) { decimal shoppingCartItemDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartItemDiscountBase, _workContext.WorkingCurrency); cartItemModel.Discount = _priceFormatter.FormatPrice(shoppingCartItemDiscount); } } } //item warnings var itemWarnings = _shoppingCartService.GetShoppingCartItemWarnings( _workContext.CurrentCustomer, sci.ShoppingCartType, sci.Product, sci.StoreId, sci.AttributesXml, sci.CustomerEnteredPrice, sci.RentalStartDateUtc, sci.RentalEndDateUtc, sci.Quantity, false); foreach (var warning in itemWarnings) { cartItemModel.Warnings.Add(warning); } model.Items.Add(cartItemModel); } #endregion #region Button payment methods var paymentMethods = _paymentService .LoadActivePaymentMethods(_workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id) .Where(pm => pm.PaymentMethodType == PaymentMethodType.Button) .Where(pm => !pm.HidePaymentMethod(cart)) .ToList(); foreach (var pm in paymentMethods) { if (cart.IsRecurring() && pm.RecurringPaymentType == RecurringPaymentType.NotSupported) { continue; } string actionName; string controllerName; RouteValueDictionary routeValues; pm.GetPaymentInfoRoute(out actionName, out controllerName, out routeValues); model.ButtonPaymentMethodActionNames.Add(actionName); model.ButtonPaymentMethodControllerNames.Add(controllerName); model.ButtonPaymentMethodRouteValues.Add(routeValues); } #endregion #region Order review data if (prepareAndDisplayOrderReviewData) { model.OrderReviewData.Display = true; //billing info var billingAddress = _workContext.CurrentCustomer.BillingAddress; if (billingAddress != null) { model.OrderReviewData.BillingAddress.PrepareModel( address: billingAddress, excludeProperties: false, addressSettings: _addressSettings, addressAttributeFormatter: _addressAttributeFormatter); } //shipping info if (cart.RequiresShipping()) { model.OrderReviewData.IsShippable = true; if (_shippingSettings.AllowPickUpInStore) { model.OrderReviewData.SelectedPickUpInStore = _workContext.CurrentCustomer.GetAttribute <bool>(SystemCustomerAttributeNames.SelectedPickUpInStore, _storeContext.CurrentStore.Id); } if (!model.OrderReviewData.SelectedPickUpInStore) { var shippingAddress = _workContext.CurrentCustomer.ShippingAddress; if (shippingAddress != null) { model.OrderReviewData.ShippingAddress.PrepareModel( address: shippingAddress, excludeProperties: false, addressSettings: _addressSettings, addressAttributeFormatter: _addressAttributeFormatter); } } //selected shipping method var shippingOption = _workContext.CurrentCustomer.GetAttribute <ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, _storeContext.CurrentStore.Id); if (shippingOption != null) { model.OrderReviewData.ShippingMethod = shippingOption.Name; } } //payment info var selectedPaymentMethodSystemName = _workContext.CurrentCustomer.GetAttribute <string>( SystemCustomerAttributeNames.SelectedPaymentMethod, _storeContext.CurrentStore.Id); var paymentMethod = _paymentService.LoadPaymentMethodBySystemName(selectedPaymentMethodSystemName); model.OrderReviewData.PaymentMethod = paymentMethod != null?paymentMethod.GetLocalizedFriendlyName(_localizationService, _workContext.WorkingLanguage.Id) : ""; } #endregion }
/// <summary> /// Gets checkout attribute value price /// </summary> /// <param name="cav">Checkout attribute value</param> /// <returns>Price</returns> public decimal GetCheckoutAttributePrice([FromBody] CheckoutAttributeValue cav) { return(_taxService.GetCheckoutAttributePrice(cav)); }
/// <summary> /// Formats attributes /// </summary> /// <param name="attributes">Attributes</param> /// <param name="customer">Customer</param> /// <param name="serapator">Serapator</param> /// <param name="htmlEncode">A value indicating whether to encode (HTML) values</param> /// <param name="renderPrices">A value indicating whether to render prices</param> /// <returns>Attributes</returns> public string FormatAttributes(string attributes, Customer customer, string serapator = "<br />", bool htmlEncode = true, bool renderPrices = true) { var result = new StringBuilder(); var caCollection = _checkoutAttributeParser.ParseCheckoutAttributes(attributes); for (int i = 0; i < caCollection.Count; i++) { var ca = caCollection[i]; var valuesStr = _checkoutAttributeParser.ParseValues(attributes, ca.Id); for (int j = 0; j < valuesStr.Count; j++) { string valueStr = valuesStr[j]; string caAttribute = string.Empty; if (!ca.ShouldHaveValues()) { if (ca.AttributeControlType == AttributeControlType.MultilineTextbox) { caAttribute = string.Format("{0}: {1}", ca.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id), HtmlHelper.FormatText(valueStr, false, true, true, false, false, false)); } else { caAttribute = string.Format("{0}: {1}", ca.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id), valueStr); } } else { int caId = 0; if (int.TryParse(valueStr, out caId)) { var caValue = _checkoutAttributeService.GetCheckoutAttributeValueById(caId); if (caValue != null) { caAttribute = string.Format("{0}: {1}", ca.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id), caValue.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id)); if (renderPrices) { decimal priceAdjustmentBase = _taxService.GetCheckoutAttributePrice(caValue, customer); decimal priceAdjustment = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency); if (priceAdjustmentBase > 0) { string priceAdjustmentStr = _priceFormatter.FormatPrice(priceAdjustment); caAttribute += string.Format(" [+{0}]", priceAdjustmentStr); } } } } } if (!String.IsNullOrEmpty(caAttribute)) { if (i != 0 || j != 0) { result.Append(serapator); } //we don't encode multiline textbox input if (htmlEncode && ca.AttributeControlType != AttributeControlType.MultilineTextbox) { result.Append(HttpUtility.HtmlEncode(caAttribute)); } else { result.Append(caAttribute); } } } } return(result.ToString()); }
/// <summary> /// Post process payment (used by payment gateways that require redirecting to a third-party URL) /// </summary> /// <param name="postProcessPaymentRequest">Payment info required for an order processing</param> public void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest) { //Base URL var builder = new StringBuilder(); builder.Append(GetMonerisUrl()); //Store Id and security token builder.AppendFormat("?ps_store_id={0}&hpp_key={1}", HttpUtility.UrlEncode(_monerisStandardPaymentSettings.StoreId), HttpUtility.UrlEncode(_monerisStandardPaymentSettings.PdtToken)); //OrderId builder.AppendFormat("&order_id={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.Id.ToString())); //Email builder.AppendFormat("&email={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.Customer.Email)); //UserName builder.AppendFormat("&cust_id={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.Customer.Username)); //Language string lang = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName; if (lang.Contains("fr")) { lang = "fr-ca"; } builder.AppendFormat("&lang={0}", HttpUtility.UrlEncode(lang)); //Billing address if (!(postProcessPaymentRequest.Order.BillingAddress == null)) { builder.AppendFormat("&bill_first_name={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.FirstName)); builder.AppendFormat("&bill_last_name={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.LastName)); builder.AppendFormat("&bill_address_one={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.Address1 + " " + postProcessPaymentRequest.Order.BillingAddress.Address2)); builder.AppendFormat("&bill_city={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.City)); builder.AppendFormat("&bill_state_or_province={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.StateProvince.Abbreviation)); builder.AppendFormat("&bill_postal_code={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.ZipPostalCode)); builder.AppendFormat("&bill_country={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.Country.TwoLetterIsoCode)); builder.AppendFormat("&bill_phone={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.PhoneNumber)); } //Shipping address if (!(postProcessPaymentRequest.Order.ShippingAddress == null)) { builder.AppendFormat("&ship_first_name={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.ShippingAddress.FirstName)); builder.AppendFormat("&ship_last_name={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.ShippingAddress.LastName)); builder.AppendFormat("&ship_address_one={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.ShippingAddress.Address1 + " " + postProcessPaymentRequest.Order.ShippingAddress.Address2)); builder.AppendFormat("&ship_city={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.ShippingAddress.City)); builder.AppendFormat("&ship_state_or_province={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.ShippingAddress.StateProvince.Abbreviation)); builder.AppendFormat("&ship_postal_code={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.ShippingAddress.ZipPostalCode)); builder.AppendFormat("&ship_country={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.ShippingAddress.Country.TwoLetterIsoCode)); builder.AppendFormat("&ship_phone={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.ShippingAddress.PhoneNumber)); } //Shipping var shippingPriceExclTax = postProcessPaymentRequest.Order.OrderShippingExclTax; var shippingPriceExclTaxRounded = Math.Round(shippingPriceExclTax, 2); builder.AppendFormat("&shipping_cost={0}", shippingPriceExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); //Send items detail if (_monerisStandardPaymentSettings.PassProductNamesAndTotals) { //Yes //get the items in the cart var cartItems = postProcessPaymentRequest.Order.OrderItems; int x = 1; foreach (var item in cartItems) { //round unit price var unitPriceExclTax = item.UnitPriceExclTax; var unitPriceExclTaxRounded = Math.Round(unitPriceExclTax, 2); //round subtotal var priceExclTax = item.PriceExclTax; var priceExclTaxRounded = Math.Round(priceExclTax, 2); //id builder.AppendFormat("&id" + x + "={0}", HttpUtility.UrlEncode(item.Product.Sku)); //description builder.AppendFormat("&description" + x + "={0}", HttpUtility.UrlEncode(item.Product.Name)); //quantity builder.AppendFormat("&quantity" + x + "={0}", item.Quantity); //unitprice builder.AppendFormat("&price" + x + "={0}", unitPriceExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); //subtotal builder.AppendFormat("&subtotal" + x + "={0}", priceExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); //Video project participation if (item.Product.Sku == CameleoEventProducts.PRODUCT_VIDEO_PROJECT) { //Yes //_genericAttributeService.SaveAttribute<ShippingOption>(customer, SystemCustomerAttributeNames.DiscountCouponCode, null); } x++; } //the checkout attributes that have a dollar value and send them to Moneris as items to be paid for var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(postProcessPaymentRequest.Order.CheckoutAttributesXml); foreach (var val in caValues) { var attPrice = _taxService.GetCheckoutAttributePrice(val, false, postProcessPaymentRequest.Order.Customer); //round var attPriceRounded = Math.Round(attPrice, 2); if (attPrice > decimal.Zero) //if it has a price { var ca = val.CheckoutAttribute; if (ca != null) { var attName = ca.Name; //set the name //id builder.AppendFormat("&id" + x + "={0}", HttpUtility.UrlEncode(attName)); //description builder.AppendFormat("&description" + x + "={0}", HttpUtility.UrlEncode(attName)); //quantity builder.AppendFormat("&quantity" + x + "={0}", 1); //unitprice builder.AppendFormat("&price" + x + "={0}", attPriceRounded.ToString("0.00", CultureInfo.InvariantCulture)); //subtotal builder.AppendFormat("&subtotal" + x + "={0}", attPriceRounded.ToString("0.00", CultureInfo.InvariantCulture)); x++; } } } } else { //pass order total only } //Charge Total var totalPriceInclTax = postProcessPaymentRequest.Order.OrderTotal; var totalPriceInclTaxRounded = Math.Round(totalPriceInclTax, 2); builder.AppendFormat("&charge_total={0}", totalPriceInclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); var totalPriceExclTax = postProcessPaymentRequest.Order.OrderTotal - postProcessPaymentRequest.Order.OrderTax; var totalPriceExclTaxRounded = Math.Round(totalPriceExclTax, 2); string provinceAbbrev = postProcessPaymentRequest.Order.BillingAddress.StateProvince.Abbreviation; if (provinceAbbrev.Contains("QC")) { //Quebec //GST var totalGST = totalPriceExclTax * (decimal)0.05; var totalGSTRounded = Math.Round(totalGST, 2); builder.AppendFormat("&gst={0}", totalGSTRounded.ToString("0.00", CultureInfo.InvariantCulture)); //PST var totalPST = totalPriceExclTax * (decimal)0.09975; var totalPSTRounded = Math.Round(totalPST, 2); builder.AppendFormat("&pst={0}", totalPSTRounded.ToString("0.00", CultureInfo.InvariantCulture)); } else if (provinceAbbrev.Contains("ON") || provinceAbbrev.Contains("NL") || provinceAbbrev.Contains("TNL") || provinceAbbrev.Contains("NB")) { //HST 13 var totalHST = totalPriceExclTax * (decimal)0.13; var totalHSTRounded = Math.Round(totalHST, 2); builder.AppendFormat("&hst={0}", totalHSTRounded.ToString("0.00", CultureInfo.InvariantCulture)); } else if (provinceAbbrev.Contains("NS") || provinceAbbrev.Contains("NE")) { //HST 15 var totalHST = totalPriceExclTax * (decimal)0.15; var totalHSTRounded = Math.Round(totalHST, 2); builder.AppendFormat("&hst={0}", totalHSTRounded.ToString("0.00", CultureInfo.InvariantCulture)); } else if (provinceAbbrev.Contains("PE") || provinceAbbrev.Contains("PEI") || provinceAbbrev.Contains("IPE")) { //HST 14 var totalHST = totalPriceExclTax * (decimal)0.14; var totalHSTRounded = Math.Round(totalHST, 2); builder.AppendFormat("&hst={0}", totalHSTRounded.ToString("0.00", CultureInfo.InvariantCulture)); } else if (provinceAbbrev.Contains("BC") || provinceAbbrev.Contains("CB") || provinceAbbrev.Contains("AB") || provinceAbbrev.Contains("SK") || provinceAbbrev.Contains("MB") || provinceAbbrev.Contains("NT") || provinceAbbrev.Contains("TNO") || provinceAbbrev.Contains("NU") || provinceAbbrev.Contains("YT") || provinceAbbrev.Contains("YU")) { //GST only var totalGST = totalPriceExclTax * (decimal)0.05; var totalGSTRounded = Math.Round(totalGST, 2); builder.AppendFormat("&gst={0}", totalGSTRounded.ToString("0.00", CultureInfo.InvariantCulture)); } //Redirect _httpContext.Response.Redirect(builder.ToString()); }
private void AddInvoiceVars(Dictionary <string, string> vars, PostProcessPaymentRequest postProcessPaymentRequest) { // article for invoice vars: http://kb.cardcom.co.il/article/AA-00244/0 var customer = _workContext.CurrentCustomer; var firstName = customer.GetAttribute <string>(SystemCustomerAttributeNames.FirstName); var lastName = customer.GetAttribute <string>(SystemCustomerAttributeNames.LastName); // customer info : vars["InvoiceHead.CustName"] = firstName + " " + lastName; // customer name vars["InvoiceHead.SendByEmail"] = "true"; // will the invoice be send by email to the customer vars["InvoiceHead.Language"] = GetLanguageNameInvoice(_workContext.WorkingLanguage.UniqueSeoCode); vars["InvoiceHead.CoinID"] = GetCurrencyIdByCurrencyName(_currencyService.GetCurrencyById(_workContext.WorkingCurrency.Id).CurrencyCode).ToString(); vars["InvoiceHead.Email"] = postProcessPaymentRequest.Order.BillingAddress.Email; // value that will be return and save in CardCom system vars["InvoiceHead.CustAddresLine1"] = postProcessPaymentRequest.Order.BillingAddress.Address1; vars["InvoiceHead.CustAddresLine2"] = postProcessPaymentRequest.Order.BillingAddress.Address2; vars["InvoiceHead.CustCity"] = postProcessPaymentRequest.Order.BillingAddress.City; vars["InvoiceHead.CustLinePH"] = postProcessPaymentRequest.Order.BillingAddress.PhoneNumber; //get the items in the cart decimal cartTotal = decimal.Zero; var cartItems = postProcessPaymentRequest.Order.OrderItems; int itemsCount = 1; foreach (var item in cartItems) //50 chars limit { var unitPriceExclTax = item.UnitPriceExclTax; var priceExclTax = item.PriceExclTax; //round var unitPriceExclTaxRounded = Math.Round(unitPriceExclTax, 2); if (item.Product.WeightProduct) { if (item.Product.ByUnit.HasValue && item.Product.ByUnit.Value == true) { vars["InvoiceLines" + itemsCount.ToString() + ".Quantity"] = HttpUtility.UrlEncode((item.Quantity).ToString() + " " + "יחידות"); vars["InvoiceLines" + itemsCount.ToString() + ".Price"] = Math.Round(item.Product.UnitPrice.Value).ToString("0.00", CultureInfo.InvariantCulture); } else { vars["InvoiceLines" + itemsCount.ToString() + ".Quantity"] = HttpUtility.UrlEncode((item.Quantity * item.Product.BaseWeight.Value).ToString() + " " + item.Product.WeightUnit); vars["InvoiceLines" + itemsCount.ToString() + ".Price"] = unitPriceExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture); } } else { vars["InvoiceLines" + itemsCount.ToString() + ".Quantity"] = HttpUtility.UrlEncode(item.Quantity.ToString()); vars["InvoiceLines" + itemsCount.ToString() + ".Price"] = unitPriceExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture); } vars["InvoiceLines" + itemsCount.ToString() + ".Description"] = HttpUtility.UrlEncode(item.Product.Name); vars["InvoiceLines" + itemsCount.ToString() + ".ProductID"] = (String.IsNullOrWhiteSpace(item.Product.Sku)) ? item.Product.Sku : ""; itemsCount++; cartTotal += priceExclTax; } //the checkout attributes that have a dollar value and send them to CardCom as items to be paid for var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(postProcessPaymentRequest.Order.CheckoutAttributesXml); foreach (var val in caValues) { var attPrice = _taxService.GetCheckoutAttributePrice(val, false, postProcessPaymentRequest.Order.Customer); //round var attPriceRounded = Math.Round(attPrice, 2); if (attPrice > decimal.Zero) //if it has a price { var ca = val.CheckoutAttribute; if (ca != null) { var attName = ca.Name; //set the name vars["InvoiceLines" + itemsCount.ToString() + ".Description"] = HttpUtility.UrlEncode(attName); vars["InvoiceLines" + itemsCount.ToString() + ".Price"] = attPriceRounded.ToString("0.00", CultureInfo.InvariantCulture); //amount vars["InvoiceLines" + itemsCount.ToString() + ".Quantity"] = "1"; //quantity itemsCount++; cartTotal += attPrice; } } } //order totals //shipping var orderShippingExclTax = postProcessPaymentRequest.Order.OrderShippingExclTax; var orderShippingExclTaxRounded = Math.Round(orderShippingExclTax, 2); if (orderShippingExclTax > decimal.Zero) { vars["InvoiceLines" + itemsCount.ToString() + ".Description"] = _localizationService.GetResource("Plugins.Payments.CardCom.ShippingFee"); vars["InvoiceLines" + itemsCount.ToString() + ".Price"] = orderShippingExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture); vars["InvoiceLines" + itemsCount.ToString() + ".Quantity"] = "1"; //quantity itemsCount++; cartTotal += orderShippingExclTax; } //payment method additional fee var paymentMethodAdditionalFeeExclTax = postProcessPaymentRequest.Order.PaymentMethodAdditionalFeeExclTax; var paymentMethodAdditionalFeeExclTaxRounded = Math.Round(paymentMethodAdditionalFeeExclTax, 2); if (paymentMethodAdditionalFeeExclTax > decimal.Zero) { vars["InvoiceLines" + itemsCount.ToString() + ".Description"] = _localizationService.GetResource("Plugins.Payments.CardCom.PaymentMethodFee"); vars["InvoiceLines" + itemsCount.ToString() + ".Price"] = paymentMethodAdditionalFeeExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture); vars["InvoiceLines" + itemsCount.ToString() + ".Quantity"] = "1"; //quantity itemsCount++; cartTotal += paymentMethodAdditionalFeeExclTax; } //tax var orderTax = postProcessPaymentRequest.Order.OrderTax; var orderTaxRounded = Math.Round(orderTax, 2); if (orderTax > decimal.Zero) { //add tax as item vars["InvoiceLines" + itemsCount.ToString() + ".Description"] = _localizationService.GetResource("Plugins.Payments.CardCom.SalesTax"); //name vars["InvoiceLines" + itemsCount.ToString() + ".Price"] = orderTaxRounded.ToString("0.00", CultureInfo.InvariantCulture); //amount vars["InvoiceLines" + itemsCount.ToString() + ".Quantity"] = "1"; //quantity cartTotal += orderTax; itemsCount++; } if (cartTotal > postProcessPaymentRequest.Order.OrderTotal) { /* Take the difference between what the order total is and what it should be and use that as the "discount". * The difference equals the amount of the gift card and/or reward points used. */ decimal discountTotal = cartTotal - postProcessPaymentRequest.Order.OrderTotal; discountTotal = Math.Round(discountTotal, 2) * (-1); //gift card or rewared point amount applied to cart in nopCommerce - shows in Paypal as "discount" vars["InvoiceLines" + itemsCount.ToString() + ".Description"] = _localizationService.GetResource("Plugins.Payments.CardCom.Discount"); //name vars["InvoiceLines" + itemsCount.ToString() + ".Price"] = discountTotal.ToString("0.00", CultureInfo.InvariantCulture); vars["InvoiceLines" + itemsCount.ToString() + ".Quantity"] = "1"; //quantity } }
/// <summary> /// Formats attributes /// </summary> /// <param name="attributes">Attributes</param> /// <param name="customer">Customer</param> /// <param name="serapator">Serapator</param> /// <param name="htmlEncode">A value indicating whether to encode (HTML) values</param> /// <param name="renderPrices">A value indicating whether to render prices</param> /// <param name="allowHyperlinks">A value indicating whether to HTML hyperink tags could be rendered (if required)</param> /// <returns>Attributes</returns> public string FormatAttributes(string attributes, Customer customer, string serapator = "<br />", bool htmlEncode = true, bool renderPrices = true, bool allowHyperlinks = true) { var result = new StringBuilder(); var caCollection = _checkoutAttributeParser.ParseCheckoutAttributes(attributes); if (caCollection.Count <= 0) { return(null); } for (int i = 0; i < caCollection.Count; i++) { var ca = caCollection[i]; var valuesStr = _checkoutAttributeParser.ParseValues(attributes, ca.Id); for (int j = 0; j < valuesStr.Count; j++) { string valueStr = valuesStr[j]; string caAttribute = ""; if (!ca.ShouldHaveValues()) { //no values if (ca.AttributeControlType == AttributeControlType.MultilineTextbox) { //multiline textbox string attributeName = ca.GetLocalized(a => a.Name, _workContext.WorkingLanguage); //encode (if required) if (htmlEncode) { attributeName = HttpUtility.HtmlEncode(attributeName); } caAttribute = string.Format("{0}: {1}", attributeName, HtmlUtils.ConvertPlainTextToHtml(valueStr.EmptyNull().Replace(":", "").HtmlEncode())); //we never encode multiline textbox input } else if (ca.AttributeControlType == AttributeControlType.FileUpload) { //file upload Guid downloadGuid; Guid.TryParse(valueStr, out downloadGuid); var download = _downloadService.GetDownloadByGuid(downloadGuid); if (download?.MediaFile != null) { //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) string attributeText = ""; var fileName = download.MediaFile.Name; //encode (if required) if (htmlEncode) { fileName = HttpUtility.HtmlEncode(fileName); } if (allowHyperlinks) { //hyperlinks are allowed var downloadLink = string.Format("{0}download/getfileupload/?downloadId={1}", _webHelper.GetStoreLocation(false), download.DownloadGuid); attributeText = string.Format("<a href=\"{0}\" class=\"fileuploadattribute\">{1}</a>", downloadLink, fileName); } else { //hyperlinks aren't allowed attributeText = fileName; } string attributeName = ca.GetLocalized(a => a.Name, _workContext.WorkingLanguage); //encode (if required) if (htmlEncode) { attributeName = HttpUtility.HtmlEncode(attributeName); } caAttribute = string.Format("{0}: {1}", attributeName, attributeText); } } else { //other attributes (textbox, datepicker) caAttribute = string.Format("{0}: {1}", ca.GetLocalized(a => a.Name, _workContext.WorkingLanguage), valueStr); //encode (if required) if (htmlEncode) { caAttribute = HttpUtility.HtmlEncode(caAttribute); } } } else { int caId = 0; if (int.TryParse(valueStr, out caId)) { var caValue = _checkoutAttributeService.GetCheckoutAttributeValueById(caId); if (caValue != null) { caAttribute = string.Format("{0}: {1}", ca.GetLocalized(a => a.Name, _workContext.WorkingLanguage), caValue.GetLocalized(a => a.Name, _workContext.WorkingLanguage)); if (renderPrices) { decimal priceAdjustmentBase = _taxService.GetCheckoutAttributePrice(caValue, customer); decimal priceAdjustment = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency); if (priceAdjustmentBase > 0) { string priceAdjustmentStr = _priceFormatter.FormatPrice(priceAdjustment); caAttribute += string.Format(" [+{0}]", priceAdjustmentStr); } } } //encode (if required) if (htmlEncode) { caAttribute = HttpUtility.HtmlEncode(caAttribute); } } } if (!String.IsNullOrEmpty(caAttribute)) { if (i != 0 || j != 0) { result.Append(serapator); } result.Append(caAttribute); } } } return(result.ToString()); }
/// <summary> /// Gets shopping cart subtotal /// </summary> /// <param name="cart">Cart</param> /// <param name="includingTax">A value indicating whether calculated price should include tax</param> /// <param name="discountAmount">Applied discount amount</param> /// <param name="appliedDiscount">Applied discount</param> /// <param name="subTotalWithoutDiscount">Sub total (without discount)</param> /// <param name="subTotalWithDiscount">Sub total (with discount)</param> /// <param name="taxRates">Tax rates (of order sub total)</param> public virtual void GetShoppingCartSubTotal(IList <ShoppingCartItem> cart, bool includingTax, out decimal discountAmount, out Discount appliedDiscount, out decimal subTotalWithoutDiscount, out decimal subTotalWithDiscount, out SortedDictionary <decimal, decimal> taxRates) { discountAmount = decimal.Zero; appliedDiscount = null; subTotalWithoutDiscount = decimal.Zero; subTotalWithDiscount = decimal.Zero; taxRates = new SortedDictionary <decimal, decimal>(); if (cart.Count == 0) { return; } //get the customer Customer customer = cart.GetCustomer(); //sub totals decimal subTotalExclTaxWithoutDiscount = decimal.Zero; decimal subTotalInclTaxWithoutDiscount = decimal.Zero; foreach (var shoppingCartItem in cart) { decimal taxRate = decimal.Zero; decimal sciSubTotal = _priceCalculationService.GetSubTotal(shoppingCartItem, true); decimal sciExclTax = _taxService.GetProductPrice(shoppingCartItem.ProductVariant, sciSubTotal, false, customer, out taxRate); decimal sciInclTax = _taxService.GetProductPrice(shoppingCartItem.ProductVariant, sciSubTotal, true, customer, out taxRate); subTotalExclTaxWithoutDiscount += sciExclTax; subTotalInclTaxWithoutDiscount += sciInclTax; //tax rates decimal sciTax = sciInclTax - sciExclTax; if (taxRate > decimal.Zero && sciTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, sciTax); } else { taxRates[taxRate] = taxRates[taxRate] + sciTax; } } } //checkout attributes if (customer != null) { var checkoutAttributesXml = customer.GetAttribute <string>(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService); var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(checkoutAttributesXml); if (caValues != null) { foreach (var caValue in caValues) { decimal taxRate = decimal.Zero; decimal caExclTax = _taxService.GetCheckoutAttributePrice(caValue, false, customer, out taxRate); decimal caInclTax = _taxService.GetCheckoutAttributePrice(caValue, true, customer, out taxRate); subTotalExclTaxWithoutDiscount += caExclTax; subTotalInclTaxWithoutDiscount += caInclTax; //tax rates decimal caTax = caInclTax - caExclTax; if (taxRate > decimal.Zero && caTax > decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) { taxRates.Add(taxRate, caTax); } else { taxRates[taxRate] = taxRates[taxRate] + caTax; } } } } } //subtotal without discount if (includingTax) { subTotalWithoutDiscount = subTotalInclTaxWithoutDiscount; } else { subTotalWithoutDiscount = subTotalExclTaxWithoutDiscount; } if (subTotalWithoutDiscount < decimal.Zero) { subTotalWithoutDiscount = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { subTotalWithoutDiscount = Math.Round(subTotalWithoutDiscount, 2); } /*We calculate discount amount on order subtotal excl tax (discount first)*/ //calculate discount amount ('Applied to order subtotal' discount) decimal discountAmountExclTax = GetOrderSubtotalDiscount(customer, subTotalExclTaxWithoutDiscount, out appliedDiscount); if (subTotalExclTaxWithoutDiscount < discountAmountExclTax) { discountAmountExclTax = subTotalExclTaxWithoutDiscount; } decimal discountAmountInclTax = discountAmountExclTax; //subtotal with discount (excl tax) decimal subTotalExclTaxWithDiscount = subTotalExclTaxWithoutDiscount - discountAmountExclTax; decimal subTotalInclTaxWithDiscount = subTotalExclTaxWithDiscount; //add tax for shopping items & checkout attributes Dictionary <decimal, decimal> tempTaxRates = new Dictionary <decimal, decimal>(taxRates); foreach (KeyValuePair <decimal, decimal> kvp in tempTaxRates) { decimal taxRate = kvp.Key; decimal taxValue = kvp.Value; if (taxValue != decimal.Zero) { //discount the tax amount that applies to subtotal items if (subTotalExclTaxWithoutDiscount > decimal.Zero) { decimal discountTax = taxRates[taxRate] * (discountAmountExclTax / subTotalExclTaxWithoutDiscount); discountAmountInclTax += discountTax; taxValue = taxRates[taxRate] - discountTax; if (_shoppingCartSettings.RoundPricesDuringCalculation) { taxValue = Math.Round(taxValue, 2); } taxRates[taxRate] = taxValue; } //subtotal with discount (incl tax) subTotalInclTaxWithDiscount += taxValue; } } if (_shoppingCartSettings.RoundPricesDuringCalculation) { discountAmountInclTax = Math.Round(discountAmountInclTax, 2); } if (includingTax) { subTotalWithDiscount = subTotalInclTaxWithDiscount; discountAmount = discountAmountInclTax; } else { subTotalWithDiscount = subTotalExclTaxWithDiscount; discountAmount = discountAmountExclTax; } //round if (subTotalWithDiscount < decimal.Zero) { subTotalWithDiscount = decimal.Zero; } if (_shoppingCartSettings.RoundPricesDuringCalculation) { subTotalWithDiscount = Math.Round(subTotalWithDiscount, 2); } }
/// <summary> /// Add order items to the request query parameters /// </summary> /// <param name="parameters">Query parameters</param> /// <param name="postProcessPaymentRequest">Payment info required for an order processing</param> private async Task AddItemsParameters(IDictionary <string, string> parameters, Order order) { //upload order items parameters.Add("cmd", "_cart"); parameters.Add("upload", "1"); double cartTotal = 0; double roundedCartTotal = 0; var itemCount = 1; //add shopping cart items foreach (var item in order.OrderItems) { var product = await _productService.GetProductById(item.ProductId); var roundedItemPrice = Math.Round(item.UnitPriceExclTax, 2); //add query parameters parameters.Add($"item_name_{itemCount}", product.Name); parameters.Add($"amount_{itemCount}", roundedItemPrice.ToString("0.00", CultureInfo.InvariantCulture)); parameters.Add($"quantity_{itemCount}", item.Quantity.ToString()); cartTotal += (item.PriceExclTax); roundedCartTotal += roundedItemPrice * item.Quantity; itemCount++; } //add checkout attributes as order items var checkoutAttributeValues = await _checkoutAttributeParser.ParseCheckoutAttributeValue(order.CheckoutAttributes); var currencyService = _serviceProvider.GetRequiredService <ICurrencyService>(); var workContext = _serviceProvider.GetRequiredService <IWorkContext>(); var customer = await _serviceProvider.GetRequiredService <ICustomerService>().GetCustomerById(order.CustomerId); foreach (var attributeValue in checkoutAttributeValues) { var attributePrice = await _taxService.GetCheckoutAttributePrice(attributeValue.ca, attributeValue.cav, false, customer); if (attributePrice.checkoutPrice > 0) { double roundedAttributePrice = Math.Round(await currencyService.ConvertFromPrimaryStoreCurrency(attributePrice.checkoutPrice, workContext.WorkingCurrency), 2); //add query parameters if (attributeValue.ca != null) { parameters.Add($"item_name_{itemCount}", attributeValue.ca.Name); parameters.Add($"amount_{itemCount}", roundedAttributePrice.ToString("0.00", CultureInfo.InvariantCulture)); parameters.Add($"quantity_{itemCount}", "1"); cartTotal += attributePrice.checkoutPrice; roundedCartTotal += roundedAttributePrice; itemCount++; } } } //add shipping fee as a separate order item, if it has price var roundedShippingPrice = Math.Round(order.OrderShippingExclTax, 2); if (roundedShippingPrice > 0) { parameters.Add($"item_name_{itemCount}", "Shipping fee"); parameters.Add($"amount_{itemCount}", roundedShippingPrice.ToString("0.00", CultureInfo.InvariantCulture)); parameters.Add($"quantity_{itemCount}", "1"); cartTotal += (order.OrderShippingExclTax); roundedCartTotal += roundedShippingPrice; itemCount++; } //add payment method additional fee as a separate order item, if it has price var roundedPaymentMethodPrice = Math.Round(order.PaymentMethodAdditionalFeeExclTax, 2); if (roundedPaymentMethodPrice > 0) { parameters.Add($"item_name_{itemCount}", "Payment method fee"); parameters.Add($"amount_{itemCount}", roundedPaymentMethodPrice.ToString("0.00", CultureInfo.InvariantCulture)); parameters.Add($"quantity_{itemCount}", "1"); cartTotal += (order.PaymentMethodAdditionalFeeExclTax); roundedCartTotal += roundedPaymentMethodPrice; itemCount++; } //add tax as a separate order item, if it has positive amount var roundedTaxAmount = Math.Round(order.OrderTax, 2); if (roundedTaxAmount > 0) { parameters.Add($"item_name_{itemCount}", "Tax amount"); parameters.Add($"amount_{itemCount}", roundedTaxAmount.ToString("0.00", CultureInfo.InvariantCulture)); parameters.Add($"quantity_{itemCount}", "1"); cartTotal += (order.OrderTax); roundedCartTotal += roundedTaxAmount; itemCount++; } if (cartTotal > order.OrderTotal) { //get the difference between what the order total is and what it should be and use that as the "discount" var discountTotal = Math.Round(cartTotal - (order.OrderTotal), 2); roundedCartTotal -= discountTotal; //gift voucher or loyalty points amount applied to cart in nopCommerce - shows in PayPal as "discount" parameters.Add("discount_amount_cart", discountTotal.ToString("0.00", CultureInfo.InvariantCulture)); } //save order total that actually sent to PayPal (used for PDT order total validation) await _userFieldService.SaveField(order, PaypalHelper.OrderTotalSentToPayPal, roundedCartTotal); }
/// <summary> /// Formats attributes /// </summary> /// <param name="attributesXml">Attributes in XML format</param> /// <param name="customer">Customer</param> /// <param name="serapator">Serapator</param> /// <param name="htmlEncode">A value indicating whether to encode (HTML) values</param> /// <param name="renderPrices">A value indicating whether to render prices</param> /// <param name="allowHyperlinks">A value indicating whether to HTML hyperink tags could be rendered (if required)</param> /// <returns>Attributes</returns> public virtual string FormatAttributes(string attributesXml, Customer customer, string serapator = "<br />", bool htmlEncode = true, bool renderPrices = true, bool allowHyperlinks = true) { var result = new StringBuilder(); var attributes = _checkoutAttributeParser.ParseCheckoutAttributes(attributesXml); for (int i = 0; i < attributes.Count; i++) { var attribute = attributes[i]; var valuesStr = _checkoutAttributeParser.ParseValues(attributesXml, attribute.Id); for (int j = 0; j < valuesStr.Count; j++) { string valueStr = valuesStr[j]; string formattedAttribute = ""; if (!attribute.ShouldHaveValues()) { //no values if (attribute.AttributeControlType == AttributeControlType.MultilineTextbox) { //multiline textbox var attributeName = attribute.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id); //encode (if required) if (htmlEncode) { attributeName = HttpUtility.HtmlEncode(attributeName); } formattedAttribute = string.Format("{0}: {1}", attributeName, HtmlHelper.FormatText(valueStr, false, true, false, false, false, false)); //we never encode multiline textbox input } else if (attribute.AttributeControlType == AttributeControlType.FileUpload) { //file upload Guid downloadGuid; Guid.TryParse(valueStr, out downloadGuid); var download = _downloadService.GetDownloadByGuid(downloadGuid); if (download != null) { //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) string attributeText = ""; var fileName = string.Format("{0}{1}", download.Filename ?? download.DownloadGuid.ToString(), download.Extension); //encode (if required) if (htmlEncode) { fileName = HttpUtility.HtmlEncode(fileName); } if (allowHyperlinks) { //hyperlinks are allowed var downloadLink = string.Format("{0}download/getfileupload/?downloadId={1}", _webHelper.GetStoreLocation(false), download.DownloadGuid); attributeText = string.Format("<a href=\"{0}\" class=\"fileuploadattribute\">{1}</a>", downloadLink, fileName); } else { //hyperlinks aren't allowed attributeText = fileName; } var attributeName = attribute.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id); //encode (if required) if (htmlEncode) { attributeName = HttpUtility.HtmlEncode(attributeName); } formattedAttribute = string.Format("{0}: {1}", attributeName, attributeText); } } else { //other attributes (textbox, datepicker) formattedAttribute = string.Format("{0}: {1}", attribute.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id), valueStr); //encode (if required) if (htmlEncode) { formattedAttribute = HttpUtility.HtmlEncode(formattedAttribute); } } } else { int attributeValueId; if (int.TryParse(valueStr, out attributeValueId)) { var attributeValue = attribute.CheckoutAttributeValues.Where(x => x.Id == attributeValueId).FirstOrDefault(); //checkoutAttributeService.GetCheckoutAttributeValueById(attributeValueId); if (attributeValue != null) { formattedAttribute = string.Format("{0}: {1}", attribute.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id), attributeValue.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id)); if (renderPrices) { decimal priceAdjustmentBase = _taxService.GetCheckoutAttributePrice(attributeValue, customer); decimal priceAdjustment = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency); if (priceAdjustmentBase > 0) { string priceAdjustmentStr = _priceFormatter.FormatPrice(priceAdjustment); formattedAttribute += string.Format(" [+{0}]", priceAdjustmentStr); } } } //encode (if required) if (htmlEncode) { formattedAttribute = HttpUtility.HtmlEncode(formattedAttribute); } } } if (!String.IsNullOrEmpty(formattedAttribute)) { if (i != 0 || j != 0) { result.Append(serapator); } result.Append(formattedAttribute); } } } return(result.ToString()); }
/// <summary> /// Formats attributes /// </summary> /// <param name="customAttributes">Attributes</param> /// <param name="customer">Customer</param> /// <param name="serapator">Serapator</param> /// <param name="htmlEncode">A value indicating whether to encode (HTML) values</param> /// <param name="renderPrices">A value indicating whether to render prices</param> /// <param name="allowHyperlinks">A value indicating whether to HTML hyperink tags could be rendered (if required)</param> /// <returns>Attributes</returns> public virtual async Task <string> FormatAttributes(IList <CustomAttribute> customAttributes, Customer customer, string serapator = "<br />", bool htmlEncode = true, bool renderPrices = true, bool allowHyperlinks = true) { var result = new StringBuilder(); if (customAttributes == null || !customAttributes.Any()) { return(result.ToString()); } var attributes = await _checkoutAttributeParser.ParseCheckoutAttributes(customAttributes); for (int i = 0; i < attributes.Count; i++) { var attribute = attributes[i]; var valuesStr = customAttributes.Where(x => x.Key == attribute.Id).Select(x => x.Value).ToList(); for (var j = 0; j < valuesStr.Count; j++) { var valueStr = valuesStr[j]; var formattedAttribute = ""; if (!attribute.ShouldHaveValues()) { //no values if (attribute.AttributeControlTypeId == AttributeControlType.MultilineTextbox) { //multiline textbox var attributeName = attribute.GetTranslation(a => a.Name, _workContext.WorkingLanguage.Id); //encode (if required) if (htmlEncode) { attributeName = WebUtility.HtmlEncode(attributeName); } formattedAttribute = string.Format("{0}: {1}", attributeName, FormatText.ConvertText(valueStr)); //we never encode multiline textbox input } else if (attribute.AttributeControlTypeId == AttributeControlType.FileUpload) { //file upload Guid downloadGuid; Guid.TryParse(valueStr, out downloadGuid); var download = await _downloadService.GetDownloadByGuid(downloadGuid); if (download != null) { string attributeText = ""; var fileName = string.Format("{0}{1}", download.Filename ?? download.DownloadGuid.ToString(), download.Extension); //encode (if required) if (htmlEncode) { fileName = WebUtility.HtmlEncode(fileName); } if (allowHyperlinks) { //hyperlinks are allowed var downloadLink = string.Format("{0}/download/getfileupload/?downloadId={1}", _workContext.CurrentStore.Url.TrimEnd('/'), download.DownloadGuid); attributeText = string.Format("<a href=\"{0}\" class=\"fileuploadattribute\">{1}</a>", downloadLink, fileName); } else { //hyperlinks aren't allowed attributeText = fileName; } var attributeName = attribute.GetTranslation(a => a.Name, _workContext.WorkingLanguage.Id); //encode (if required) if (htmlEncode) { attributeName = WebUtility.HtmlEncode(attributeName); } formattedAttribute = string.Format("{0}: {1}", attributeName, attributeText); } } else { //other attributes (textbox, datepicker) formattedAttribute = string.Format("{0}: {1}", attribute.GetTranslation(a => a.Name, _workContext.WorkingLanguage.Id), valueStr); //encode (if required) if (htmlEncode) { formattedAttribute = WebUtility.HtmlEncode(formattedAttribute); } } } else { var attributeValue = attribute.CheckoutAttributeValues.Where(x => x.Id == valueStr).FirstOrDefault(); if (attributeValue != null) { formattedAttribute = string.Format("{0}: {1}", attribute.GetTranslation(a => a.Name, _workContext.WorkingLanguage.Id), attributeValue.GetTranslation(a => a.Name, _workContext.WorkingLanguage.Id)); if (renderPrices) { decimal priceAdjustmentBase = (await _taxService.GetCheckoutAttributePrice(attribute, attributeValue, customer)).checkoutPrice; decimal priceAdjustment = await _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency); if (priceAdjustmentBase > 0) { string priceAdjustmentStr = _priceFormatter.FormatPrice(priceAdjustment); formattedAttribute += string.Format(" [+{0}]", priceAdjustmentStr); } } } //encode (if required) if (htmlEncode) { formattedAttribute = WebUtility.HtmlEncode(formattedAttribute); } } if (!String.IsNullOrEmpty(formattedAttribute)) { if (i != 0 || j != 0) { result.Append(serapator); } result.Append(formattedAttribute); } } } return(result.ToString()); }