public ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest)
        {
            var result = new ProcessPaymentResult();

            try
            {
                var options     = IyzicoHelper.GetIyzicoOptions(_iyzicoPaymentSettings);
                var paymentCard = new PaymentCard()
                {
                    CardHolderName = processPaymentRequest.CreditCardName,
                    CardNumber     = processPaymentRequest.CreditCardNumber,
                    ExpireMonth    = processPaymentRequest.CreditCardExpireMonth.ToString(),
                    ExpireYear     = processPaymentRequest.CreditCardExpireYear.ToString(),
                    Cvc            = processPaymentRequest.CreditCardCvv2
                };

                var customer        = _customerService.GetCustomerById(processPaymentRequest.CustomerId);
                var billingAddress  = _iyzicoService.PrepareAddress(_customerService.GetCustomerBillingAddress(customer));
                var shippingAddress = _customerService.GetCustomerShippingAddress(customer) != null?_iyzicoService.PrepareAddress(_customerService.GetCustomerShippingAddress(customer)) : billingAddress;

                var installment = GetInstallment(processPaymentRequest, paymentCard, options);

                var shoppingCart      = _shoppingCartService.GetShoppingCart(customer, ShoppingCartType.ShoppingCart);
                var shoppingCartTotal = _orderTotalCalculationService.GetShoppingCartTotal(shoppingCart, out var orderDiscountAmount, out var orderAppliedDiscounts, out var appliedGiftCards, out var redeemedRewardPoints, out var redeemedRewardPointsAmount, usePaymentMethodAdditionalFee: false);

                var paymentRequest = new CreatePaymentRequest
                {
                    Price           = _priceCalculationService.RoundPrice(shoppingCartTotal ?? 0).ToString("f8", CultureInfo.InvariantCulture),
                    PaidPrice       = installment.TotalPrice,
                    Currency        = Currency.TRY.ToString(),
                    Installment     = installment.InstallmentNumber,
                    BasketId        = processPaymentRequest.OrderGuid.ToString(),
                    PaymentCard     = paymentCard,
                    Buyer           = _iyzicoService.PrepareBuyer(processPaymentRequest.CustomerId),
                    ShippingAddress = shippingAddress,
                    BillingAddress  = billingAddress,
                    BasketItems     = GetItems(customer, processPaymentRequest.StoreId)
                };
                paymentRequest.PaymentGroup = PaymentGroup.LISTING.ToString();

                var payment = Payment.Create(paymentRequest, options);
                if (payment.Status != "success")
                {
                    string errorMessage = _localizationService.GetResource(String.Format("Plugins.Payments.Iyzico.ErrorMessage.{0}", payment.ErrorCode)) ?? payment.ErrorMessage;
                    result.AddError(errorMessage);
                    return(result);
                }

                result.NewPaymentStatus = PaymentStatus.Pending;

                return(result);
            }
            catch (Exception ex)
            {
                result.AddError(ex.Message);
                return(result);
            }
        }
        public void Can_get_shopping_cart_total_without_shipping_required()
        {
            //customer
            var customer = _customerService.GetCustomerById(1);

            //shopping cart
            var product1 = new Product
            {
                Name          = "Product name 1",
                Price         = 10M,
                Published     = true,
                IsShipEnabled = false
            };

            _productService.InsertProduct(product1);

            var sci1 = new ShoppingCartItem
            {
                ProductId = product1.Id,
                Quantity  = 2
            };

            var product2 = new Product
            {
                Name          = "Product name 2",
                Price         = 12M,
                Published     = true,
                IsShipEnabled = false
            };

            _productService.InsertProduct(product2);

            var sci2 = new ShoppingCartItem
            {
                ProductId = product2.Id,
                Quantity  = 3
            };

            var cart = new List <ShoppingCartItem> {
                sci1, sci2
            };

            cart.ForEach(sci => sci.CustomerId = customer.Id);

            //shipping is taxable, payment fee is taxable
            _taxSettings.ShippingIsTaxable = true;
            _taxSettings.PaymentMethodAdditionalFeeIsTaxable = true;

            //56 - items, 20 - payment fee, 7.6 - tax
            _orderTotalCalcService.GetShoppingCartTotal(cart, out _, out _, out _, out _, out _)
            .Should().Be(83.6M);
        }
Exemple #3
0
        public void CanGetShoppingCartTotalWithoutShippingRequired()
        {
            //shipping is taxable, payment fee is taxable
            _taxSettings.ShippingIsTaxable = true;
            _taxSettings.PaymentMethodAdditionalFeeIsTaxable = true;
            _settingService.SaveSetting(_taxSettings);

            TestPaymentMethod.AdditionalHandlingFee = 20M;

            //207 - items, 20 - payment fee, 22.7 - tax
            _orderTotalCalcService.GetShoppingCartTotal(ShoppingCart, out _, out _, out _, out _, out _)
            .Should().Be(249.7M);

            TestPaymentMethod.AdditionalHandlingFee = 0M;
        }
        /// <summary>
        /// Calculate payment method fee
        /// </summary>
        /// <param name="paymentMethod">Payment method</param>
        /// <param name="orderTotalCalculationService">Order total calculation service</param>
        /// <param name="cart">Shopping cart</param>
        /// <param name="fee">Fee value</param>
        /// <param name="usePercentage">Is fee amount specified as percentage or fixed value?</param>
        /// <returns>Result</returns>
        public static decimal CalculateAdditionalFee(this IPaymentMethod paymentMethod,
			IOrderTotalCalculationService orderTotalCalculationService, 
			IList<OrganizedShoppingCartItem> cart,
            decimal fee, 
			bool usePercentage)
        {
            if (paymentMethod == null)
                throw new ArgumentNullException("paymentMethod");

            if (fee == decimal.Zero)
                return fee;

            var result = decimal.Zero;
            if (usePercentage)
            {
                //percentage
                var orderTotalWithoutPaymentFee = orderTotalCalculationService.GetShoppingCartTotal(cart, usePaymentMethodAdditionalFee: false);
                result = (decimal)((((float)orderTotalWithoutPaymentFee) * ((float)fee)) / 100f);
            }
            else
            {
                //fixed value
                result = fee;
            }
            return result;
        }
Exemple #5
0
        /// <summary>
        /// Calculate payment method fee
        /// </summary>
        /// <param name="paymentMethod">Payment method</param>
        /// <param name="orderTotalCalculationService">Order total calculation service</param>
        /// <param name="cart">Shopping cart</param>
        /// <param name="fee">Fee value</param>
        /// <param name="usePercentage">Is fee amount specified as percentage or fixed value?</param>
        /// <returns>Result</returns>
        public static decimal CalculateAdditionalFee(this IPaymentMethod paymentMethod,
                                                     IOrderTotalCalculationService orderTotalCalculationService,
                                                     IList <OrganizedShoppingCartItem> cart,
                                                     decimal fee,
                                                     bool usePercentage)
        {
            if (paymentMethod == null)
            {
                throw new ArgumentNullException("paymentMethod");
            }

            if (fee <= 0)
            {
                return(fee);
            }

            var result = decimal.Zero;

            if (usePercentage)
            {
                //percentage
                var orderTotalWithoutPaymentFee = orderTotalCalculationService.GetShoppingCartTotal(cart, usePaymentMethodAdditionalFee: false);
                result = (decimal)((((float)orderTotalWithoutPaymentFee) * ((float)fee)) / 100f);
            }
            else
            {
                //fixed value
                result = fee;
            }
            return(result);
        }
Exemple #6
0
        private async Task PrepareTotal(OrderTotalsModel model, GetOrderTotals request)
        {
            var carttotal = await _orderTotalCalculationService.GetShoppingCartTotal(request.Cart);

            decimal?shoppingCartTotalBase           = carttotal.shoppingCartTotal;
            decimal orderTotalDiscountAmountBase    = carttotal.discountAmount;
            List <AppliedGiftCard> appliedGiftCards = carttotal.appliedGiftCards;
            int     redeemedRewardPoints            = carttotal.redeemedRewardPoints;
            decimal redeemedRewardPointsAmount      = carttotal.redeemedRewardPointsAmount;

            if (shoppingCartTotalBase.HasValue)
            {
                decimal shoppingCartTotal = await _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartTotalBase.Value, request.Currency);

                model.OrderTotal = _priceFormatter.FormatPrice(shoppingCartTotal, true, false);
            }
            //discount
            if (orderTotalDiscountAmountBase > decimal.Zero)
            {
                decimal orderTotalDiscountAmount = await _currencyService.ConvertFromPrimaryStoreCurrency(orderTotalDiscountAmountBase, request.Currency);

                model.OrderTotalDiscount = _priceFormatter.FormatPrice(-orderTotalDiscountAmount, true, false);
            }

            //gift cards
            if (appliedGiftCards != null && appliedGiftCards.Any())
            {
                foreach (var appliedGiftCard in appliedGiftCards)
                {
                    await PrepareGiftCards(appliedGiftCard, model, request);
                }
            }

            //reward points to be spent (redeemed)
            if (redeemedRewardPointsAmount > decimal.Zero)
            {
                decimal redeemedRewardPointsAmountInCustomerCurrency = await _currencyService.ConvertFromPrimaryStoreCurrency(redeemedRewardPointsAmount, request.Currency);

                model.RedeemedRewardPoints       = redeemedRewardPoints;
                model.RedeemedRewardPointsAmount = _priceFormatter.FormatPrice(-redeemedRewardPointsAmountInCustomerCurrency, true, false);
            }

            //reward points to be earned
            if (_rewardPointsSettings.Enabled &&
                _rewardPointsSettings.DisplayHowMuchWillBeEarned &&
                shoppingCartTotalBase.HasValue)
            {
                decimal?shippingBaseInclTax = model.RequiresShipping
                    ? (await _orderTotalCalculationService.GetShoppingCartShippingTotal(request.Cart, true)).shoppingCartShippingTotal
                    : 0;
                var earnRewardPoints = shoppingCartTotalBase.Value - shippingBaseInclTax.Value;
                if (earnRewardPoints > 0)
                {
                    model.WillEarnRewardPoints = await _mediator.Send(new CalculateRewardPointsCommand()
                    {
                        Customer = request.Customer, Amount = earnRewardPoints
                    });
                }
            }
        }
Exemple #7
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var result = true;

            // We must prevent the rule from indirectly calling itself. It would cause a stack overflow on cart page
            // and wrong discount calculation (due to MergeWithCombination, if the cart contains a product several times).
            if (Interlocked.CompareExchange(ref _reentrancyNum, 1, 0) == 0)
            {
                try
                {
                    var cart = _shoppingCartService.GetCartItems(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

                    var cartTotal = ((decimal?)_orderTotalCalculationService.GetShoppingCartTotal(cart)) ?? decimal.Zero;

                    // Currency values must be rounded, otherwise unexpected results may occur.
                    var money = new Money(cartTotal, context.WorkContext.WorkingCurrency);
                    cartTotal = money.RoundedAmount;

                    result = expression.Operator.Match(cartTotal, expression.Value);
                }
                finally
                {
                    _reentrancyNum = 0;
                }
            }

            return(result);
        }
