From d48a2d696eee548925339c4c46c54462345033fb Mon Sep 17 00:00:00 2001 From: "gorbenko.pavel" Date: Wed, 12 Aug 2026 17:49:35 +0500 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D1=84=D0=B8=D0=BA=D1=88=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B1=D0=B0=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Reminders/ApprovalRow.cs | 43 +++++++++++++++++-- .../ReminderServiceTests.cs | 23 +++++++++- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/backend/Tnsu.ApprovalRoute.Application/Reminders/ApprovalRow.cs b/backend/Tnsu.ApprovalRoute.Application/Reminders/ApprovalRow.cs index 3fcf63f..dacb884 100644 --- a/backend/Tnsu.ApprovalRoute.Application/Reminders/ApprovalRow.cs +++ b/backend/Tnsu.ApprovalRoute.Application/Reminders/ApprovalRow.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.Text.Json; namespace Tnsu.ApprovalRoute.Application.Reminders; @@ -44,19 +45,53 @@ internal sealed record ApprovalRow( private static string? GetString(JsonElement e, string name) => e.TryGetProperty(name, out var v) && v.ValueKind == JsonValueKind.String ? v.GetString() : null; + /// + /// Целое из JSON — с поправкой на то, КАК SharePoint отдаёт Number-колонки. + /// + /// Одного TryGetInt32 здесь мало: у колонки типа Number значение приходит + /// дробным («1.0», а не «1»), а TryGetInt32 на числе с десятичной точкой + /// возвращает false — и поле молча становилось null. На фронтенде этой + /// проблемы нет вовсе: в JavaScript 1.0 и 1 — одно и то же число, поэтому + /// там те же данные читались верно, а на бэкенде терялись. + /// + /// Строку тоже принимаем: с odata=verbose (и у части полей) SharePoint + /// отдаёт числа строками. + /// private static bool TryGetInt(JsonElement e, string name, out int value) { value = 0; - return e.TryGetProperty(name, out var v) && v.ValueKind == JsonValueKind.Number && v.TryGetInt32(out value); + if (!e.TryGetProperty(name, out var v)) return false; + + if (v.ValueKind == JsonValueKind.Number) + { + if (v.TryGetInt32(out value)) return true; + if (!v.TryGetDouble(out var d) || d is < int.MinValue or > int.MaxValue) return false; + value = (int)Math.Round(d); + return true; + } + + if (v.ValueKind != JsonValueKind.String) return false; + if (!double.TryParse(v.GetString(), NumberStyles.Float, CultureInfo.InvariantCulture, out var parsed)) + return false; + if (parsed is < int.MinValue or > int.MaxValue) return false; + + value = (int)Math.Round(parsed); + return true; } private static bool TryGetBool(JsonElement e, string name, out bool value) { value = false; if (!e.TryGetProperty(name, out var v)) return false; - if (v.ValueKind is not (JsonValueKind.True or JsonValueKind.False)) return false; - value = v.GetBoolean(); - return true; + + if (v.ValueKind is JsonValueKind.True or JsonValueKind.False) + { + value = v.GetBoolean(); + return true; + } + + // Да/Нет-колонка тоже может прийти строкой («true»/«false») — см. TryGetInt. + return v.ValueKind == JsonValueKind.String && bool.TryParse(v.GetString(), out value); } private static DateTimeOffset? TryGetDate(JsonElement e, string name) => diff --git a/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/ReminderServiceTests.cs b/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/ReminderServiceTests.cs index 0d32178..3467c06 100644 --- a/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/ReminderServiceTests.cs +++ b/backend/tests/Tnsu.ApprovalRoute.IntegrationTests/ApplicationServices/ReminderServiceTests.cs @@ -54,7 +54,7 @@ public sealed class ReminderServiceTests : IClassFixture + string? date = null, string email = "approver@tnsu.kz", object? slaHours = null, bool? ask = null) => new { Id = id, @@ -207,6 +207,27 @@ public sealed class ReminderServiceTests : IClassFixture