skip to Main Content

I am running into a snag trying to patch a PayPal order with updated totals. I am using the PayPal Checkout-NET-SDK that they provide out on GitHub, but the sample documentation they have for Patch Order Sample is a bit too simplistic:
https://github.com/paypal/Checkout-NET-SDK/blob/develop/Samples/PatchOrderSample.cs

I am trying to update the following path:
/purchase_units/@reference_id==’default’/amount"

I’ve tried using a combination of setting the value as:

  • A JSON string representing the AmountWithBreakdown object
  • An AmountWithBreakdown object

When calling the API with an AmountWithBreakdown object assigned as the value, I am met with a .NET exception:

Type ‘PayPalCheckoutSdk.Orders.AmountWithBreakdown’ with data contract name ‘AmountWithBreakdown:http://schemas.datacontract.org/2004/07/PayPalCheckoutSdk.Orders’ is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types – for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.

Sample Function that builds the PATCH request:

 Private Function BuildPatchRequest() As List(Of Patch(Of Object))

        Dim patches = New List(Of Patch(Of Object)) From {
            New Patch(Of Object) With {
                .Op = "replace",
                .Path = "/intent",
                .Value = "CAPTURE"
            },
            New Patch(Of Object) With {
                .Op = "replace",
                .Path = "/purchase_units/@reference_id=='default'/amount",
                .Value = New AmountWithBreakdown With {
                            .CurrencyCode = Me.Order.CurrencyCode,
                            .Value = Me.Order.Total.ToString("N2"),
                            .AmountBreakdown = New AmountBreakdown With {
                                .ItemTotal = New PayPalCheckoutSdk.Orders.Money With {.CurrencyCode = Me.Order.CurrencyCode, .Value = Me.Order.SubTotal.ToString("N2")},
                                .TaxTotal = New PayPalCheckoutSdk.Orders.Money With {.CurrencyCode = Me.Order.CurrencyCode, .Value = Me.Order.TaxTotal.ToString("N2")},
                                .Shipping = New PayPalCheckoutSdk.Orders.Money With {.CurrencyCode = Me.Order.CurrencyCode, .Value = Me.Order.ShippingTotal.ToString("N2")},
                                .Discount = New PayPalCheckoutSdk.Orders.Money With {.CurrencyCode = Me.Order.CurrencyCode, .Value = Me.Order.DiscountTotal.ToString("N2")},
                                .Handling = New PayPalCheckoutSdk.Orders.Money With {.CurrencyCode = Me.Order.CurrencyCode, .Value = Me.Order.HandlingFeeTotal.ToString("N2")},
                                .Insurance = New PayPalCheckoutSdk.Orders.Money With {.CurrencyCode = Me.Order.CurrencyCode, .Value = "0.00"},
                                .ShippingDiscount = New PayPalCheckoutSdk.Orders.Money With {.CurrencyCode = Me.Order.CurrencyCode, .Value = "0.00"}
                            }
                        }
            }
        }
        Return patches

End Function

All attempts at constructing the JSON manually as a string and assigning it to the value are met with the generic INVALID_PARAMETER_SYNTAX error response, despite the output passing JSON validation tools.

Has anyone had any success updating this datapoint with PayPal using this SDK? My implementation is in VB but I have gotten the gist of implementing all other functionality with the SDK being sourced in C#.

2