Exemple #8
0
        public async Task <bool> Handle(ValidateShoppingCartTotalAmountCommand request, CancellationToken cancellationToken)
        {
            if (request.Cart == null)
            {
                throw new ArgumentNullException("cart");
            }

            if (request.Customer == null)
            {
                throw new ArgumentNullException("customer");
            }

            var minroles       = request.Customer.CustomerRoles.OrderBy(x => x.MinOrderAmount).FirstOrDefault(x => x.Active && x.MinOrderAmount.HasValue);
            var minOrderAmount = minroles?.MinOrderAmount ?? decimal.MinValue;

            var maxroles       = request.Customer.CustomerRoles.OrderByDescending(x => x.MaxOrderAmount).FirstOrDefault(x => x.Active && x.MaxOrderAmount.HasValue);
            var maxOrderAmount = maxroles?.MaxOrderAmount ?? decimal.MaxValue;

            if (request.Cart.Any() && (minOrderAmount > decimal.Zero || maxOrderAmount > decimal.Zero))
            {
                decimal?shoppingCartTotalBase = (await _orderTotalCalculationService.GetShoppingCartTotal(request.Cart)).shoppingCartTotal;
                if (shoppingCartTotalBase.HasValue && (shoppingCartTotalBase.Value < minOrderAmount || shoppingCartTotalBase.Value > maxOrderAmount))
                {
                    return(false);
                }
            }

            return(true);
        }
Exemple #9
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var sessionKey = context.SessionKey;
            var lockKey    = "rule:cart:carttotalrule:" + sessionKey.ToString();

            if (KeyedLock.IsLockHeld(lockKey))
            {
                return(false);
            }

            // We must prevent the rule from indirectly calling itself. It would cause a stack overflow on cart page.
            using (KeyedLock.Lock(lockKey))
            {
                var cart = _shoppingCartService.GetCartItems(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

                var cartTotal = ((decimal?)_orderTotalCalculationService.GetShoppingCartTotal(cart)) ?? decimal.Zero;

                // Currency values must be rounded, otherwise unexpected results may occur.
                var money = new Money(cartTotal, context.WorkContext.WorkingCurrency);
                cartTotal = money.RoundedAmount;

                var result = expression.Operator.Match(cartTotal, expression.Value);
                return(result);
            }
        }
Exemple #10
0
        protected bool IsPaymentWorkflowRequired(IList <OrganizedShoppingCartItem> cart, bool ignoreRewardPoints = false)
        {
            // Check whether order total equals zero
            decimal?shoppingCartTotalBase = _orderTotalCalculationService.GetShoppingCartTotal(cart, ignoreRewardPoints);

            if (shoppingCartTotalBase.HasValue && shoppingCartTotalBase.Value == decimal.Zero)
            {
                return(false);
            }

            if (_httpContext.GetCheckoutState().IsPaymentSelectionSkipped)
            {
                return(false);
            }

            return(true);
        }
Exemple #11
0
        /// <summary>
        /// Invoke view component
        /// </summary>
        /// <param name="widgetZone">Widget zone name</param>
        /// <param name="additionalData">Additional data</param>
        /// <returns>View component result</returns>
        public IViewComponentResult Invoke(string widgetZone, object additionalData)
        {
            var model = new PaymentInfoModel();

            if (_braintreePaymentSettings.Use3DS)
            {
                try
                {
                    var gateway = new BraintreeGateway
                    {
                        Environment = _braintreePaymentSettings.UseSandbox ? Environment.SANDBOX : Environment.PRODUCTION,
                        MerchantId  = _braintreePaymentSettings.MerchantId,
                        PublicKey   = _braintreePaymentSettings.PublicKey,
                        PrivateKey  = _braintreePaymentSettings.PrivateKey
                    };
                    var clientToken = gateway.ClientToken.Generate();

                    var cart = _shoppingCartService
                               .GetShoppingCart(_workContext.CurrentCustomer, ShoppingCartType.ShoppingCart, _storeContext.CurrentStore.Id);
                    var orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart);

                    model.ClientToken = clientToken;
                    model.OrderTotal  = orderTotal;
                }
                catch (Exception exception)
                {
                    model.Errors = exception.Message;
                    if (_orderSettings.OnePageCheckoutEnabled)
                    {
                        ModelState.AddModelError(string.Empty, exception.Message);
                    }
                    else
                    {
                        _notificationService.ErrorNotification(exception);
                    }
                }

                return(View("~/Plugins/Payments.Braintree/Views/PaymentInfo.3DS.cshtml", model));
            }

            for (var i = 0; i < 15; i++)
            {
                var year = Convert.ToString(DateTime.Now.Year + i);
                model.ExpireYears.Add(new SelectListItem {
                    Text = year, Value = year,
                });
            }

            for (var i = 1; i <= 12; i++)
            {
                var text = (i < 10) ? "0" + i : i.ToString();
                model.ExpireMonths.Add(new SelectListItem {
                    Text = text, Value = i.ToString(),
                });
            }

            return(View("~/Plugins/Payments.Braintree/Views/PaymentInfo.cshtml", model));
        }
        /// <summary>
        /// Invoke view component
        /// </summary>
        /// <param name="widgetZone">Widget zone name</param>
        /// <param name="additionalData">Additional data</param>
        /// <returns>View component result</returns>
        public IViewComponentResult Invoke(string widgetZone, object additionalData)
        {
            var model = new PaymentInfoModel
            {
                //whether current customer is guest
                IsGuest = _workContext.CurrentCustomer.IsGuest(),

                //get postal code from the billing address or from the shipping one
                PostalCode = _workContext.CurrentCustomer.BillingAddress?.ZipPostalCode
                             ?? _workContext.CurrentCustomer.ShippingAddress?.ZipPostalCode
            };

            //whether customer already has stored cards
            var customerId = _genericAttributeService
                             .GetAttribute <string>(_workContext.CurrentCustomer, SquarePaymentDefaults.CustomerIdAttribute) ?? string.Empty;
            var customer = _squarePaymentManager.GetCustomer(customerId);

            if (customer?.Cards != null)
            {
                var cardNumberMask = _localizationService.GetResource("Plugins.Payments.Square.Fields.StoredCard.Mask");
                model.StoredCards = customer.Cards
                                    .Select(card => new SelectListItem {
                    Text = string.Format(cardNumberMask, card.Last4), Value = card.Id
                })
                                    .ToList();
            }

            //add the special item for 'select card' with empty GUID value
            if (model.StoredCards.Any())
            {
                var selectCardText = _localizationService.GetResource("Plugins.Payments.Square.Fields.StoredCard.SelectCard");
                model.StoredCards.Insert(0, new SelectListItem {
                    Text = selectCardText, Value = Guid.Empty.ToString()
                });
            }

            //set verfication details
            if (_squarePaymentSettings.Use3ds)
            {
                var cart = _shoppingCartService.GetShoppingCart(_workContext.CurrentCustomer,
                                                                ShoppingCartType.ShoppingCart, _storeContext.CurrentStore.Id);
                model.OrderTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart, false, false) ?? decimal.Zero;

                var currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId);
                model.Currency = currency?.CurrencyCode;

                model.BillingFirstName  = _workContext.CurrentCustomer.BillingAddress?.FirstName;
                model.BillingLastName   = _workContext.CurrentCustomer.BillingAddress?.LastName;
                model.BillingEmail      = _workContext.CurrentCustomer.BillingAddress?.Email;
                model.BillingCountry    = _workContext.CurrentCustomer.BillingAddress?.Country?.TwoLetterIsoCode;
                model.BillingState      = _workContext.CurrentCustomer.BillingAddress?.StateProvince?.Name;
                model.BillingCity       = _workContext.CurrentCustomer.BillingAddress?.City;
                model.BillingPostalCode = _workContext.CurrentCustomer.BillingAddress?.ZipPostalCode;
            }

            return(View("~/Plugins/Payments.Square/Views/PaymentInfo.cshtml", model));
        }
        public IActionResult ParatikaInstallment(string cardpin)
        {
            //validation
            var model = new PaymentInfoModel();
            Dictionary <String, String> requestParameters = new Dictionary <String, String>();

            var cart = _workContext.CurrentCustomer.ShoppingCartItems
                       .Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart)
                       .LimitPerStore(_storeContext.CurrentStore.Id)
                       .ToList();

            if (!cart.Any())
            {
                return(RedirectToRoute("ShoppingCart"));
            }

            var orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart, out var orderDiscountAmount, out var orderAppliedDiscounts, out var appliedGiftCards, out var redeemedRewardPoints, out var redeemedRewardPointsAmount);

            var getSessionToken = _session.Get <string>("SESSIONTOKEN_" + _workContext.CurrentCustomer.Id);

            requestParameters.Add("MERCHANT", _paratikaOrderPaymentSettings.Code);
            requestParameters.Add("MERCHANTUSER", _paratikaOrderPaymentSettings.Username);
            requestParameters.Add("MERCHANTPASSWORD", _paratikaOrderPaymentSettings.Password);
            requestParameters.Add("ACTION", "QUERYPAYMENTSYSTEMS");
            requestParameters.Add("SESSIONTOKEN", getSessionToken.ToString());
            requestParameters.Add("BIN", cardpin);

            var requestData = HelperParatikaService.convertToRequestData(requestParameters);
            var response    = HelperParatikaService.getConnection(_paratikaOrderPaymentSettings.URL, requestData);

            var getResponseInstallment = Newtonsoft.Json.JsonConvert.DeserializeObject <InstallmentsDetail>(response);

            if (getResponseInstallment == null)
            {
                getResponseInstallment = new InstallmentsDetail();
            }
            if (getResponseInstallment.installmentPaymentSystem == null)
            {
                getResponseInstallment.installmentPaymentSystem = new InstallmentPaymentSystem();
            }
            if (getResponseInstallment.installmentPaymentSystem.installmentList == null)
            {
                getResponseInstallment.installmentPaymentSystem.installmentList = new List <InstallmentList>();
            }

            getResponseInstallment.installmentPaymentSystem.installmentList.Add(new InstallmentList()
            {
                count = "1", customerCostCommissionRate = 1, customerCostCommissionPrice = orderTotal.Value * 1
            });

            getResponseInstallment.installmentPaymentSystem.installmentList.ForEach(x => x.customerCostCommissionPrice = orderTotal.Value * x.customerCostCommissionRate);
            getResponseInstallment.installmentPaymentSystem.currencyCode   = _workContext.WorkingCurrency.CurrencyCode;
            getResponseInstallment.installmentPaymentSystem.displayLocales = _workContext.WorkingCurrency.DisplayLocale;

            return(Json(getResponseInstallment));
        }
        public virtual IActionResult GetInstallment(string binNumber)
        {
            if (String.IsNullOrEmpty(binNumber))
            {
                return(Json(String.Empty));
            }

            var customer          = _customerService.GetCustomerById(_workContext.CurrentCustomer.Id);
            var shoppingCart      = _shoppingCartService.GetShoppingCart(customer, ShoppingCartType.ShoppingCart);
            var shoppingCartTotal = _orderTotalCalculationService.GetShoppingCartTotal(shoppingCart, out var orderDiscountAmount, out var orderAppliedDiscounts, out var appliedGiftCards, out var redeemedRewardPoints, out var redeemedRewardPointsAmount);

            var options = IyzicoHelper.GetIyzicoOptions(_iyzicoPaymentSettings);
            var retrieveInstallmentInfoRequest = new RetrieveInstallmentInfoRequest()
            {
                BinNumber      = binNumber.ToString(),
                Locale         = Locale.TR.ToString(),
                Price          = _priceCalculationService.RoundPrice(shoppingCartTotal.Value).ToString("f8", CultureInfo.InvariantCulture),
                ConversationId = string.Empty
            };
            var installmentInfo = InstallmentInfo.Retrieve(retrieveInstallmentInfoRequest, options);

            var subTotalIncludingTax = _workContext.TaxDisplayType == TaxDisplayType.IncludingTax && !_taxSettings.ForceTaxExclusionFromOrderSubtotal;
            var subtotal             = decimal.Zero;
            var list = new List <Installment>();

            if (installmentInfo.Status == "success" && installmentInfo.InstallmentDetails.Count > 0)
            {
                foreach (var installmentDetail in installmentInfo.InstallmentDetails.FirstOrDefault().InstallmentPrices)
                {
                    var installment = new Installment();

                    installment.DisplayName       = _localizationService.GetResource("Plugins.Payments.Iyzico.Installment" + installmentDetail.InstallmentNumber);
                    installment.InstallmentNumber = installmentDetail.InstallmentNumber ?? 0;
                    decimal.TryParse(installmentDetail.Price.Replace(".", ","), out decimal price);
                    installment.Price = _priceFormatter.FormatPrice(price, true, _workContext.WorkingCurrency, _workContext.WorkingLanguage.Id, subTotalIncludingTax);
                    decimal.TryParse(installmentDetail.TotalPrice.Replace(".", ","), out decimal totalPrice);
                    installment.TotalPrice = _priceFormatter.FormatPrice(totalPrice, true, _workContext.WorkingCurrency, _workContext.WorkingLanguage.Id, subTotalIncludingTax);

                    list.Add(installment);
                }
            }
            else
            {
                subtotal = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartTotal ?? 0, _workContext.WorkingCurrency);

                list.Add(new Installment()
                {
                    DisplayName       = _localizationService.GetResource("Plugins.Payments.Iyzico.Installment1"),
                    InstallmentNumber = 1,
                    Price             = _priceFormatter.FormatPrice(subtotal, true, _workContext.WorkingCurrency, _workContext.WorkingLanguage.Id, subTotalIncludingTax),
                    TotalPrice        = _priceFormatter.FormatPrice(subtotal, true, _workContext.WorkingCurrency, _workContext.WorkingLanguage.Id, subTotalIncludingTax)
                });
            }

            return(Json(list));
        }
