/// <remarks>return 503 (HttpStatusCode.ServiceUnavailable) to ask paypal to resend it at later time again</remarks>
        public HttpStatusCode ProcessWebhook(
            PayPalApiSettingsBase settings,
            NameValueCollection headers,
            string rawJson,
            string providerSystemName)
        {
            if (rawJson.IsEmpty())
            {
                return(HttpStatusCode.OK);
            }

            dynamic json      = JObject.Parse(rawJson);
            var     eventType = (string)json.event_type;

            //foreach (var key in headers.AllKeys)"{0}: {1}".FormatInvariant(key, headers[key]).Dump();
            //string data = JsonConvert.SerializeObject(json, Formatting.Indented);data.Dump();


            // validating against PayPal SDK failing using sandbox, so better we do not use it:
            //var apiContext = new global::PayPal.Api.APIContext
            //{
            //	AccessToken = "I do not have one here",
            //	Config = new Dictionary<string, string>
            //		{
            //			{ "mode", settings.UseSandbox ? "sandbox" : "live" },
            //			{ "clientId", settings.ClientId },
            //			{ "clientSecret", settings.Secret },
            //			{ "webhook.id", setting.WebhookId },
            //		}
            //};
            //var result = global::PayPal.Api.WebhookEvent.ValidateReceivedEvent(apiContext, headers, rawJson, webhookId);
            //}

            var paymentId = (string)json.resource.parent_payment;

            if (paymentId.IsEmpty())
            {
                LogError(null, T("Plugins.cloudCommerce.PayPal.FoundOrderForPayment", 0, "".NaIfEmpty()), JsonConvert.SerializeObject(json, Formatting.Indented), isWarning: true);
                return(HttpStatusCode.OK);
            }

            var orders = _orderRepository.Value.Table
                         .Where(x => x.PaymentMethodSystemName == providerSystemName && x.AuthorizationTransactionCode == paymentId)
                         .ToList();

            if (orders.Count != 1)
            {
                LogError(null, T("Plugins.cloudCommerce.PayPal.FoundOrderForPayment", orders.Count, paymentId), JsonConvert.SerializeObject(json, Formatting.Indented), isWarning: true);
                return(HttpStatusCode.OK);
            }

            var order = orders.First();
            var store = _services.StoreService.GetStoreById(order.StoreId);

            var total           = decimal.Zero;
            var currency        = (string)json.resource.amount.currency;
            var primaryCurrency = store.PrimaryStoreCurrency.CurrencyCode;

            if (!primaryCurrency.IsCaseInsensitiveEqual(currency))
            {
                LogError(null, T("Plugins.cloudCommerce.PayPal.CurrencyNotEqual", currency.NaIfEmpty(), primaryCurrency), JsonConvert.SerializeObject(json, Formatting.Indented), isWarning: true);
                return(HttpStatusCode.OK);
            }

            eventType = eventType.Substring(eventType.LastIndexOf('.') + 1);

            var newPaymentStatus = GetPaymentStatus(eventType, "authorization", order.PaymentStatus);

            var isValidTotal = decimal.TryParse((string)json.resource.amount.total, NumberStyles.Currency, CultureInfo.InvariantCulture, out total);

            if (newPaymentStatus == PaymentStatus.Refunded && (Math.Abs(order.OrderTotal) - Math.Abs(total)) > decimal.Zero)
            {
                newPaymentStatus = PaymentStatus.PartiallyRefunded;
            }

            switch (newPaymentStatus)
            {
            case PaymentStatus.Pending:
                break;

            case PaymentStatus.Authorized:
                if (_orderProcessingService.CanMarkOrderAsAuthorized(order))
                {
                    _orderProcessingService.MarkAsAuthorized(order);
                }
                break;

            case PaymentStatus.Paid:
                if (_orderProcessingService.CanMarkOrderAsPaid(order))
                {
                    _orderProcessingService.MarkOrderAsPaid(order);
                }
                break;

            case PaymentStatus.Refunded:
                if (_orderProcessingService.CanRefundOffline(order))
                {
                    _orderProcessingService.RefundOffline(order);
                }
                break;

            case PaymentStatus.PartiallyRefunded:
                if (_orderProcessingService.CanPartiallyRefundOffline(order, Math.Abs(total)))
                {
                    _orderProcessingService.PartiallyRefundOffline(order, Math.Abs(total));
                }
                break;

            case PaymentStatus.Voided:
                if (_orderProcessingService.CanVoidOffline(order))
                {
                    _orderProcessingService.VoidOffline(order);
                }
                break;
            }

            AddOrderNote(settings, order, (string)ToInfoString(json), true);

            return(HttpStatusCode.OK);
        }
