/// <summary> /// Validates credentials have been entered in the back office. /// </summary> /// <param name="settings"> /// The settings. /// </param> /// <param name="isExpress"> /// The is express. /// </param> /// <returns> /// The <see cref="Attempt"/>. /// </returns> private static Attempt<bool> ValidatePayPayProviderSettings(PayPalProviderSettings settings, bool isExpress = false) { var success = true; if (isExpress) { //success = // !(settings.ApiUsername.IsNullOrWhiteSpace() || // settings.ApiPassword.IsNullOrWhiteSpace() || // settings.ApiSignature.IsNullOrWhiteSpace() || // settings.ApplicationId.IsNullOrWhiteSpace()); success = !(settings.ApiUsername.IsNullOrWhiteSpace() || settings.ApiPassword.IsNullOrWhiteSpace() || settings.ApiSignature.IsNullOrWhiteSpace()); } else { success = !(settings.ClientId.IsNullOrWhiteSpace() || settings.ClientSecret.IsNullOrWhiteSpace()); } var ex = new PayPalApiException("One or more of the required API credentials has not been set in the back office"); return success ? Attempt<bool>.Succeed(true) : Attempt<bool>.Fail(false, ex); }
/// <summary> /// Performs a refund or a partial refund. /// </summary> /// <param name="invoice"> /// The invoice. /// </param> /// <param name="payment"> /// The payment. /// </param> /// <param name="amount"> /// The amount. /// </param> /// <param name="args"> /// The processor arguments. /// </param> /// <returns> /// The <see cref="IPaymentResult"/>. /// </returns> protected override IPaymentResult PerformRefundPayment(IInvoice invoice, IPayment payment, decimal amount, ProcessorArgumentCollection args) { var record = payment.GetPayPalTransactionRecord(); if (StringExtensions.IsNullOrWhiteSpace(record.Data.CaptureTransactionId)) { var error = new NullReferenceException("PayPal transaction could not be found and/or deserialized from payment extended data collection"); return new PaymentResult(Attempt<IPayment>.Fail(payment, error), invoice, false); } var attempt = _paypalApiService.ExpressCheckout.Refund(invoice, payment, amount); // store the transaction var refundTransActions = record.RefundTransactions.ToList(); refundTransActions.Add(attempt); record.RefundTransactions = refundTransActions; if (!attempt.Success()) { // In the case of a failure, package up the exception so we can bubble it up. var ex = new PayPalApiException("PayPal Checkout Express refund response ACK was not Success"); if (record.SetExpressCheckout.ErrorTypes.Any()) ex.ErrorTypes = record.SetExpressCheckout.ErrorTypes; // ensure that transaction is stored in the payment payment.SavePayPalTransactionRecord(record); GatewayProviderService.Save(payment); return new PaymentResult(Attempt<IPayment>.Fail(payment, ex), invoice, false); } foreach (var applied in payment.AppliedPayments()) { applied.TransactionType = AppliedPaymentType.Refund; applied.Amount = 0; applied.Description += " - Refunded"; this.GatewayProviderService.Save(applied); } payment.Amount = payment.Amount - amount; if (payment.Amount != 0) { this.GatewayProviderService.ApplyPaymentToInvoice(payment.Key, invoice.Key, AppliedPaymentType.Debit, "To show partial payment remaining after refund", payment.Amount); } this.GatewayProviderService.Save(payment); return new PaymentResult(Attempt<IPayment>.Succeed(payment), invoice, false); }
/// <summary> /// Performs the AuthorizePayment operation. /// </summary> /// <param name="invoice"> /// The invoice. /// </param> /// <param name="args"> /// The <see cref="ProcessorArgumentCollection"/>. /// </param> /// <returns> /// The <see cref="IPaymentResult"/>. /// </returns> /// <remarks> /// For the ExpressCheckout there is not technically an "Authorize" but we use this to start the checkout process and to /// mark intent to pay before redirecting the customer to PayPal. e.g. This method is called after the customer has /// clicked the Pay button, we then save the invoice and "Authorize" a payment setting the invoice status to Unpaid before redirecting. /// IN this way, we have both an Invoice and a Payment (denoting the redirect). When the customer completes the purchase on PayPal sites /// the payment will be used to perform a capture and the invoice status will be changed to Paid. In the event the customer cancels, /// the invoice will either be voided or deleted depending on the configured setting. /// Events are included in the controller handling the response to allow developers to override success and cancel redirect URLs. /// </remarks> protected override IPaymentResult PerformAuthorizePayment(IInvoice invoice, ProcessorArgumentCollection args) { var payment = GatewayProviderService.CreatePayment(PaymentMethodType.Redirect, invoice.Total, PaymentMethod.Key); payment.CustomerKey = invoice.CustomerKey; payment.PaymentMethodName = PaymentMethod.Name; payment.ReferenceNumber = PaymentMethod.PaymentCode + "-" + invoice.PrefixedInvoiceNumber(); payment.Collected = false; payment.Authorized = false; // this is technically not the authorization. We'll mark this in a later step. // Have to save here to generate the payment key GatewayProviderService.Save(payment); // Now we want to get things setup for the ExpressCheckout var record = this._paypalApiService.ExpressCheckout.SetExpressCheckout(invoice, payment); payment.SavePayPalTransactionRecord(record); // Have to save here to persist the record so it can be used in later processing. GatewayProviderService.Save(payment); // In this case, we want to do our own Apply Payment operation as the amount has not been collected - // so we create an applied payment with a 0 amount. Once the payment has been "collected", another Applied Payment record will // be created showing the full amount and the invoice status will be set to Paid. GatewayProviderService.ApplyPaymentToInvoice(payment.Key, invoice.Key, AppliedPaymentType.Debit, string.Format("To show promise of a {0} payment via PayPal Express Checkout", PaymentMethod.Name), 0); // if the ACK was success return a success IPaymentResult if (record.Success) { return new PaymentResult(Attempt<IPayment>.Succeed(payment), invoice, false, record.SetExpressCheckout.RedirectUrl); } // In the case of a failure, package up the exception so we can bubble it up. var ex = new PayPalApiException("PayPal Checkout Express initial response ACK was not Success"); if (record.SetExpressCheckout.ErrorTypes.Any()) ex.ErrorTypes = record.SetExpressCheckout.ErrorTypes; return new PaymentResult(Attempt<IPayment>.Fail(payment, ex), invoice, false); }
/// <summary> /// Refunds or partially refunds a payment. /// </summary> /// <param name="invoice"> /// The invoice. /// </param> /// <param name="payment"> /// The payment. /// </param> /// <param name="amount"> /// The amount of the refund. /// </param> /// <returns> /// The <see cref="PayPalExpressTransactionRecord"/>. /// </returns> public ExpressCheckoutResponse Refund(IInvoice invoice, IPayment payment, decimal amount) { var record = payment.GetPayPalTransactionRecord(); // Ensure the currency code if (record.Data.CurrencyCode.IsNullOrWhiteSpace()) { var ex = new PayPalApiException("CurrencyCode was not found in payment extended data PayPal transaction data record. Cannot perform refund."); return _responseFactory.Build(ex); } // Ensure the transaction id if (record.Data.CaptureTransactionId.IsNullOrWhiteSpace()) { var ex = new PayPalApiException("CaptureTransactionId was not found in payment extended data PayPal transaction data record. Cannot perform refund."); return _responseFactory.Build(ex); } // Get the decimal configuration for the current currency var currencyCodeType = PayPalApiHelper.GetPayPalCurrencyCode(record.Data.CurrencyCode); var basicAmountFactory = new PayPalBasicAmountTypeFactory(currencyCodeType); ExpressCheckoutResponse result = null; if (amount > payment.Amount) amount = payment.Amount; try { var request = new RefundTransactionRequestType { InvoiceID = invoice.PrefixedInvoiceNumber(), PayerID = record.Data.PayerId, RefundSource = RefundSourceCodeType.DEFAULT, Version = record.DoCapture.Version, TransactionID = record.Data.CaptureTransactionId, Amount = basicAmountFactory.Build(amount) }; var wrapper = new RefundTransactionReq { RefundTransactionRequest = request }; var refundTransactionResponse = GetPayPalService().RefundTransaction(wrapper); result = _responseFactory.Build(refundTransactionResponse, record.Data.Token); } catch (Exception ex) { result = _responseFactory.Build(ex); } return result; }