/// <summary> /// Process payment when user checkout. /// </summary> /// <param name="cart">The current cart.</param> /// <param name="payment">The payment to process.</param> /// <returns>return false and set the message will make the WorkFlow activity raise PaymentExcetion(message)</returns> private PaymentProcessingResult ProcessPaymentCheckout(ICart cart, IPayment payment) { var orderNumberID = _orderNumberGenerator.GenerateOrderNumber(cart); if (string.IsNullOrEmpty(_paymentMethodConfiguration.ExpChkoutURL) || string.IsNullOrEmpty(_paymentMethodConfiguration.PaymentAction)) { return(PaymentProcessingResult.CreateUnsuccessfulResult(Utilities.Translate("PayPalSettingsError"))); } var caller = PayPalAPIHelper.GetPayPalAPICallerServices(_paymentMethodConfiguration); var setExpressChkOutReqType = new SetExpressCheckoutRequestType(SetupExpressCheckoutReqDetailsType(cart, payment, orderNumberID)); var setChkOutResponse = caller.SetExpressCheckout(new SetExpressCheckoutReq { SetExpressCheckoutRequest = setExpressChkOutReqType }); var errorCheck = _payPalAPIHelper.CheckErrors(setChkOutResponse); if (!string.IsNullOrEmpty(errorCheck)) { _logger.Error(errorCheck); return(PaymentProcessingResult.CreateUnsuccessfulResult(PaymentTransactionFailedMessage)); } payment.Properties[PayPalOrderNumberPropertyName] = orderNumberID; payment.Properties[PayPalExpTokenPropertyName] = setChkOutResponse.Token; _orderRepository.Save(cart); // validation checking with PayPal OK (Server's PayPal API, Billing Address, Shipping Address, ... do redirect to PayPal.com var redirectUrl = CreateRedirectUrl(_paymentMethodConfiguration.ExpChkoutURL, setChkOutResponse.Token); var message = $"---PayPal-SetExpressCheckout is successful. Redirect end user to {redirectUrl}"; _logger.Information(message); return(PaymentProcessingResult.CreateSuccessfulResult(message, redirectUrl)); }
/// <summary> /// Captures an authorized payment. /// </summary> /// <para> /// See API doc here https://developer.paypal.com/webapps/developer/docs/classic/api/merchant/DoCapture_API_Operation_SOAP/ /// </para> /// <param name="orderGroup">The order group to process.</param> /// <param name="payment">The payment to process</param> /// <returns>return false and set the message will make the WorkFlow activity raise PaymentExcetion(message)</returns> private PaymentProcessingResult ProcessPaymentCapture(IOrderGroup orderGroup, IPayment payment) { // Implement refund feature logic for current payment gateway var captureAmount = payment.Amount; var purchaseOrder = orderGroup as IPurchaseOrder; if (purchaseOrder == null || captureAmount <= 0) { return(PaymentProcessingResult.CreateUnsuccessfulResult("Nothing to capture")); } var captureRequest = new DoCaptureRequestType { AuthorizationID = payment.TransactionID, // original transactionID (which PayPal gave us when DoExpressCheckoutPayment, DoDirectPayment, or CheckOut) Amount = _payPalAPIHelper.ToPayPalAmount(captureAmount, orderGroup.Currency), // if refund with Partial, we have to set the Amount CompleteType = payment.Amount >= purchaseOrder.GetTotal().Amount ? CompleteCodeType.COMPLETE : CompleteCodeType.NOTCOMPLETE, InvoiceID = purchaseOrder.OrderNumber }; captureRequest.Note = $"[{payment.PaymentMethodName}-{payment.TransactionID}] captured {captureAmount}{captureRequest.Amount.currencyID} for [PurchaseOrder-{purchaseOrder.OrderNumber}]"; var caller = PayPalAPIHelper.GetPayPalAPICallerServices(_paymentMethodConfiguration); var doCaptureReq = new DoCaptureReq { DoCaptureRequest = captureRequest }; var captureResponse = caller.DoCapture(doCaptureReq); var errorCheck = _payPalAPIHelper.CheckErrors(captureResponse); if (!string.IsNullOrEmpty(errorCheck)) { _logger.Error(errorCheck); return(PaymentProcessingResult.CreateUnsuccessfulResult(PaymentTransactionFailedMessage)); } var captureResponseDetails = captureResponse.DoCaptureResponseDetails; var paymentInfo = captureResponseDetails.PaymentInfo; // Extract the response details. payment.ProviderTransactionID = paymentInfo.TransactionID; payment.Status = paymentInfo.PaymentStatus.ToString(); var message = $"[{payment.PaymentMethodName}] [Capture payment-{paymentInfo.TransactionID}] [Status: {paymentInfo.PaymentStatus.ToString()}] " + $".Response: {captureResponse.Ack.ToString()} at Timestamp={captureResponse.Timestamp.ToString()}: {paymentInfo.GrossAmount.value}{paymentInfo.GrossAmount.currencyID}"; // add a new order note about this capture AddNoteToPurchaseOrder("CAPTURE", message, purchaseOrder.CustomerId, purchaseOrder); _orderRepository.Save(purchaseOrder); return(PaymentProcessingResult.CreateSuccessfulResult(message)); }
/// <summary> /// Process payment when a refund request happens. /// </summary> /// <remarks> /// <para> /// See API doc here https://www.x.com/developers/paypal/documentation-tools/api/refundtransaction-api-operation-soap /// </para> /// <para> /// You may offer a refund only for a limited time, usually 60 days. If you need to make a refund after that time, you will need to initiate a new PayPal payment to your buyer. /// If you offer the buyer a partial refund, she has 10 days to decline it if she wishes. (Full refunds are automatically processed.) /// </para> /// </remarks> /// <param name="payment">The payment to process.</param> /// <param name="orderGroup">The order group to process.</param> /// <returns>True if refund was completed, otherwise false and set the message will make the WorkFlow activity raise PaymentExcetion(message).</returns> private PaymentProcessingResult ProcessPaymentRefund(IOrderGroup orderGroup, IPayment payment) { // Implement refund feature logic for current payment gateway var refundAmount = payment.Amount; var purchaseOrder = (orderGroup as IPurchaseOrder); if (purchaseOrder == null || refundAmount <= 0) { return(PaymentProcessingResult.CreateUnsuccessfulResult(Utilities.Translate("PayPalRefundError"))); } // Call payment gateway API to do refund business // Create the Refund Request var refundRequest = new RefundTransactionRequestType { TransactionID = payment.ProviderTransactionID, // original transactionID (which payPal gave us when do ExpressCheckout) Memo = $"[{payment.PaymentMethodName}-{payment.TransactionID}] refunds {refundAmount}{purchaseOrder.Currency} for [PurchaseOrder-{purchaseOrder.OrderNumber}]", // NOTE: If RefundType is Full, do not set the amount. // refundRequest.RefundType = RefundType.Full; //refund a full or partial amount RefundType = RefundType.PARTIAL, //refund a partial amount Amount = _payPalAPIHelper.ToPayPalAmount(refundAmount, orderGroup.Currency) // if refund with Partial, we have to set the Amount }; var caller = PayPalAPIHelper.GetPayPalAPICallerServices(_paymentMethodConfiguration); var refundResponse = caller.RefundTransaction(new RefundTransactionReq { RefundTransactionRequest = refundRequest }); var errorCheck = _payPalAPIHelper.CheckErrors(refundResponse); if (!string.IsNullOrEmpty(errorCheck)) { _logger.Error(errorCheck); return(PaymentProcessingResult.CreateUnsuccessfulResult(PaymentTransactionFailedMessage)); } // Extract the response details. payment.TransactionID = refundResponse.RefundTransactionID; var message = $"[{payment.PaymentMethodName}] [RefundTransaction-{refundResponse.RefundTransactionID}] " + $"Response: {refundResponse.Ack.ToString()} at Timestamp={refundResponse.Timestamp.ToString()}: {refundResponse.GrossRefundAmount.value}{refundResponse.GrossRefundAmount.currencyID}"; // add a new order note about this refund AddNoteToPurchaseOrder("REFUND", message, purchaseOrder.CustomerId, purchaseOrder); _orderRepository.Save(purchaseOrder); return(PaymentProcessingResult.CreateSuccessfulResult(message)); }
public PayPalPaymentGateway( IFeatureSwitch featureSwitch, IInventoryProcessor inventoryProcessor, IOrderNumberGenerator orderNumberGenerator, IOrderRepository orderRepository, IOrderGroupCalculator orderGroupCalculator, PayPalAPIHelper paypalAPIHelper) { _featureSwitch = featureSwitch; _inventoryProcessor = inventoryProcessor; _orderNumberGenerator = orderNumberGenerator; _orderRepository = orderRepository; _orderGroupCalculator = orderGroupCalculator; _payPalAPIHelper = paypalAPIHelper; _paymentMethodConfiguration = new PayPalConfiguration(Settings); }
/// <summary> /// Handles the Load event of the Page control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> private void Page_Load(object sender, System.EventArgs e) { if (_payPalConfiguration == null) { _payPalConfiguration = new PayPalConfiguration(); } var pal = _payPalConfiguration.PAL; if (string.IsNullOrEmpty(pal)) { pal = ViewState["PAL"] as string; } if (string.IsNullOrEmpty(pal)) { //Obtain the PAL code using API var caller = PayPalAPIHelper.GetPayPalAPICallerServices(_payPalConfiguration); if (caller != null) { var palResponse = caller.GetPalDetails(new GetPalDetailsReq() { GetPalDetailsRequest = new GetPalDetailsRequestType() }); if (palResponse.Ack == AckCodeType.SUCCESSWITHWARNING || palResponse.Ack == AckCodeType.SUCCESS) { pal = palResponse.Pal; ViewState["PAL"] = pal; } } } SetupImageMark(_payPalConfiguration, pal); Message.Text = Utilities.Translate("PayPalText"); if (string.Equals(Request["accept"], "false") && !string.IsNullOrEmpty(Request.QueryString["hash"])) { ErrorManager.GenerateError(Utilities.Translate("CancelMessage")); return; } }
/// <summary> /// Processes the successful transaction, was called when PayPal.com redirect back. /// </summary> /// <param name="orderGroup">The order group that was processed.</param> /// <param name="payment">The order payment.</param> /// <param name="acceptUrl">The redirect url when finished.</param> /// <param name="cancelUrl">The redirect url when error happens.</param> /// <returns>The url redirection after process.</returns> public string ProcessSuccessfulTransaction(IOrderGroup orderGroup, IPayment payment, string acceptUrl, string cancelUrl) { if (HttpContext.Current == null) { return(cancelUrl); } var cart = orderGroup as ICart; if (cart == null) { // return to the shopping cart page immediately and show error messages return(ProcessUnsuccessfulTransaction(cancelUrl, Utilities.Translate("CommitTranErrorCartNull"))); } string redirectionUrl; var getDetailRequest = new GetExpressCheckoutDetailsRequestType { Token = payment.Properties[PayPalExpTokenPropertyName] as string // Add request-specific fields to the request. }; // Execute the API operation and obtain the response. var caller = PayPalAPIHelper.GetPayPalAPICallerServices(_paymentMethodConfiguration); var getDetailsResponse = caller.GetExpressCheckoutDetails(new GetExpressCheckoutDetailsReq { GetExpressCheckoutDetailsRequest = getDetailRequest }); var errorCheck = _payPalAPIHelper.CheckErrors(getDetailsResponse); if (!string.IsNullOrEmpty(errorCheck)) { // unsuccessful get detail call _logger.Error(errorCheck); return(ProcessUnsuccessfulTransaction(cancelUrl, PaymentTransactionFailedMessage)); } var expressCheckoutDetailsResponse = getDetailsResponse.GetExpressCheckoutDetailsResponseDetails; // get commerceOrderId from what we put to PayPal instead of getting from cookie payment.Properties[PayPalOrderNumberPropertyName] = expressCheckoutDetailsResponse.InvoiceID; //process details sent from paypal, changing addresses if required var emptyAddressMsg = string.Empty; //process billing address var payPalBillingAddress = expressCheckoutDetailsResponse.BillingAddress; if (payPalBillingAddress != null && AddressHandling.IsAddressChanged(payment.BillingAddress, payPalBillingAddress)) { emptyAddressMsg = _payPalAPIHelper.ProcessOrderAddress(expressCheckoutDetailsResponse.PayerInfo, payPalBillingAddress, payment.BillingAddress, CustomerAddressTypeEnum.Billing, "CommitTranErrorPayPalBillingAddressEmpty"); if (!string.IsNullOrEmpty(emptyAddressMsg)) { return(ProcessUnsuccessfulTransaction(cancelUrl, emptyAddressMsg)); } } //process shipping address var payPalShippingAddress = expressCheckoutDetailsResponse.PaymentDetails[0].ShipToAddress; if (payPalShippingAddress != null && AddressHandling.IsAddressChanged(cart.GetFirstShipment().ShippingAddress, payPalShippingAddress)) { //when address was changed on PayPal site, it might cause changing tax value changed and changing order value also. var taxValueBefore = cart.GetTaxTotal(_orderGroupCalculator); var shippingAddress = orderGroup.CreateOrderAddress("address"); emptyAddressMsg = _payPalAPIHelper.ProcessOrderAddress(expressCheckoutDetailsResponse.PayerInfo, payPalShippingAddress, shippingAddress, CustomerAddressTypeEnum.Shipping, "CommitTranErrorPayPalShippingAddressEmpty"); if (!string.IsNullOrEmpty(emptyAddressMsg)) { return(ProcessUnsuccessfulTransaction(cancelUrl, emptyAddressMsg)); } cart.GetFirstShipment().ShippingAddress = shippingAddress; var taxValueAfter = cart.GetTaxTotal(_orderGroupCalculator); if (taxValueBefore != taxValueAfter) { _orderRepository.Save(cart); // Saving cart to submit order address changed. return(ProcessUnsuccessfulTransaction(cancelUrl, Utilities.Translate("ProcessPaymentTaxValueChangedWarning"))); } } // Add request-specific fields to the request. // Create the request details object. var doExpressChkOutPaymentReqDetails = CreateExpressCheckoutPaymentRequest(getDetailsResponse, orderGroup, payment); // Execute the API operation and obtain the response. var doCheckOutResponse = caller.DoExpressCheckoutPayment(new DoExpressCheckoutPaymentReq { DoExpressCheckoutPaymentRequest = new DoExpressCheckoutPaymentRequestType(doExpressChkOutPaymentReqDetails) }); errorCheck = _payPalAPIHelper.CheckErrors(doCheckOutResponse); if (!string.IsNullOrEmpty(errorCheck)) { // unsuccessful doCheckout response _logger.Error(errorCheck); return(ProcessUnsuccessfulTransaction(cancelUrl, PaymentTransactionFailedMessage)); } // everything is fine, this is a flag to tell ProcessPayment know about this case: redirect back from PayPal with accepted payment var errorMessages = new List <string>(); var cartCompleted = DoCompletingCart(cart, errorMessages); if (!cartCompleted) { return(UriUtil.AddQueryString(cancelUrl, "message", string.Join(";", errorMessages.Distinct().ToArray()))); } // Place order var purchaseOrder = MakePurchaseOrder(doCheckOutResponse, cart, payment); redirectionUrl = CreateRedirectionUrl(purchaseOrder, acceptUrl, payment.BillingAddress.Email); _logger.Information($"PayPal transaction succeeds, redirect end user to {redirectionUrl}"); return(redirectionUrl); }