feat(отчёт): строка на каждый приём + столбец «Ф.И.О. нанимаемого сотрудника»
На одну заявку на подбор приходится несколько заявок на приём («Разнорабочий, 4 вакансии» → 4 кандидата), и раньше они схлопывались в одну строку: ФИО не было вовсе, а «Дата выхода» показывала только САМУЮ ПОЗДНЮЮ из четырёх. Кто именно вышел и когда — из отчёта было не узнать. Теперь вакансия занимает столько строк, сколько по ней приёмов. Построчные колонки — «Дата выхода», новая «Ф.И.О. нанимаемого сотрудника» и «Вместо сотрудника Ф.И.О.» (у каждого приёма своё «взамен кого»); все остальные общие и объединяются по вертикали. Модель: VacancyReportRow.Lines — именно СТРОКИ ЛИСТА, а не «приёмы». У вакансии без приёмов строка всё равно одна (иначе она пропала бы из отчёта), с пустыми ФИО и датой, но с «Вместо сотрудника» из причины открытия вакансии — прежнее поведение сохранено. Реальное число приёмов осталось в ClosedCount. Отклонённые приёмы теперь отбрасываются целиком, а не только из счётчика: отдельная строка с ФИО отклонённого кандидата утверждала бы «вот кого приняли». Объединение заводится только при lineCount > 1 — область 1×1 Excel считает некорректной и портит файл. Значение общих колонок пишется ТОЛЬКО в первую строку: у объединённой области Excel хранит его в верхней левой ячейке, а дубли сломали бы SUM в итогах (посчитал бы вакансию по разу на каждый приём) — на это есть отдельный тест. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,33 +14,54 @@ public sealed record VacancyReport(DateOnly From, DateOnly To, IReadOnlyList<Vac
|
||||
public sealed record VacancyReportGroup(string Name, IReadOnlyList<VacancyReportRow> Rows);
|
||||
|
||||
/// <summary>
|
||||
/// Одна вакансия — строка листа. Колонки A/B (нумерация), G (в работе), J (срок
|
||||
/// отработки) и итоги здесь не хранятся: их считает сам xlsx формулами, чтобы
|
||||
/// цифры пересчитывались, если строку в файле поправят руками.
|
||||
/// Одна ВАКАНСИЯ (заявка на подбор). Поля этой записи — ОБЩИЕ для всех её строк
|
||||
/// на листе, там они объединяются по вертикали; то, что различается от приёма к
|
||||
/// приёму, лежит в Lines.
|
||||
///
|
||||
/// Колонки нумерации, «в работе», «срок отработки» и итоги здесь не хранятся:
|
||||
/// их считает сам xlsx формулами, чтобы цифры пересчитывались, если строку в
|
||||
/// файле поправят руками.
|
||||
/// </summary>
|
||||
public sealed record VacancyReportRow(
|
||||
// C — «Вакансия»: должность из заявки на подбор.
|
||||
// «Вакансия» — должность из заявки на подбор.
|
||||
string Position,
|
||||
// D — «Подразделение» ответственного за подачу заявки.
|
||||
// «Подразделение» ответственного за подачу заявки.
|
||||
string? Department,
|
||||
// E — «Кол-во вакансий».
|
||||
// «Кол-во вакансий».
|
||||
int VacanciesCount,
|
||||
// F — «количество закрытых вакансий»: сколько заявок на приём завели по этой заявке на подбор.
|
||||
// «количество закрытых вакансий»: сколько заявок на приём завели по этой заявке на подбор.
|
||||
int ClosedCount,
|
||||
// H — «Дата подачи заявки».
|
||||
// «Дата подачи заявки».
|
||||
DateOnly? SubmitDate,
|
||||
// I — «Дата закрытия вакансии»: дата решения по последнему шагу исполнения.
|
||||
// «Дата закрытия вакансии»: дата решения по последнему шагу исполнения.
|
||||
DateOnly? ClosingDate,
|
||||
// K — «Дата выхода»: самая поздняя дата приёма среди принятых по этой вакансии.
|
||||
DateOnly? StartDate,
|
||||
// L — «Инициатор заявки».
|
||||
// «Инициатор заявки».
|
||||
string? Initiator,
|
||||
// M — «Вместо сотрудника Ф.И.О.».
|
||||
string? ReplacedEmployee,
|
||||
// O — «Закрыта вакансия»: да / нет / частично.
|
||||
// «Закрыта вакансия»: да / нет / частично.
|
||||
string ClosedFlag,
|
||||
// P — «Рекрутер»: исполнитель фазы исполнения заявки на подбор.
|
||||
string? Recruiter);
|
||||
// «Рекрутер»: исполнитель фазы исполнения заявки на подбор.
|
||||
string? Recruiter,
|
||||
// Строки листа по этой вакансии — ВСЕГДА не меньше одной (см. VacancyReportLine).
|
||||
IReadOnlyList<VacancyReportLine> Lines);
|
||||
|
||||
/// <summary>
|
||||
/// Одна СТРОКА ЛИСТА в пределах вакансии — то, что различается между её строками.
|
||||
/// Обычно это один приём: на заявку на подбор «Разнорабочий, 4 вакансии»
|
||||
/// приходится четыре заявки на приём, у каждой свой кандидат, своя дата выхода и
|
||||
/// свой «взамен кого».
|
||||
///
|
||||
/// Именно СТРОКА, а не «приём»: у вакансии, по которой приёмов ещё нет (или все
|
||||
/// отклонены), строка всё равно одна — с пустыми ФИО и датой выхода, но с
|
||||
/// заполненным «Вместо сотрудника» из причины открытия вакансии. Реальное число
|
||||
/// приёмов лежит в VacancyReportRow.ClosedCount, так что информация не теряется.
|
||||
/// </summary>
|
||||
public sealed record VacancyReportLine(
|
||||
// «Ф.И.О. нанимаемого сотрудника» — кандидат из заявки на приём.
|
||||
string? CandidateName,
|
||||
// «Дата выхода» — дата приёма этого кандидата.
|
||||
DateOnly? StartDate,
|
||||
// «Вместо сотрудника Ф.И.О.».
|
||||
string? ReplacedEmployee);
|
||||
|
||||
/// <summary>Значения колонки O. «Пауза» из образца отчёта не выводится — такого статуса в заявке нет.</summary>
|
||||
public static class VacancyClosedFlags
|
||||
|
||||
Reference in New Issue
Block a user