⟨/⟩ Nts/35_ChangeRequests/DOC_CR_2026_10_30_ApplyModificationTriggersRecalc.cs

133 строк · в начало

using Rugrid.Sdaid.Notation.Documents;

namespace Rugrid.Sdaid.Epas.Nts.ChangeRequests
{
    /// <summary>
    /// «Применить» в окне подбора модификаций должно запускать безусловный пересчёт, как любой
    /// другой триггер (приём данных из АИС) — сейчас прототип вместо этого сбрасывает результат
    /// расчёта в «не выполнялся». Заодно правится устаревшая формулировка правила 8
    /// `ModificationSelectionModal.cs`, не переживившая более раннюю правку «расчёт безусловен».
    /// </summary>
    public class DOC_CR_2026_10_30_ApplyModificationTriggersRecalc : IChangeRequestDocument, IHasStructuralLinks, IFolder<NtsChangeRequestsFolder>
    {
        public SdaidLink[] Links => new[]
        {
            Rel.Uses<Rugrid.Sdaid.Epas.Nts.Ui.DOC_ModificationSelectionModal>(),
            Rel.Uses<Rugrid.Sdaid.Epas.Nts.Backend.Calc.DOC_CalcValidators>(),
            Rel.Uses<Rugrid.Sdaid.Epas.Nts.Backend.Calc.DOC_ProcessingStatusPolicy>(),
        };

        public static string _refName = "CR 2026-10-30: «Применить» запускает пересчёт";

        public string Name => "«Применить» в окне подбора модификаций запускает пересчёт";

        public string Description =>
            @"После «Применить» в окне подбора модификаций статус расчёта и статус обработки ТС
            сбрасываются в «не выполнялся», хотя подбор прошёл успешно и данные для расчёта полны.
            Нужен безусловный пересчёт — тем же путём, что и после приёма данных из АИС.";

        public string Version => "0.1";
        public string Status => "done";
        public string[] Comments => new string[0];

        public static string Source = """"
            ## Источник (как есть)

            По итогам ручного тестирования карточки ТС (Уаз-31512): пользователь открыл окно
            подбора модификаций, выбрал единственную подходящую модификацию и нажал «Применить» —
            способ подбора стал «эксперт», статус подбора «Определена», базовая норма заполнена.
            Все обязательные для расчёта поля (включая дату начала эксплуатации) заданы. При этом
            Статус расчёта стал серым «Не выполнен», Статус обработки — серым «Не выполнена»
            («Расчёт ещё не выполнялся»), хотя до открытия окна подбора расчёт мог быть успешным.

            Причина в прототипе: обработчик `onApply` (`Ntr/65_Ui/html/shell.js:2356-2359`) вызывает
            `renderNorm()` и `resetCalculationState()` — не `computeNorm()`. `resetCalculationState()`
            (`shell.js:1909-1918`) принудительно обнуляет результат и ставит «Не выполнен».
            """";

        public static string Analysis = """"
            ## Разбор

            Ни {{SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Ui.DOC_ModificationSelectionModal>()}}
            (правило 7 «Применить»), ни
            {{SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Backend.Calc.DOC_AisRefreshPolicy>()}} не
            описывали, что должно происходить со статусом расчёта после ручного применения
            модификации — `AisRefreshPolicy` по названию и назначению ограничена реакцией на приём
            данных из АИС (два триггера: первый приём, «Обновить из АИС»), «Применить» в окне
            подбора — третий, самостоятельный триггер того же действия, не относящийся к АИС.

            Решение: «Применить» запускает расчёт безусловно — тем же механизмом, что и любой
            другой пересчёт (валидаторы секций {{SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Backend.Calc.DOC_CalcValidators>()}}
            либо дают результат, либо классифицированную ошибку). Это не расширение
            `AisRefreshPolicy` на чужой для неё триггер, а отдельное, явное правило в
            `ModificationSelectionModal.cs` — у расчёта нет единого «диспетчера триггеров» в спеке,
            и вводить его ради этого одного случая избыточно; у каждого триггера — своё правило в
            своём документе, принцип безусловности общий и описан один раз в `DOC_CalcValidators`.

            Попутно найдена и правится устаревшая формулировка. Правило 8 «Пустая группа»
            (`ModificationSelectionModal.cs`) всё ещё гласит: «расчёт без базовой нормы не
            выполняется вовсе, а не завершается ошибкой» — это текст из модели ДО перехода на
            безусловный расчёт (правка сессии 2026-10-29 в `AisRefreshPolicy.cs`/
            `ProcessingStatusPolicy.cs`/`VehicleCard.cs`), который не был обновлён в этом файле.
            Актуально: расчёт запускается безусловно и в этом случае, валидатор секции
            `fuel.base_norm` возвращает ошибку «Базовая норма не определена», статус расчёта —
            «Выполнен с ошибкой», статус обработки — «Нет модификаций»
            ({{SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Backend.Calc.DOC_ProcessingStatusPolicy>()}},
            правило 2).
            """";

        public static string BlastRadius = """"
            ## Blast radius

            ### Спецификация

            | Документ | Правка |
            |---|---|
            | {{SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Ui.DOC_ModificationSelectionModal>()}} | правило 7 «Применить» — добавить безусловный запуск расчёта; правило 8 «Пустая группа» — убрать устаревшее «расчёт не выполняется вовсе», согласовать с безусловной моделью |

            ### Прототип

            | Файл | Правка |
            |---|---|
            | `Ntr/65_Ui/html/shell.js:2356-2359` | обработчик `onApply` — заменить `resetCalculationState()` на `computeNorm()` |
            """";

        public static string Plan = """"
            ## План

            1. `ModificationSelectionModal.cs` — правило 7: добавить предложение о безусловном
               запуске расчёта после «Применить».
            2. `ModificationSelectionModal.cs` — правило 8: убрать «расчёт не выполняется вовсе»,
               заменить на согласованную с `ProcessingStatusPolicy` формулировку (ошибка валидатора,
               «Выполнен с ошибкой», «Нет модификаций»).
            3. `shell.js` — обработчик `onApply`: `computeNorm()` вместо `resetCalculationState()`.
            4. Собрать (`dotnet build`, `build-html.cmd`), проверить `testovich` реальным
               выполнением на Уаз-31512 (или эквивалентном сценарии: применить единственную
               модификацию при уже полных данных — статус расчёта должен стать «Успешно выполнен»,
               не «Не выполнен»).
            5. Зафиксировать «Итог».
            """";

        public static string Acceptance = """"
            ## Acceptance criteria

            - **AC-1.** После «Применить» в окне подбора модификаций (способ «эксперт», статус
              подбора «Определена» или «Определена группа») расчёт запускается безусловно, статус
              расчёта отражает его фактический результат — не сбрасывается в «Не выполнен».
            - **AC-2.** Если применённый отбор даёт «Не определена» (пустая группа) — расчёт всё
              равно запускается, валидатор `fuel.base_norm` возвращает «Базовая норма не
              определена», статус расчёта «Выполнен с ошибкой», статус обработки «Нет
              модификаций» — не «Не выполнена».
            """";

        public static string Result = """"
            ## Итог

            Реализовано и проверено `testovich` реальным выполнением (jsdom, Уаз-31512):
            AC-1 и AC-2 подтверждены буквально. «Применить» при успешном подборе даёт «Успешно
            выполнен»/«Завершена»; при пустой группе — «Выполнен с ошибкой» («Базовая норма не
            определена»)/«Нет модификаций». Расхождений спека↔код не найдено.
            """";
    }
}