问题补丁订单金额明细 - Paypal Checkout NET SDK

Issue Patching Order Amount with Breakdown - Paypal Checkout NET SDK

我 运行 在尝试用更新的总计修补 PayPal 订单时遇到了麻烦。我正在使用他们在 GitHub 上提供的 PayPal Checkout-NET-SDK,但是他们为 Patch Order Sample 提供的示例文档有点过于简单: https://github.com/paypal/Checkout-NET-SDK/blob/develop/Samples/PatchOrderSample.cs

我正在尝试更新以下路径: /purchase_units/@reference_id=='default'/金额

我尝试使用将值设置为的组合:

当调用 API 并将 AmountWithBreakdown 对象指定为值时,我遇到了 .NET 异常:

类型 'PayPalCheckoutSdk.Orders.AmountWithBreakdown' 数据协定名称为 'AmountWithBreakdown:http://schemas.datacontract.org/2004/07/PayPalCheckoutSdk.Orders' 不是预期的。如果您正在使用 DataContractSerializer 或将任何静态未知类型添加到已知类型列表中,请考虑使用 DataContractResolver - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给序列化程序的已知类型列表中。

构建 PATCH 请求的示例函数:

 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

所有尝试将 JSON 手动构造为字符串并将其分配给值的尝试都会遇到通用的 INVALID_PARAMETER_SYNTAX 错误响应,尽管输出通过 JSON 验证工具。

是否有人使用此 SDK 通过 PayPal 成功更新了此数据点?我的实现在 VB 中,但我已经掌握了使用 C# 中的 SDK 实现所有其他功能的要点。

我 运行 遇到了同样的问题。

System.Runtime.Serialization.SerializationException:数据协定名称为“AmountWithBreakdown:http://schemas.datacontract.org/2004/07/PayPalCheckoutSdk.Orders' 的类型 'PayPalCheckoutSdk.Orders.AmountWithBreakdown' 不是预期的。如果您正在使用 DataContractSerializer 或将任何静态未知类型添加到已知类型列表中,请考虑使用 DataContractResolver - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给序列化程序的已知类型列表中。

调用从未到达 PayPal 以获得响应,因为它无法序列化请求。我能够让它工作的唯一方法是在没有 SDK 的情况下生成我自己的请求。这不是生产就绪代码。我只是想看看如果我自己设计请求是否可行,它确实可行。

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;
    }
}

我也遇到了这个问题,我查看了 PayPalHttp.HttpClient 源代码并找到了适合我的解决方案。也许这会对你有所帮助。

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());
}