Exemple #15
0
        public decimal GetCartTotal(IList <ShoppingCartItem> cart, out decimal orderTotalDiscountAmount, out List <Discount> appliedDiscounts,
                                    out int redeemedRewardPoints, out decimal redeemedRewardPointsAmount, out List <AppliedGiftCard> appliedGiftCards)
        {
            _orderTotalCalculationService.GetShoppingCartTotal(cart, out orderTotalDiscountAmount,
                                                               out appliedDiscounts,
                                                               out appliedGiftCards, out redeemedRewardPoints,
                                                               out redeemedRewardPointsAmount);

            return(GetCartTotal(cart) - (orderTotalDiscountAmount + appliedGiftCards.Sum(x => x.AmountCanBeUsed)));
        }
        /// <summary>
        /// Create item for discount to order total
        /// </summary>
        /// <param name="shoppingCart">Shopping cart</param>
        /// <returns>PayPal item</returns>
        protected Item CreateItemForTotalDiscount(IList <ShoppingCartItem> shoppingCart)
        {
            //get total discount amount
            var orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(shoppingCart,
                                                                                out decimal discountAmount,
                                                                                out List <DiscountForCaching> _, out List <AppliedGiftCard> _, out int _, out decimal _);

            if (discountAmount <= decimal.Zero)
            {
                return(null);
            }

            //create item with negative price
            return(new Item
            {
                name = "Discount for the total of order",
                price = (-discountAmount).ToString("N", new CultureInfo("en-US")),
                quantity = "1"
            });
        }
        public async Task <bool> Handle(GetIsPaymentWorkflowRequired request, CancellationToken cancellationToken)
        {
            bool result = true;
            //check whether order total equals zero
            decimal?shoppingCartTotalBase = (await _orderTotalCalculationService.GetShoppingCartTotal(request.Cart, useRewardPoints: request.UseRewardPoints)).shoppingCartTotal;

            if (shoppingCartTotalBase.HasValue && shoppingCartTotalBase.Value == decimal.Zero && !_paymentSettings.ShowPaymentMethodIfCartIsZero)
            {
                result = false;
            }
            return(result);
        }
Exemple #18
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var cart = _shoppingCartService.GetCartItems(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

            var cartTotal = ((decimal?)_orderTotalCalculationService.GetShoppingCartTotal(cart)) ?? decimal.Zero;

            // Currency values must be rounded, otherwise unexpected results may occur.
            var money = new Money(cartTotal, context.WorkContext.WorkingCurrency);

            cartTotal = money.RoundedAmount;

            return(expression.Operator.Match(cartTotal, expression.Value));
        }
        public virtual async Task <bool> IsPaymentWorkflowRequired(IList <ShoppingCartItem> cart, bool?useRewardPoints = null)
        {
            bool result = true;

            //check whether order total equals zero
            decimal?shoppingCartTotalBase = (await _orderTotalCalculationService.GetShoppingCartTotal(cart, useRewardPoints: useRewardPoints)).shoppingCartTotal;

            if (shoppingCartTotalBase.HasValue && shoppingCartTotalBase.Value == decimal.Zero)
            {
                result = false;
            }
            return(result);
        }
Exemple #20
0
        /// <summary>
        /// Process a payment
        /// </summary>
        /// <param name="processPaymentRequest">Payment info required for an order processing</param>
        /// <returns>Process payment result</returns>
        public ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest)
        {
            var result = new ProcessPaymentResult();

            result.NewPaymentStatus = PaymentStatus.Pending;

            var customer = _customerService.GetCustomerById(processPaymentRequest.CustomerId);

            if (customer == null)
            {
                throw new Exception("找不到客户信息");
            }

            //从支付页面传递过来的值
            processPaymentRequest.CustomValues.TryGetValue("selectPaymentCompanyId", out Object selectPaymentCompanyIdObj)
            .FalseThrow("获取支付信息异常");

            //选择的发薪公司编码
            int selectPaymentCompanyId = (int)selectPaymentCompanyIdObj;

            (selectPaymentCompanyId <= 0).TrueThrow("支付失败,发薪公司编码不能小于0");

            #region  支付操作
            //购物车详细
            var cart = processPaymentRequest.ShoppingCartItems.ToList();

            #region 购物车总金额

            decimal?shoppingCartTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart);
            if (shoppingCartTotal.HasValue)
            {
                //总金额
                decimal totalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartTotal.Value, _workContext.WorkingCurrency);
            }

            //selectPaymentCompanyId为发薪公司编码
            //totalAmount 为待支付金额
            //processPaymentRequest.OrderGuid 为订单Guid编码
            //以上信息臻顺溜支付时会用到

            #endregion

            #endregion


            result.AuthorizationTransactionResult = "已支付(测试阶段)";
            result.NewPaymentStatus = PaymentStatus.Paid;


            return(result);
        }
Exemple #21
0
        public ActionResult PaymentInfo()
        {
            var returnUrl = this.Url.Action("Return", "PaymentStripe", new { accountId = _stripePaymentSettings.ConnectAccountId }, this.Request.Url.Scheme);

            _stripePaymentSettings.ReturnUrl = _webHelper.GetStoreLocation(false) + "Plugins/PaymentStripe/ProcessPayment";
            _settingService.SaveSetting(_stripePaymentSettings);
            var cart  = _workContext.CurrentCustomer.ShoppingCartItems.ToList();
            var model = new PaymentInfoModel()
            {
                StripePublicApiKey = _paymentStripeService.GetPublicApiKey(),
                Amount             = Decimal.ToInt32(_orderTotalCalculationService.GetShoppingCartTotal(cart) * 100 ?? 0),
                CustomerEmail      = _workContext.CurrentCustomer.Email,
                AccountId          = _stripePaymentSettings.ConnectAccountId,
                ReturnUrl          = returnUrl,
            };

            return(View("~/Plugins/Payments.Stripe/Views/PaymentInfo.cshtml", model));
        }
Exemple #22
0
        public OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, string orderReferenceId, string currencyCode, List <OrganizedShoppingCartItem> cart)
        {
            decimal  orderTotalDiscountAmountBase   = decimal.Zero;
            Discount orderTotalAppliedDiscount      = null;
            List <AppliedGiftCard> appliedGiftCards = null;
            int     redeemedRewardPoints            = 0;
            decimal redeemedRewardPointsAmount      = decimal.Zero;

            decimal?shoppingCartTotalBase = _orderTotalCalculationService.GetShoppingCartTotal(cart,
                                                                                               out orderTotalDiscountAmountBase, out orderTotalAppliedDiscount, out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount);

            if (shoppingCartTotalBase.HasValue)
            {
                return(SetOrderReferenceDetails(client, orderReferenceId, shoppingCartTotalBase, currencyCode));
            }

            return(null);
        }
