Yandex.Checkout.V3 icon indicating copy to clipboard operation
Yandex.Checkout.V3 copied to clipboard

Неверная сериализация в AsyncClient.CreatePayoutAsync

Open Ch0bits opened this issue 5 months ago • 0 comments

Столкнулся с проблемой, что у Юкассы в этом методе особо хитрое требование к формату валюты. Требуется два нуля после запятой, чего при обычной сериализации не бывает. Например если вызвать Serializer.SerializeObject(payout); То получится следующий JSON

{
  "amount": {
    "value": 169.0,  <== ТУТ
    "currency": "RUB"
  },
  "description": "Выплата",
  "metadata": {
    "paymentId": "08f2ac771d80496f91c083832bbfd54d",
    "payoutId": "03f3137e83d94d8494b70db54088bbaf",
    "salt": "ba6a6accd9844ce3af991465ccbdfe24"
  },
  "payout_token": "16VCK88aSGbyWsYpGhAa31QR.SC.003.202403",
  "deal": {
    "id": "dl-2e567c1f-0022-5000-8000-064e574a201a"
  }
}

Однако его отправка приводит к ошибке Yandex.Checkout.V3.YandexCheckoutException: Error in the payout amount. Specify the amount in the correct format. For example, 100.00 amount.value

Из-за это приходится использовать вот такой костыль)

    public async Task<Payout> CreatePayoutAsync(NewPayout payout, string idempotenceKey, CancellationToken ct)
    {
        // В клиенте есть нужный метод, но он вызывает ошибку
        // Yandex.Checkout.V3.YandexCheckoutException: Error in the payout amount. Specify the amount in the correct format. For example, 100.00 amount.value
        // return await _client.CreatePayoutAsync(payout, idempotenceKey, ct);
        // Последний раз проверял на версии 4.2.0
        var badJson = Serializer.SerializeObject(payout);

        // Надо поменять "value":4250.0, на "value":"4250.00",
        var start = badJson.IndexOf("\"value\":", StringComparison.InvariantCulture) + 8;
        var end = badJson.IndexOf(',', start);
        var amount = badJson.Substring(start, end - start);
        var requestJson = badJson.Replace(amount, $"\"{amount}0\"");
        if (badJson == requestJson)
        {
            throw new InvalidOperationException($"Nothing replaced. Amount={amount} Json={badJson}");
        }

        var authenticationString = $"{_options.ShopId}:{_options.SecretKey}";
        var base64String = Convert.ToBase64String(Encoding.ASCII.GetBytes(authenticationString));

        var request = new HttpRequestMessage(HttpMethod.Post, "https://api.yookassa.ru/v3/payouts")
        {
            Content = new StringContent(requestJson, Encoding.UTF8, "application/json"),
        };

        request.Headers.Authorization = new AuthenticationHeaderValue("Basic", base64String);
        request.Headers.Add("Idempotence-Key", idempotenceKey);

        using var httpClient = _httpClientFactory.CreateClient();
        var response = await httpClient.SendAsync(request, ct);
        var json = await response.Content.ReadAsStringAsync(ct);

        if (!response.IsSuccessStatusCode)
        {
            throw new InvalidOperationException($"Cannot create payout. Request={requestJson} Response={json}");
        }

        return Serializer.DeserializeObject<Payout>(json);
    }

Ch0bits avatar Sep 04 '24 08:09 Ch0bits