Beispiel #2
0
        protected virtual void ProcessPayment(string orderNumber, string ipnInfo, PaymentStatus newPaymentStatus, decimal mcGross, string transactionId)
        {
            Guid orderNumberGuid;

            try
            {
                orderNumberGuid = new Guid(orderNumber);
            }
            catch
            {
                orderNumberGuid = Guid.Empty;
            }

            var order = _orderService.GetOrderByGuid(orderNumberGuid);

            if (order == null)
            {
                _logger.Error("PayPal IPN. Order is not found", new NopException(ipnInfo));
                return;
            }

            //order note
            order.OrderNotes.Add(new OrderNote
            {
                Note = ipnInfo,
                DisplayToCustomer = false,
                CreatedOnUtc = DateTime.UtcNow
            });

            _orderService.UpdateOrder(order);

            //validate order total
            if ((newPaymentStatus == PaymentStatus.Authorized || newPaymentStatus == PaymentStatus.Paid) && !Math.Round(mcGross, 2).Equals(Math.Round(order.OrderTotal, 2)))
            {
                var errorStr = $"PayPal IPN. Returned order total {mcGross} doesn't equal order total {order.OrderTotal}. Order# {order.Id}.";
                //log
                _logger.Error(errorStr);
                //order note
                order.OrderNotes.Add(new OrderNote
                {
                    Note = errorStr,
                    DisplayToCustomer = false,
                    CreatedOnUtc = DateTime.UtcNow
                });
                _orderService.UpdateOrder(order);

                return;
            }

            switch (newPaymentStatus)
            {
                case PaymentStatus.Authorized:
                    if (_orderProcessingService.CanMarkOrderAsAuthorized(order))
                        _orderProcessingService.MarkAsAuthorized(order);
                    break;
                case PaymentStatus.Paid:
                    if (_orderProcessingService.CanMarkOrderAsPaid(order))
                    {
                        order.AuthorizationTransactionId = transactionId;
                        _orderService.UpdateOrder(order);

                        _orderProcessingService.MarkOrderAsPaid(order);
                    }

                    break;
                case PaymentStatus.Refunded:
                    var totalToRefund = Math.Abs(mcGross);
                    if (totalToRefund > 0 && Math.Round(totalToRefund, 2).Equals(Math.Round(order.OrderTotal, 2)))
                    {
                        //refund
                        if (_orderProcessingService.CanRefundOffline(order))
                            _orderProcessingService.RefundOffline(order);
                    }
                    else
                    {
                        //partial refund
                        if (_orderProcessingService.CanPartiallyRefundOffline(order, totalToRefund))
                            _orderProcessingService.PartiallyRefundOffline(order, totalToRefund);
                    }

                    break;
                case PaymentStatus.Voided:
                    if (_orderProcessingService.CanVoidOffline(order))
                        _orderProcessingService.VoidOffline(order);

                    break;
            }
        }
