Exemple #1
0
        /// <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(string.Join("; ", setChkOutResponse.Errors.Select(e => e.LongMessage))));
            }

            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));
        }
Exemple #2
0
        /// <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;

            if (!(orderGroup is IPurchaseOrder purchaseOrder) || 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))
            {
                return(PaymentProcessingResult.CreateUnsuccessfulResult(errorCheck));
            }

            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}: {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));
        }
Exemple #3
0
        /// <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;

            if (!(orderGroup is IPurchaseOrder purchaseOrder) || 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))
            {
                return(PaymentProcessingResult.CreateUnsuccessfulResult(errorCheck));
            }

            // Extract the response details.
            payment.TransactionID = refundResponse.RefundTransactionID;

            var message = $"[{payment.PaymentMethodName}] [RefundTransaction-{refundResponse.RefundTransactionID}] " +
                          $"Response: {refundResponse.Ack.ToString()} at Timestamp={refundResponse.Timestamp}: {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));
        }
Exemple #4
0
        /// <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);
            }

            if (HttpContext.Current.Session != null)
            {
                HttpContext.Current.Session.Remove("LastCouponCode");
            }

            if (!(orderGroup is ICart cart))
            {
                // return to the shopping cart page immediately and show error messages
                return(ProcessUnsuccessfulTransaction(cancelUrl, Utilities.Translate("CommitTranErrorCartNull")));
            }

            string redirectionUrl;

            using (var scope = new TransactionScope())
            {
                SetSecurityProtocolToTls12();

                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))
                {
                    RestoreSecurityProtocol();

                    // unsuccessful get detail call
                    return(ProcessUnsuccessfulTransaction(cancelUrl, errorCheck));
                }

                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
                string emptyAddressMsg;

                //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))
                    {
                        RestoreSecurityProtocol();

                        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 = _taxCalculator.GetTaxTotal(cart, cart.Market, cart.Currency);

                    var shippingAddress = orderGroup.CreateOrderAddress("address");

                    emptyAddressMsg = _payPalApiHelper.ProcessOrderAddress(expressCheckoutDetailsResponse.PayerInfo, payPalShippingAddress, shippingAddress, CustomerAddressTypeEnum.Shipping, "CommitTranErrorPayPalShippingAddressEmpty");
                    if (!string.IsNullOrEmpty(emptyAddressMsg))
                    {
                        RestoreSecurityProtocol();

                        return(ProcessUnsuccessfulTransaction(cancelUrl, emptyAddressMsg));
                    }

                    cart.GetFirstShipment().ShippingAddress = shippingAddress;

                    var taxValueAfter = _taxCalculator.GetTaxTotal(cart, cart.Market, cart.Currency);
                    if (taxValueBefore != taxValueAfter)
                    {
                        RestoreSecurityProtocol();

                        _orderRepository.Save(cart); // Saving cart to submit order address changed.
                        scope.Complete();
                        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))
                {
                    RestoreSecurityProtocol();

                    // unsuccessful doCheckout response
                    return(ProcessUnsuccessfulTransaction(cancelUrl, errorCheck));
                }

                // 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)
                {
                    RestoreSecurityProtocol();

                    return(UriSupport.AddQueryString(cancelUrl, "message", string.Join(";", errorMessages.Distinct().ToArray())));
                }

                // Place order
                var purchaseOrder = MakePurchaseOrder(doCheckOutResponse, cart, payment);

                // Commit changes
                scope.Complete();

                redirectionUrl = CreateRedirectionUrl(purchaseOrder, acceptUrl, payment.BillingAddress.Email);

                RestoreSecurityProtocol();
            }

            _logger.Information($"PayPal transaction succeeds, redirect end user to {redirectionUrl}");
            return(redirectionUrl);
        }