Answers


  1. I’m running into the same issue.

    System.Runtime.Serialization.SerializationException: Type ‘PayPalCheckoutSdk.Orders.AmountWithBreakdown’ with data contract name ‘AmountWithBreakdown:http://schemas.datacontract.org/2004/07/PayPalCheckoutSdk.Orders‘ is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types – for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.

    The call never makes it to PayPal for a response because it is failing to serialize the request. The only way I’ve been able to get it to work is by generating my own request without the SDK. This isn’t production ready code. I was just testing to see if it would work if I crafted the request myself, and it does.

    var ppe = PayPalClient.environment(productLine);
    
            var accessTokenClient = new HttpClient(ppe);
            var accessTokenRequest = new AccessTokenRequest(ppe, null);
    
            var accessTokenResponse = Task.Run(async () =>
            {
                var httpResponse = await accessTokenClient.Execute(accessTokenRequest);
                return httpResponse;
            }).Result;
    
            if (accessTokenResponse.StatusCode != HttpStatusCode.OK)
            {
                Logger.Error("[PayPalRestService] Unable to get access token.");
                return null;
            }
            
            var accessToken = accessTokenResponse.Result<AccessToken>();
    
            var client = new RestClient(ppe.BaseUrl());
            client.AddDefaultHeader("Authorization", $"Bearer {accessToken.Token}");
    
    
            var body = BuildUpdateTaxPatchRequest(cart, paypalOrder);
            var request = new RestRequest($"/v2/checkout/orders/{paypalOrder.Id}")
                .AddJsonBody(JsonConvert.SerializeObject(body));
    
            var response = client.Patch(request);
    
            if (response.StatusCode == HttpStatusCode.NoContent)
            {
                return GetOrder(paypalOrder.Id, productLine);
            }
    
    
    
    
    private static List<Patch<object>> BuildUpdateTaxPatchRequest(ICart cart, Order paypalOrder)
        {
            //Doc: https://developer.paypal.com/docs/api/orders/v2/#orders_patch
    
            var subtotal = $"{cart.GetSubTotal():N2}";
            var shipping = $"{cart.GetShippingTotal():N2}";
            var discount = $"{cart.GetOrderDiscountTotal():N2}";
            var tax = $"{cart.GetTaxTotal():N2}";
            var total = double.Parse(tax, CultureInfo.GetCultureInfo("en-US")) + double.Parse(shipping, CultureInfo.GetCultureInfo("en-US")) + double.Parse(subtotal, CultureInfo.GetCultureInfo("en-US")) - double.Parse(discount, CultureInfo.GetCultureInfo("en-US"));
            var strTotal = total.ToString("0.00", CultureInfo.GetCultureInfo("en-US"));
    
    
            var updates = new AmountWithBreakdown()
            {
                CurrencyCode = paypalOrder.PurchaseUnits.First().AmountWithBreakdown.CurrencyCode,
                Value = strTotal,
                AmountBreakdown = new AmountBreakdown
                {
                    ItemTotal = new Money
                    {
                        CurrencyCode = cart.Currency.CurrencyCode,
                        Value = subtotal
                    },
                    Shipping = new Money
                    {
                        CurrencyCode = cart.Currency.CurrencyCode,
                        Value = shipping
                    },
                    TaxTotal = new Money
                    {
                        CurrencyCode = cart.Currency.CurrencyCode,
                        Value = tax
                    },
                }
            };
    
            var patches = new List<Patch<object>>
            {
                new Patch<object>
                {
                    Op= "replace",
                    Path= "/purchase_units/@reference_id=='default'/amount",
                    Value = updates
                }
            };
    
            return patches;
        }
    }
    
    Login or Signup to reply.
  2. I had this problem too and I looked to PayPalHttp.HttpClient source code and found the solution that working for me. Maybe this would be helpful for you.

    public async Task<UpdatePayPalV2CheckoutPaymentResponse> UpdatePayment(string orderId, decimal amount)
    {
        try
        {
            var request = new OrdersPatchRequest<object>(orderId);
    
            // This doesn't work bacause DataContractSerializer.
            // request.RequestBody(BuildPatchRequest(amount));
    
            var json = JsonConvert.SerializeObject(BuildPatchRequest(amount));
            request.Content = new StringContent(json, Encoding.UTF8, "application/json");
    
            await CreatePayPalClient().Execute(request);
        }
        catch (Exception e)
        {
            return new UpdatePayPalV2CheckoutPaymentResponse
            {
                Success = false,
                Message = e.Message
            };
        }
    
        return new UpdatePayPalV2CheckoutPaymentResponse
        {
            Success = true
        };
    }
    
    private static List<Patch<object>> BuildPatchRequest(decimal amount)
    {
        var patches = new List<Patch<object>>
        {
            new Patch<object>
            {
                Op = "replace",
                Path = "/purchase_units/@reference_id=='default'/amount",
                Value = new AmountWithBreakdown
                {
                    CurrencyCode = "USD",
                    Value = amount.ToString("F")
                }
            }
        };
    
        return patches;
    }
    
    private PayPalEnvironment CreatePayPalEnvironment()
    {
        PayPalEnvironment environment;
        if (_orderProcessingConfiguration.PayPalCheckoutConfiguration.Sandbox)
        {
            environment = new SandboxEnvironment(
                _orderProcessingConfiguration.PayPalCheckoutConfiguration.ClientId,
                _orderProcessingConfiguration.PayPalCheckoutConfiguration.ClientSecret
                );
        }
        else
        {
            environment = new LiveEnvironment(
                _orderProcessingConfiguration.PayPalCheckoutConfiguration.ClientId,
                _orderProcessingConfiguration.PayPalCheckoutConfiguration.ClientSecret
                );
        }
    
        return environment;
    }
    
    private PayPalHttp.HttpClient CreatePayPalClient()
    {
        return new PayPalHttpClient(CreatePayPalEnvironment());
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search