Exemple #23
0
        /// <summary>
        /// Returns a value indicating whether payment method should be hidden during checkout
        /// </summary>
        /// <param name="cart">Shopping cart</param>
        /// <returns>true - hide; false - display.</returns>
        public bool HidePaymentMethod(IList <ShoppingCartItem> cart)
        {
            //you can put any logic here
            //for example, hide this payment method if all products in the cart are downloadable
            //or hide this payment method if current customer is from certain country

            var orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart);

            if (_sezzlePaymentSettings.MinCheckoutAmount > 0)
            {
                if (orderTotal < _sezzlePaymentSettings.MinCheckoutAmount)
                {
                    return(true);
                }
            }
            else if (String.IsNullOrEmpty(_sezzlePaymentSettings.PublicKey) ||
                     String.IsNullOrEmpty(_sezzlePaymentSettings.PrivateKey))
            {
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Prepare the order totals model
        /// </summary>
        /// <param name="cart">List of the shopping cart item</param>
        /// <param name="isEditable">Whether model is editable</param>
        /// <returns>Order totals model</returns>
        public override OrderTotalsModel PrepareOrderTotalsModel(IList <ShoppingCartItem> cart, bool isEditable)
        {
            var model = new OrderTotalsModel
            {
                IsEditable = isEditable
            };

            if (cart.Any())
            {
                //Avalara plugin changes
                PrepareTaxDetails(cart);
                //Avalara plugin changes

                //subtotal
                var subTotalIncludingTax = _workContext.TaxDisplayType == TaxDisplayType.IncludingTax && !_taxSettings.ForceTaxExclusionFromOrderSubtotal;
                _orderTotalCalculationService.GetShoppingCartSubTotal(cart, subTotalIncludingTax, out var orderSubTotalDiscountAmountBase, out var _, out var subTotalWithoutDiscountBase, out var _);
                var subtotalBase = subTotalWithoutDiscountBase;
                var subtotal     = _currencyService.ConvertFromPrimaryStoreCurrency(subtotalBase, _workContext.WorkingCurrency);
                model.SubTotal = _priceFormatter.FormatPrice(subtotal, true, _workContext.WorkingCurrency, _workContext.WorkingLanguage, subTotalIncludingTax);

                if (orderSubTotalDiscountAmountBase > decimal.Zero)
                {
                    var orderSubTotalDiscountAmount = _currencyService.ConvertFromPrimaryStoreCurrency(orderSubTotalDiscountAmountBase, _workContext.WorkingCurrency);
                    model.SubTotalDiscount = _priceFormatter.FormatPrice(-orderSubTotalDiscountAmount, true, _workContext.WorkingCurrency, _workContext.WorkingLanguage, subTotalIncludingTax);
                }

                //LoadAllShippingRateComputationMethods
                var shippingRateComputationMethods = _shippingPluginManager.LoadActivePlugins(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id);

                //shipping info
                model.RequiresShipping = _shoppingCartService.ShoppingCartRequiresShipping(cart);
                if (model.RequiresShipping)
                {
                    var shoppingCartShippingBase = _orderTotalCalculationService.GetShoppingCartShippingTotal(cart, shippingRateComputationMethods);
                    if (shoppingCartShippingBase.HasValue)
                    {
                        var shoppingCartShipping = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartShippingBase.Value, _workContext.WorkingCurrency);
                        model.Shipping = _priceFormatter.FormatShippingPrice(shoppingCartShipping, true);

                        //selected shipping method
                        var shippingOption = _genericAttributeService.GetAttribute <ShippingOption>(_workContext.CurrentCustomer,
                                                                                                    NopCustomerDefaults.SelectedShippingOptionAttribute, _storeContext.CurrentStore.Id);
                        if (shippingOption != null)
                        {
                            model.SelectedShippingMethod = shippingOption.Name;
                        }
                    }
                }
                else
                {
                    model.HideShippingTotal = _shippingSettings.HideShippingTotal;
                }

                //payment method fee
                var paymentMethodSystemName               = _genericAttributeService.GetAttribute <string>(_workContext.CurrentCustomer, NopCustomerDefaults.SelectedPaymentMethodAttribute, _storeContext.CurrentStore.Id);
                var paymentMethodAdditionalFee            = _paymentService.GetAdditionalHandlingFee(cart, paymentMethodSystemName);
                var paymentMethodAdditionalFeeWithTaxBase = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, _workContext.CurrentCustomer);
                if (paymentMethodAdditionalFeeWithTaxBase > decimal.Zero)
                {
                    var paymentMethodAdditionalFeeWithTax = _currencyService.ConvertFromPrimaryStoreCurrency(paymentMethodAdditionalFeeWithTaxBase, _workContext.WorkingCurrency);
                    model.PaymentMethodAdditionalFee = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeWithTax, true);
                }

                //tax
                var displayTax      = true;
                var displayTaxRates = true;
                if (_taxSettings.HideTaxInOrderSummary && _workContext.TaxDisplayType == TaxDisplayType.IncludingTax)
                {
                    displayTax      = false;
                    displayTaxRates = false;
                }
                else
                {
                    var shoppingCartTaxBase = _orderTotalCalculationService.GetTaxTotal(cart, shippingRateComputationMethods, out var taxRates);

                    //Avalara plugin changes
                    //get tax details from the Avalara tax service, it may slightly differ from the original calculated tax
                    var taxDetails = _httpContextAccessor.HttpContext.Session.Get <TaxDetails>(AvalaraTaxDefaults.TaxDetailsSessionValue);
                    if (taxDetails != null)
                    {
                        //adjust tax total according to received value from the Avalara
                        if (taxDetails.TaxTotal.HasValue)
                        {
                            shoppingCartTaxBase = taxDetails.TaxTotal.Value;
                        }

                        if (taxDetails.TaxRates?.Any() ?? false)
                        {
                            taxRates = new SortedDictionary <decimal, decimal>(taxDetails.TaxRates);
                        }
                    }
                    //Avalara plugin changes

                    var shoppingCartTax = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartTaxBase, _workContext.WorkingCurrency);

                    if (shoppingCartTaxBase == 0 && _taxSettings.HideZeroTax)
                    {
                        displayTax      = false;
                        displayTaxRates = false;
                    }
                    else
                    {
                        displayTaxRates = _taxSettings.DisplayTaxRates && taxRates.Any();
                        displayTax      = !displayTaxRates;

                        model.Tax = _priceFormatter.FormatPrice(shoppingCartTax, true, false);
                        foreach (var tr in taxRates)
                        {
                            model.TaxRates.Add(new OrderTotalsModel.TaxRate
                            {
                                Rate  = _priceFormatter.FormatTaxRate(tr.Key),
                                Value = _priceFormatter.FormatPrice(_currencyService.ConvertFromPrimaryStoreCurrency(tr.Value, _workContext.WorkingCurrency), true, false),
                            });
                        }
                    }
                }
                model.DisplayTaxRates = displayTaxRates;
                model.DisplayTax      = displayTax;

                //total
                var shoppingCartTotalBase = _orderTotalCalculationService.GetShoppingCartTotal(cart, out var orderTotalDiscountAmountBase, out var _, out var appliedGiftCards, out var redeemedRewardPoints, out var redeemedRewardPointsAmount);
                if (shoppingCartTotalBase.HasValue)
                {
                    var shoppingCartTotal = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartTotalBase.Value, _workContext.WorkingCurrency);
                    model.OrderTotal = _priceFormatter.FormatPrice(shoppingCartTotal, true, false);
                }

                //discount
                if (orderTotalDiscountAmountBase > decimal.Zero)
                {
                    var orderTotalDiscountAmount = _currencyService.ConvertFromPrimaryStoreCurrency(orderTotalDiscountAmountBase, _workContext.WorkingCurrency);
                    model.OrderTotalDiscount = _priceFormatter.FormatPrice(-orderTotalDiscountAmount, true, false);
                }

                //gift cards
                if (appliedGiftCards != null && appliedGiftCards.Any())
                {
                    foreach (var appliedGiftCard in appliedGiftCards)
                    {
                        var gcModel = new OrderTotalsModel.GiftCard
                        {
                            Id         = appliedGiftCard.GiftCard.Id,
                            CouponCode = appliedGiftCard.GiftCard.GiftCardCouponCode,
                        };
                        var amountCanBeUsed = _currencyService.ConvertFromPrimaryStoreCurrency(appliedGiftCard.AmountCanBeUsed, _workContext.WorkingCurrency);
                        gcModel.Amount = _priceFormatter.FormatPrice(-amountCanBeUsed, true, false);

                        var remainingAmountBase = _giftCardService.GetGiftCardRemainingAmount(appliedGiftCard.GiftCard) - appliedGiftCard.AmountCanBeUsed;
                        var remainingAmount     = _currencyService.ConvertFromPrimaryStoreCurrency(remainingAmountBase, _workContext.WorkingCurrency);
                        gcModel.Remaining = _priceFormatter.FormatPrice(remainingAmount, true, false);

                        model.GiftCards.Add(gcModel);
                    }
                }

                //reward points to be spent (redeemed)
                if (redeemedRewardPointsAmount > decimal.Zero)
                {
                    var redeemedRewardPointsAmountInCustomerCurrency = _currencyService.ConvertFromPrimaryStoreCurrency(redeemedRewardPointsAmount, _workContext.WorkingCurrency);
                    model.RedeemedRewardPoints       = redeemedRewardPoints;
                    model.RedeemedRewardPointsAmount = _priceFormatter.FormatPrice(-redeemedRewardPointsAmountInCustomerCurrency, true, false);
                }

                //reward points to be earned
                if (_rewardPointsSettings.Enabled && _rewardPointsSettings.DisplayHowMuchWillBeEarned && shoppingCartTotalBase.HasValue)
                {
                    //get shipping total
                    var shippingBaseInclTax = !model.RequiresShipping ? 0 : _orderTotalCalculationService.GetShoppingCartShippingTotal(cart, true, shippingRateComputationMethods) ?? 0;

                    //get total for reward points
                    var totalForRewardPoints = _orderTotalCalculationService
                                               .CalculateApplicableOrderTotalForRewardPoints(shippingBaseInclTax, shoppingCartTotalBase.Value);
                    if (totalForRewardPoints > decimal.Zero)
                    {
                        model.WillEarnRewardPoints = _orderTotalCalculationService.CalculateRewardPoints(_workContext.CurrentCustomer, totalForRewardPoints);
                    }
                }
            }

            return(model);
        }
        public async Task <IViewComponentResult> InvokeAsync()
        {
            var model = new PaymentInfoModel();

            if (_brainTreePaymentSettings.Use3DS)
            {
                var cart = _shoppingCartService.GetShoppingCart(_storeContext.CurrentStore.Id, ShoppingCartType.ShoppingCart);

                if (!cart.Any())
                {
                    throw new Exception("Your cart is empty");
                }

                //get settings
                var useSandBox = _brainTreePaymentSettings.UseSandBox;
                var merchantId = _brainTreePaymentSettings.MerchantId;
                var publicKey  = _brainTreePaymentSettings.PublicKey;
                var privateKey = _brainTreePaymentSettings.PrivateKey;

                var gateway = new BraintreeGateway {
                    Environment = useSandBox ? Braintree.Environment.SANDBOX : Braintree.Environment.PRODUCTION,
                    MerchantId  = merchantId,
                    PublicKey   = publicKey,
                    PrivateKey  = privateKey
                };

                ViewBag.ClientToken = gateway.ClientToken.Generate();
                ViewBag.OrderTotal  = (await _orderTotalCalculationService.GetShoppingCartTotal(cart)).shoppingCartTotal;

                return(View("~/Plugins/Payments.BrainTree/Views/PaymentInfo_3DS.cshtml", model));
            }

            //years
            for (var i = 0; i < 15; i++)
            {
                var year = Convert.ToString(DateTime.Now.Year + i);
                model.ExpireYears.Add(new SelectListItem {
                    Text  = year,
                    Value = year,
                });
            }

            //months
            for (var i = 1; i <= 12; i++)
            {
                var text = (i < 10) ? "0" + i : i.ToString();
                model.ExpireMonths.Add(new SelectListItem {
                    Text  = text,
                    Value = i.ToString(),
                });
            }

            //set postback values (we cannot access "Form" with "GET" requests)
            if (Request.Method == WebRequestMethods.Http.Get)
            {
                return(View("~/Plugins/Payments.BrainTree/Views/PaymentInfo.cshtml", model));
            }

            var form = await HttpContext.Request.ReadFormAsync();

            model.CardholderName = form["CardholderName"];
            model.CardNumber     = form["CardNumber"];
            model.CardCode       = form["CardCode"];

            var selectedMonth = model.ExpireMonths
                                .FirstOrDefault(x => x.Value.Equals(form["ExpireMonth"], StringComparison.InvariantCultureIgnoreCase));

            if (selectedMonth != null)
            {
                selectedMonth.Selected = true;
            }
            var selectedYear = model.ExpireYears
                               .FirstOrDefault(x => x.Value.Equals(form["ExpireYear"], StringComparison.InvariantCultureIgnoreCase));

            if (selectedYear != null)
            {
                selectedYear.Selected = true;
            }

            var validator = new PaymentInfoValidator(_brainTreePaymentSettings, _localizationService);
            var results   = validator.Validate(model);

            if (!results.IsValid)
            {
                var query = from error in results.Errors
                            select error.ErrorMessage;
                model.Errors = string.Join(", ", query);
            }

            return(View("~/Plugins/Payments.BrainTree/Views/PaymentInfo.cshtml", model));
        }
        public async Task <CheckoutPaymentMethodModel> Handle(GetPaymentMethod request, CancellationToken cancellationToken)
        {
            var model = new CheckoutPaymentMethodModel();

            //reward points
            if (_rewardPointsSettings.Enabled && !request.Cart.IsRecurring())
            {
                int rewardPointsBalance = await _rewardPointsService.GetRewardPointsBalance(request.Customer.Id, request.Store.Id);

                decimal rewardPointsAmountBase = await _orderTotalCalculationService.ConvertRewardPointsToAmount(rewardPointsBalance);

                decimal rewardPointsAmount = await _currencyService.ConvertFromPrimaryStoreCurrency(rewardPointsAmountBase, request.Currency);

                if (rewardPointsAmount > decimal.Zero &&
                    _orderTotalCalculationService.CheckMinimumRewardPointsToUseRequirement(rewardPointsBalance))
                {
                    model.DisplayRewardPoints = true;
                    model.RewardPointsAmount  = _priceFormatter.FormatPrice(rewardPointsAmount, true, false);
                    model.RewardPointsBalance = rewardPointsBalance;
                    var shoppingCartTotalBase = (await _orderTotalCalculationService.GetShoppingCartTotal(request.Cart, useRewardPoints: true)).shoppingCartTotal;
                    model.RewardPointsEnoughToPayForOrder = (shoppingCartTotalBase.HasValue && shoppingCartTotalBase.Value == decimal.Zero);
                }
            }

            //filter by country
            var paymentMethods = (await _paymentService
                                  .LoadActivePaymentMethods(request.Customer, request.Store.Id, request.FilterByCountryId))
                                 .Where(pm => pm.PaymentMethodType == PaymentMethodType.Standard || pm.PaymentMethodType == PaymentMethodType.Redirection).ToList();
            var availablepaymentMethods = new List <IPaymentMethod>();

            foreach (var pm in paymentMethods)
            {
                if (!await pm.HidePaymentMethod(request.Cart))
                {
                    availablepaymentMethods.Add(pm);
                }
            }

            foreach (var pm in availablepaymentMethods)
            {
                if (request.Cart.IsRecurring() && pm.RecurringPaymentType == RecurringPaymentType.NotSupported)
                {
                    continue;
                }

                var pmModel = new CheckoutPaymentMethodModel.PaymentMethodModel {
                    Name                    = pm.GetLocalizedFriendlyName(_localizationService, request.Language.Id),
                    Description             = _paymentSettings.ShowPaymentMethodDescriptions ? await pm.PaymentMethodDescription() : string.Empty,
                    PaymentMethodSystemName = pm.PluginDescriptor.SystemName,
                    LogoUrl                 = pm.PluginDescriptor.GetLogoUrl(_webHelper)
                };
                //payment method additional fee
                decimal paymentMethodAdditionalFee = await _paymentService.GetAdditionalHandlingFee(request.Cart, pm.PluginDescriptor.SystemName);

                decimal rateBase = (await _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, request.Customer)).paymentPrice;
                decimal rate     = await _currencyService.ConvertFromPrimaryStoreCurrency(rateBase, request.Currency);

                if (rate > decimal.Zero)
                {
                    pmModel.Fee = _priceFormatter.FormatPaymentMethodAdditionalFee(rate, true);
                }

                model.PaymentMethods.Add(pmModel);
            }

            //find a selected (previously) payment method
            var selectedPaymentMethodSystemName = request.Customer.GetAttributeFromEntity <string>(SystemCustomerAttributeNames.SelectedPaymentMethod, request.Store.Id);

            if (!string.IsNullOrEmpty(selectedPaymentMethodSystemName))
            {
                var paymentMethodToSelect = model.PaymentMethods.ToList()
                                            .Find(pm => pm.PaymentMethodSystemName.Equals(selectedPaymentMethodSystemName, StringComparison.OrdinalIgnoreCase));
                if (paymentMethodToSelect != null)
                {
                    paymentMethodToSelect.Selected = true;
                }
            }
            //if no option has been selected, let's do it for the first one
            if (model.PaymentMethods.FirstOrDefault(so => so.Selected) == null)
            {
                var paymentMethodToSelect = model.PaymentMethods.FirstOrDefault();
                if (paymentMethodToSelect != null)
                {
                    paymentMethodToSelect.Selected = true;
                }
            }

            return(model);
        }
        /// <summary>
        /// Prepare details to place an order. It also sets some properties to "processPaymentRequest"
        /// </summary>
        /// <param name="processPaymentRequest">Process payment request</param>
        /// <returns>Details</returns>
        protected override PlaceOrderContainer PreparePlaceOrderDetails(ProcessPaymentRequest processPaymentRequest)
        {
            var details = new PlaceOrderContainer
            {
                //customer
                Customer = _customerService.GetCustomerById(processPaymentRequest.CustomerId)
            };

            if (details.Customer == null)
            {
                throw new ArgumentException("Customer is not set");
            }

            //affiliate
            var affiliate = _affiliateService.GetAffiliateById(details.Customer.AffiliateId);

            if (affiliate != null && affiliate.Active && !affiliate.Deleted)
            {
                details.AffiliateId = affiliate.Id;
            }

            //check whether customer is guest
            if (details.Customer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed)
            {
                throw new QNetException("Anonymous checkout is not allowed");
            }

            //customer currency
            var currencyTmp = _currencyService.GetCurrencyById(
                _genericAttributeService.GetAttribute <int>(details.Customer, QNetCustomerDefaults.CurrencyIdAttribute, processPaymentRequest.StoreId));
            var customerCurrency     = currencyTmp != null && currencyTmp.Published ? currencyTmp : _workContext.WorkingCurrency;
            var primaryStoreCurrency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId);

            details.CustomerCurrencyCode = customerCurrency.CurrencyCode;
            details.CustomerCurrencyRate = customerCurrency.Rate / primaryStoreCurrency.Rate;

            //customer language
            details.CustomerLanguage = _languageService.GetLanguageById(
                _genericAttributeService.GetAttribute <int>(details.Customer, QNetCustomerDefaults.LanguageIdAttribute, processPaymentRequest.StoreId));
            if (details.CustomerLanguage == null || !details.CustomerLanguage.Published)
            {
                details.CustomerLanguage = _workContext.WorkingLanguage;
            }

            //billing address
            if (details.Customer.BillingAddress == null)
            {
                throw new QNetException("Billing address is not provided");
            }

            if (!CommonHelper.IsValidEmail(details.Customer.BillingAddress.Email))
            {
                throw new QNetException("Email is not valid");
            }

            details.BillingAddress = (Address)details.Customer.BillingAddress.Clone();
            if (details.BillingAddress.Country != null && !details.BillingAddress.Country.AllowsBilling)
            {
                throw new QNetException($"Country '{details.BillingAddress.Country.Name}' is not allowed for billing");
            }

            //checkout attributes
            details.CheckoutAttributesXml        = _genericAttributeService.GetAttribute <string>(details.Customer, QNetCustomerDefaults.CheckoutAttributes, processPaymentRequest.StoreId);
            details.CheckoutAttributeDescription = _checkoutAttributeFormatter.FormatAttributes(details.CheckoutAttributesXml, details.Customer);

            //load shopping cart
            details.Cart = _shoppingCartService.GetShoppingCart(details.Customer, ShoppingCartType.ShoppingCart, processPaymentRequest.StoreId);

            if (!details.Cart.Any())
            {
                throw new QNetException("Cart is empty");
            }

            //validate the entire shopping cart
            var warnings = _shoppingCartService.GetShoppingCartWarnings(details.Cart, details.CheckoutAttributesXml, true);

            if (warnings.Any())
            {
                throw new QNetException(warnings.Aggregate(string.Empty, (current, next) => $"{current}{next};"));
            }

            //validate individual cart items
            foreach (var sci in details.Cart)
            {
                var sciWarnings = _shoppingCartService.GetShoppingCartItemWarnings(details.Customer,
                                                                                   sci.ShoppingCartType, sci.Product, processPaymentRequest.StoreId, sci.AttributesXml,
                                                                                   sci.CustomerEnteredPrice, sci.RentalStartDateUtc, sci.RentalEndDateUtc, sci.Quantity, false, sci.Id);
                if (sciWarnings.Any())
                {
                    throw new QNetException(sciWarnings.Aggregate(string.Empty, (current, next) => $"{current}{next};"));
                }
            }

            //min totals validation
            if (!ValidateMinOrderSubtotalAmount(details.Cart))
            {
                var minOrderSubtotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderSubtotalAmount, _workContext.WorkingCurrency);
                throw new QNetException(string.Format(_localizationService.GetResource("Checkout.MinOrderSubtotalAmount"),
                                                      _priceFormatter.FormatPrice(minOrderSubtotalAmount, true, false)));
            }

            if (!ValidateMinOrderTotalAmount(details.Cart))
            {
                var minOrderTotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderTotalAmount, _workContext.WorkingCurrency);
                throw new QNetException(string.Format(_localizationService.GetResource("Checkout.MinOrderTotalAmount"),
                                                      _priceFormatter.FormatPrice(minOrderTotalAmount, true, false)));
            }

            //tax display type
            if (_taxSettings.AllowCustomersToSelectTaxDisplayType)
            {
                details.CustomerTaxDisplayType = (TaxDisplayType)_genericAttributeService.GetAttribute <int>(details.Customer, QNetCustomerDefaults.TaxDisplayTypeIdAttribute, processPaymentRequest.StoreId);
            }
            else
            {
                details.CustomerTaxDisplayType = _taxSettings.TaxDisplayType;
            }

            //sub total (incl tax)
            _orderTotalCalculationService.GetShoppingCartSubTotal(details.Cart, true, out var orderSubTotalDiscountAmount, out var orderSubTotalAppliedDiscounts, out var subTotalWithoutDiscountBase, out var _);
            details.OrderSubTotalInclTax         = subTotalWithoutDiscountBase;
            details.OrderSubTotalDiscountInclTax = orderSubTotalDiscountAmount;

            //discount history
            foreach (var disc in orderSubTotalAppliedDiscounts)
            {
                if (!_discountService.ContainsDiscount(details.AppliedDiscounts, disc))
                {
                    details.AppliedDiscounts.Add(disc);
                }
            }

            //sub total (excl tax)
            _orderTotalCalculationService.GetShoppingCartSubTotal(details.Cart, false, out orderSubTotalDiscountAmount,
                                                                  out orderSubTotalAppliedDiscounts, out subTotalWithoutDiscountBase, out _);
            details.OrderSubTotalExclTax         = subTotalWithoutDiscountBase;
            details.OrderSubTotalDiscountExclTax = orderSubTotalDiscountAmount;

            //shipping info
            if (_shoppingCartService.ShoppingCartRequiresShipping(details.Cart))
            {
                var pickupPoint = _genericAttributeService.GetAttribute <PickupPoint>(details.Customer,
                                                                                      QNetCustomerDefaults.SelectedPickupPointAttribute, processPaymentRequest.StoreId);
                if (_shippingSettings.AllowPickupInStore && pickupPoint != null)
                {
                    var country = _countryService.GetCountryByTwoLetterIsoCode(pickupPoint.CountryCode);
                    var state   = _stateProvinceService.GetStateProvinceByAbbreviation(pickupPoint.StateAbbreviation, country?.Id);

                    details.PickupInStore = true;
                    details.PickupAddress = new Address
                    {
                        Address1      = pickupPoint.Address,
                        City          = pickupPoint.City,
                        County        = pickupPoint.County,
                        Country       = country,
                        StateProvince = state,
                        ZipPostalCode = pickupPoint.ZipPostalCode,
                        CreatedOnUtc  = DateTime.UtcNow
                    };
                }
                else
                {
                    if (details.Customer.ShippingAddress == null)
                    {
                        throw new QNetException("Shipping address is not provided");
                    }

                    if (!CommonHelper.IsValidEmail(details.Customer.ShippingAddress.Email))
                    {
                        throw new QNetException("Email is not valid");
                    }

                    //clone shipping address
                    details.ShippingAddress = (Address)details.Customer.ShippingAddress.Clone();
                    if (details.ShippingAddress.Country != null && !details.ShippingAddress.Country.AllowsShipping)
                    {
                        throw new QNetException($"Country '{details.ShippingAddress.Country.Name}' is not allowed for shipping");
                    }
                }

                var shippingOption = _genericAttributeService.GetAttribute <ShippingOption>(details.Customer,
                                                                                            QNetCustomerDefaults.SelectedShippingOptionAttribute, processPaymentRequest.StoreId);
                if (shippingOption != null)
                {
                    details.ShippingMethodName = shippingOption.Name;
                    details.ShippingRateComputationMethodSystemName = shippingOption.ShippingRateComputationMethodSystemName;
                }

                details.ShippingStatus = ShippingStatus.NotYetShipped;
            }
            else
            {
                details.ShippingStatus = ShippingStatus.ShippingNotRequired;
            }

            //LoadAllShippingRateComputationMethods
            var shippingRateComputationMethods = _shippingPluginManager.LoadActivePlugins(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id);

            //shipping total
            var orderShippingTotalInclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(details.Cart, true, shippingRateComputationMethods, out var _, out var shippingTotalDiscounts);
            var orderShippingTotalExclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(details.Cart, false, shippingRateComputationMethods);

            if (!orderShippingTotalInclTax.HasValue || !orderShippingTotalExclTax.HasValue)
            {
                throw new QNetException("Shipping total couldn't be calculated");
            }

            details.OrderShippingTotalInclTax = orderShippingTotalInclTax.Value;
            details.OrderShippingTotalExclTax = orderShippingTotalExclTax.Value;

            foreach (var disc in shippingTotalDiscounts)
            {
                if (!_discountService.ContainsDiscount(details.AppliedDiscounts, disc))
                {
                    details.AppliedDiscounts.Add(disc);
                }
            }

            //payment total
            var paymentAdditionalFee = _paymentService.GetAdditionalHandlingFee(details.Cart, processPaymentRequest.PaymentMethodSystemName);

            details.PaymentAdditionalFeeInclTax = _taxService.GetPaymentMethodAdditionalFee(paymentAdditionalFee, true, details.Customer);
            details.PaymentAdditionalFeeExclTax = _taxService.GetPaymentMethodAdditionalFee(paymentAdditionalFee, false, details.Customer);

            //tax amount
            details.OrderTaxTotal = _orderTotalCalculationService.GetTaxTotal(details.Cart, shippingRateComputationMethods, out var taxRatesDictionary);

            //Avalara plugin changes
            //get previously saved tax details received from the Avalara tax service
            var taxDetails = _httpContextAccessor.HttpContext.Session.Get <TaxDetails>(AvalaraTaxDefaults.TaxDetailsSessionValue);

            if (taxDetails != null)
            {
                //adjust tax total according to received value from the Avalara
                if (taxDetails.TaxTotal.HasValue)
                {
                    details.OrderTaxTotal = taxDetails.TaxTotal.Value;
                }

                if (taxDetails.TaxRates?.Any() ?? false)
                {
                    taxRatesDictionary = new SortedDictionary <decimal, decimal>(taxDetails.TaxRates);
                }
            }
            //Avalara plugin changes

            //VAT number
            var customerVatStatus = (VatNumberStatus)_genericAttributeService.GetAttribute <int>(details.Customer, QNetCustomerDefaults.VatNumberStatusIdAttribute);

            if (_taxSettings.EuVatEnabled && customerVatStatus == VatNumberStatus.Valid)
            {
                details.VatNumber = _genericAttributeService.GetAttribute <string>(details.Customer, QNetCustomerDefaults.VatNumberAttribute);
            }

            //tax rates
            details.TaxRates = taxRatesDictionary.Aggregate(string.Empty, (current, next) =>
                                                            $"{current}{next.Key.ToString(CultureInfo.InvariantCulture)}:{next.Value.ToString(CultureInfo.InvariantCulture)};   ");

            //order total (and applied discounts, gift cards, reward points)
            var orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(details.Cart, out var orderDiscountAmount, out var orderAppliedDiscounts, out var appliedGiftCards, out var redeemedRewardPoints, out var redeemedRewardPointsAmount);

            if (!orderTotal.HasValue)
            {
                throw new QNetException("Order total couldn't be calculated");
            }

            details.OrderDiscountAmount        = orderDiscountAmount;
            details.RedeemedRewardPoints       = redeemedRewardPoints;
            details.RedeemedRewardPointsAmount = redeemedRewardPointsAmount;
            details.AppliedGiftCards           = appliedGiftCards;
            details.OrderTotal = orderTotal.Value;

            //discount history
            foreach (var disc in orderAppliedDiscounts)
            {
                if (!_discountService.ContainsDiscount(details.AppliedDiscounts, disc))
                {
                    details.AppliedDiscounts.Add(disc);
                }
            }

            processPaymentRequest.OrderTotal = details.OrderTotal;

            //Avalara plugin changes
            //delete custom value
            _httpContextAccessor.HttpContext.Session.Set <TaxDetails>(AvalaraTaxDefaults.TaxDetailsSessionValue, null);
            //Avalara plugin changes

            //recurring or standard shopping cart?
            details.IsRecurringShoppingCart = _shoppingCartService.ShoppingCartIsRecurring(details.Cart);
            if (!details.IsRecurringShoppingCart)
            {
                return(details);
            }

            var recurringCyclesError = _shoppingCartService.GetRecurringCycleInfo(details.Cart,
                                                                                  out var recurringCycleLength, out var recurringCyclePeriod, out var recurringTotalCycles);

            if (!string.IsNullOrEmpty(recurringCyclesError))
            {
                throw new QNetException(recurringCyclesError);
            }

            processPaymentRequest.RecurringCycleLength = recurringCycleLength;
            processPaymentRequest.RecurringCyclePeriod = recurringCyclePeriod;
            processPaymentRequest.RecurringTotalCycles = recurringTotalCycles;

            return(details);
        }
        /// <summary>
        /// Handle shopping cart changed event
        /// </summary>
        /// <param name="cartItem">Shopping cart item</param>
        public void HandleShoppingCartChangedEvent(ShoppingCartItem cartItem)
        {
            //whether marketing automation is enabled
            if (!_sendInBlueSettings.UseMarketingAutomation)
            {
                return;
            }

            try
            {
                //create API client
                var client = CreateMarketingAutomationClient();

                //first, try to identify current customer
                client.Identify(new Identify(cartItem.Customer.Email));

                //get shopping cart GUID
                var shoppingCartGuid = _genericAttributeService.GetAttribute <Guid?>(cartItem.Customer, SendinBlueDefaults.ShoppingCartGuidAttribute);

                //create track event object
                var trackEvent = new TrackEvent(cartItem.Customer.Email, string.Empty);

                //get current customer's shopping cart
                var cart = cartItem.Customer.ShoppingCartItems
                           .Where(item => item.ShoppingCartType == ShoppingCartType.ShoppingCart)
                           .LimitPerStore(_storeContext.CurrentStore.Id).ToList();

                if (cart.Any())
                {
                    //get URL helper
                    var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContextAccessor.ActionContext);

                    //get shopping cart amounts
                    _orderTotalCalculationService.GetShoppingCartSubTotal(cart, _workContext.TaxDisplayType == TaxDisplayType.IncludingTax,
                                                                          out var cartDiscount, out _, out var cartSubtotal, out _);
                    var cartTax      = _orderTotalCalculationService.GetTaxTotal(cart, false);
                    var cartShipping = _orderTotalCalculationService.GetShoppingCartShippingTotal(cart);
                    var cartTotal    = _orderTotalCalculationService.GetShoppingCartTotal(cart, false, false);

                    //get products data by shopping cart items
                    var itemsData = cart.Where(item => item.Product != null).Select(item =>
                    {
                        //try to get product attribute combination
                        var combination = _productAttributeParser.FindProductAttributeCombination(item.Product, item.AttributesXml);

                        //get default product picture
                        var picture = _pictureService.GetProductPicture(item.Product, item.AttributesXml);

                        //get product SEO slug name
                        var seName = _urlRecordService.GetSeName(item.Product);

                        //create product data
                        return(new
                        {
                            id = item.Product.Id,
                            name = item.Product.Name,
                            variant_id = combination?.Id ?? item.Product.Id,
                            variant_name = combination?.Sku ?? item.Product.Name,
                            sku = combination?.Sku ?? item.Product.Sku,
                            category = item.Product.ProductCategories.Aggregate(",", (all, category) => {
                                var res = category.Category.Name;
                                res = all == "," ? res : all + ", " + res;
                                return res;
                            }),
                            url = urlHelper.RouteUrl("Product", new { SeName = seName }, _webHelper.CurrentRequestProtocol),
                            image = _pictureService.GetPictureUrl(picture),
                            quantity = item.Quantity,
                            price = _priceCalculationService.GetSubTotal(item)
                        });
                    }).ToArray();

                    //prepare cart data
                    var cartData = new
                    {
                        affiliation      = _storeContext.CurrentStore.Name,
                        subtotal         = cartSubtotal,
                        shipping         = cartShipping ?? decimal.Zero,
                        total_before_tax = cartSubtotal + cartShipping ?? decimal.Zero,
                        tax      = cartTax,
                        discount = cartDiscount,
                        revenue  = cartTotal ?? decimal.Zero,
                        url      = urlHelper.RouteUrl("ShoppingCart", null, _webHelper.CurrentRequestProtocol),
                        currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)?.CurrencyCode,
                        //gift_wrapping = string.Empty, //currently we can't get this value
                        items = itemsData
                    };

                    //if there is a single item in the cart, so the cart is just created
                    if (cart.Count == 1)
                    {
                        shoppingCartGuid = Guid.NewGuid();
                    }
                    else
                    {
                        //otherwise cart is updated
                        shoppingCartGuid = shoppingCartGuid ?? Guid.NewGuid();
                    }
                    trackEvent.EventName = SendinBlueDefaults.CartUpdatedEventName;
                    trackEvent.EventData = new { id = $"cart:{shoppingCartGuid}", data = cartData };
                }
                else
                {
                    //there are no items in the cart, so the cart is deleted
                    shoppingCartGuid     = shoppingCartGuid ?? Guid.NewGuid();
                    trackEvent.EventName = SendinBlueDefaults.CartDeletedEventName;
                    trackEvent.EventData = new { id = $"cart:{shoppingCartGuid}" };
                }

                //track event
                client.TrackEvent(trackEvent);

                //update GUID for the current customer's shopping cart
                _genericAttributeService.SaveAttribute(cartItem.Customer, SendinBlueDefaults.ShoppingCartGuidAttribute, shoppingCartGuid);
            }
            catch (Exception exception)
            {
                //log full error
                _logger.Error($"SendinBlue Marketing Automation error: {exception.Message}.", exception, cartItem.Customer);
            }
        }
        /// <summary>
        /// Register a new transaction with Sagepay before the iframe shows. In fact, this method should give us the URL for the iframe
        /// </summary>
        /// <returns></returns>
        public RegisterTransactionResult RegisterTransaction()
        {
            var result = new RegisterTransactionResult();

            if (_request.IsLocal)
            {
                result.Message =
                    "This plugin does not work in local hosts. You need to publish NopCommerce on a publicly accessible internet address.";
                return(result);
            }

            var webClient = new WebClient();

            var orderGuid = Guid.NewGuid();

            var data = new QueryStringNameValueCollection
            {
                { "VPSProtocol", SagePayHelper.GetProtocol() },
                { "TxType", TransactTypeValues.Deferred.ToString() },             //we always use Deferred because we only take the payment after user has confirmed
                { "Vendor", _sagePayServerPaymentSettings.VendorName.ToLower() },
                { "VendorTxCode", orderGuid.ToString() }
            };

            if (!String.IsNullOrWhiteSpace(_sagePayServerPaymentSettings.PartnerId))
            {
                data.Add("ReferrerID", _sagePayServerPaymentSettings.PartnerId);
            }

            var cart = _workContext.CurrentCustomer.ShoppingCartItems.ToList();

            cart = cart.Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList();

            var orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart).GetValueOrDefault();

            data.Add("Amount", orderTotal.ToString("F2", CultureInfo.InvariantCulture));

            data.Add("Currency", _workContext.WorkingCurrency != null
                         ? _workContext.WorkingCurrency.CurrencyCode
                         : _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode);

            data.Add("Description", "eCommerce Order from " + _sagePayServerPaymentSettings.VendorName);

            // The Notification URL is the page to which Server calls back when a transaction completes
            data.Add("NotificationURL", _webHelper.GetStoreLocation() + "Plugins/PaymentSagePayServer/NotificationPage");

            // Billing Details
            data.Add("BillingSurname", _workContext.CurrentCustomer.BillingAddress.LastName);
            data.Add("BillingFirstnames", _workContext.CurrentCustomer.BillingAddress.FirstName);
            data.Add("BillingAddress1", _workContext.CurrentCustomer.BillingAddress.Address1);

            if (!String.IsNullOrWhiteSpace(_workContext.CurrentCustomer.BillingAddress.Address2))
            {
                data.Add("BillingAddress2", _workContext.CurrentCustomer.BillingAddress.Address2);
            }

            data.Add("BillingCity", _workContext.CurrentCustomer.BillingAddress.City);
            data.Add("BillingPostCode", _workContext.CurrentCustomer.BillingAddress.ZipPostalCode);
            data.Add("BillingCountry", _workContext.CurrentCustomer.BillingAddress.Country.TwoLetterIsoCode); //TODO: Verify if it is ISO 3166-1 country code

            if (_workContext.CurrentCustomer.BillingAddress.StateProvince != null && _workContext.CurrentCustomer.BillingAddress.Country.TwoLetterIsoCode.ToLower() == "us")
            {
                var state = _workContext.CurrentCustomer.BillingAddress.StateProvince.Abbreviation;
                data.Add("BillingState", (state.Length > 2) ? state.Substring(0, 2) : state);
            }

            if (!String.IsNullOrWhiteSpace(_workContext.CurrentCustomer.BillingAddress.PhoneNumber))
            {
                data.Add("BillingPhone", _workContext.CurrentCustomer.BillingAddress.PhoneNumber);
            }



            // Delivery Details
            if (_workContext.CurrentCustomer.ShippingAddress != null)
            {
                data.Add("DeliverySurname", _workContext.CurrentCustomer.ShippingAddress.LastName);
                data.Add("DeliveryFirstnames", _workContext.CurrentCustomer.ShippingAddress.FirstName);
                data.Add("DeliveryAddress1", _workContext.CurrentCustomer.ShippingAddress.Address1);

                if (!String.IsNullOrWhiteSpace(_workContext.CurrentCustomer.ShippingAddress.Address2))
                {
                    data.Add("DeliveryAddress2", _workContext.CurrentCustomer.ShippingAddress.Address2);
                }

                data.Add("DeliveryCity", _workContext.CurrentCustomer.ShippingAddress.City);
                data.Add("DeliveryPostCode", _workContext.CurrentCustomer.ShippingAddress.ZipPostalCode);

                if (_workContext.CurrentCustomer.ShippingAddress.Country != null)
                {
                    data.Add("DeliveryCountry", _workContext.CurrentCustomer.ShippingAddress.Country.TwoLetterIsoCode);

                    if (_workContext.CurrentCustomer.ShippingAddress.StateProvince != null && _workContext.CurrentCustomer.ShippingAddress.Country.TwoLetterIsoCode.ToLower() == "us")
                    {
                        var state = _workContext.CurrentCustomer.ShippingAddress.StateProvince.Abbreviation;
                        data.Add("DeliveryState", (state.Length > 2) ? state.Substring(0, 2) : state);
                    }
                }

                if (!String.IsNullOrWhiteSpace(_workContext.CurrentCustomer.ShippingAddress.PhoneNumber))
                {
                    data.Add("DeliveryPhone", _workContext.CurrentCustomer.ShippingAddress.PhoneNumber);
                }
            }
            else
            {
                data.Add("DeliverySurname", "");
                data.Add("DeliveryFirstnames", "");
                data.Add("DeliveryAddress1", "");
                data.Add("DeliveryAddress2", "");
                data.Add("DeliveryCity", "");
                data.Add("DeliveryPostCode", "");
                data.Add("DeliveryCountry", "");
                data.Add("DeliveryState", "");
                data.Add("DeliveryPhone", "");
            }

            data.Add("CustomerEMail", _workContext.CurrentCustomer.Email);

            //var strBasket = String.Empty;
            //strBasket = cart.Count + ":";

            //for (int i = 0; i < cart.Count; i++)
            //{
            //    ShoppingCartItem item = cart[i];
            //    strBasket += item.ProductVariant.FullProductName) + ":" +
            //                    item.Quantity + ":" + item.ProductVariant.Price + ":" +
            //                    item.ProductVariant.TaxCategoryId;
            //};

            //data.Add("Basket", strBasket);

            data.Add("AllowGiftAid", "0");

            // Allow fine control over AVS/CV2 checks and rules by changing this value. 0 is Default
            //data.Add("ApplyAVSCV2", "0");

            // Allow fine control over 3D-Secure checks and rules by changing this value. 0 is Default
            //data.Add("Apply3DSecure", "0");

            if (_sagePayServerPaymentSettings.Profile == ProfileValues.Low)
            {
                data.Add("Profile", "LOW"); //simpler payment page version.
            }

            var sageSystemUrl = SagePayHelper.GetSageSystemUrl(_sagePayServerPaymentSettings.ConnectTo, "purchase");

            string strResponse;

            try
            {
                var responseData = webClient.UploadValues(sageSystemUrl, data);

                strResponse = Encoding.ASCII.GetString(responseData);
            }
            catch (WebException ex)
            {
                result.Message = String.Format(@"Your server was unable to register this transaction with Sage Pay.
                    Check that you do not have a firewall restricting the POST and 
                    that your server can correctly resolve the address {0}. <br/>
                    The Status Number is: {1}<br/>
                    The Description given is: {2}", sageSystemUrl, ex.Status, ex.Message);

                return(result);
            }

            if (!string.IsNullOrWhiteSpace(strResponse))
            {
                var strStatus       = SagePayHelper.FindField("Status", strResponse);
                var strStatusDetail = SagePayHelper.FindField("StatusDetail", strResponse);

                switch (strStatus)
                {
                case "OK":

                    var strVpsTxId     = SagePayHelper.FindField("VPSTxId", strResponse);
                    var strSecurityKey = SagePayHelper.FindField("SecurityKey", strResponse);
                    var strNextUrl     = SagePayHelper.FindField("NextURL", strResponse);

                    var transx = new SagePayServerTransaction
                    {
                        CreatedOnUtc         = DateTime.UtcNow,
                        VpsTxId              = strVpsTxId,
                        SecurityKey          = strSecurityKey,
                        NotificationResponse = strResponse.Replace(Environment.NewLine, ";"),
                        VendorTxCode         = orderGuid.ToString(),
                    };

                    //Store this record in DB
                    _sagePayServerTransactionService.InsertSagePayServerTransaction(transx);

                    result.Success    = true;
                    result.PaymentUrl = strNextUrl;

                    return(result);

                case "MALFORMED":

                    result.Message = string.Format("Error {0}, {1} - {2}", strStatus, strStatusDetail, data.Encode());

                    break;

                case "INVALID":

                    result.Message = string.Format("Error {0}, {1} - {2}", strStatus, strStatusDetail, data.Encode());

                    break;

                default:

                    result.Message = string.Format("Error {0}, {1}", strStatus, strStatusDetail);

                    break;
                }
            }

            return(result);
        }
