⟨/⟩ 50_Domain/Export/CardExport.cs

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

using System;
using System.Collections.Generic;
using Ban.Sdaid.Notation.Documents;
using Ban.Sdaid.Icd.Domain.Cards;

namespace Ban.Sdaid.Icd.Domain.Export
{
    /// <summary>Как возникла выгрузка.</summary>
    public enum ExportOrigin
    {
        /// <summary>При создании информационной карты — обычный путь.</summary>
        CardCreation,

        /// <summary>По команде администратора из реестра карт — файл понадобился заново.</summary>
        Manual,
    }

    /// <summary>Выгрузка — сформированный файл для загрузки в АБИС и его состав.</summary>
    [DomainEntity]
    public class CardExport
    {
        /// <summary>Идентификатор выгрузки.</summary>
        public Guid Id { get; init; }

        /// <summary>Момент формирования файла.</summary>
        public DateTime CreatedAt { get; init; }

        /// <summary>Пользователь, чьё действие привело к формированию файла.</summary>
        public Guid CreatedByUserId { get; init; }

        /// <summary>Как возникла выгрузка: при создании карты или по команде администратора.</summary>
        [Relation]
        public ExportOrigin Origin { get; init; }

        /// <summary>Код формата обмена, в котором сформирован файл.</summary>
        public string FormatCode { get; init; } = string.Empty;

        /// <summary>Имя файла — то, по чему его опознают снаружи Сервиса.</summary>
        public string FileName { get; init; } = string.Empty;

        /// <summary>Ключ файла в хранилище.</summary>
        public string StorageKey { get; init; } = string.Empty;

        /// <summary>Карты, вошедшие в файл; при выгрузке по созданию — одна.</summary>
        [Relation(Min = 1)]
        public IReadOnlyList<InformationCard> Cards { get; init; } = new InformationCard[0];
    }

    /// <summary>Описание доменной сущности <see cref="CardExport"/>.</summary>
    public class CardExportSpec : IDomainEntityDocument, IHasStructuralLinks
    {
        public Type Entity => typeof(CardExport);

        /// <summary>Display-текст для типизированных ссылок <c>SdaidAnchors.RefTo&lt;CardExportSpec&gt;()</c>.</summary>
        public static string _refName = "выгрузка";

        public string Name => "Выгрузка";

        public string Description =>
            @"Сформированный файл для загрузки в АБИС: когда сформирован, из каких карт, в каком формате и где лежит.";

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

        public string[] Comments => new[]
        {
            "2026-08-28. Заведена по запросу на изменение «Выгрузка в АБИС без отбора выборки».",
        };

        public SdaidLink[] Links => new[]
        {
            Rel.Realizes<Ban.Sdaid.Icd.Arch.Adr.ADR_013_ExportFileOnCardCreation>(),
        };

        public static string S1_Purpose = $"""
            ## Назначение

            Выгрузка — **факт того, что файл сформирован**, и всё, что о нём известно: момент, состав,
            формат, место в хранилище. Дальше файл живёт вне Сервиса: он его кладёт, а не отправляет,
            и судьбы его не наблюдает
            ({SdaidAnchors.RefTo<Ban.Sdaid.Icd.Arch.Adr.ADR_013_ExportFileOnCardCreation>()}).

            Обычный путь — формирование при создании карты, без отдельного действия пользователя.
            Реже файл понадобится заново: прежний утрачен или испорчен, и администратор формирует
            его повторно из реестра карт. Обе выгрузки устроены одинаково и различаются только
            происхождением.

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

        public static string S2_Composition = """
            ## Состав

            В выгрузку входит одна карта или несколько — это зависит от формата обмена, а не
            от устройства модели. Формат, допускающий файл на карту, даёт выгрузки из одной записи;
            формат, требующий пачку, — из многих.

            Связь с картами **многие ко многим**: карта может входить в несколько выгрузок, если
            файл формировался повторно. Дата выгрузки в самой карте — отметка «файл сформирован»
            и указывает на последнюю по времени; это проекция для реестра, источник истины —
            выгрузка.
            """;

        public static string S3_Invariants = """
            ## Инварианты

            - Выгрузка не создаётся пустой: как минимум одна карта.
            - Запись появляется **после** того, как файл сформирован. Незавершённой выгрузки
              не существует, состояний у неё нет.
            - Момент, состав и файл не меняются: понадобился новый файл — заводится новая выгрузка,
              прежняя остаётся как была.
            - В выгрузку входят только созданные карты. Другой и не бывает: неполной карты
              не существует.
            """;

        public static string S4_Failure = """
            ## Если файл не сформировался

            Записи не появляется, и карта остаётся непомеченной. Создание карты при этом не
            отменяется: работа оператора не должна пропадать из-за сбоя записи файла.

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