/// <summary>
 /// Stores a <see cref="PayPalExpressTransactionRecord"/> into the <see cref="IPayment"/>'s <see cref="ExtendedDataCollection"/>.
 /// </summary>
 /// <param name="payment">
 /// The payment.
 /// </param>
 /// <param name="record">
 /// The record.
 /// </param>
 public static void SavePayPalTransactionRecord(this IPayment payment, PayPalExpressTransactionRecord record)
 {
     payment.ExtendedData.SetValue(Constants.PayPal.ExtendedDataKeys.PayPalExpressTransaction, record);
 }
        /// <summary>
        /// Performs the GetExpressCheckoutDetails operation.
        /// </summary>
        /// <param name="payment">
        /// The payment.
        /// </param>
        /// <param name="token">
        /// The token.
        /// </param>
        /// <param name="record">
        /// The record.
        /// </param>
        /// <returns>
        /// The <see cref="PayPalExpressTransactionRecord"/>.
        /// </returns>
        internal PayPalExpressTransactionRecord GetExpressCheckoutDetails(IPayment payment, string token, PayPalExpressTransactionRecord record)
        {
            record.Success = true;
            ExpressCheckoutResponse result = null;
            try
            {
                var getDetailsRequest = new GetExpressCheckoutDetailsReq
                {
                    GetExpressCheckoutDetailsRequest = new GetExpressCheckoutDetailsRequestType(token)
                };

                var service = GetPayPalService();
                var response = service.GetExpressCheckoutDetails(getDetailsRequest);
                result = _responseFactory.Build(response, token);

                if (result.Success())
                {
                    record.Data.PayerId = response.GetExpressCheckoutDetailsResponseDetails.PayerInfo.PayerID;
                }
            }
            catch (Exception ex)
            {
                result = _responseFactory.Build(ex);
            }

            record.GetExpressCheckoutDetails = result;
            record.Success = result.Success();
            return record;
        }
        /// <summary>
        /// Performs the setup for an express checkout.
        /// </summary>
        /// <param name="invoice">
        /// The <see cref="IInvoice"/>.
        /// </param>
        /// <param name="payment">
        /// The <see cref="IPayment"/>
        /// </param>
        /// <param name="returnUrl">
        /// The return URL.
        /// </param>
        /// <param name="cancelUrl">
        /// The cancel URL.
        /// </param>
        /// <returns>
        /// The <see cref="ExpressCheckoutResponse"/>.
        /// </returns>
        protected virtual PayPalExpressTransactionRecord SetExpressCheckout(IInvoice invoice, IPayment payment, string returnUrl, string cancelUrl)
        {
            var record = new PayPalExpressTransactionRecord
                             {
                                 Success = true,
                                 Data = { Authorized = false, CurrencyCode = invoice.CurrencyCode }
                             };

            var factory = new PayPalPaymentDetailsTypeFactory(new PayPalFactorySettings { WebsiteUrl = _websiteUrl });
            var paymentDetailsType = factory.Build(invoice, PaymentActionCodeType.ORDER);

            // The API requires this be in a list
            var paymentDetailsList = new List<PaymentDetailsType>() { paymentDetailsType };

            // ExpressCheckout details
            //// We do not want the customer to be able to reset their shipping address at PayPal
            //// due to the fact that it could affect shipping charges and in some cases tax rates.
            //// This is the AddressOverride = "0" - NOT WORKING!
            var ecDetails = new SetExpressCheckoutRequestDetailsType()
                    {
                        ReturnURL = returnUrl,
                        CancelURL = cancelUrl,
                        PaymentDetails = paymentDetailsList,
                        AddressOverride = "0"
                    };

            // Trigger the event to allow for overriding ecDetails
            var ecdOverride = new PayPalExpressCheckoutRequestDetailsOverride(invoice, payment, ecDetails);
            SettingCheckoutRequestDetails.RaiseEvent(new ObjectEventArgs<PayPalExpressCheckoutRequestDetailsOverride>(ecdOverride), this);

            // The ExpressCheckoutRequest
            var request = new SetExpressCheckoutRequestType
                    {
                        Version = Version,
                        SetExpressCheckoutRequestDetails = ecdOverride.ExpressCheckoutDetails
                    };

            // Crete the wrapper for Express Checkout
            var wrapper = new SetExpressCheckoutReq
                              {
                                  SetExpressCheckoutRequest = request
                              };

            try
            {
                var service = GetPayPalService();
                var response = service.SetExpressCheckout(wrapper);
                record.SetExpressCheckout = _responseFactory.Build(response, response.Token);
                record.Data.Token = response.Token;
                record.SetExpressCheckout.RedirectUrl = GetRedirectUrl(response.Token);
            }
            catch (Exception ex)
            {
                record.Success = false;
                record.SetExpressCheckout = _responseFactory.Build(ex);
            }

            return record;
        }
        /// <summary>
        /// The do express checkout payment.
        /// </summary>
        /// <param name="invoice">
        /// The invoice.
        /// </param>
        /// <param name="payment">
        /// The payment.
        /// </param>
        /// <param name="token">
        /// The token.
        /// </param>
        /// <param name="payerId">
        /// The payer id.
        /// </param>
        /// <param name="record">
        /// The record of the transaction.
        /// </param>
        /// <returns>
        /// The <see cref="PayPalExpressTransactionRecord"/>.
        /// </returns>
        internal PayPalExpressTransactionRecord DoExpressCheckoutPayment(IInvoice invoice, IPayment payment, string token, string payerId, PayPalExpressTransactionRecord record)
        {
            var factory = new PayPalPaymentDetailsTypeFactory();

            ExpressCheckoutResponse result = null;
            try
            {
                // do express checkout
                var request = new DoExpressCheckoutPaymentRequestType(
                        new DoExpressCheckoutPaymentRequestDetailsType
                        {
                            Token = token,
                            PayerID = payerId,
                            PaymentDetails =
                                    new List<PaymentDetailsType>
                                        {
                                            factory.Build(invoice, PaymentActionCodeType.ORDER)
                                        }
                        });

                var doExpressCheckoutPayment = new DoExpressCheckoutPaymentReq
                {
                    DoExpressCheckoutPaymentRequest = request
                };

                var service = GetPayPalService();
                var response = service.DoExpressCheckoutPayment(doExpressCheckoutPayment);
                result = _responseFactory.Build(response, token);

                var transactionId = response.DoExpressCheckoutPaymentResponseDetails.PaymentInfo[0].TransactionID;
                var currency = response.DoExpressCheckoutPaymentResponseDetails.PaymentInfo[0].GrossAmount.currencyID;
                var amount = response.DoExpressCheckoutPaymentResponseDetails.PaymentInfo[0].GrossAmount.value;

                record.Data.CheckoutPaymentTransactionId = transactionId;
                record.Data.CurrencyId = currency.ToString();
                record.Data.AuthorizedAmount = amount;

            }
            catch (Exception ex)
            {
                result = _responseFactory.Build(ex);
            }

            record.DoExpressCheckoutPayment = result;
            record.Success = result.Success();

            return record;
        }
        /// <summary>
        /// Validates a successful response.
        /// </summary>
        /// <param name="invoice">
        /// The invoice.
        /// </param>
        /// <param name="payment">
        /// The payment.
        /// </param>
        /// <param name="token">
        /// The token.
        /// </param>
        /// <param name="payerId">
        /// The payer id.
        /// </param>
        /// <param name="record">
        /// The record.
        /// </param>
        /// <returns>
        /// The <see cref="ExpressCheckoutResponse"/>.
        /// </returns>
        /// <remarks>
        /// PayPal returns to the success URL even if the payment was declined. e.g.  The success URL represents a successful transaction
        /// not a successful payment so we need to do another request to verify the payment was completed and get additional information
        /// such as the transaction id so we can do refunds etc.
        /// </remarks>
        internal PayPalExpressTransactionRecord Authorize(IInvoice invoice, IPayment payment, string token, string payerId, PayPalExpressTransactionRecord record)
        {
            // Now we have to get the transaction details for the successful payment
            ExpressCheckoutResponse result = null;
            try
            {
                // do authorization
                var service = GetPayPalService();
                var doAuthorizationResponse = service.DoAuthorization(new DoAuthorizationReq
                {
                    DoAuthorizationRequest = new DoAuthorizationRequestType
                    {
                        TransactionID = record.Data.CheckoutPaymentTransactionId,
                        Amount = new BasicAmountType(PayPalApiHelper.GetPayPalCurrencyCode(record.Data.CurrencyId), record.Data.AuthorizedAmount)
                    }
                });

                result = _responseFactory.Build(doAuthorizationResponse, token);
                if (result.Success())
                {
                    record.Data.Authorized = true;
                    record.Data.AuthorizationTransactionId = doAuthorizationResponse.TransactionID;
                }
            }
            catch (Exception ex)
            {
                result = _responseFactory.Build(ex);
            }

            record.DoAuthorization = result;

            return record;
        }
 /// <summary>
 /// Processes the payment.
 /// </summary>
 /// <param name="payment">
 /// The payment.
 /// </param>
 /// <param name="record">
 /// The record.
 /// </param>
 /// <returns>
 /// The <see cref="PayPalExpressTransactionRecord"/>.
 /// </returns>
 private PayPalExpressTransactionRecord Process(IPayment payment, PayPalExpressTransactionRecord record)
 {
     payment.SavePayPalTransactionRecord(record);
     return record;
 }
 /// <summary>
 /// Stores a <see cref="PayPalExpressTransactionRecord"/> into the <see cref="IPayment"/>'s <see cref="ExtendedDataCollection"/>.
 /// </summary>
 /// <param name="payment">
 /// The payment.
 /// </param>
 /// <param name="record">
 /// The record.
 /// </param>
 public static void SavePayPalTransactionRecord(this IPayment payment, PayPalExpressTransactionRecord record)
 {
     payment.ExtendedData.SetValue(Constants.PayPal.ExtendedDataKeys.PayPalExpressTransaction, record);
 }
        /// <summary>
        /// Performs the setup for an express checkout.
        /// </summary>
        /// <param name="invoice">
        /// The <see cref="IInvoice"/>.
        /// </param>
        /// <param name="payment">
        /// The <see cref="IPayment"/>
        /// </param>
        /// <param name="returnUrl">
        /// The return URL.
        /// </param>
        /// <param name="cancelUrl">
        /// The cancel URL.
        /// </param>
        /// <returns>
        /// The <see cref="ExpressCheckoutResponse"/>.
        /// </returns>
        protected virtual PayPalExpressTransactionRecord SetExpressCheckout(IInvoice invoice, IPayment payment, string returnUrl, string cancelUrl)
        {
            var record = new PayPalExpressTransactionRecord
                             {
                                 Success = true,
                                 Data = { Authorized = false, CurrencyCode = invoice.CurrencyCode }
                             };

            var factory = new PayPalPaymentDetailsTypeFactory(new PayPalFactorySettings { WebsiteUrl = _websiteUrl });
            var paymentDetailsType = factory.Build(invoice, PaymentActionCodeType.ORDER);

            // The API requires this be in a list
            var paymentDetailsList = new List<PaymentDetailsType>() { paymentDetailsType };

            // ExpressCheckout details
            var ecDetails = new SetExpressCheckoutRequestDetailsType()
                    {
                        ReturnURL = returnUrl,
                        CancelURL = cancelUrl,
                        PaymentDetails = paymentDetailsList,
                        AddressOverride = "0"
                    };

            // Trigger the event to allow for overriding ecDetails
            var ecdOverride = new PayPalExpressCheckoutRequestDetailsOverride(invoice, payment, ecDetails);
            SettingCheckoutRequestDetails.RaiseEvent(new ObjectEventArgs<PayPalExpressCheckoutRequestDetailsOverride>(ecdOverride), this);

            // The ExpressCheckoutRequest
            var request = new SetExpressCheckoutRequestType
                    {
                        Version = Version,
                        SetExpressCheckoutRequestDetails = ecdOverride.ExpressCheckoutDetails
                    };

            // Crete the wrapper for Express Checkout
            var wrapper = new SetExpressCheckoutReq
                              {
                                  SetExpressCheckoutRequest = request
                              };

            try
            {
                var service = GetPayPalService();
                var response = service.SetExpressCheckout(wrapper);

                record.SetExpressCheckout = _responseFactory.Build(response, response.Token);
                if (record.SetExpressCheckout.Success())
                {
                    record.Data.Token = response.Token;
                    record.SetExpressCheckout.RedirectUrl = GetRedirectUrl(response.Token);
                }
                else
                {
                    foreach (var et in record.SetExpressCheckout.ErrorTypes)
                    {
                        var code = et.ErrorCode;
                        var sm = et.ShortMessage;
                        var lm = et.LongMessage;
                        MultiLogHelper.Warn<PayPalExpressCheckoutService>(string.Format("{0} {1} {2}", code, lm, sm));
                    }

                    record.Success = false;
                }
            }
            catch (Exception ex)
            {
                record.Success = false;
                record.SetExpressCheckout = _responseFactory.Build(ex);
            }

            return record;
        }