namespace Tnsu.ApprovalRoute.Application.Reports; /// /// Отчёт по вакансиям за период — ровно то, что ложится на лист «Список вакансий /// (все)» в xlsx: интервал плюс вакансии, разбитые по объектам/проектам. /// public sealed record VacancyReport(DateOnly From, DateOnly To, IReadOnlyList Groups); /// /// Объект/проект и его вакансии. Имя группы становится строкой-разделителем на /// листе (как «КЭС КУРЧАТОВ» в образце отчёта); пустое имя — вакансии, у которых /// объект в заявке не указан, они идут первым блоком без разделителя. /// public sealed record VacancyReportGroup(string Name, IReadOnlyList Rows); /// /// Одна ВАКАНСИЯ (заявка на подбор). Поля этой записи — ОБЩИЕ для всех её строк /// на листе, там они объединяются по вертикали; то, что различается от приёма к /// приёму, лежит в Lines. /// /// Колонки нумерации, «в работе», «срок отработки» и итоги здесь не хранятся: /// их считает сам xlsx формулами, чтобы цифры пересчитывались, если строку в /// файле поправят руками. /// public sealed record VacancyReportRow( // «Вакансия» — должность из заявки на подбор. string Position, // «Подразделение» ответственного за подачу заявки. string? Department, // «Кол-во вакансий». int VacanciesCount, // «количество закрытых вакансий»: сколько заявок на приём завели по этой заявке на подбор. int ClosedCount, // «Дата подачи заявки». DateOnly? SubmitDate, // «Дата закрытия вакансии»: дата решения по последнему шагу исполнения. DateOnly? ClosingDate, // «Инициатор заявки». string? Initiator, // «Закрыта вакансия»: да / нет / частично. string ClosedFlag, // «Рекрутер»: исполнитель фазы исполнения заявки на подбор. string? Recruiter, // Строки листа по этой вакансии — ВСЕГДА не меньше одной (см. VacancyReportLine). IReadOnlyList Lines); /// /// Одна СТРОКА ЛИСТА в пределах вакансии — то, что различается между её строками. /// Обычно это один приём: на заявку на подбор «Разнорабочий, 4 вакансии» /// приходится четыре заявки на приём, у каждой свой кандидат, своя дата выхода и /// свой «взамен кого». /// /// Именно СТРОКА, а не «приём»: у вакансии, по которой приёмов ещё нет (или все /// отклонены), строка всё равно одна — с пустыми ФИО и датой выхода, но с /// заполненным «Вместо сотрудника» из причины открытия вакансии. Реальное число /// приёмов лежит в VacancyReportRow.ClosedCount, так что информация не теряется. /// public sealed record VacancyReportLine( // «Ф.И.О. нанимаемого сотрудника» — кандидат из заявки на приём. string? CandidateName, // «Дата выхода» — дата приёма этого кандидата. DateOnly? StartDate, // «Вместо сотрудника Ф.И.О.». string? ReplacedEmployee); /// Значения колонки O. «Пауза» из образца отчёта не выводится — такого статуса в заявке нет. public static class VacancyClosedFlags { public const string Yes = "да"; public const string No = "нет"; public const string Partial = "частично"; }