⟨/⟩ 50_Domain/Cards/Template/Vocabularies/VocabularyCatalog.cs

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

using Ban.Sdaid.Notation.Documents;

namespace Ban.Sdaid.Icd.Domain.Cards.Template.Vocabularies
{
    /// <summary>
    /// Каталог справочников, переданных заказчиком: что за справочник, к какому полю бланка
    /// относится, из каких значений состоит.
    /// </summary>
    public class VocabularyCatalog : ISdaidDocument, IHasStructuralLinks
    {
        public static string _refName = "каталог справочников";

        public string Name => "Справочники заказчика";

        public string Description =>
            @"Что передал заказчик для полей информационной карты, значения которых берутся из справочника, а не вписываются произвольным текстом.";

        public string Version => "0.2";
        public string Status => "draft";

        public string[] Comments => new[]
        {
            "2026-08-27. Заведён по материалам заказчика: 19 файлов .mnu и список пользователей.",
            "2026-08-27. Добавлено, как справочники ложатся в модель: типом значения, значения — в ограничениях.",
        };

        public SdaidLink[] Links => new[]
        {
            Rel.Uses<AttributeValueTypeSpec>(),
            Rel.Uses<FormFieldSpec>(),
        };

        public static string S1_Purpose = $"""
            ## Зачем это

            Бумажный бланк заполняется от руки, и написать в поле можно что угодно. Но часть полей —
            это отметка в клетке с напечатанной подписью: «Кожа», «Пергамент», «Ткань». Такое значение
            переносится в электронную карту не как текст, а как **значение справочника**: у него есть
            код, и в АБИС уходит именно код.

            Заказчик передал справочники в том виде, в каком они ведутся в его системе. Здесь описано,
            что именно передано и к каким полям относится; сами файлы лежат в `Vocabularies/Source/`.

            Вид значения атрибута «выбор из справочника» описан
            в {SdaidAnchors.RefTo<AttributeValueTypeSpec>()}; критерий «справочник или перечисление» —
            там же.
            """;

        public static string S2_Format = """
            ## Формат файлов

            Файлы `.mnu` — меню АБИС ИРБИС: обычный текст в кодировке **cp1251**, строки идут парами
            (код, затем значение), последняя строка — терминатор `*****`.

            ```
            a
            Кожа
            b
            Пергамент
            *****
            ```

            **Код — часть данных, а не порядковый номер.** Это буква подполя в записи ИРБИС: `a`, `b`,
            `c`, у исполнителей — инициалы (`КИН`), у экспертов — кириллические буквы (`Х`, `К`, `Б`),
            у языков — трёхбуквенный код (`rus`, `jpn`). Коды переиспользуются между справочниками
            и означают в каждом своё, поэтому уникальны только внутри своего справочника.

            Значение `0` («Ничего», «Нет тиснения», «Отсутствует») — не пустота, а **явное «ничего
            не отмечено»**: сотрудник посмотрел и зафиксировал отсутствие. От незаполненного поля
            оно отличается так же, как «Б.и.» отличается от пустого издательства.
            """;

        public static string S3_Catalog = """
            ## Что передано

            Девятнадцать справочников. Все относятся к форме ИК на издание: восемнадцать — к листу 2
            «Сохранность», один (язык издания) — к листу 1.

            | Файл | Справочник | Поле бланка | Значений | «Ничего» |
            |---|---|---|---|---|
            | `sost1.mnu` | Состояние переплёта | Переплёт → Состояние | 5 | нет |
            | `sostav.mnu` | Состав переплёта | Переплёт → Состав | 3 | `0` Ничего |
            | `matpok.mnu` | Материалы покрытия | Переплёт → Материалы покрытия | 6 | `0` Отсутствует |
            | `matosn.mnu` | Материалы основы | Переплёт → Материалы основы | 5 | `0` Без основы |
            | `dekor1.mnu` | Тиснение | Переплёт → Декор → Тиснение | 4 | `0` Нет тиснения |
            | `dekor2.mnu` | Украшения | Переплёт → Декор → Украшения | 5 | `0` Нет украшений |
            | `dekor3.mnu` | Обрез | Переплёт → Декор → Обрез | 6 | `0` Нет обреза |
            | `fismat1.mnu` | Физико-механические повреждения переплёта | Переплёт → Повреждения | 11 | `0` Ничего |
            | `sost2.mnu` | Состояние блока | Блок → Состояние | 4 | `0` Ничего |
            | `tet.mnu` | Состояние тетрадей | Блок → Тетради | 4 | `0` Ничего |
            | `list.mnu` | Состояние листов | Блок → Листы | 3 | `0` Ничего |
            | `fismat2.mnu` | Физико-механические повреждения блока | Блок → Повреждения | 10 | `0` Ничего |
            | `mib.mnu` | Микробиологические повреждения | Повреждения → Биологические | 5 | `0` Нет |
            | `enm.mnu` | Энтомологические повреждения | Повреждения → Биологические | 5 | `0` Нет |
            | `stpov.mnu` | Степень повреждения | Степень повреждения (шесть мест на листе) | 4 | `0` Ничего |
            | `exp.mnu` | Роль эксперта | Эксперт → роль | 3 | нет |
            | `isp.mnu` | Исполнители | Мониторинг → Исполнитель; Эксперт → ФИО | 16 | нет |
            | `jz.mnu` | Языки | лист 1 → Язык издания | 589 | нет |

            `dekor3.mnu` перечислен как «Обрез», хотя часть его значений («Золото», «Тиснение»)
            совпадает по словам с тиснением переплёта — коды у них разные, и это разные справочники.
            """;

