Exemplo n.º 1
0
        /// <summary>
        /// Charge transaction
        /// </summary>
        /// <param name="chargeRequest">Request parameters to charge transaction</param>
        /// <returns>Transaction and/or errors if exist</returns>
        public PaymentResponse <Transaction> Charge(ExtendedChargeRequest chargeRequest)
        {
            try
            {
                //try to get the selected location
                var selectedLocation = GetActiveLocations().FirstOrDefault(location => location.Id.Equals(_squarePaymentSettings.LocationId));
                if (selectedLocation == null)
                {
                    throw new NopException("Location is a required parameter for payment requests");
                }

                //create transaction API
                var configuration   = CreateApiConfiguration();
                var transactionsApi = new TransactionsApi(configuration);

                //create charge transaction
                var chargeResponse = transactionsApi.Charge(selectedLocation.Id, chargeRequest);
                if (chargeResponse == null)
                {
                    throw new NopException("No service response");
                }

                //check whether there are errors in the service response
                if (chargeResponse.Errors?.Any() ?? false)
                {
                    var errorsMessage = string.Join(";", chargeResponse.Errors.Select(error => error.ToString()));
                    throw new NopException($"There are errors in the service response. {errorsMessage}");
                }

                return(new PaymentResponse <Transaction> {
                    ResponseValue = chargeResponse.Transaction
                });
            }
            catch (Exception exception)
            {
                //log full error
                var errorMessage = exception.Message;
                _logger.Error($"Square payment error: {errorMessage}.", exception, _workContext.CurrentCustomer);

                if (exception is ApiException apiException)
                {
                    //try to get error details
                    var response = JsonConvert.DeserializeObject <ChargeResponse>(apiException.ErrorContent) as ChargeResponse;
                    if (response?.Errors?.Any() ?? false)
                    {
                        errorMessage = string.Join(";", response.Errors.Select(error => error.Detail));
                    }
                }

                return(new PaymentResponse <Transaction> {
                    Error = errorMessage
                });
            }
        }
        /// <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");
                    }
                }
            }