/// <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;
            }
        }
        /// <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;
            }
        }