Exemple #30
0
        public PayPalResponse CreatePayment(
            PayPalApiSettingsBase settings,
            PayPalSessionData session,
            List <OrganizedShoppingCartItem> cart,
            string providerSystemName,
            string returnUrl,
            string cancelUrl)
        {
            var store        = _services.StoreContext.CurrentStore;
            var customer     = _services.WorkContext.CurrentCustomer;
            var language     = _services.WorkContext.WorkingLanguage;
            var currencyCode = store.PrimaryStoreCurrency.CurrencyCode;

            var dateOfBirth = customer.GetAttribute <DateTime?>(SystemCustomerAttributeNames.DateOfBirth);

            Discount orderAppliedDiscount;
            List <AppliedGiftCard> appliedGiftCards;
            int     redeemedRewardPoints = 0;
            decimal redeemedRewardPointsAmount;
            decimal orderDiscountInclTax;
            decimal totalOrderItems = decimal.Zero;

            var includingTax = (_services.WorkContext.GetTaxDisplayTypeFor(customer, store.Id) == TaxDisplayType.IncludingTax);

            var shipping = (_orderTotalCalculationService.GetShoppingCartShippingTotal(cart) ?? decimal.Zero);

            var paymentFee = _paymentService.GetAdditionalHandlingFee(cart, providerSystemName);

            var total = (_orderTotalCalculationService.GetShoppingCartTotal(cart, out orderDiscountInclTax, out orderAppliedDiscount, out appliedGiftCards,
                                                                            out redeemedRewardPoints, out redeemedRewardPointsAmount) ?? decimal.Zero);

            var data          = new Dictionary <string, object>();
            var redirectUrls  = new Dictionary <string, object>();
            var payer         = new Dictionary <string, object>();
            var payerInfo     = new Dictionary <string, object>();
            var transaction   = new Dictionary <string, object>();
            var amount        = new Dictionary <string, object>();
            var amountDetails = new Dictionary <string, object>();
            var items         = new List <Dictionary <string, object> >();
            var itemList      = new Dictionary <string, object>();

            // "PayPal PLUS only supports transaction type “Sale” (instant settlement)"
            if (providerSystemName == PayPalPlusProvider.SystemName)
            {
                data.Add("intent", "sale");
            }
            else
            {
                data.Add("intent", settings.TransactMode == TransactMode.AuthorizeAndCapture ? "sale" : "authorize");
            }

            if (settings.ExperienceProfileId.HasValue())
            {
                data.Add("experience_profile_id", settings.ExperienceProfileId);
            }

            // redirect urls
            if (returnUrl.HasValue())
            {
                redirectUrls.Add("return_url", returnUrl);
            }

            if (cancelUrl.HasValue())
            {
                redirectUrls.Add("cancel_url", cancelUrl);
            }

            if (redirectUrls.Any())
            {
                data.Add("redirect_urls", redirectUrls);
            }

            // payer, payer_info
            if (dateOfBirth.HasValue)
            {
                payerInfo.Add("birth_date", dateOfBirth.Value.ToString("yyyy-MM-dd"));
            }
            if (customer.BillingAddress != null)
            {
                payerInfo.Add("billing_address", CreateAddress(customer.BillingAddress, false));
            }

            payer.Add("payment_method", "paypal");
            payer.Add("payer_info", payerInfo);
            data.Add("payer", payer);

            // line items
            foreach (var item in cart)
            {
                decimal unitPriceTaxRate = decimal.Zero;
                decimal unitPrice        = _priceCalculationService.GetUnitPrice(item, true);
                decimal productPrice     = _taxService.GetProductPrice(item.Item.Product, unitPrice, includingTax, customer, out unitPriceTaxRate);

                var line = new Dictionary <string, object>();
                line.Add("quantity", item.Item.Quantity);
                line.Add("name", item.Item.Product.GetLocalized(x => x.Name, language.Id, true, false).Truncate(127));
                line.Add("price", productPrice.FormatInvariant());
                line.Add("currency", currencyCode);
                line.Add("sku", item.Item.Product.Sku.Truncate(50));
                items.Add(line);

                totalOrderItems += (productPrice * item.Item.Quantity);
            }

            var itemsPlusMisc = (totalOrderItems + shipping + paymentFee);

            if (total != itemsPlusMisc)
            {
                var line = new Dictionary <string, object>();
                line.Add("quantity", "1");
                line.Add("name", T("Plugins.SmartStore.PayPal.Other").Text.Truncate(127));
                line.Add("price", (total - itemsPlusMisc).FormatInvariant());
                line.Add("currency", currencyCode);
                items.Add(line);

                totalOrderItems += (total - itemsPlusMisc);
            }

            itemList.Add("items", items);
            if (customer.ShippingAddress != null)
            {
                itemList.Add("shipping_address", CreateAddress(customer.ShippingAddress, true));
            }

            // transactions
            amountDetails.Add("shipping", shipping.FormatInvariant());
            amountDetails.Add("subtotal", totalOrderItems.FormatInvariant());
            if (!includingTax)
            {
                // "To avoid rounding errors we recommend not submitting tax amounts on line item basis.
                // Calculated tax amounts for the entire shopping basket may be submitted in the amount objects.
                // In this case the item amounts will be treated as amounts excluding tax.
                // In a B2C scenario, where taxes are included, no taxes should be submitted to PayPal."

                SortedDictionary <decimal, decimal> taxRates = null;
                var taxTotal = _orderTotalCalculationService.GetTaxTotal(cart, out taxRates);

                amountDetails.Add("tax", taxTotal.FormatInvariant());
            }
            if (paymentFee != decimal.Zero)
            {
                amountDetails.Add("handling_fee", paymentFee.FormatInvariant());
            }

            amount.Add("total", total.FormatInvariant());
            amount.Add("currency", currencyCode);
            amount.Add("details", amountDetails);

            transaction.Add("amount", amount);
            transaction.Add("item_list", itemList);
            transaction.Add("invoice_number", session.OrderGuid.ToString());

            data.Add("transactions", new List <Dictionary <string, object> > {
                transaction
            });

            var result = CallApi("POST", "/v1/payments/payment", session.AccessToken, settings, JsonConvert.SerializeObject(data));

            if (result.Success && result.Json != null)
            {
                result.Id = (string)result.Json.id;
            }

            //Logger.InsertLog(LogLevel.Information, "PayPal PLUS", JsonConvert.SerializeObject(data, Formatting.Indented) + "\r\n\r\n" + (result.Json != null ? result.Json.ToString() : ""));

            return(result);
        }
