Механизм формирования отчетов по отпускам сотрудников и их корректировка
Текст написан ИИ при решении конкретной задачи по корректировке использованных отпусков. Необходимо было дополнить записи об упущенных отпусках прошлых периодов, проведенных в старых версиях 1С и корректировке периодов отпусков в текущей программе.
Введение
В конфигурации 1С:Зарплата и Управление Персоналом (ЗУП) механизм формирования отчетов по отпускам сотрудников построен на динамическом формировании данных из различных источников. В отличие от классических подходов, где данные хранятся в регистрах, здесь используется гибридная модель: часть данных хранится в регистрах, а часть формируется динамически при формировании отчетов.
Архитектура хранения данных об отпусках
1. Регистр сведений «ДанныеОтпусковКарточкиСотрудника»
Характеристики регистра:
- Тип: Регистр сведений
- Периодичность: Непериодический
- Режим записи: Независимый (Independent)
- Назначение: Хранение данных об отпусках для карточек сотрудников
Структура регистра:
- Измерения:
Сотрудник— ссылка на справочник СотрудникиПериодЗаписи— дата записи (используется для фильтрации по периоду)
- Ресурсы и реквизиты:
ДокументОснование— документ, на основании которого предоставлен отпускВидОтпуска— вид отпуска (ссылка или представление)РабочийПериодС,РабочийПериодПо— рабочий период, за который предоставлен отпускКоличествоДней— количество дней отпускаДатаНачала,ДатаОкончания— период отсутствияОснование— текстовое основание отпуска- И другие поля
Особенности заполнения:
Регистр заполняется не через движения документов, а через специальные процедуры. Это означает, что данные могут быть записаны как при проведении документов, так и в процессе регламентных операций или корректировок.
Важно понимать:
- Регистр НЕ формируется динамически — записи сохраняются в базе данных
- Регистр непериодический — одна запись может существовать неограниченное время
- Регистр независимый — записи не удаляются автоматически при отмене проведения документов
- Ключ записи:
Сотрудник+ПериодЗаписи— определяет уникальность записи - При записи новой записи с тем же ключом старая запись заменяется, а не добавляется новая
Механизм заполнения регистра «ДанныеОтпусковКарточкиСотрудника»
Регистр заполняется через механизм обработчиков правил регистрации для независимых регистров.
1. Регистрация обработчика
Модуль: InformationRegisters/ДанныеОтпусковКарточкиСотрудника/Ext/ManagerModule.bsl
#Область ОбработчикиПравилРегистрации
// См. ЗарплатаКадрыРасширенныйСинхронизацияДанных.ШаблонОбработчика
Процедура ПриЗаполненииНастроекОбработчиковПравилРегистрации(Настройки) Экспорт
ЗарплатаКадрыРасширенныйСинхронизацияДанных.ДляНезависимогоРегистра(Настройки,
Метаданные.РегистрыСведений.ДанныеОтпусковКарточкиСотрудника.Измерения.Сотрудник,
"РегламентированныеДанные");
КонецПроцедуры
#КонецОбласти
Что происходит:
- Регистр регистрирует обработчик правил регистрации через модуль
СинхронизацияДанныхБЗКПравилаНезависимыеРегистры - Обработчик настроен на отслеживание изменений по измерению
Сотрудник - Раздел данных:
РегламентированныеДанные
2. Регистраторы, влияющие на заполнение
Определенный тип: РегистраторыПериодовОтпусковКарточкиСотрудника
Включает следующие документы:
Документ.ОтпускДокумент.ОтпускБезСохраненияОплатыДокумент.ОтпускаСотрудниковДокумент.ОтпускПоУходуЗаРебенкомДокумент.БольничныйЛистДокумент.УвольнениеДокумент.УвольнениеСпискомДокумент.СторнированиеНачисленийДокумент.ПереносДанных
3. Механизм синхронизации данных
Модуль: CommonModules/СинхронизацияДанныхБЗКПравилаНезависимыеРегистры/Ext/Module.bsl
// См. ЗарплатаКадрыРасширенныйСинхронизацияДанных.ШаблонОбработчикаПослеОбработки
Процедура ПослеОбработкиПравилаРегистрации(Объект, Отказ, Параметры) Экспорт
ИмяПроцедуры = "СинхронизацияДанныхБЗКОбработчикиНезависимыеРегистры.ПослеОбработкиПравилаРегистрации";
ТекстОшибки = НСтр("ru = 'В параметре Параметры.ДополнительныеПараметры отсутствует свойство ""Данные""'");
ОбщегоНазначенияКлиентСервер.Проверить(Параметры.ДополнительныеПараметры.Свойство("Данные"), ТекстОшибки,
СтрШаблон(НСтр("ru = '%1'"), ИмяПроцедуры));
Данные = Параметры.ДополнительныеПараметры.Данные;
ОжидаемыеТипы = ОбщегоНазначенияБЗККлиентСервер.ЗначенияВМассиве(Тип("Строка"), Тип("ОбъектМетаданных"));
ОбщегоНазначенияКлиентСервер.ПроверитьПараметр(ИмяПроцедуры, "Данные", Данные, ОжидаемыеТипы);
Если ТипЗнч(Данные) = Тип("Строка") Тогда
ИмяДанных = Данные;
ИначеЕсли ТипЗнч(Данные) = Тип("ОбъектМетаданных") Тогда
ИмяДанных = Данные.Имя;
КонецЕсли;
СинхронизацияДанныхЗарплатаКадрыСервер.ОпределитьМассивыУзловДляНабораЗаписейПоРегистрацииОбъектаВладельца(
Объект, Отказ, ИмяДанных, Параметры);
КонецПроцедуры
4. Стандартный метод заполнения
Для независимых регистров используется стандартный метод платформы:
РегистрыСведений.ДанныеОтпусковКарточкиСотрудника.ЗаполнитьДвиженияПоДаннымВыборкиРегистраторов(
Выборка, // Выборка с данными регистраторов (документов)
Ложь, // Признак удаления записей
ПараметрыОбновления // Параметры обновления (опционально)
);
5. Моменты заполнения регистра
1. При изменении объекта-владельца (Сотрудник)
Триггер: Изменение справочника Сотрудники или связанных объектов
Обработчики:
ПриОбработкеПравилаРегистрацииПередИзменениемОбъектаПриОбработкеПравилаРегистрацииПослеИзмененияОбъектаПослеОбработкиПравилаРегистрации
Момент: После записи изменений в объект-владелец (Сотрудник)
2. При проведении документов-регистраторов
Документы-регистраторы:
Документ.ОтпускДокумент.ОтпускБезСохраненияОплатыДокумент.ОтпускаСотрудников- И другие документы из определенного типа
Момент: После проведения документа через механизм обработчиков правил регистрации
Процесс:
- Документ проводится (
ОбработкаПроведения) - Формируются движения в зависимые регистры
- Срабатывает обработчик правил регистрации для независимого регистра
- Вызывается
ЗаполнитьДвиженияПоДаннымВыборкиРегистраторов - Данные записываются в регистр
ДанныеОтпусковКарточкиСотрудника
3. При регламентном обновлении
Момент: При выполнении обработок обновления информационной базы
Процедуры обновления:
- Могут вызывать
ЗаполнитьДвиженияПоДаннымВыборкиРегистраторовдля массового обновления - Используются при миграции данных или корректировке регистра
4. При синхронизации данных между узлами
Момент: При синхронизации данных в распределенной информационной базе
Механизм:
- Через
СинхронизацияДанныхЗарплатаКадрыСервер.ОпределитьМассивыУзловДляНабораЗаписейПоРегистрацииОбъектаВладельца - Обеспечивает синхронизацию регистра при изменении данных в других узлах
6. Пример запроса для заполнения регистра
Для заполнения регистра формируется запрос к документам-регистраторам:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Отпуск.Ссылка КАК Регистратор,
| Отпуск.Сотрудник КАК Сотрудник,
| Отпуск.ДатаНачалаОсновногоОтпуска КАК ДатаНачала,
| Отпуск.ДатаОкончанияОсновногоОтпуска КАК ДатаОкончания,
| ...
|ИЗ
| Документ.Отпуск КАК Отпуск
|ГДЕ
| Отпуск.Проведен
| И Отпуск.Сотрудник В(&Сотрудники)
|
|УПОРЯДОЧИТЬ ПО
| Сотрудник,
| ДатаНачала";
Выборка = Запрос.Выполнить().Выбрать();
РегистрыСведений.ДанныеОтпусковКарточкиСотрудника.ЗаполнитьДвиженияПоДаннымВыборкиРегистраторов(
Выборка,
Ложь,
ПараметрыОбновления
);
7. Схема процесса заполнения
1. Изменение документа Отпуск
↓
2. Проведение документа (ОбработкаПроведения)
↓
3. Срабатывание обработчика правил регистрации
↓
4. Определение узлов для синхронизации
↓
5. Формирование запроса к документам-регистраторам
↓
6. Вызов ЗаполнитьДвиженияПоДаннымВыборкиРегистраторов
↓
7. Запись данных в регистр ДанныеОтпусковКарточкиСотрудника
Ключевой момент: Заполнение происходит после проведения документа, а не во время проведения, что обеспечивает актуальность данных в регистре.
2. Временная таблица «РеестрОтпусков»
Важное уточнение: «РеестрОтпусков» — это не физический регистр, а временная таблица, которая формируется динамически при формировании отчетов.
Процедура формирования: КадровыйУчетРасширенный.СоздатьВТРеестрОтпусков()
Механизм формирования:
- Создание временной таблицы сотрудников:
ВЫБРАТЬ ТаблицаСотрудников.Период КАК Период, ТаблицаСотрудников.Сотрудник КАК Сотрудник ПОМЕСТИТЬ ВТТаблицаСотрудников ИЗ &ТаблицаСотрудников КАК ТаблицаСотрудников - Объединение данных из двух источников:
Источник 1: Регистр сведений
ДанныеОтпусковКарточкиСотрудникаВЫБРАТЬ РеестрОтпусков.ПериодЗаписи КАК Период, РеестрОтпусков.Сотрудник КАК Сотрудник, РеестрОтпусков.ДокументОснование, РеестрОтпусков.ВидОтпуска, РеестрОтпусков.РабочийПериодС КАК РабочийГодС, РеестрОтпусков.РабочийПериодПо КАК РабочийГодПо, РеестрОтпусков.КоличествоДней КАК ДнейОтпуска, РеестрОтпусков.ДатаНачала КАК ДатаС, РеестрОтпусков.ДатаОкончания КАК ДатаПо, ... ИЗ ВТТаблицаСотрудников КАК ТаблицаСотрудников ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК РеестрОтпусков ПО ТаблицаСотрудников.Сотрудник = РеестрОтпусков.Сотрудник И ТаблицаСотрудников.Период >= РеестрОтпусков.ПериодЗаписиИсточник 2: Физический регистр
РеестрОтпусков(только для документовПереносДанных)Важно: Существует отдельный физический регистр сведений
РеестрОтпусков, который используется специально для документовПереносДанных. Этот регистр также непериодический и независимый.ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ РеестрОтпусков.Период, РеестрОтпусков.Сотрудник, РеестрОтпусков.ДокументОснование, ... ИЗ ВТТаблицаСотрудников КАК ТаблицаСотрудников ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.РеестрОтпусков КАК РеестрОтпусков ПО ТаблицаСотрудников.Сотрудник = РеестрОтпусков.Сотрудник И ТаблицаСотрудников.Период >= РеестрОтпусков.ДатаНачалаПериодаОтсутствия И (РеестрОтпусков.Регистратор ССЫЛКА Документ.ПереносДанных)Примечание: Регистр
РеестрОтпусковиспользуется только для документовПереносДанныхи не предназначен для обычных документовОтпуск. Для корректировок рекомендуется использовать регистрДанныеОтпусковКарточкиСотрудника. - Фильтрация по виду договора:
В зависимости от варианта отчета (Т2, Т2ГСМС) применяется фильтрация по виду договора с сотрудником.
Формирование отчетов по отпускам
Отчет «Унифицированная форма Т-2»
Модуль отчета: Reports/УнифицированнаяФормаТ2/Ext/ObjectModule.bsl
Процедура формирования: ПриКомпоновкеРезультата()
Механизм получения данных об отпусках:
- Вызов функции сбора дополнительных сведений:
ДополнительныеСведения = КадровыйУчет.ДополнительныеСведенияУнифицированнойФормыТ2( Данные.Строки, ДатаОтчета, КлючВарианта ); - Получение данных об отпусках:
ДанныеЗаполнения = ДополнительныеСведения.Получить("ДанныеЗаполненияОтпуска"); ДанныеЗаполненияПоСотруднику = ДанныеЗаполнения.Получить(СтрокаДанных.Сотрудник);
Функция ДополнительныеСведенияУнифицированнойФормыТ2
Модуль: CommonModules/КадровыйУчетБазовый/Ext/Module.bsl
Ключевой момент: Данные об отпусках формируются напрямую из документов, а не из регистра!
Запрос к документам Отпуск:
Запрос.Текст =
"ВЫБРАТЬ
| Отпуск.Сотрудник КАК Сотрудник,
| Отпуск.Номер КАК НомерПриказа,
| Отпуск.Дата КАК ДатаПриказа,
| Отпуск.ДатаНачалаОсновногоОтпуска КАК ДатаС,
| Отпуск.ДатаОкончанияОсновногоОтпуска КАК ДатаПо,
| Отпуск.КоличествоДнейОсновногоОтпуска КАК ДнейОтпуска,
| Отпуск.НачалоПериодаЗаКоторыйПредоставляетсяОтпуск КАК РабочийГодС,
| Отпуск.КонецПериодаЗаКоторыйПредоставляетсяОтпуск КАК РабочийГодПо,
| Отпуск.Основание
|ИЗ
| Документ.Отпуск КАК Отпуск
|ГДЕ
| Отпуск.Проведен
| И Отпуск.Сотрудник В(&Сотрудники)
|
|УПОРЯДОЧИТЬ ПО
| Сотрудник,
| ДатаС";
Обработка результатов:
ДанныеЗаполнения = Новый Соответствие;
ВыборкаОтпуска = РезультатЗапроса.Выбрать();
Пока ВыборкаОтпуска.СледующийПоЗначениюПоля("Сотрудник") Цикл
ДанныеЗаполненияПоСотруднику = Новый Массив;
Пока ВыборкаОтпуска.Следующий() Цикл
СтруктураСтроки = Новый Структура();
СтруктураСтроки.Вставить("ВидОтпуска", НСтр("ru='Основной'"));
СтруктураСтроки.Вставить("ДатаС", ВыборкаОтпуска.ДатаС);
СтруктураСтроки.Вставить("ДатаПо", ВыборкаОтпуска.ДатаПо);
СтруктураСтроки.Вставить("ДнейОтпуска", ВыборкаОтпуска.ДнейОтпуска);
СтруктураСтроки.Вставить("РабочийГодС", ВыборкаОтпуска.РабочийГодС);
СтруктураСтроки.Вставить("РабочийГодПо", ВыборкаОтпуска.РабочийГодПо);
СтруктураСтроки.Вставить("ОснованиеОтпуска", "Пр.№ "+ СокрЛП(ВыборкаОтпуска.НомерПриказа)
+" от " + Формат(ВыборкаОтпуска.ДатаПриказа, "ДЛФ=D")
+ " " + ВыборкаОтпуска.Основание);
ДанныеЗаполненияПоСотруднику.Добавить(СтруктураСтроки);
КонецЦикла;
ДанныеЗаполнения.Вставить(ВыборкаОтпуска.Сотрудник, ДанныеЗаполненияПоСотруднику);
КонецЦикла;
Проведение документа «Отпуск»
Модуль: Documents/Отпуск/Ext/ManagerModule.bsl
Процедура: ПровестиПоУчетам()
При проведении документа «Отпуск» формируются движения в различные регистры:
- Регистры начислений и удержаний (если документ рассчитан)
- Регистр «ФактическиеОтпуска» — для учета фактических отпусков
- Регистр «ПериодыОтпусков» — для учета периодов отпусков
- Регистр «СостоянияСотрудников» — для регистрации состояний сотрудников
Важно: Движения в регистр ДанныеОтпусковКарточкиСотрудника формируются не напрямую при проведении документа, а через специальные механизмы.
Корректировка данных об отпусках
Механизмы корректировки
- Исправление документов:
- Использование документа «Исправление» для корректировки проведенных документов «Отпуск»
- При исправлении формируются сторнирующие движения
- Корректировка регистра:
- Поскольку регистр
ДанныеОтпусковКарточкиСотрудниканезависимый, его записи могут быть изменены напрямую - Однако рекомендуется использовать механизмы корректировки через документы
- Поскольку регистр
- Регламентные операции:
- Обновление данных регистра может выполняться через регламентные операции
- Процедуры обновления могут быть вызваны из обработок обновления информационной базы
Процедуры корректировки
Заполнение движений регистра:
РегистрыСведений.ДанныеОтпусковКарточкиСотрудника.ЗаполнитьДвиженияПоДаннымВыборкиРегистраторов(
Выборка,
Ложь,
ПараметрыОбновления
);
Особенности и рекомендации
1. Двойной источник данных
В системе используются два источника данных об отпусках:
- Регистр сведений
ДанныеОтпусковКарточкиСотрудника— для хранения структурированных данных - Документы
Отпуск— как первичный источник данных
Рекомендация: При формировании отчетов предпочтительно использовать данные из регистра, но для некоторых отчетов (например, Т2) данные берутся напрямую из документов для обеспечения актуальности.
2. Динамическое формирование
Временная таблица «РеестрОтпусков» формируется динамически при каждом формировании отчета. Это обеспечивает:
- Актуальность данных
- Возможность применения различных фильтров
- Гибкость в формировании отчетов
Недостаток: Увеличение времени формирования отчетов при больших объемах данных.
3. Независимый режим записи регистра
Регистр ДанныеОтпусковКарточкиСотрудника имеет режим записи «Независимый», что означает:
- Записи могут быть изменены независимо от документов-регистраторов
- Необходимо контролировать целостность данных вручную
- Возможны расхождения между данными документов и регистра
Рекомендация: Использовать механизмы синхронизации данных для поддержания целостности.
4. Корректировка данных
При необходимости корректировки данных об отпусках:
- Корректировка документа:
- Создать документ «Исправление» для документа «Отпуск»
- Провести исправление — будут сформированы сторнирующие движения
- Корректировка регистра:
- Использовать процедуры обновления регистра
- Убедиться в согласованности данных с документами
- Регламентное обновление:
- Использовать обработки обновления информационной базы
- Выполнять обновление в нерабочее время
Добавление данных об отпусках за прошлые периоды и корректировка закрытых периодов
Проблематика
В практике работы с системой возникают следующие ситуации:
- Добавление исторических данных: Необходимо внести данные об отпусках, которые были предоставлены до начала ведения учета в текущей программе (миграция данных из другой системы).
- Корректировка закрытых периодов: Обнаружены некорректные данные об отпусках за уже закрытые периоды, когда корректировка исходных документов нежелательна или невозможна.
Варианты решения
Вариант 1: Прямая запись в регистр через набор записей (Рекомендуется)
Преимущества:
- Простота реализации
- Не требует создания новых объектов конфигурации
- Использует существующий механизм регистра
- Минимальное влияние на существующую логику
Недостатки:
- Нет документирования операций корректировки
- Сложнее отслеживать историю изменений
- Требует ручного контроля целостности данных
Реализация:
// Процедура для добавления/корректировки данных об отпусках
Процедура ДобавитьДанныеОбОтпускахВРегистр(ТаблицаДанныхОбОтпусках)
// ТаблицаДанныхОбОтпусках должна содержать колонки:
// - Сотрудник (СправочникСсылка.Сотрудники)
// - ПериодЗаписи (Дата)
// - ДокументОснование (ДокументСсылка) - может быть пустым или ссылкой на виртуальный документ
// - ВидОтпуска (Строка или СправочникСсылка.ВидыОтпусков)
// - РабочийПериодС, РабочийПериодПо (Дата)
// - КоличествоДней (Число)
// - ДатаНачала, ДатаОкончания (Дата)
// - Основание (Строка)
// - И другие реквизиты регистра
Для Каждого СтрокаДанных Из ТаблицаДанныхОбОтпусках Цикл
НаборЗаписей = РегистрыСведений.ДанныеОтпусковКарточкиСотрудника.СоздатьНаборЗаписей();
// Устанавливаем отбор по сотруднику и периоду записи
НаборЗаписей.Отбор.Сотрудник.Установить(СтрокаДанных.Сотрудник);
НаборЗаписей.Отбор.ПериодЗаписи.Установить(СтрокаДанных.ПериодЗаписи);
// Если запись существует - удаляем старую
Если НаборЗаписей.Количество() > 0 Тогда
НаборЗаписей.Удалить(НаборЗаписей[0]);
КонецЕсли;
// Добавляем новую запись
Запись = НаборЗаписей.Добавить();
ЗаполнитьЗначенияСвойств(Запись, СтрокаДанных);
// Если документ-основание не указан, можно использовать виртуальный документ
// или оставить пустым (если регистр это допускает)
Если НЕ ЗначениеЗаполнено(Запись.ДокументОснование) Тогда
// Можно создать виртуальный документ "ПереносДанных" или оставить пустым
// Запись.ДокументОснование = СоздатьВиртуальныйДокументПереноса();
КонецЕсли;
КонецЦикла;
// Записываем изменения
НаборЗаписей.Записать();
КонецПроцедуры
Использование:
- Создать обработку или документ для ввода данных
- Заполнить таблицу значений данными об отпусках
- Вызвать процедуру записи в регистр
- Проверить корректность данных в отчетах
Вариант 2: Создание собственного документа «КорректировкаДанныхОбОтпусках»
Преимущества:
- Полное документирование операций
- Возможность контроля прав доступа
- История изменений через документы
- Возможность отмены корректировок
- Интеграция с существующими механизмами отчетности
Недостатки:
- Требует разработки нового объекта конфигурации
- Необходимо реализовать логику проведения
- Больше времени на разработку
Важно: Куда писать данные?
Регистр ДанныеОтпусковКарточкиСотрудника является непериодическим независимым регистром, что означает:
- ✅ Записи сохраняются в регистре и не удаляются автоматически
- ✅ Не формируется динамически — данные записываются один раз и остаются
- ✅ Обработчики правил регистрации вызывают заполнение только при изменении документов-регистраторов
Ответ: Писать нужно напрямую в регистр ДанныеОтпусковКарточкиСотрудника!
Почему данные не затрутся:
- Регистр независимый — записи не удаляются автоматически при перепроведении документов
- Обработчики правил регистрации вызывают
ЗаполнитьДвиженияПоДаннымВыборкиРегистраторовтолько для документов-регистраторов из определенного типа - Если документ «КорректировкаДанныхОбОтпусках» НЕ включен в тип
РегистраторыПериодовОтпусковКарточкиСотрудника, то обработчики не будут его трогать - Если включен — нужно правильно обработать логику, чтобы не было конфликтов
Структура документа:
Документ.КорректировкаДанныхОбОтпусках
├── Реквизиты:
│ ├── Сотрудник (СправочникСсылка.Сотрудники)
│ ├── ДатаКорректировки (Дата)
│ ├── ПричинаКорректировки (Строка)
│ └── ИсточникДанных (Строка) - например, "Миграция из системы X"
└── Табличная часть "Отпуска":
├── ПериодЗаписи (Дата) - ключевое поле для идентификации записи
├── ВидОтпуска (Строка)
├── РабочийПериодС, РабочийПериодПо (Дата)
├── КоличествоДней (Число)
├── ДатаНачала, ДатаОкончания (Дата)
├── Основание (Строка)
└── Действие (Перечисление: Добавить, Изменить, Удалить)
Реализация проведения с защитой от наложений:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
ПроведениеСервер.ПодготовитьНаборыЗаписейКРегистрацииДвижений(ЭтотОбъект);
// ВАЖНО: Писать напрямую в регистр ДанныеОтпусковКарточкиСотрудника
НаборЗаписей = РегистрыСведений.ДанныеОтпусковКарточкиСотрудника.СоздатьНаборЗаписей();
Для Каждого СтрокаОтпуска Из Отпуска Цикл
// Ключ записи: Сотрудник + ПериодЗаписи
// Это позволяет избежать наложений - каждая запись уникальна по этим полям
НаборЗаписей.Отбор.Сотрудник.Установить(Сотрудник);
НаборЗаписей.Отбор.ПериодЗаписи.Установить(СтрокаОтпуска.ПериодЗаписи);
Если СтрокаОтпуска.Действие = Перечисления.ДействияСКорректировкамиОтпусков.Удалить Тогда
// Удаление записи
Если НаборЗаписей.Количество() > 0 Тогда
НаборЗаписей.Удалить(НаборЗаписей[0]);
КонецЕсли;
Иначе
// Проверка на наложения с существующими документами Отпуск
Если НЕ ПроверитьОтсутствиеНаложений(Сотрудник, СтрокаОтпуска.ДатаНачала,
СтрокаОтпуска.ДатаОкончания, Ссылка) Тогда
Отказ = Истина;
ВызватьИсключение "Обнаружено наложение с существующим документом Отпуск!";
КонецЕсли;
// Добавление или изменение записи
Если НаборЗаписей.Количество() > 0 Тогда
Запись = НаборЗаписей[0];
Иначе
Запись = НаборЗаписей.Добавить();
КонецЕсли;
// Заполняем реквизиты записи
Запись.Сотрудник = Сотрудник;
Запись.ПериодЗаписи = СтрокаОтпуска.ПериодЗаписи;
Запись.ДокументОснование = Ссылка; // Ссылка на документ корректировки
Запись.ВидОтпуска = СтрокаОтпуска.ВидОтпуска;
Запись.РабочийПериодС = СтрокаОтпуска.РабочийПериодС;
Запись.РабочийПериодПо = СтрокаОтпуска.РабочийПериодПо;
Запись.КоличествоДней = СтрокаОтпуска.КоличествоДней;
Запись.ДатаНачала = СтрокаОтпуска.ДатаНачала;
Запись.ДатаОкончания = СтрокаОтпуска.ДатаОкончания;
Запись.Основание = СтрокаОтпуска.Основание;
КонецЕсли;
КонецЦикла;
// Записываем изменения в регистр
НаборЗаписей.Записать();
КонецПроцедуры
// Проверка на наложения с документами Отпуск
Функция ПроверитьОтсутствиеНаложений(Сотрудник, ДатаНачала, ДатаОкончания, ИсключаемыйДокумент)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Отпуск.Ссылка
|ИЗ
| Документ.Отпуск КАК Отпуск
|ГДЕ
| Отпуск.Проведен
| И Отпуск.Сотрудник = &Сотрудник
| И Отпуск.Ссылка <> &ИсключаемыйДокумент
| И (
| (Отпуск.ДатаНачалаОсновногоОтпуска МЕЖДУ &ДатаНачала И &ДатаОкончания)
| ИЛИ (Отпуск.ДатаОкончанияОсновногоОтпуска МЕЖДУ &ДатаНачала И &ДатаОкончания)
| ИЛИ (&ДатаНачала МЕЖДУ Отпуск.ДатаНачалаОсновногоОтпуска И Отпуск.ДатаОкончанияОсновногоОтпуска)
| ИЛИ (&ДатаОкончания МЕЖДУ Отпуск.ДатаНачалаОсновногоОтпуска И Отпуск.ДатаОкончанияОсновногоОтпуска)
| )";
Запрос.УстановитьПараметр("Сотрудник", Сотрудник);
Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);
Запрос.УстановитьПараметр("ИсключаемыйДокумент", ИсключаемыйДокумент);
Результат = Запрос.Выполнить();
Возврат Результат.Пустой(); // Истина, если наложений нет
КонецФункции
Интеграция с отчетами:
Вариант А: НЕ включать документ в тип РегистраторыПериодовОтпусковКарточкиСотрудника
Преимущества:
- Данные в регистре не будут перезаписываться обработчиками правил регистрации
- Полный контроль над данными
- Нет конфликтов с существующими механизмами
Недостатки:
- Данные из документа не будут автоматически учитываться в отчетах, которые используют временную таблицу «РеестрОтпусков»
- Нужно модифицировать процедуру
СоздатьВТРеестрОтпусковдля учета документов корректировки
Вариант Б: Включить документ в тип РегистраторыПериодовОтпусковКарточкиСотрудника
Преимущества:
- Автоматическое учет данных в отчетах
- Использование существующих механизмов
Недостатки:
- Нужно правильно обработать логику, чтобы избежать конфликтов
- Обработчики правил регистрации могут перезаписать данные
Рекомендация: Использовать Вариант А — не включать документ в тип регистраторов, а модифицировать процедуру СоздатьВТРеестрОтпусков для учета документов корректировки.
Альтернативный подход: Разделение данных по периодам
Идея: Разделить данные об отпусках по периодам, используя разные регистры для разных временных интервалов.
Предложение:
- Данные до 2018 года → Регистр
РеестрОтпусков(через документПереносДанныхили собственный документ) - Данные с 2018 года → Регистр
ДанныеОтпусковКарточкиСотрудника(через документКорректировкаДанныхОбОтпусках)
Преимущества:
- ✅ Четкое разделение исторических и текущих данных
- ✅ Избежание конфликтов между старыми и новыми данными
- ✅ Регистр
РеестрОтпусковуже используется для документовПереносДанных - ✅ Логичное разделение по периодам
Недостатки:
- ⚠️ Регистр
РеестрОтпусков— подчиненный регистратору (RecorderSubordinate) - ⚠️ Требует создания движений через документ, а не прямую запись
- ⚠️ Нужно модифицировать процедуру
СоздатьВТРеестрОтпусковдля учета обоих регистров
Характеристики регистра РеестрОтпусков:
- Периодичность:
RecorderPosition(по позиции регистратора) - Режим записи:
RecorderSubordinate(подчиненный регистратору) - Измерения:
Сотрудник,Период(по регистратору) - Ресурсы:
ВидОтпуска,НачалоПериодаЗаКоторыйПредоставляетсяОтпуск,КонецПериодаЗаКоторыйПредоставляетсяОтпуск,КоличествоДнейОтпуска,ДатаНачалаПериодаОтсутствия,ДатаОкончанияПериодаОтсутствия,ВидДоговора,Основание
Важно: Регистр РеестрОтпусков — подчиненный регистратору, что означает:
- ❌ НЕЛЬЗЯ писать напрямую через набор записей (как в
ДанныеОтпусковКарточкиСотрудника) - ✅ НУЖНО создавать движения через документ (через
Движения.РеестрОтпусков) - ✅ Движения создаются автоматически при проведении документа-регистратора
- ✅ При отмене проведения документа движения автоматически удаляются
Реализация для старых данных (до 2018 г):
Вариант А: Использовать документ «ПереносДанных»
Документ ПереносДанных уже поддерживает запись в регистр РеестрОтпусков. Можно использовать его для ввода исторических данных.
Вариант Б: Создать собственный документ «КорректировкаИсторическихОтпусков»
Важно: Регистр РеестрОтпусков — подчиненный регистратору, поэтому нужно создавать движения через Движения.РеестрОтпусков, а не напрямую через набор записей.
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
ПроведениеСервер.ПодготовитьНаборыЗаписейКРегистрацииДвижений(ЭтотОбъект);
// ВАЖНО: Регистр РеестрОтпусков - подчиненный регистратору
// Нужно создавать движения через Движения.РеестрОтпусков
// Граничная дата (можно вынести в константу)
ГраничнаяДата = '20180101';
Для Каждого СтрокаОтпуска Из Отпуска Цикл
// Проверяем, что дата начала отпуска до граничной даты
Если СтрокаОтпуска.ДатаНачала >= ГраничнаяДата Тогда
Отказ = Истина;
ВызватьИсключение СтрШаблон(
"Для отпусков с %1 используйте документ 'КорректировкаДанныхОбОтпусках'",
Формат(ГраничнаяДата, "ДЛФ=D"));
КонецЕсли;
// Создаем движение в регистр РеестрОтпусков
Движение = Движения.РеестрОтпусков.Добавить();
Движение.Сотрудник = Сотрудник;
Движение.Период = СтрокаОтпуска.ДатаНачала; // Период по регистратору
Движение.ВидОтпуска = СтрокаОтпуска.ВидОтпуска;
Движение.НачалоПериодаЗаКоторыйПредоставляетсяОтпуск = СтрокаОтпуска.РабочийПериодС;
Движение.КонецПериодаЗаКоторыйПредоставляетсяОтпуск = СтрокаОтпуска.РабочийПериодПо;
Движение.КоличествоДнейОтпуска = СтрокаОтпуска.КоличествоДней;
Движение.ДатаНачалаПериодаОтсутствия = СтрокаОтпуска.ДатаНачала;
Движение.ДатаОкончанияПериодаОтсутствия = СтрокаОтпуска.ДатаОкончания;
Движение.ВидДоговора = СтрокаОтпуска.ВидДоговора;
Движение.Основание = СтрокаОтпуска.Основание;
КонецЦикла;
КонецПроцедуры
Примечание: При отмене проведения документа движения в регистре РеестрОтпусков будут автоматически удалены, так как регистр подчиненный регистратору.
Реализация для новых данных (с 2018 г):
Использовать документ «КорректировкаДанныхОбОтпусках» с записью в регистр ДанныеОтпусковКарточкиСотрудника (как описано выше в Варианте 2).
Добавить проверку граничной даты:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
ПроведениеСервер.ПодготовитьНаборыЗаписейКРегистрацииДвижений(ЭтотОбъект);
// Граничная дата (можно вынести в константу)
ГраничнаяДата = '20180101';
НаборЗаписей = РегистрыСведений.ДанныеОтпусковКарточкиСотрудника.СоздатьНаборЗаписей();
Для Каждого СтрокаОтпуска Из Отпуска Цикл
// Проверяем, что дата начала отпуска после граничной даты
Если СтрокаОтпуска.ДатаНачала < ГраничнаяДата Тогда
Отказ = Истина;
ВызватьИсключение СтрШаблон(
"Для отпусков до %1 используйте документ 'КорректировкаИсторическихОтпусков'",
Формат(ГраничнаяДата, "ДЛФ=D"));
КонецЕсли;
// ... остальная логика записи в регистр ДанныеОтпусковКарточкиСотрудника
КонецЦикла;
КонецПроцедуры
Модификация процедуры СоздатьВТРеестрОтпусков:
Процедура уже учитывает оба регистра:
- Регистр
ДанныеОтпусковКарточкиСотрудника— основной источник - Регистр
РеестрОтпусков— для документовПереносДанных(и теперь для исторических данных)
Дополнительная модификация для учета документов корректировки:
// В процедуре СоздатьВТРеестрОтпусков добавить после объединения с РеестрОтпусков:
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Корректировка.ПериодЗаписи КАК Период,
Корректировка.Сотрудник КАК Сотрудник,
Корректировка.Ссылка КАК ДокументОснование,
...
ИЗ
ВТТаблицаСотрудников КАК ТаблицаСотрудников
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК Корректировка
ПО ТаблицаСотрудников.Сотрудник = Корректировка.Сотрудник
И ТаблицаСотрудников.Период >= Корректировка.ПериодЗаписи
И Корректировка.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках
И Корректировка.ПериодЗаписи >= '20180101' // Только данные с 2018 года
Рекомендация по использованию:
- Для исторических данных (до 2018 г):
- Использовать документ
ПереносДанныхили создать документКорректировкаИсторическихОтпусков - Писать в регистр
РеестрОтпусковчерез движения (черезДвижения.РеестрОтпусков) - Данные автоматически учитываются в отчетах (регистр уже используется в
СоздатьВТРеестрОтпусков) - При отмене проведения документа движения автоматически удаляются
- Использовать документ
- Для данных с 2018 года:
- Использовать документ
КорректировкаДанныхОбОтпусках - Писать в регистр
ДанныеОтпусковКарточкиСотрудниканапрямую через набор записей - Данные учитываются в отчетах через основной запрос к регистру
- Данные не удаляются при отмене проведения (регистр независимый)
- Использовать документ
- Граничная дата:
- Рекомендуется использовать
01.01.2018как граничную дату - Можно настроить через константу для гибкости
- Проверять граничную дату при проведении документов корректировки
- Рекомендуется использовать
Сравнение регистров:
| Характеристика | РеестрОтпусков | ДанныеОтпусковКарточкиСотрудника |
|---|---|---|
| Режим записи | Подчиненный регистратору | Независимый |
| Способ записи | Через движения (Движения.РеестрОтпусков) |
Напрямую через набор записей |
| Удаление при отмене | Автоматически | Не удаляется |
| Периодичность | По позиции регистратора | Непериодический |
| Использование | Для документов ПереносДанных и исторических данных | Для текущих данных и корректировок |
| Рекомендуемый период | До 2018 года | С 2018 года |
Преимущества такого подхода:
- ✅ Четкое разделение по периодам
- ✅ Избежание конфликтов между старыми и новыми данными
- ✅ Использование существующих механизмов
- ✅ Логичная структура данных
- ✅ Регистр
РеестрОтпусковуже интегрирован в процедуруСоздатьВТРеестрОтпусков - ✅ Для старых данных не нужно модифицировать процедуру формирования отчетов
Недостатки:
- ⚠️ Два разных механизма записи (движения vs. набор записей)
- ⚠️ Нужно контролировать граничную дату при проведении документов
- ⚠️ При формировании отчетов данные берутся из двух регистров (но это уже реализовано)
- ⚠️ Регистр
РеестрОтпусковподчиненный — движения удаляются при отмене проведения
Итоговая рекомендация:
Использовать разделение по периодам:
- До 2018 года → Регистр
РеестрОтпусков(через движения документа) - С 2018 года → Регистр
ДанныеОтпусковКарточкиСотрудника(напрямую через набор записей)
Это оптимальный подход, так как:
- Использует существующие механизмы без дополнительных модификаций
- Четко разделяет исторические и текущие данные
- Избегает конфликтов между периодами
- Учитывается в отчетах автоматически (оба регистра уже используются в
СоздатьВТРеестрОтпусков)
Схема работы:
Исторические данные (до 2018 г)
↓
Документ "КорректировкаИсторическихОтпусков" или "ПереносДанных"
↓
Движения.РеестрОтпусков.Добавить()
↓
Регистр РеестрОтпусков (подчиненный регистратору)
↓
Учитывается в СоздатьВТРеестрОтпусков автоматически
Текущие данные (с 2018 г)
↓
Документ "КорректировкаДанныхОбОтпусках"
↓
НаборЗаписей = РегистрыСведений.ДанныеОтпусковКарточкиСотрудника.СоздатьНаборЗаписей()
↓
Регистр ДанныеОтпусковКарточкиСотрудника (независимый)
↓
Учитывается в СоздатьВТРеестрОтпусков автоматически
Важно: Оба регистра уже используются в процедуре СоздатьВТРеестрОтпусков, поэтому данные из обоих регистров автоматически учитываются при формировании отчетов без дополнительных модификаций!
Механизм приоритета корректировок и «затирания» данных
Проблема
При наличии корректировок из документа «КорректировкаДанныхОбОтпусках» и реальных данных из документов «Отпуск» за один и тот же период возникает вопрос: какие данные использовать в отчетах?
Требование:
- Если есть корректировка за определенный период → использовать данные из корректировки (приоритет корректировок)
- Если нет корректировки → использовать реальные данные из документов «Отпуск»
Механизм «затирания» данных
Идея: Корректировки должны «затирать» (переопределять) данные из документов «Отпуск» за тот же период.
Ключ для сопоставления:
Сотрудник+ период отпуска (ДатаНачала—ДатаОкончания)
Реализация механизма приоритета
Вариант 1: Исключение данных из документов при наличии корректировок (Рекомендуется)
Принцип: Сначала собираем данные из корректировок, затем из документов, но исключаем те периоды, для которых есть корректировки.
Модификация процедуры СоздатьВТРеестрОтпусков:
// В процедуре КадровыйУчетРасширенный.СоздатьВТРеестрОтпусков
// После создания ВТТаблицаСотрудников добавить:
////////////////////////////////////////////////////////////////////////////////
// Создаем временную таблицу корректировок для определения приоритета
ВЫБРАТЬ
Корректировка.Сотрудник КАК Сотрудник,
Корректировка.ДатаНачала КАК ДатаНачала,
Корректировка.ДатаОкончания КАК ДатаОкончания
ПОМЕСТИТЬ ВТКорректировкиОтпусков
ИЗ
РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК Корректировка
ГДЕ
Корректировка.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках
И Корректировка.ДокументОснование.Проведен
И Корректировка.ПериодЗаписи >= '20180101' // Только данные с 2018 года
;
////////////////////////////////////////////////////////////////////////////////
// Основной запрос с приоритетом корректировок
Запрос.Текст =
"ВЫБРАТЬ
| РеестрОтпусков.ПериодЗаписи КАК Период,
| РеестрОтпусков.Сотрудник КАК Сотрудник,
| РеестрОтпусков.ДокументОснование КАК ДокументОснование,
| РеестрОтпусков.ВидОтпуска КАК ВидОтпускаСсылка,
| РеестрОтпусков.ВидОтпускаПредставление КАК ВидОтпуска,
| РеестрОтпусков.РабочийПериодС КАК РабочийГодС,
| РеестрОтпусков.РабочийПериодПо КАК РабочийГодПо,
| РеестрОтпусков.КоличествоДней КАК ДнейОтпуска,
| РеестрОтпусков.ДатаНачала КАК ДатаС,
| РеестрОтпусков.ДатаОкончания КАК ДатаПо,
| ...
|ПОМЕСТИТЬ ВТРеестрОтпусковПредварительно
|ИЗ
| ВТТаблицаСотрудников КАК ТаблицаСотрудников
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК РеестрОтпусков
| ПО ТаблицаСотрудников.Сотрудник = РеестрОтпусков.Сотрудник
| И ТаблицаСотрудников.Период >= РеестрОтпусков.ПериодЗаписи
| И РеестрОтпусков.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках
| И РеестрОтпусков.ПериодЗаписи >= '20180101'
|
|ОБЪЕДИНИТЬ ВСЕ
|
|// Данные из документов Отпуск, но исключаем периоды с корректировками
|ВЫБРАТЬ
| Отпуск.Дата КАК Период,
| Отпуск.Сотрудник КАК Сотрудник,
| Отпуск.Ссылка КАК ДокументОснование,
| ЗНАЧЕНИЕ(Справочник.ВидыОтпусков.ПустаяСсылка) КАК ВидОтпускаСсылка,
| НСтр("ru='Основной'") КАК ВидОтпуска,
| Отпуск.НачалоПериодаЗаКоторыйПредоставляетсяОтпуск КАК РабочийГодС,
| Отпуск.КонецПериодаЗаКоторыйПредоставляетсяОтпуск КАК РабочийГодПо,
| Отпуск.КоличествоДнейОсновногоОтпуска КАК ДнейОтпуска,
| Отпуск.ДатаНачалаОсновногоОтпуска КАК ДатаС,
| Отпуск.ДатаОкончанияОсновногоОтпуска КАК ДатаПо,
| ...
|ИЗ
| ВТТаблицаСотрудников КАК ТаблицаСотрудников
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Отпуск КАК Отпуск
| ПО ТаблицаСотрудников.Сотрудник = Отпуск.Сотрудник
| И ТаблицаСотрудников.Период >= Отпуск.ДатаНачалаОсновногоОтпуска
| И Отпуск.Проведен
| // ИСКЛЮЧАЕМ периоды, для которых есть корректировки
| ЛЕВОЕ СОЕДИНЕНИЕ ВТКорректировкиОтпусков КАК Корректировки
| ПО Отпуск.Сотрудник = Корректировки.Сотрудник
| И (
| (Отпуск.ДатаНачалаОсновногоОтпуска МЕЖДУ Корректировки.ДатаНачала И Корректировки.ДатаОкончания)
| ИЛИ (Отпуск.ДатаОкончанияОсновногоОтпуска МЕЖДУ Корректировки.ДатаНачала И Корректировки.ДатаОкончания)
| ИЛИ (Корректировки.ДатаНачала МЕЖДУ Отпуск.ДатаНачалаОсновногоОтпуска И Отпуск.ДатаОкончанияОсновногоОтпуска)
| )
|ГДЕ
| Корректировки.Сотрудник ЕСТЬ NULL // Исключаем документы Отпуск, для которых есть корректировки
|
|ОБЪЕДИНИТЬ ВСЕ
|
|// Данные из регистра РеестрОтпусков (для ПереносДанных и исторических данных)
|ВЫБРАТЬ
| ...
|ИЗ
| ВТТаблицаСотрудников КАК ТаблицаСотрудников
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.РеестрОтпусков КАК РеестрОтпусков
| ПО ТаблицаСотрудников.Сотрудник = РеестрОтпусков.Сотрудник
| И ТаблицаСотрудников.Период >= РеестрОтпусков.ДатаНачалаПериодаОтсутствия
| И (РеестрОтпусков.Регистратор ССЫЛКА Документ.ПереносДанных)";
Преимущества:
- ✅ Четкий приоритет корректировок
- ✅ Автоматическое исключение данных из документов при наличии корректировок
- ✅ Простая логика — корректировки всегда имеют приоритет
Недостатки:
- ⚠️ Требует создания временной таблицы корректировок
- ⚠️ Усложняет запрос
Вариант 2: Использование COALESCE с LEFT JOIN (Альтернативный)
Принцип: Использовать LEFT JOIN и COALESCE для выбора данных с приоритетом.
ВЫБРАТЬ
ВЫБОР
КОГДА Корректировка.Сотрудник ЕСТЬ NULL
ТОГДА Отпуск.ДатаНачалаОсновногоОтпуска
ИНАЧЕ Корректировка.ДатаНачала
КОНЕЦ КАК ДатаС,
ВЫБОР
КОГДА Корректировка.Сотрудник ЕСТЬ NULL
ТОГДА Отпуск.ДатаОкончанияОсновногоОтпуска
ИНАЧЕ Корректировка.ДатаОкончания
КОНЕЦ КАК ДатаПо,
...
ИЗ
ВТТаблицаСотрудников КАК ТаблицаСотрудников
ЛЕВОЕ СОЕДИНЕНИЕ Документ.Отпуск КАК Отпуск
ПО ТаблицаСотрудников.Сотрудник = Отпуск.Сотрудник
И ТаблицаСотрудников.Период >= Отпуск.ДатаНачалаОсновногоОтпуска
И Отпуск.Проведен
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК Корректировка
ПО Отпуск.Сотрудник = Корректировка.Сотрудник
И Корректировка.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках
И (
(Отпуск.ДатаНачалаОсновногоОтпуска МЕЖДУ Корректировка.ДатаНачала И Корректировка.ДатаОкончания)
ИЛИ (Отпуск.ДатаОкончанияОсновногоОтпуска МЕЖДУ Корректировка.ДатаНачала И Корректировка.ДатаОкончания)
ИЛИ (Корректировка.ДатаНачала МЕЖДУ Отпуск.ДатаНачалаОсновногоОтпуска И Отпуск.ДатаОкончанияОсновногоОтпуска)
)
ГДЕ
Корректировка.Сотрудник ЕСТЬ NULL
ИЛИ Отпуск.Сотрудник ЕСТЬ NULL
Недостатки:
- ⚠️ Сложнее в реализации
- ⚠️ Может создавать дубли, если корректировка частично перекрывает период документа
Вариант 3: Двухэтапный подход (Наиболее надежный)
Принцип:
- Сначала собираем все корректировки
- Затем собираем данные из документов, исключая периоды корректировок
- Объединяем результаты
////////////////////////////////////////////////////////////////////////////////
// Этап 1: Собираем данные из корректировок
ВЫБРАТЬ
Корректировка.ПериодЗаписи КАК Период,
Корректировка.Сотрудник КАК Сотрудник,
Корректировка.ДокументОснование КАК ДокументОснование,
Корректировка.ВидОтпуска КАК ВидОтпуска,
Корректировка.РабочийПериодС КАК РабочийГодС,
Корректировка.РабочийПериодПо КАК РабочийГодПо,
Корректировка.КоличествоДней КАК ДнейОтпуска,
Корректировка.ДатаНачала КАК ДатаС,
Корректировка.ДатаОкончания КАК ДатаПо,
Корректировка.Основание КАК Основание,
ИСТИНА КАК ЭтоКорректировка // Флаг для идентификации
ПОМЕСТИТЬ ВТРеестрОтпусковСКорректировками
ИЗ
ВТТаблицаСотрудников КАК ТаблицаСотрудников
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК Корректировка
ПО ТаблицаСотрудников.Сотрудник = Корректировка.Сотрудник
И ТаблицаСотрудников.Период >= Корректировка.ПериодЗаписи
И Корректировка.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках
И Корректировка.ДокументОснование.Проведен
И Корректировка.ПериодЗаписи >= '20180101'
;
////////////////////////////////////////////////////////////////////////////////
// Этап 2: Собираем данные из документов Отпуск, исключая периоды с корректировками
ВЫБРАТЬ
Отпуск.Дата КАК Период,
Отпуск.Сотрудник КАК Сотрудник,
Отпуск.Ссылка КАК ДокументОснование,
ЗНАЧЕНИЕ(Справочник.ВидыОтпусков.ПустаяСсылка) КАК ВидОтпускаСсылка,
НСтр("ru='Основной'") КАК ВидОтпуска,
Отпуск.НачалоПериодаЗаКоторыйПредоставляетсяОтпуск КАК РабочийГодС,
Отпуск.КонецПериодаЗаКоторыйПредоставляетсяОтпуск КАК РабочийГодПо,
Отпуск.КоличествоДнейОсновногоОтпуска КАК ДнейОтпуска,
Отпуск.ДатаНачалаОсновногоОтпуска КАК ДатаС,
Отпуск.ДатаОкончанияОсновногоОтпуска КАК ДатаПо,
Отпуск.Основание КАК Основание,
ЛОЖЬ КАК ЭтоКорректировка
ПОМЕСТИТЬ ВТРеестрОтпусковИзДокументов
ИЗ
ВТТаблицаСотрудников КАК ТаблицаСотрудников
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Отпуск КАК Отпуск
ПО ТаблицаСотрудников.Сотрудник = Отпуск.Сотрудник
И ТаблицаСотрудников.Период >= Отпуск.ДатаНачалаОсновногоОтпуска
И Отпуск.Проведен
// ИСКЛЮЧАЕМ периоды, для которых есть корректировки
ЛЕВОЕ СОЕДИНЕНИЕ ВТРеестрОтпусковСКорректировками КАК Корректировки
ПО Отпуск.Сотрудник = Корректировки.Сотрудник
И (
(Отпуск.ДатаНачалаОсновногоОтпуска МЕЖДУ Корректировки.ДатаС И Корректировки.ДатаПо)
ИЛИ (Отпуск.ДатаОкончанияОсновногоОтпуска МЕЖДУ Корректировки.ДатаС И Корректировки.ДатаПо)
ИЛИ (Корректировки.ДатаС МЕЖДУ Отпуск.ДатаНачалаОсновногоОтпуска И Отпуск.ДатаОкончанияОсновногоОтпуска)
)
ГДЕ
Корректировки.Сотрудник ЕСТЬ NULL // Исключаем документы Отпуск, для которых есть корректировки
;
////////////////////////////////////////////////////////////////////////////////
// Этап 3: Объединяем корректировки и данные из документов
ВЫБРАТЬ
РеестрОтпусков.Период,
РеестрОтпусков.Сотрудник,
РеестрОтпусков.ДокументОснование,
...
ПОМЕСТИТЬ ВТРеестрОтпусковПредварительно
ИЗ
ВТРеестрОтпусковСКорректировками КАК РеестрОтпусков
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
РеестрОтпусков.Период,
РеестрОтпусков.Сотрудник,
РеестрОтпусков.ДокументОснование,
...
ИЗ
ВТРеестрОтпусковИзДокументов КАК РеестрОтпусков
ОБЪЕДИНИТЬ ВСЕ
// Данные из регистра РеестрОтпусков (для ПереносДанных)
ВЫБРАТЬ
...
ИЗ
ВТТаблицаСотрудников КАК ТаблицаСотрудников
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.РеестрОтпусков КАК РеестрОтпусков
ПО ТаблицаСотрудников.Сотрудник = РеестрОтпусков.Сотрудник
И ТаблицаСотрудников.Период >= РеестрОтпусков.ДатаНачалаПериодаОтсутствия
И (РеестрОтпусков.Регистратор ССЫЛКА Документ.ПереносДанных)
Преимущества:
- ✅ Четкая логика разделения этапов
- ✅ Легко отлаживать и понимать
- ✅ Надежный механизм исключения данных
- ✅ Можно добавить флаг
ЭтоКорректировкадля отслеживания источника данных
Определение периода для сопоставления
Ключевой вопрос: Как определить, что корректировка относится к конкретному документу «Отпуск»?
Варианты сопоставления:
- По датам отпуска (рекомендуется):
- Сравнивать
ДатаНачалаиДатаОкончанияотпуска - Если периоды пересекаются → корректировка «затирает» документ
- Сравнивать
- По рабочему периоду:
- Сравнивать
РабочийПериодСиРабочийПериодПо - Менее надежно, так как один рабочий период может содержать несколько отпусков
- Сравнивать
- По документу-основанию:
- Если в корректировке указан конкретный документ «Отпуск» → затирать только его
- Требует дополнительного поля в корректировке
Рекомендация: Использовать сопоставление по датам отпуска с проверкой пересечения периодов.
Пример функции проверки пересечения периодов
// Функция проверяет, пересекаются ли два периода отпуска
Функция ПериодыОтпусковПересекаются(ДатаНачала1, ДатаОкончания1, ДатаНачала2, ДатаОкончания2)
// Периоды пересекаются, если:
// 1. Начало первого периода внутри второго
// 2. Конец первого периода внутри второго
// 3. Начало второго периода внутри первого
// 4. Конец второго периода внутри первого
Возврат (ДатаНачала1 >= ДатаНачала2 И ДатаНачала1 <= ДатаОкончания2)
ИЛИ (ДатаОкончания1 >= ДатаНачала2 И ДатаОкончания1 <= ДатаОкончания2)
ИЛИ (ДатаНачала2 >= ДатаНачала1 И ДатаНачала2 <= ДатаОкончания1)
ИЛИ (ДатаОкончания2 >= ДатаНачала1 И ДатаОкончания2 <= ДатаОкончания1);
КонецФункции
Схема работы механизма приоритета
1. Формирование временной таблицы сотрудников
↓
2. Сбор данных из корректировок (приоритет 1)
↓
3. Сбор данных из документов Отпуск
↓
4. Исключение периодов с корректировками из документов
↓
5. Объединение: Корректировки + Документы (без затертых) + РеестрОтпусков
↓
6. Формирование итоговой временной таблицы ВТРеестрОтпусков
Рекомендации по реализации
- Использовать Вариант 3 (двухэтапный подход) — наиболее надежный и понятный
- Добавить флаг источника данных (
ЭтоКорректировка) для отслеживания:- Откуда взяты данные (корректировка или документ)
- Для отладки и аудита
- Логировать операции «затирания»:
- Записывать в журнал регистрации, какие документы «Отпуск» были затерты корректировками
- Для контроля и аудита
- Проверка целостности:
- После формирования временной таблицы проверять отсутствие дублей
- Проверять, что все корректировки применены
- Обработка частичных пересечений:
- Если корректировка частично перекрывает период документа — нужно определить стратегию
- Варианты: затирать полностью, затирать только пересекающуюся часть, или выдавать ошибку
Конкретные места для модификации кода
Место 1: Процедура СоздатьВТРеестрОтпусков (КадровыйУчетРасширенный)
Файл: CommonModules/КадровыйУчетРасширенный/Ext/Module.bsl
Процедура: СоздатьВТРеестрОтпусков (строки 771-940)
Место модификации: Запрос на строках 800-895
Текущий код (строки 800-836):
Запрос.Текст =
"ВЫБРАТЬ
| РеестрОтпусков.ПериодЗаписи КАК Период,
| РеестрОтпусков.Сотрудник КАК Сотрудник,
| ...
|ПОМЕСТИТЬ ВТРеестрОтпусковПредварительно
|ИЗ
| ВТТаблицаСотрудников КАК ТаблицаСотрудников
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК РеестрОтпусков
| ПО ТаблицаСотрудников.Сотрудник = РеестрОтпусков.Сотрудник
| И ТаблицаСотрудников.Период >= РеестрОтпусков.ПериодЗаписи
| ...
|ГДЕ
| &УсловиеДоговора
Проблема: Запрос берет ВСЕ данные из регистра ДанныеОтпусковКарточкиСотрудника, включая:
- Данные из корректировок (КорректировкаДанныхОбОтпусках)
- Данные из обычных документов (Отпуск, ОтпускБезСохраненияОплаты и др.)
Что нужно изменить:
- Разделить запрос на два этапа:
- Этап 1: Собрать только корректировки (приоритет)
- Этап 2: Собрать обычные данные, исключив периоды с корректировками
- Добавить временную таблицу корректировок перед основным запросом (после строки 795):
// После строки 795 добавить:
////////////////////////////////////////////////////////////////////////////////
// Создаем временную таблицу корректировок для определения приоритета
Запрос.Текст =
"ВЫБРАТЬ
| Корректировка.Сотрудник КАК Сотрудник,
| Корректировка.ДатаНачала КАК ДатаНачала,
| Корректировка.ДатаОкончания КАК ДатаОкончания
|ПОМЕСТИТЬ ВТКорректировкиОтпусков
|ИЗ
| ВТТаблицаСотрудников КАК ТаблицаСотрудников
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК Корректировка
| ПО ТаблицаСотрудников.Сотрудник = Корректировка.Сотрудник
| И ТаблицаСотрудников.Период >= Корректировка.ПериодЗаписи
| И Корректировка.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках
| И Корректировка.ДокументОснование.Проведен
| И Корректировка.ПериодЗаписи >= '20180101'";
Запрос.Выполнить();
- Модифицировать основной запрос (строки 800-836):
Запрос.Текст =
"ВЫБРАТЬ
| РеестрОтпусков.ПериодЗаписи КАК Период,
| РеестрОтпусков.Сотрудник КАК Сотрудник,
| РеестрОтпусков.ДокументОснование КАК ДокументОснование,
| РеестрОтпусков.ВидОтпуска КАК ВидОтпускаСсылка,
| РеестрОтпусков.ВидОтпускаПредставление КАК ВидОтпуска,
| РеестрОтпусков.РабочийПериодС КАК РабочийГодС,
| РеестрОтпусков.РабочийПериодПо КАК РабочийГодПо,
| РеестрОтпусков.КоличествоДней КАК ДнейОтпуска,
| РеестрОтпусков.ДатаНачала КАК ДатаС,
| РеестрОтпусков.ДатаОкончания КАК ДатаПо,
| РеестрОтпусков.ВидДоговора КАК ВидДоговора,
| РеестрОтпусков.Основание КАК Основание,
| РеестрОтпусков.ИсходныйДокумент КАК ИсходныйДокумент,
| РеестрОтпусков.ИсходныйДокументДата КАК ИсходныйДокументДата,
| РеестрОтпусков.ИсходныйДокументНомер КАК ИсходныйДокументНомер,
| ВЫБОР
| КОГДА РеестрОтпусков.Компенсация
| ТОГДА 1
| ИНАЧЕ 0
| КОНЕЦ КАК ЭтоКомпенсацияОтпуска,
| КадровыеДанныеСотрудников.ДатаНачалаУчета КАК ДатаНачалаУчета,
| РеестрОтпусков.Состояние КАК Состояние,
| РеестрОтпусков.ДатаНачала КАК СостояниеС,
| РеестрОтпусков.ДатаОкончания КАК СостояниеПо,
| ИСТИНА КАК ЭтоКорректировка
|ПОМЕСТИТЬ ВТРеестрОтпусковПредварительно
|ИЗ
| ВТТаблицаСотрудников КАК ТаблицаСотрудников
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК РеестрОтпусков
| ПО ТаблицаСотрудников.Сотрудник = РеестрОтпусков.Сотрудник
| И ТаблицаСотрудников.Период >= РеестрОтпусков.ПериодЗаписи
| И РеестрОтпусков.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках
| И РеестрОтпусков.ДокументОснование.Проведен
| И РеестрОтпусков.ПериодЗаписи >= '20180101'
| ЛЕВОЕ СОЕДИНЕНИЕ ВТКадровыеДанныеСотрудников КАК КадровыеДанныеСотрудников
| ПО ТаблицаСотрудников.Сотрудник = КадровыеДанныеСотрудников.Сотрудник
| И ТаблицаСотрудников.Период = КадровыеДанныеСотрудников.Период
|ГДЕ
| &УсловиеДоговора
|
|ОБЪЕДИНИТЬ ВСЕ
|
|// Обычные данные из регистра (НЕ корректировки), исключая периоды с корректировками
|ВЫБРАТЬ
| РеестрОтпусков.ПериодЗаписи КАК Период,
| РеестрОтпусков.Сотрудник КАК Сотрудник,
| РеестрОтпусков.ДокументОснование КАК ДокументОснование,
| РеестрОтпусков.ВидОтпуска КАК ВидОтпускаСсылка,
| РеестрОтпусков.ВидОтпускаПредставление КАК ВидОтпуска,
| РеестрОтпусков.РабочийПериодС КАК РабочийГодС,
| РеестрОтпусков.РабочийПериодПо КАК РабочийГодПо,
| РеестрОтпусков.КоличествоДней КАК ДнейОтпуска,
| РеестрОтпусков.ДатаНачала КАК ДатаС,
| РеестрОтпусков.ДатаОкончания КАК ДатаПо,
| РеестрОтпусков.ВидДоговора КАК ВидДоговора,
| РеестрОтпусков.Основание КАК Основание,
| РеестрОтпусков.ИсходныйДокумент КАК ИсходныйДокумент,
| РеестрОтпусков.ИсходныйДокументДата КАК ИсходныйДокументДата,
| РеестрОтпусков.ИсходныйДокументНомер КАК ИсходныйДокументНомер,
| ВЫБОР
| КОГДА РеестрОтпусков.Компенсация
| ТОГДА 1
| ИНАЧЕ 0
| КОНЕЦ КАК ЭтоКомпенсацияОтпуска,
| КадровыеДанныеСотрудников.ДатаНачалаУчета КАК ДатаНачалаУчета,
| РеестрОтпусков.Состояние КАК Состояние,
| РеестрОтпусков.ДатаНачала КАК СостояниеС,
| РеестрОтпусков.ДатаОкончания КАК СостояниеПо,
| ЛОЖЬ КАК ЭтоКорректировка
|ИЗ
| ВТТаблицаСотрудников КАК ТаблицаСотрудников
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК РеестрОтпусков
| ПО ТаблицаСотрудников.Сотрудник = РеестрОтпусков.Сотрудник
| И ТаблицаСотрудников.Период >= РеестрОтпусков.ПериодЗаписи
| И НЕ (РеестрОтпусков.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках)
| // ИСКЛЮЧАЕМ периоды, для которых есть корректировки
| ЛЕВОЕ СОЕДИНЕНИЕ ВТКорректировкиОтпусков КАК Корректировки
| ПО РеестрОтпусков.Сотрудник = Корректировки.Сотрудник
| И (
| (РеестрОтпусков.ДатаНачала МЕЖДУ Корректировки.ДатаНачала И Корректировки.ДатаОкончания)
| ИЛИ (РеестрОтпусков.ДатаОкончания МЕЖДУ Корректировки.ДатаНачала И Корректировки.ДатаОкончания)
| ИЛИ (Корректировки.ДатаНачала МЕЖДУ РеестрОтпусков.ДатаНачала И РеестрОтпусков.ДатаОкончания)
| )
| ЛЕВОЕ СОЕДИНЕНИЕ ВТКадровыеДанныеСотрудников КАК КадровыеДанныеСотрудников
| ПО ТаблицаСотрудников.Сотрудник = КадровыеДанныеСотрудников.Сотрудник
| И ТаблицаСотрудников.Период = КадровыеДанныеСотрудников.Период
|ГДЕ
| Корректировки.Сотрудник ЕСТЬ NULL // Исключаем обычные данные, для которых есть корректировки
| И &УсловиеДоговора";
- Добавить уничтожение временной таблицы в запрос на строке 934:
Запрос.Текст =
"ВЫБРАТЬ
| ...
|ПОМЕСТИТЬ ВТРеестрОтпусков
|ИЗ
| ВТРеестрОтпусковПредварительно КАК РеестрОтпусков
|;
|
|////////////////////////////////////////////////////////////////////////////////
|УНИЧТОЖИТЬ ВТТаблицаСотрудников
|;
|
|////////////////////////////////////////////////////////////////////////////////
|УНИЧТОЖИТЬ ВТКадровыеДанныеСотрудников
|;
|
|////////////////////////////////////////////////////////////////////////////////
|УНИЧТОЖИТЬ ВТРеестрОтпусковПредварительно
|;
|
|////////////////////////////////////////////////////////////////////////////////
|УНИЧТОЖИТЬ ВТКорректировкиОтпусков";
Место 2: Функция ДополнительныеСведенияУнифицированнойФормыТ2 (КадровыйУчетБазовый)
Файл: CommonModules/КадровыйУчетБазовый/Ext/Module.bsl
Функция: ДополнительныеСведенияУнифицированнойФормыТ2 (строки 1457-1623)
Место модификации: Запрос на строках 1562-1581
Текущий код:
Запрос.Текст =
"ВЫБРАТЬ
| Отпуск.Сотрудник КАК Сотрудник,
| Отпуск.Номер КАК НомерПриказа,
| Отпуск.Дата КАК ДатаПриказа,
| Отпуск.ДатаНачалаОсновногоОтпуска КАК ДатаС,
| Отпуск.ДатаОкончанияОсновногоОтпуска КАК ДатаПо,
| ...
|ИЗ
| Документ.Отпуск КАК Отпуск
|ГДЕ
| Отпуск.Проведен
| И Отпуск.Сотрудник В(&Сотрудники)";
Проблема: Запрос берет данные напрямую из документов «Отпуск», не учитывая корректировки.
Что нужно изменить:
Вариант А (Рекомендуется): Использовать временную таблицу ВТРеестрОтпусков, если она уже создана в расширенном модуле.
Вариант Б: Модифицировать запрос для учета корректировок:
Запрос.Текст =
"ВЫБРАТЬ
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.Сотрудник
| ИНАЧЕ Корректировка.Сотрудник
| КОНЕЦ КАК Сотрудник,
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.Номер
| ИНАЧЕ Корректировка.ДокументОснование.Номер
| КОНЕЦ КАК НомерПриказа,
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.Дата
| ИНАЧЕ Корректировка.ДокументОснование.Дата
| КОНЕЦ КАК ДатаПриказа,
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.ДатаНачалаОсновногоОтпуска
| ИНАЧЕ Корректировка.ДатаНачала
| КОНЕЦ КАК ДатаС,
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.ДатаОкончанияОсновногоОтпуска
| ИНАЧЕ Корректировка.ДатаОкончания
| КОНЕЦ КАК ДатаПо,
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.КоличествоДнейОсновногоОтпуска
| ИНАЧЕ Корректировка.КоличествоДней
| КОНЕЦ КАК ДнейОтпуска,
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.НачалоПериодаЗаКоторыйПредоставляетсяОтпуск
| ИНАЧЕ Корректировка.РабочийПериодС
| КОНЕЦ КАК РабочийГодС,
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.КонецПериодаЗаКоторыйПредоставляетсяОтпуск
| ИНАЧЕ Корректировка.РабочийПериодПо
| КОНЕЦ КАК РабочийГодПо,
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.Основание
| ИНАЧЕ Корректировка.Основание
| КОНЕЦ КАК Основание
|ИЗ
| Документ.Отпуск КАК Отпуск
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК Корректировка
| ПО Отпуск.Сотрудник = Корректировка.Сотрудник
| И Корректировка.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках
| И Корректировка.ДокументОснование.Проведен
| И Корректировка.ПериодЗаписи >= '20180101'
| И (
| (Отпуск.ДатаНачалаОсновногоОтпуска МЕЖДУ Корректировка.ДатаНачала И Корректировка.ДатаОкончания)
| ИЛИ (Отпуск.ДатаОкончанияОсновногоОтпуска МЕЖДУ Корректировка.ДатаНачала И Корректировка.ДатаОкончания)
| ИЛИ (Корректировка.ДатаНачала МЕЖДУ Отпуск.ДатаНачалаОсновногоОтпуска И Отпуск.ДатаОкончанияОсновногоОтпуска)
| )
|ГДЕ
| Отпуск.Проведен
| И Отпуск.Сотрудник В(&Сотрудники)
|
|ОБЪЕДИНИТЬ ВСЕ
|
|// Добавляем корректировки, для которых нет документов Отпуск
|ВЫБРАТЬ
| Корректировка.Сотрудник КАК Сотрудник,
| Корректировка.ДокументОснование.Номер КАК НомерПриказа,
| Корректировка.ДокументОснование.Дата КАК ДатаПриказа,
| Корректировка.ДатаНачала КАК ДатаС,
| Корректировка.ДатаОкончания КАК ДатаПо,
| Корректировка.КоличествоДней КАК ДнейОтпуска,
| Корректировка.РабочийПериодС КАК РабочийГодС,
| Корректировка.РабочийПериодПо КАК РабочийГодПо,
| Корректировка.Основание КАК Основание
|ИЗ
| РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК Корректировка
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.Отпуск КАК Отпуск
| ПО Корректировка.Сотрудник = Отпуск.Сотрудник
| И Отпуск.Проведен
| И (
| (Отпуск.ДатаНачалаОсновногоОтпуска МЕЖДУ Корректировка.ДатаНачала И Корректировка.ДатаОкончания)
| ИЛИ (Отпуск.ДатаОкончанияОсновногоОтпуска МЕЖДУ Корректировка.ДатаНачала И Корректировка.ДатаОкончания)
| ИЛИ (Корректировка.ДатаНачала МЕЖДУ Отпуск.ДатаНачалаОсновногоОтпуска И Отпуск.ДатаОкончанияОсновногоОтпуска)
| )
|ГДЕ
| Корректировка.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках
| И Корректировка.ДокументОснование.Проведен
| И Корректировка.ПериодЗаписи >= '20180101'
| И Корректировка.Сотрудник В(&Сотрудники)
| И Отпуск.Сотрудник ЕСТЬ NULL // Только корректировки без документов Отпуск
|
|УПОРЯДОЧИТЬ ПО
| Сотрудник,
| ДатаС";
Итоговая реализация механизма приоритета
Рекомендуемый подход: Использовать двухэтапный механизм с исключением периодов документов при наличии корректировок.
Ключевые моменты:
- ✅ Корректировки всегда имеют приоритет
- ✅ Данные из документов «Отпуск» исключаются, если есть корректировка за тот же период
- ✅ Механизм работает автоматически при формировании отчетов
- ✅ Легко отслеживать источник данных через флаг
ЭтоКорректировка
Важное уточнение: Различение корректировок и обычных данных
Проблема: В регистре ДанныеОтпусковКарточкиСотрудника могут быть данные:
- Из обычных документов-регистраторов (Отпуск, ОтпускБезСохраненияОплаты и др.) — через обработчики правил регистрации
- Из документов корректировки (КорректировкаДанныхОбОтпусках) — напрямую через набор записей
Решение: Использовать поле ДокументОснование для идентификации источника данных.
В запросе фильтровать по виду документа:
ГДЕ
Корректировка.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках
И Корректировка.ДокументОснование.Проведен
Для обычных данных из регистра (не корректировки):
ГДЕ
РеестрОтпусков.ДокументОснование.ВидДокумента <> Документы.КорректировкаДанныхОбОтпусках
ИЛИ РеестрОтпусков.ДокументОснование.ВидДокумента = Документы.Отпуск
ИЛИ РеестрОтпусков.ДокументОснование.ВидДокумента = Документы.ОтпускБезСохраненияОплаты
// и т.д. для других документов-регистраторов
Полная схема приоритета данных
Порядок приоритета (от высшего к низшему):
- Корректировки из документа «КорректировкаДанныхОбОтпусках» (регистр
ДанныеОтпусковКарточкиСотрудника)- Высший приоритет
- «Затирают» все остальные данные за тот же период
- Данные из документов «Отпуск» (регистр
ДанныеОтпусковКарточкиСотрудника, заполненный через обработчики)- Используются, если нет корректировок за тот же период
- Данные из регистра «РеестрОтпусков» (для документов
ПереносДанныхи исторических данных)- Используются для исторических данных (до 2018 г)
- Данные напрямую из документов «Отпуск» (для отчета Т2)
- Используются в базовом модуле
КадровыйУчетБазовыйдля отчета Т2 - Важно: Этот механизм не учитывает корректировки, нужно модифицировать!
- Используются в базовом модуле
Модификация функции ДополнительныеСведенияУнифицированнойФормыТ2
Проблема: Функция ДополнительныеСведенияУнифицированнойФормыТ2 в модуле КадровыйУчетБазовый берет данные напрямую из документов «Отпуск», не учитывая корректировки.
Решение: Модифицировать функцию для учета корректировок:
// В функции КадровыйУчетБазовый.ДополнительныеСведенияУнифицированнойФормыТ2
// Вместо прямого запроса к документам Отпуск:
// Вариант 1: Использовать временную таблицу ВТРеестрОтпусков (если она уже создана)
// Или создать её здесь
// Вариант 2: Модифицировать запрос для учета корректировок
Запрос.Текст =
"ВЫБРАТЬ
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.Сотрудник
| ИНАЧЕ Корректировка.Сотрудник
| КОНЕЦ КАК Сотрудник,
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.Номер
| ИНАЧЕ Корректировка.ДокументОснование.Номер
| КОНЕЦ КАК НомерПриказа,
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.Дата
| ИНАЧЕ Корректировка.ДокументОснование.Дата
| КОНЕЦ КАК ДатаПриказа,
| ВЫБОР
| КОГДА Корректировка.Сотрудник ЕСТЬ NULL
| ТОГДА Отпуск.ДатаНачалаОсновногоОтпуска
| ИНАЧЕ Корректировка.ДатаНачала
| КОНЕЦ КАК ДатаС,
| ...
|ИЗ
| Документ.Отпуск КАК Отпуск
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК Корректировка
| ПО Отпуск.Сотрудник = Корректировка.Сотрудник
| И Корректировка.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках
| И Корректировка.ДокументОснование.Проведен
| И (
| (Отпуск.ДатаНачалаОсновногоОтпуска МЕЖДУ Корректировка.ДатаНачала И Корректировка.ДатаОкончания)
| ИЛИ (Отпуск.ДатаОкончанияОсновногоОтпуска МЕЖДУ Корректировка.ДатаНачала И Корректировка.ДатаОкончания)
| ИЛИ (Корректировка.ДатаНачала МЕЖДУ Отпуск.ДатаНачалаОсновногоОтпуска И Отпуск.ДатаОкончанияОсновногоОтпуска)
| )
|ГДЕ
| Отпуск.Проведен
| И Отпуск.Сотрудник В(&Сотрудники)
| И (Корректировка.Сотрудник ЕСТЬ NULL ИЛИ Корректировка.Сотрудник ЕСТЬ НЕ NULL)
|
|ОБЪЕДИНИТЬ ВСЕ
|
|// Добавляем корректировки, для которых нет документов Отпуск
|ВЫБРАТЬ
| Корректировка.Сотрудник КАК Сотрудник,
| Корректировка.ДокументОснование.Номер КАК НомерПриказа,
| Корректировка.ДокументОснование.Дата КАК ДатаПриказа,
| Корректировка.ДатаНачала КАК ДатаС,
| Корректировка.ДатаОкончания КАК ДатаПо,
| ...
|ИЗ
| РегистрСведений.ДанныеОтпусковКарточкиСотрудника КАК Корректировка
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.Отпуск КАК Отпуск
| ПО Корректировка.Сотрудник = Отпуск.Сотрудник
| И Отпуск.Проведен
| И (
| (Отпуск.ДатаНачалаОсновногоОтпуска МЕЖДУ Корректировка.ДатаНачала И Корректировка.ДатаОкончания)
| ИЛИ (Отпуск.ДатаОкончанияОсновногоОтпуска МЕЖДУ Корректировка.ДатаНачала И Корректировка.ДатаОкончания)
| ИЛИ (Корректировка.ДатаНачала МЕЖДУ Отпуск.ДатаНачалаОсновногоОтпуска И Отпуск.ДатаОкончанияОсновногоОтпуска)
| )
|ГДЕ
| Корректировка.ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках
| И Корректировка.ДокументОснование.Проведен
| И Корректировка.Сотрудник В(&Сотрудники)
| И Отпуск.Сотрудник ЕСТЬ NULL // Только корректировки без документов Отпуск
|
|УПОРЯДОЧИТЬ ПО
| Сотрудник,
| ДатаС";
Но это усложняет логику. Лучше использовать уже созданную временную таблицу ВТРеестрОтпусков, если она доступна в контексте функции.
Рекомендация по реализации механизма приоритета
Оптимальный подход:
- Модифицировать процедуру
СоздатьВТРеестрОтпусковдля реализации механизма приоритета (как описано в Варианте 3) - Использовать созданную временную таблицу в функции
ДополнительныеСведенияУнифицированнойФормыТ2вместо прямого запроса к документам - Добавить параметр в функцию
ДополнительныеСведенияУнифицированнойФормыТ2для передачи уже созданной временной таблицыВТРеестрОтпусков
Преимущества:
- ✅ Единая логика формирования данных
- ✅ Корректировки учитываются во всех отчетах
- ✅ Нет дублирования логики
- ✅ Легче поддерживать
Итоговая схема работы с приоритетом
Формирование отчета Т2
↓
Вызов ПриКомпоновкеРезультата
↓
Вызов ДополнительныеСведенияУнифицированнойФормыТ2
↓
Создание ВТРеестрОтпусков (с учетом приоритета корректировок)
↓
Использование данных из ВТРеестрОтпусков
↓
Отчет содержит данные с учетом корректировок
Ключевой принцип: Корректировки из документа «КорректировкаДанныхОбОтпусках» всегда имеют приоритет и «затирают» данные из документов «Отпуск» за тот же период.
Краткое резюме: Где вносить изменения
Место 1: CommonModules/КадровыйУчетРасширенный/Ext/Module.bsl
- Процедура:
СоздатьВТРеестрОтпусков(строки 771-940) - Что изменить:
- После строки 795: добавить создание временной таблицы
ВТКорректировкиОтпусков - Строки 800-836: модифицировать запрос — разделить на корректировки и обычные данные
- Добавить LEFT JOIN для исключения периодов с корректировками
- Строка 934: добавить уничтожение
ВТКорректировкиОтпусков
- После строки 795: добавить создание временной таблицы
Место 2: CommonModules/КадровыйУчетБазовый/Ext/Module.bsl
- Функция:
ДополнительныеСведенияУнифицированнойФормыТ2(строки 1457-1623) - Что изменить:
- Строки 1562-1581: модифицировать запрос к документам «Отпуск» для учета корректировок
- Добавить LEFT JOIN с регистром
ДанныеОтпусковКарточкиСотрудника(фильтр по виду документа) - Использовать COALESCE для выбора данных с приоритетом корректировок
- Добавить UNION для корректировок без документов «Отпуск»
Ключевые изменения в запросах:
- ✅ Фильтрация по
ДокументОснование.ВидДокумента = Документы.КорректировкаДанныхОбОтпусках - ✅ Проверка пересечения периодов отпуска (МЕЖДУ)
- ✅ Исключение обычных данных при наличии корректировок (LEFT JOIN + ЕСТЬ NULL)
- ✅ Приоритет корректировок через COALESCE или разделение на этапы
Модификация процедуры СоздатьВТРеестрОтпусков для учета корректировок:
// В процедуре КадровыйУчетРасширенный.СоздатьВТРеестрОтпусков
// Добавить после объединения с РеестрОтпусков (для ПереносДанных):
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Корректировка.ПериодЗаписи КАК Период,
Корректировка.Сотрудник КАК Сотрудник,
Корректировка.Ссылка КАК ДокументОснование,
Корректировка.ВидОтпуска КАК ВидОтпускаСсылка,
Корректировка.ВидОтпуска КАК ВидОтпуска,
Корректировка.РабочийПериодС КАК РабочийГодС,
Корректировка.РабочийПериодПо КАК РабочийГодПо,
Корректировка.КоличествоДней КАК ДнейОтпуска,
Корректировка.ДатаНачала КАК ДатаС,
Корректировка.ДатаОкончания КАК ДатаПо,
...
ИЗ
ВТТаблицаСотрудников КАК ТаблицаСотрудников
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.КорректировкаДанныхОбОтпусках.Отпуска КАК Корректировка
ПО ТаблицаСотрудников.Сотрудник = Корректировка.Ссылка.Сотрудник
И ТаблицаСотрудников.Период >= Корректировка.ПериодЗаписи
И Корректировка.Ссылка.Проведен
Ключевые моменты по предотвращению наложений
1. Ключ записи в регистре
Регистр ДанныеОтпусковКарточкиСотрудника имеет ключ:
Сотрудник(измерение)ПериодЗаписи(измерение)
Это означает:
- Для одного сотрудника может быть только одна запись с конкретным значением
ПериодЗаписи - При записи новой записи с тем же ключом старая запись будет заменена
- Наложений по ключу быть не может — записи с одинаковым ключом заменяют друг друга
2. Проблема наложений по периодам отпуска
Проблема: Если в текущем периоде уже есть документ Отпуск с датами 01.01.2024 — 15.01.2024, а мы добавляем корректировку с датами 10.01.2024 — 20.01.2024, то в отчете могут быть дубли или некорректные данные.
Решение:
- Использовать уникальный
ПериодЗаписидля корректировок:- Для исторических данных (прошлые периоды): использовать дату начала отпуска как
ПериодЗаписи - Для корректировок текущего периода: использовать дату документа корректировки + смещение (например,
ДатаДокумента + 1 день)
- Для исторических данных (прошлые периоды): использовать дату начала отпуска как
- Проверять пересечения периодов перед записью (см. функцию
ПроверитьОтсутствиеНаложенийвыше) - Приоритет данных:
- Если есть документ
Отпуск— использовать данные из него - Если есть только корректировка — использовать данные из корректировки
- Если есть и то, и другое — нужно определить приоритет (например, документ Отпуск имеет приоритет)
- Если есть документ
3. Стратегия работы с текущим периодом
Для корректировок закрытых периодов (прошлые годы):
- ✅ Безопасно — нет конфликтов с текущими документами
- ✅ Использовать дату начала отпуска как
ПериодЗаписи
Для корректировок текущего периода:
- ⚠️ Требует осторожности — возможны наложения
- ✅ Рекомендуется:
- Проверять наличие документов
Отпускна тот же период - Если документ есть — корректировать его, а не создавать запись в регистре
- Если документа нет (исторические данные) — создавать запись с уникальным
ПериодЗаписи
- Проверять наличие документов
4. Альтернативный подход: Использование регистра «РеестрОтпусков»
Важно: В конфигурации существует еще один регистр — РеестрОтпусков (физический регистр сведений), который используется для документов ПереносДанных.
Характеристики регистра РеестрОтпусков:
- Используется только для документов
ПереносДанных - Учитывается при формировании временной таблицы «РеестрОтпусков»
- Может быть альтернативой для хранения корректировок
Но: Использование этого регистра требует:
- Модификации процедуры
СоздатьВТРеестрОтпусков - Понимания структуры регистра
РеестрОтпусков - Возможных конфликтов с существующими механизмами
Рекомендация: Использовать регистр ДанныеОтпусковКарточкиСотрудника как основной, так как он уже используется для всех документов-регистраторов.
Итоговая рекомендация по Варианту 2
Куда писать: В регистр ДанныеОтпусковКарточкиСотрудника напрямую через набор записей.
Почему данные не затрутся:
- Регистр независимый — записи сохраняются
- Обработчики правил регистрации работают только с документами из типа
РегистраторыПериодовОтпусковКарточкиСотрудника - Если документ корректировки НЕ включен в этот тип — обработчики его не трогают
Как избежать наложений:
- Использовать уникальный
ПериодЗаписидля каждой записи - Проверять пересечения периодов перед записью
- Для текущего периода — проверять наличие документов
Отпуск - Для прошлых периодов — безопасно использовать дату начала отпуска как
ПериодЗаписи
Интеграция с отчетами:
- Модифицировать процедуру
СоздатьВТРеестрОтпусковдля учета данных из регистра, созданных документами корректировки - Или использовать данные напрямую из регистра (они уже там есть)
Вариант 3: Использование документа «ПереносДанных»
Преимущества:
- Существующий механизм в конфигурации
- Уже интегрирован с системой
- Поддерживает массовый ввод данных
Недостатки:
- Может не подходить для корректировок (предназначен для переноса)
- Ограниченная функциональность для работы с отпусками
- Может требовать доработки
Использование:
Документ «ПереносДанных» уже включен в определенный тип РегистраторыПериодовОтпусковКарточкиСотрудника, что означает, что данные из него учитываются при формировании временной таблицы «РеестрОтпусков».
Вариант 4: Создание дополнительного регистра для корректировок
Преимущества:
- Разделение исторических данных и корректировок
- Возможность независимого управления корректировками
- Легче отслеживать изменения
Недостатки:
- Требует модификации процедуры
СоздатьВТРеестрОтпусков - Усложнение логики формирования отчетов
- Дублирование структуры данных
Реализация:
- Создать регистр
КорректировкиДанныхОбОтпускахс аналогичной структурой - Модифицировать процедуру
СоздатьВТРеестрОтпусковдля объединения данных:
// В процедуре СоздатьВТРеестрОтпусков добавить объединение:
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Корректировки.ПериодЗаписи КАК Период,
Корректировки.Сотрудник КАК Сотрудник,
Корректировки.ДокументОснование,
...
ИЗ
ВТТаблицаСотрудников КАК ТаблицаСотрудников
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КорректировкиДанныхОбОтпусках КАК Корректировки
ПО ТаблицаСотрудников.Сотрудник = Корректировки.Сотрудник
И ТаблицаСотрудников.Период >= Корректировки.ПериодЗаписи
Рекомендации по выбору варианта
Для добавления исторических данных (миграция):
Рекомендуется: Вариант 1 (Прямая запись) или Вариант 2 (Собственный документ)
- Если данные вносятся один раз при миграции → Вариант 1 (проще и быстрее)
- Если требуется документирование и контроль → Вариант 2 (лучше для аудита)
Для корректировки закрытых периодов:
Рекомендуется: Вариант 2 (Собственный документ)
- Обеспечивает полное документирование операций
- Позволяет отслеживать историю изменений
- Дает возможность отмены корректировок
- Интегрируется с существующими механизмами контроля
Практические рекомендации
- Использовать существующие механизмы: По возможности использовать стандартный метод
ЗаполнитьДвиженияПоДаннымВыборкиРегистраторов, создав виртуальные документы-регистраторы. - Документирование: Всегда документировать операции корректировки (причина, дата, ответственный).
- Контроль целостности: После внесения корректировок проверять:
- Отсутствие дублей записей
- Корректность периодов
- Согласованность с другими регистрами (если применимо)
- Тестирование: Перед массовым вводом данных тестировать на небольшом объеме.
- Резервное копирование: Перед массовыми корректировками создавать резервную копию данных.
Пример реализации (Вариант 1 — Прямая запись)
// Обработка для массового ввода данных об отпусках
Процедура ЗаполнитьДанныеОбОтпускахЗаПрошлыеПериоды(ТаблицаДанных)
НачатьТранзакцию();
Попытка
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
НаборЗаписей = РегистрыСведений.ДанныеОтпусковКарточкиСотрудника.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Сотрудник.Установить(СтрокаДанных.Сотрудник);
НаборЗаписей.Отбор.ПериодЗаписи.Установить(СтрокаДанных.ПериодЗаписи);
// Удаляем существующую запись, если есть
Пока НаборЗаписей.Количество() > 0 Цикл
НаборЗаписей.Удалить(НаборЗаписей[0]);
КонецЦикла;
// Добавляем новую запись
Запись = НаборЗаписей.Добавить();
Запись.Сотрудник = СтрокаДанных.Сотрудник;
Запись.ПериодЗаписи = СтрокаДанных.ПериодЗаписи;
Запись.ДокументОснование = СтрокаДанных.ДокументОснование; // Может быть пустым
Запись.ВидОтпуска = СтрокаДанных.ВидОтпуска;
Запись.РабочийПериодС = СтрокаДанных.РабочийПериодС;
Запись.РабочийПериодПо = СтрокаДанных.РабочийПериодПо;
Запись.КоличествоДней = СтрокаДанных.КоличествоДней;
Запись.ДатаНачала = СтрокаДанных.ДатаНачала;
Запись.ДатаОкончания = СтрокаДанных.ДатаОкончания;
Запись.Основание = СтрокаДанных.Основание;
НаборЗаписей.Записать();
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
Заключение по корректировкам
Оптимальный подход:
- Для разовых операций миграции: Использовать Вариант 1 (прямая запись в регистр) через обработку или скрипт.
- Для регулярных корректировок: Создать Вариант 2 (собственный документ «КорректировкаДанныхОбОтпусках») для обеспечения документирования и контроля.
- Не рекомендуется: Создавать отдельный регистр (Вариант 4), так как это усложняет логику без существенных преимуществ.
Важно: Независимо от выбранного варианта, все корректировки должны быть задокументированы и протестированы перед применением в продуктивной базе.
Куда писать данные: Регистр «ДанныеОтпусковКарточкиСотрудника»
Ответ на ключевой вопрос
Вопрос: Куда писать данные из документа «КорректировкаДанныхОбОтпусках»? Регистр формируется динамически, не затрутся ли изменения?
Ответ: Писать нужно напрямую в регистр ДанныеОтпусковКарточкиСотрудника. Данные НЕ затрутся, потому что:
- Регистр непериодический и независимый — записи сохраняются в базе данных и не удаляются автоматически
- Регистр не формируется динамически — данные записываются один раз и остаются в базе
- Обработчики правил регистрации вызывают заполнение только для документов из определенного типа
РегистраторыПериодовОтпусковКарточкиСотрудника - Если документ корректировки НЕ включен в этот тип — обработчики его не трогают, данные остаются в регистре
Структура ключа записи
Ключ записи в регистре:
Сотрудник(измерение)ПериодЗаписи(измерение)
Важно:
- Для одного сотрудника может быть только одна запись с конкретным значением
ПериодЗаписи - При записи новой записи с тем же ключом старая запись заменяется
- Это означает, что наложений по ключу быть не может — записи с одинаковым ключом заменяют друг друга
Проблема наложений по периодам отпуска
Суть проблемы:
Если в текущем периоде уже есть документ Отпуск с датами 01.01.2024 — 15.01.2024, а мы добавляем корректировку с датами 10.01.2024 — 20.01.2024, то:
- В регистре
ДанныеОтпусковКарточкиСотрудникабудет запись из документаОтпуск(если он проведен) - В регистре может быть запись из документа корректировки (если он проведен)
- При формировании отчетов могут быть дубли или некорректные данные
Решение:
- Использовать уникальный
ПериодЗаписидля корректировок:- Для исторических данных (прошлые периоды): использовать дату начала отпуска как
ПериодЗаписи - Для корректировок текущего периода: использовать дату документа корректировки + уникальное смещение
- Для исторических данных (прошлые периоды): использовать дату начала отпуска как
- Проверять пересечения периодов перед записью:
// Проверка на наложения с документами Отпуск Функция ПроверитьОтсутствиеНаложений(Сотрудник, ДатаНачала, ДатаОкончания, ИсключаемыйДокумент) Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | Отпуск.Ссылка |ИЗ | Документ.Отпуск КАК Отпуск |ГДЕ | Отпуск.Проведен | И Отпуск.Сотрудник = &Сотрудник | И Отпуск.Ссылка <> &ИсключаемыйДокумент | И ( | (Отпуск.ДатаНачалаОсновногоОтпуска МЕЖДУ &ДатаНачала И &ДатаОкончания) | ИЛИ (Отпуск.ДатаОкончанияОсновногоОтпуска МЕЖДУ &ДатаНачала И &ДатаОкончания) | ИЛИ (&ДатаНачала МЕЖДУ Отпуск.ДатаНачалаОсновногоОтпуска И Отпуск.ДатаОкончанияОсновногоОтпуска) | ИЛИ (&ДатаОкончания МЕЖДУ Отпуск.ДатаНачалаОсновногоОтпуска И Отпуск.ДатаОкончанияОсновногоОтпуска) | )"; Запрос.УстановитьПараметр("Сотрудник", Сотрудник); Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала); Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания); Запрос.УстановитьПараметр("ИсключаемыйДокумент", ИсключаемыйДокумент); Результат = Запрос.Выполнить(); Возврат Результат.Пустой(); // Истина, если наложений нет КонецФункции - Приоритет данных:
- Если есть документ
Отпуск— использовать данные из него (он имеет приоритет) - Если есть только корректировка — использовать данные из корректировки
- Если есть и то, и другое — нужно определить приоритет в логике формирования отчетов
- Если есть документ
Стратегия работы с периодами
Для корректировок закрытых периодов (прошлые годы)
Безопасно:
- ✅ Нет конфликтов с текущими документами
- ✅ Использовать дату начала отпуска как
ПериодЗаписи - ✅ Можно записывать напрямую в регистр без дополнительных проверок
Пример:
Запись.Сотрудник = Сотрудник;
Запись.ПериодЗаписи = ДатаНачалаОтпуска; // Дата из прошлого периода
Запись.ДокументОснование = Ссылка; // Ссылка на документ корректировки
// ... остальные поля
Для корректировок текущего периода
Требует осторожности:
- ⚠️ Возможны наложения с документами
Отпуск - ✅ Рекомендуется:
- Проверять наличие документов
Отпускна тот же период - Если документ есть — корректировать его через документ «Исправление», а не создавать запись в регистре
- Если документа нет (исторические данные) — создавать запись с уникальным
ПериодЗаписи
- Проверять наличие документов
Пример с проверкой:
// Проверяем наличие документов Отпуск
Если НЕ ПроверитьОтсутствиеНаложений(Сотрудник, ДатаНачала, ДатаОкончания, Ссылка) Тогда
Отказ = Истина;
ВызватьИсключение "Обнаружено наложение с существующим документом Отпуск!
Рекомендуется использовать документ 'Исправление' для корректировки.";
КонецЕсли;
// Если наложений нет - записываем в регистр
Запись.Сотрудник = Сотрудник;
Запись.ПериодЗаписи = ДатаДокумента + 1; // Уникальный период для корректировки
Запись.ДокументОснование = Ссылка;
// ... остальные поля
Итоговая схема работы с корректировками
1. Создание документа "КорректировкаДанныхОбОтпусках"
↓
2. Проверка на наложения с документами Отпуск
↓
3. Определение уникального ПериодЗаписи
↓
4. Запись данных в регистр ДанныеОтпусковКарточкиСотрудника
(напрямую через набор записей)
↓
5. Данные сохраняются в регистре
(НЕ затрутся, т.к. регистр независимый)
↓
6. При формировании отчетов данные учитываются из регистра
(через временную таблицу "РеестрОтпусков")
Рекомендации по реализации
- НЕ включать документ «КорректировкаДанныхОбОтпусках» в тип
РегистраторыПериодовОтпусковКарточкиСотрудника- Это предотвратит автоматическое перезаполнение регистра обработчиками
- Данные останутся в регистре после записи
- Писать напрямую в регистр
ДанныеОтпусковКарточкиСотрудникачерез набор записей- Использовать ключ:
Сотрудник+ПериодЗаписи - При одинаковом ключе старая запись заменяется новой
- Использовать ключ:
- Проверять наложения перед записью для текущего периода
- Использовать функцию проверки пересечений периодов
- Для прошлых периодов проверка не обязательна
- Модифицировать процедуру
СоздатьВТРеестрОтпусковдля учета корректировок- Добавить объединение данных из регистра, созданных документами корректировки
- Или использовать данные напрямую из регистра (они уже там есть)
- Рекомендуемый подход: Разделение по периодам
- До 2018 года: Использовать регистр
РеестрОтпусковчерез движения документа - С 2018 года: Использовать регистр
ДанныеОтпусковКарточкиСотрудникачерез набор записей - Преимущества: четкое разделение, использование существующих механизмов, автоматический учет в отчетах
- До 2018 года: Использовать регистр
Заключение
Механизм формирования отчетов по отпускам в 1С:ЗУП построен на гибридной модели:
- Хранение данных: Регистр сведений
ДанныеОтпусковКарточкиСотрудника - Формирование отчетов: Динамическое формирование из документов и регистра
- Временные таблицы: Использование временных таблиц для агрегации данных
Такой подход обеспечивает гибкость и актуальность данных, но требует внимательного подхода к корректировке и синхронизации данных между различными источниками.
Полезные ссылки на код
- Модуль формирования временной таблицы:
CommonModules/КадровыйУчетРасширенный/Ext/Module.bsl(процедураСоздатьВТРеестрОтпусков) - Модуль сбора данных для Т2:
CommonModules/КадровыйУчетБазовый/Ext/Module.bsl(функцияДополнительныеСведенияУнифицированнойФормыТ2) - Модуль отчета Т2:
Reports/УнифицированнаяФормаТ2/Ext/ObjectModule.bsl - Модуль проведения документа Отпуск:
Documents/Отпуск/Ext/ManagerModule.bsl