Beispiel #3
0
        public ActionResult IPNHandler()
        {
            byte[] param      = Request.BinaryRead(Request.ContentLength);
            string strRequest = Encoding.ASCII.GetString(param);
            Dictionary <string, string> values;

            var processor = _paymentService.LoadPaymentMethodBySystemName("Payments.PayPalStandard") as PayPalStandardPaymentProcessor;

            if (processor == null ||
                !processor.IsPaymentMethodActive(_paymentSettings) || !processor.PluginDescriptor.Installed)
            {
                throw new NopException("PayPal Standard module cannot be loaded");
            }

            if (processor.VerifyIpn(strRequest, out values))
            {
                #region values
                decimal mc_gross = decimal.Zero;
                try
                {
                    mc_gross = decimal.Parse(values["mc_gross"], new CultureInfo("en-US"));
                }
                catch { }

                string payer_status = string.Empty;
                values.TryGetValue("payer_status", out payer_status);
                string payment_status = string.Empty;
                values.TryGetValue("payment_status", out payment_status);
                string pending_reason = string.Empty;
                values.TryGetValue("pending_reason", out pending_reason);
                string mc_currency = string.Empty;
                values.TryGetValue("mc_currency", out mc_currency);
                string txn_id = string.Empty;
                values.TryGetValue("txn_id", out txn_id);
                string txn_type = string.Empty;
                values.TryGetValue("txn_type", out txn_type);
                string rp_invoice_id = string.Empty;
                values.TryGetValue("rp_invoice_id", out rp_invoice_id);
                string payment_type = string.Empty;
                values.TryGetValue("payment_type", out payment_type);
                string payer_id = string.Empty;
                values.TryGetValue("payer_id", out payer_id);
                string receiver_id = string.Empty;
                values.TryGetValue("receiver_id", out receiver_id);
                string invoice = string.Empty;
                values.TryGetValue("invoice", out invoice);
                string payment_fee = string.Empty;
                values.TryGetValue("payment_fee", out payment_fee);

                #endregion

                var sb = new StringBuilder();
                sb.AppendLine("Paypal IPN:");
                foreach (KeyValuePair <string, string> kvp in values)
                {
                    sb.AppendLine(kvp.Key + ": " + kvp.Value);
                }

                var newPaymentStatus = PaypalHelper.GetPaymentStatus(payment_status, pending_reason);
                sb.AppendLine("New payment status: " + newPaymentStatus);

                switch (txn_type)
                {
                case "recurring_payment_profile_created":
                    //do nothing here
                    break;

                case "recurring_payment":
                    #region Recurring payment
                {
                    Guid orderNumberGuid = Guid.Empty;
                    try
                    {
                        orderNumberGuid = new Guid(rp_invoice_id);
                    }
                    catch
                    {
                    }

                    var initialOrder = _orderService.GetOrderByGuid(orderNumberGuid);
                    if (initialOrder != null)
                    {
                        var recurringPayments = _orderService.SearchRecurringPayments(initialOrderId: initialOrder.Id);
                        foreach (var rp in recurringPayments)
                        {
                            switch (newPaymentStatus)
                            {
                            case PaymentStatus.Authorized:
                            case PaymentStatus.Paid:
                            {
                                var recurringPaymentHistory = rp.RecurringPaymentHistory;
                                if (!recurringPaymentHistory.Any())
                                {
                                    //first payment
                                    var rph = new RecurringPaymentHistory
                                    {
                                        RecurringPaymentId = rp.Id,
                                        OrderId            = initialOrder.Id,
                                        CreatedOnUtc       = DateTime.UtcNow
                                    };
                                    rp.RecurringPaymentHistory.Add(rph);
                                    _orderService.UpdateRecurringPayment(rp);
                                }
                                else
                                {
                                    //next payments
                                    var processPaymentResult = new ProcessPaymentResult();
                                    processPaymentResult.NewPaymentStatus = newPaymentStatus;
                                    if (newPaymentStatus == PaymentStatus.Authorized)
                                    {
                                        processPaymentResult.AuthorizationTransactionId = txn_id;
                                    }
                                    else
                                    {
                                        processPaymentResult.CaptureTransactionId = txn_id;
                                    }

                                    _orderProcessingService.ProcessNextRecurringPayment(rp, processPaymentResult);
                                }
                            }
                            break;
                            }
                        }

                        //this.OrderService.InsertOrderNote(newOrder.OrderId, sb.ToString(), DateTime.UtcNow);
                        _logger.Information("PayPal IPN. Recurring info", new NopException(sb.ToString()));
                    }
                    else
                    {
                        _logger.Error("PayPal IPN. Order is not found", new NopException(sb.ToString()));
                    }
                }
                    #endregion
                    break;

                default:
                    #region Standard payment
                {
                    string orderNumber = string.Empty;
                    values.TryGetValue("custom", out orderNumber);
                    Guid orderNumberGuid = Guid.Empty;
                    try
                    {
                        orderNumberGuid = new Guid(orderNumber);
                    }
                    catch
                    {
                    }

                    var order = _orderService.GetOrderByGuid(orderNumberGuid);
                    if (order != null)
                    {
                        //order note
                        order.OrderNotes.Add(new OrderNote
                            {
                                Note = sb.ToString(),
                                DisplayToCustomer = false,
                                CreatedOnUtc      = DateTime.UtcNow
                            });
                        _orderService.UpdateOrder(order);

                        switch (newPaymentStatus)
                        {
                        case PaymentStatus.Pending:
                        {
                        }
                        break;

                        case PaymentStatus.Authorized:
                        {
                            //validate order total
                            if (Math.Round(mc_gross, 2).Equals(Math.Round(order.OrderTotal, 2)))
                            {
                                //valid
                                if (_orderProcessingService.CanMarkOrderAsAuthorized(order))
                                {
                                    _orderProcessingService.MarkAsAuthorized(order);
                                }
                            }
                            else
                            {
                                //not valid
                                string errorStr = string.Format("PayPal IPN. Returned order total {0} doesn't equal order total {1}. Order# {2}.", mc_gross, order.OrderTotal, order.Id);
                                //log
                                _logger.Error(errorStr);
                                //order note
                                order.OrderNotes.Add(new OrderNote
                                        {
                                            Note = errorStr,
                                            DisplayToCustomer = false,
                                            CreatedOnUtc      = DateTime.UtcNow
                                        });
                                _orderService.UpdateOrder(order);
                            }
                        }
                        break;

                        case PaymentStatus.Paid:
                        {
                            //validate order total
                            if (Math.Round(mc_gross, 2).Equals(Math.Round(order.OrderTotal, 2)))
                            {
                                //valid
                                if (_orderProcessingService.CanMarkOrderAsPaid(order))
                                {
                                    order.AuthorizationTransactionId = txn_id;
                                    _orderService.UpdateOrder(order);

                                    _orderProcessingService.MarkOrderAsPaid(order);
                                }
                            }
                            else
                            {
                                //not valid
                                string errorStr = string.Format("PayPal IPN. Returned order total {0} doesn't equal order total {1}. Order# {2}.", mc_gross, order.OrderTotal, order.Id);
                                //log
                                _logger.Error(errorStr);
                                //order note
                                order.OrderNotes.Add(new OrderNote
                                        {
                                            Note = errorStr,
                                            DisplayToCustomer = false,
                                            CreatedOnUtc      = DateTime.UtcNow
                                        });
                                _orderService.UpdateOrder(order);
                            }
                        }
                        break;

                        case PaymentStatus.Refunded:
                        {
                            var totalToRefund = Math.Abs(mc_gross);
                            if (totalToRefund > 0 && Math.Round(totalToRefund, 2).Equals(Math.Round(order.OrderTotal, 2)))
                            {
                                //refund
                                if (_orderProcessingService.CanRefundOffline(order))
                                {
                                    _orderProcessingService.RefundOffline(order);
                                }
                            }
                            else
                            {
                                //partial refund
                                if (_orderProcessingService.CanPartiallyRefundOffline(order, totalToRefund))
                                {
                                    _orderProcessingService.PartiallyRefundOffline(order, totalToRefund);
                                }
                            }
                        }
                        break;

                        case PaymentStatus.Voided:
                        {
                            if (_orderProcessingService.CanVoidOffline(order))
                            {
                                _orderProcessingService.VoidOffline(order);
                            }
                        }
                        break;

                        default:
                            break;
                        }
                    }
                    else
                    {
                        _logger.Error("PayPal IPN. Order is not found", new NopException(sb.ToString()));
                    }
                }
                    #endregion
                    break;
                }
            }
            else
            {
                _logger.Error("PayPal IPN failed.", new NopException(strRequest));
            }

            //nothing should be rendered to visitor
            return(Content(""));
        }