Exemple #31
0
        /// <summary>
        /// Creates the payment info model
        /// </summary>
        /// <returns>The <see cref="Task"/> containing the payment info model</returns>
        public virtual async Task <PaymentInfoModel> CreatePaymentInfoAsync()
        {
            if (string.IsNullOrWhiteSpace(_cryptoPaymentSettings.SecretKey))
            {
                return(null);
            }

            var customer = _workContext.CurrentCustomer;

            if (customer == null)
            {
                return(null);
            }

            var request = new CreatePaymentRequest();

            // set currency
            if (_workContext.WorkingCurrency == null)
            {
                return(null);
            }

            var currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId);

            if (currency == null)
            {
                return(null);
            }

            request.Currency = currency.CurrencyCode;

            // set payment amount
            var cart = _shoppingCartService.GetShoppingCart(customer, ShoppingCartType.ShoppingCart, _storeContext.CurrentStore.Id);

            if (cart?.Any() == true)
            {
                var subTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart);

                request.Amount = subTotal.HasValue
                    ? (int)(subTotal.Value * 100)
                    : 0;
            }

            // set order id
            var httpContext = _httpContextAccessor.HttpContext;

            var processPaymentRequest = new ProcessPaymentRequest();

            _paymentService.GenerateOrderGuid(processPaymentRequest);
            request.OrderId = processPaymentRequest.OrderGuid.ToString();

            try
            {
                var paymentResponse = await _paymentApi.CreatePaymentAsync(request);

                if (paymentResponse != null)
                {
                    var paymentId = paymentResponse.Id.ToString();

                    processPaymentRequest.CustomValues.Add(_localizationService.GetResource("Plugins.Payments.Crypto.PaymentId"), paymentId);
                    httpContext.Session.Set(Defaults.PaymentRequestSessionKey, processPaymentRequest);

                    return(new PaymentInfoModel
                    {
                        PaymentId = paymentId
                    });
                }
            }
            catch (ApiException exception)
            {
                _logger.Error($"{Defaults.SystemName}: {exception.Message}", exception, customer);
            }

            return(null);
        }