Ejemplo n.º 1
0
        public ActionResult PaymentInfo()
        {
            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 = _workContext.CurrentCustomer.GetAttribute <string>(SquarePaymentDefaults.CustomerIdAttribute);
            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 value 0
            if (model.StoredCards.Any())
            {
                var selectCardText = _localizationService.GetResource("Plugins.Payments.Square.Fields.StoredCard.SelectCard");
                model.StoredCards.Insert(0, new SelectListItem {
                    Text = selectCardText, Value = "0"
                });
            }

            return(View("~/Plugins/Payments.Square/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));
        }
        /// <summary>
        /// Create request parameters to charge transaction
        /// </summary>
        /// <param name="paymentRequest">Payment request parameters</param>
        /// <param name="isRecurringPayment">Whether it is a recurring payment</param>
        /// <returns>Charge request parameters</returns>
        private ExtendedChargeRequest CreateChargeRequest(ProcessPaymentRequest paymentRequest, bool isRecurringPayment)
        {
            //get customer
            var customer = _customerService.GetCustomerById(paymentRequest.CustomerId);

            if (customer == null)
            {
                throw new NopException("Customer cannot be loaded");
            }

            //get the primary store currency
            var currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId);

            if (currency == null)
            {
                throw new NopException("Primary store currency cannot be loaded");
            }

            //whether the currency is supported by the Square
            if (!CheckSupportCurrency(currency))
            {
                throw new NopException($"The {currency.CurrencyCode} currency is not supported by the Square");
            }

            //check customer's billing address, shipping address and email,
            SquareModel.Address createAddress(Address address) => address == null ? null : new SquareModel.Address
            (
                AddressLine1: address.Address1,
                AddressLine2: address.Address2,
                AdministrativeDistrictLevel1: address.StateProvince?.Abbreviation,
                AdministrativeDistrictLevel2: address.County,
                Country: string.Equals(address.Country?.TwoLetterIsoCode, new RegionInfo(address.Country?.TwoLetterIsoCode).TwoLetterISORegionName, StringComparison.InvariantCultureIgnoreCase)
                    ? address.Country?.TwoLetterIsoCode : null,
                FirstName: address.FirstName,
                LastName: address.LastName,
                Locality: address.City,
                PostalCode: address.ZipPostalCode
            );

            var billingAddress  = createAddress(customer.BillingAddress);
            var shippingAddress = billingAddress == null?createAddress(customer.ShippingAddress) : null;

            var email = customer.BillingAddress != null ? customer.BillingAddress.Email : customer.ShippingAddress?.Email;

            //the transaction is ineligible for chargeback protection if they are not provided
            if ((billingAddress == null && shippingAddress == null) || string.IsNullOrEmpty(email))
            {
                _logger.Warning("Square payment warning: Address or email is not provided, so the transaction is ineligible for chargeback protection", customer: customer);
            }

            //the amount of money, in the smallest denomination of the currency indicated by currency. For example, when currency is USD, amount is in cents;
            //most currencies consist of 100 units of smaller denomination, so we multiply the total by 100
            var orderTotal  = (int)(paymentRequest.OrderTotal * 100);
            var amountMoney = new SquareModel.Money(Amount: orderTotal, Currency: currency.CurrencyCode);

            //create common charge request parameters
            var chargeRequest = new ExtendedChargeRequest
                                (
                amountMoney: amountMoney,
                billingAddress: billingAddress,
                buyerEmailAddress: email,
                delayCapture: _squarePaymentSettings.TransactionMode == TransactionMode.Authorize,
                idempotencyKey: Guid.NewGuid().ToString(),
                integrationId: !string.IsNullOrEmpty(SquarePaymentDefaults.IntegrationId) ? SquarePaymentDefaults.IntegrationId : null,
                note: string.Format(SquarePaymentDefaults.PaymentNote, paymentRequest.OrderGuid),
                referenceId: paymentRequest.OrderGuid.ToString(),
                shippingAddress: shippingAddress
                                );

            //try to get previously stored card details
            var storedCardKey = _localizationService.GetResource("Plugins.Payments.Square.Fields.StoredCard.Key");

            if (paymentRequest.CustomValues.TryGetValue(storedCardKey, out var storedCardId) && !storedCardId.ToString().Equals(Guid.Empty.ToString()))
            {
                //check whether customer exists
                var customerId     = _genericAttributeService.GetAttribute <string>(customer, SquarePaymentDefaults.CustomerIdAttribute);
                var squareCustomer = _squarePaymentManager.GetCustomer(customerId);
                if (squareCustomer == null)
                {
                    throw new NopException("Failed to retrieve customer");
                }

                //set 'card on file' to charge
                chargeRequest.CustomerId     = squareCustomer.Id;
                chargeRequest.CustomerCardId = storedCardId.ToString();
                return(chargeRequest);
            }

            //or try to get the card nonce
            var cardNonceKey = _localizationService.GetResource("Plugins.Payments.Square.Fields.CardNonce.Key");

            if (!paymentRequest.CustomValues.TryGetValue(cardNonceKey, out var cardNonce) || string.IsNullOrEmpty(cardNonce?.ToString()))
            {
                throw new NopException("Failed to get the card nonce");
            }

            //remove the card nonce from payment custom values, since it is no longer needed
            paymentRequest.CustomValues.Remove(cardNonceKey);

            //whether to save card details for the future purchasing
            var saveCardKey = _localizationService.GetResource("Plugins.Payments.Square.Fields.SaveCard.Key");

            if (paymentRequest.CustomValues.TryGetValue(saveCardKey, out var saveCardValue) && saveCardValue is bool saveCard && saveCard && !customer.IsGuest())
            {
                //remove the value from payment custom values, since it is no longer needed
                paymentRequest.CustomValues.Remove(saveCardKey);

                try
                {
                    //check whether customer exists
                    var customerId     = _genericAttributeService.GetAttribute <string>(customer, SquarePaymentDefaults.CustomerIdAttribute);
                    var squareCustomer = _squarePaymentManager.GetCustomer(customerId);

                    if (squareCustomer == null)
                    {
                        //try to create the new one, if not exists
                        var customerRequest = new SquareModel.CreateCustomerRequest
                                              (
                            EmailAddress: customer.Email,
                            Nickname: customer.Username,
                            GivenName: _genericAttributeService.GetAttribute <string>(customer, NopCustomerDefaults.FirstNameAttribute),
                            FamilyName: _genericAttributeService.GetAttribute <string>(customer, NopCustomerDefaults.LastNameAttribute),
                            PhoneNumber: _genericAttributeService.GetAttribute <string>(customer, NopCustomerDefaults.PhoneAttribute),
                            CompanyName: _genericAttributeService.GetAttribute <string>(customer, NopCustomerDefaults.CompanyAttribute),
                            ReferenceId: customer.CustomerGuid.ToString()
                                              );
                        squareCustomer = _squarePaymentManager.CreateCustomer(customerRequest);
                        if (squareCustomer == null)
                        {
                            throw new NopException("Failed to create customer. Error details in the log");
                        }

                        //save customer identifier as generic attribute
                        _genericAttributeService.SaveAttribute(customer, SquarePaymentDefaults.CustomerIdAttribute, squareCustomer.Id);
                    }

                    //create request parameters to create the new card
                    var cardRequest = new SquareModel.CreateCustomerCardRequest
                                      (
                        BillingAddress: chargeRequest.BillingAddress ?? chargeRequest.ShippingAddress,
                        CardNonce: cardNonce.ToString()
                                      );

                    //set postal code
                    var postalCodeKey = _localizationService.GetResource("Plugins.Payments.Square.Fields.PostalCode.Key");
                    if (paymentRequest.CustomValues.TryGetValue(postalCodeKey, out var postalCode) && !string.IsNullOrEmpty(postalCode.ToString()))
                    {
                        //remove the value from payment custom values, since it is no longer needed
                        paymentRequest.CustomValues.Remove(postalCodeKey);

                        cardRequest.BillingAddress            = cardRequest.BillingAddress ?? new SquareModel.Address();
                        cardRequest.BillingAddress.PostalCode = postalCode.ToString();
                    }

                    //try to create card
                    var card = _squarePaymentManager.CreateCustomerCard(squareCustomer.Id, cardRequest);
                    if (card == null)
                    {
                        throw new NopException("Failed to create card. Error details in the log");
                    }

                    //save card identifier to payment custom values for further purchasing
                    if (isRecurringPayment)
                    {
                        paymentRequest.CustomValues.Add(storedCardKey, card.Id);
                    }

                    //set 'card on file' to charge
                    chargeRequest.CustomerId     = squareCustomer.Id;
                    chargeRequest.CustomerCardId = card.Id;
                    return(chargeRequest);
                }
                catch (Exception exception)
                {
                    _logger.Warning(exception.Message, exception, customer);
                    if (isRecurringPayment)
                    {
                        throw new NopException("For recurring payments you need to save the card details");
                    }
                }
            }