        public static string S35_Model = $"""
            ## Как это ложится в модель

            Каждый файл становится **типом значения**
            ({SdaidAnchors.RefTo<AttributeValueTypeSpec>()}) вида «выбор из перечисления»:
            имя типа — из названия справочника, значения — парами «код — значение»
            в ограничениях. Отдельного хранилища значений не заводим — почему именно так
            и когда это изменится, сказано там же.

            Поле бланка ссылается на тип не напрямую, а через атрибут вида документа: тип
            выбирают, описывая атрибут. Поэтому один тип обслуживает столько полей, сколько нужно:
            `stpov` — шесть мест на листе сохранности, `isp` — и мониторинг, и таблицу экспертов.

            **Заведение справочников — наполнение данными, а не правка кода.** Ни новых сущностей,
            ни миграций: типы значений и виды документов заводятся до начала оцифровки, вместе
            с формами.

            Исключение одно — `jz.mnu`: 589 языков в ограничениях типа вести нельзя. Это первый
            кандидат на вид «выбор из справочника», и хранилище значений появится тогда же,
            когда за него возьмёмся.
            """;

        public static string S4_Users = """
            ## Пользователи БАН

            Отдельный файл `Пользователи БАН.docx` — не справочник значений поля. Это соответствие
            **учётной записи АБИС месту хранения и фонду**: одиннадцать записей вида
            `RADZSZ → ОФО, Радзивиллы Славянский фонд`, `BINKS → БИН, фонд по консервации
            и сохранности`.

            Он отвечает на вопрос, откуда берётся место хранения — обязательный реквизит карты,
            которого на бланке нет и который подставляется из профиля пользователя. То есть это
            материал сразу к двум вещам: к справочнику мест хранения и к настройке профиля.
            """;

        public static string S5_Observations = """
            ## Что видно по материалам

            **Справочники частично дублируют друг друга.** `fismat1` и `fismat2` различаются одним
            значением («Оторван» есть у переплёта, у блока нет); `sost1` и `sost2` — тем же способом.
            Заказчик ведёт их как разные меню, потому что в его системе меню привязано к полю.
            Соединять их в один справочник с ограничением по полю — решение, которое надо принимать
            осознанно: список значений тогда придётся фильтровать на каждом поле.

            **Бланк и справочник расходятся.** В `fismat1` есть «Общие загрязнения», на бланке
            инв. 74870 такой клетки нет. Бланки разных редакций печатались с разным набором клеток,
            а справочник один и накопительный. Значит распознавание опирается на **состав формы**,
            а не на состав справочника: справочник говорит, какие значения бывают, форма — какие
            клетки есть на этом листе.

            **Один справочник — много полей.** `stpov` используется на листе 2 шесть раз, `isp` —
            и в мониторинге, и в таблице экспертов. Это ровно тот случай, ради которого справочник
            отделён от перечисления.

            **Исполнители — живые данные.** `isp.mnu` состоит из фамилий сотрудников. Состав меняется,
            это персональные данные, и в отличие от материалов покрытия такой справочник кто-то ведёт
            постоянно.

            **Опечатки заказчика сохранены.** В `mib.mnu` — «микробиолиогических», в `sost1.mnu` —
            двойной пробел в «Не  поврежден». Правим при загрузке или оставляем как есть — вопрос
            к заказчику; молча менять переданные данные не следует.
            """;

        public static string S55_Decisions = """
            ## Принятые решения

            **Близкие справочники держим раздельно, как передано.** `fismat1` и `fismat2`
            различаются одним значением, `sost1` и `sost2` — тем же способом. Соединять их
            в один набор и отбирать часть значений на каждом поле означало бы завести механизм
            фильтрации, которого в модели нет, ради экономии двух записей. Тип значения стоит
            дёшево — пусть их будет два.

            **Значение «Ничего» — обычное значение набора.** `0` «Нет тиснения», «Отсутствует»,
            «Без основы» хранится наравне с остальными, отдельного признака «это пустышка» нет.
            Поле с «Нет тиснения» заполнено во всех смыслах: ни проверка обязательности, ни
            выгрузка, ни показ его не различают, а признак, который нигде не читается, заводить
            незачем. Пустое поле по-прежнему означает «значение не указано».
            """;

        public static string S6_OpenQuestions = """
            ## Открытые вопросы

            | № | Вопрос |
            |---|---|
            | OQ-VC-1 | Справочники переданы к форме ИК на издание. Действуют ли те же значения для рукописи и графики, или для них будут свои файлы |
            | OQ-VC-2 | Обязан ли Сервис сохранять коды ИРБИС при выгрузке в АБИС, или достаточно совпадения значений |
            | OQ-VC-4 | Кто ведёт справочники после запуска: сопровождение, экран Сервиса или синхронизация из ИРБИС. Вопрос внутренний, не к заказчику: ему безразличен способ ведения |
            | OQ-VC-5 | Исправлять ли опечатки в переданных значениях |
            | OQ-VC-6 | Место хранения: справочник строится по файлу пользователей, или заказчик передаст его отдельно |
            """;
    }
}