/// <summary>
        /// Handles a cancellation payment response from the PayPal Express checkout.
        /// </summary>
        /// <param name="invoiceKey">
        /// The invoice key.
        /// </param>
        /// <param name="paymentKey">
        /// The payment key.
        /// </param>
        /// <param name="token">
        /// The token.
        /// </param>
        /// <param name="payerId">
        /// The payer id.
        /// </param>
        /// <returns>
        /// The <see cref="ActionResult"/>.
        /// </returns>
        public override ActionResult Cancel(Guid invoiceKey, Guid paymentKey, string token, string payerId = null)
        {
            var redirecting = new PaymentRedirectingUrl("Cancel")
            {
                RedirectingToUrl = _cancelUrl
            };

            try
            {
                var invoice = GetInvoice(invoiceKey);
                var payment = GetPayment(paymentKey);

                if (_deleteInvoiceOnCancel)
                {
                    InvoiceService.Delete(invoice);
                }
                else
                {
                    payment.VoidPayment(invoice, _paymentMethod.PaymentMethod.Key);
                }

                // raise the event so the redirect URL can be manipulated
                RedirectingForCancel.RaiseEvent(new ObjectEventArgs <PaymentRedirectingUrl>(redirecting), this);
                return(Redirect(redirecting.RedirectingToUrl));
            }
            catch (Exception ex)
            {
                var logData = GetExtendedLoggerData();

                var extra = new { InvoiceKey = invoiceKey, PaymentKey = paymentKey, Token = token, PayerId = payerId };

                logData.SetValue <object>("extra", extra);

                MultiLogHelper.Error <PayPalExpressController>(
                    "Failed to Cancel PayPal Express checkout response.",
                    ex,
                    logData);

                throw;
            }
        }
        /// <summary>
        /// Handles the a successful payment response from the PayPal Express checkout
        /// </summary>
        /// <param name="invoiceKey">
        /// The invoice key.
        /// </param>
        /// <param name="paymentKey">
        /// The payment key.
        /// </param>
        /// <param name="token">
        /// The token.
        /// </param>
        /// <param name="payerId">
        /// The payer id.
        /// </param>
        /// <returns>
        /// The <see cref="ActionResult"/>.
        /// </returns>
        public override ActionResult Success(Guid invoiceKey, Guid paymentKey, string token, string payerId)
        {
            var redirecting = new PaymentRedirectingUrl("Success")
            {
                RedirectingToUrl = _successUrl
            };

            var logData = GetExtendedLoggerData();

            try
            {
                var invoice = GetInvoice(invoiceKey);
                var payment = GetPayment(paymentKey);

                // We can now capture the payment
                // This will actually make a few more API calls back to PayPal to get required transaction
                // data so that we can refund the payment later through the back office if needed.
                var attempt = invoice.CapturePayment(payment, _paymentMethod, invoice.Total);

                // Raise the event to process the email
                Processed.RaiseEvent(new PaymentAttemptEventArgs <IPaymentResult>(attempt), this);

                // If this is an AJAX request return the JSON
                if (payment.ExtendedData.GetPayPalRequestIsAjaxRequest())
                {
                    var resp = new PaymentResultAsyncResponse
                    {
                        Success           = attempt.Payment.Success,
                        InvoiceKey        = attempt.Invoice.Key,
                        PaymentKey        = attempt.Payment.Result.Key,
                        PaymentMethodName = "PayPal Express Checkout"
                    };

                    if (attempt.Payment.Exception != null)
                    {
                        resp.Messages.Add(attempt.Payment.Exception.Message);
                    }

                    return(Json(resp));
                }

                if (attempt.Payment.Success)
                {
                    // we need to empty the basket here
                    Basket.Empty();

                    // raise the event so the redirect URL can be manipulated
                    RedirectingForSuccess.RaiseEvent(new ObjectEventArgs <PaymentRedirectingUrl>(redirecting), this);

                    return(Redirect(redirecting.RedirectingToUrl));
                }

                var retrying = new PaymentRedirectingUrl("Cancel")
                {
                    RedirectingToUrl = _cancelUrl
                };
                var qs = string.Format("?invoicekey={0}&paymentkey={1}", invoiceKey, paymentKey);
                if (!retrying.RedirectingToUrl.IsNullOrWhiteSpace())
                {
                    return(Redirect(retrying.RedirectingToUrl + qs));
                }

                var invalidOp = new InvalidOperationException("Retry url was not specified");

                MultiLogHelper.Error <PayPalExpressController>("Could not redirect to retry", invalidOp);
                throw invalidOp;
            }
            catch (Exception ex)
            {
                var extra = new { InvoiceKey = invoiceKey, PaymentKey = paymentKey, Token = token, PayerId = payerId };

                logData.SetValue <object>("extra", extra);

                MultiLogHelper.Error <PayPalExpressController>(
                    "Failed to Capture SUCCESSFUL PayPal Express checkout response.",
                    ex,
                    logData);

                throw;
            }
        }