При разработке в среде 1С:Зарплата и управление персоналом 3.1 программисты часто сталкиваются с задачей расширения типового функционала. Одной из популярных задач является добавление пользовательских колонок в табличные части основных документов, таких как Начисление зарплаты и взносов. Однако стандартные механизмы программы могут преподнести сюрприз: при нажатии кнопки «Пересчитать сотрудника» все данные, введенные вручную в новую колонку, бесследно исчезают. Разберем подробно, почему это происходит и как правильно реализовать сохранение данных через расширение конфигурации.
Многие начинающие разработчики полагают, что пересчет строки в документе — это просто обновление числовых показателей (результата расчета) в уже существующих строках. На самом деле в ЗУП 3.1 (особенно в ранних релизах, таких как 3.1.1) реализован механизм полного перезаполнения. Рассмотрим, что происходит «под капотом» системы при вызове команды пересчета:
Начисления.Так как ваш реквизит добавлен через расширение, типовой код формирования новых строк ничего не знает о его существовании. Новая строка инициализируется пустой, и данные из удаленной «старой» строки в нее не переносятся. Чтобы решить эту проблему, нам необходимо вмешаться в процесс пересчета.
Это наиболее прямой технический способ решения задачи. Нам нужно «запомнить» значения нашей колонки до того, как строки будут удалены, и «вернуть» их после того, как новые строки будут созданы. Выясним, какие процедуры нам потребуются.
Обычно команда пересчета на форме документа вызывает серверную процедуру. Нам необходимо создать в расширении два метода с аннотациями &Перед и &После. Рассмотрим примерный алгоритм реализации:
Шаг 1. Сохранение данных. В процедуре &Перед мы выгружаем данные по сотруднику во временную таблицу значений, которую сохраняем в переменной модуля формы или передаем через параметры.
&Перед("ПересчитатьСотрудникаСервер")
Процедура Расш1_ПередПересчитатьСотрудникаСервер(Сотрудник, ИдентификаторСтроки)
// Создаем таблицу для хранения «старых» данных
ТЗ_Буфер = Новый ТаблицаЗначений;
ТЗ_Буфер.Колонки.Добавить("ВидРасчета");
ТЗ_Буфер.Колонки.Добавить("МойРеквизит"); // Ваше кастомное поле
// Находим строки сотрудника и сохраняем значение
ПараметрыОтбора = Новый Структура("Сотрудник", Сотрудник);
НайденныеСтроки = Объект.Начисления.НайтиСтроки(ПараметрыОтбора);
Для Каждого СтрокаТЧ Из НайденныеСтроки Цикл
НоваяЗапись = ТЗ_Буфер.Добавить();
ЗаполнитьЗначенияСвойств(НоваяЗапись, СтрокаТЧ);
КонецЦикла;
// Сохраняем ТЗ в реквизит формы или временное хранилище для доступа в &После
ЭтотОбъект.ПараметрыПересчета.Вставить("БуферДанных", ТЗ_Буфер);
КонецПроцедуры
Шаг 2. Восстановление данных. В процедуре &После мы ищем новые созданные строки и сопоставляем их с нашим буфером по ключевым полям (например, по Сотрудник и ВидРасчета).
&После("ПересчитатьСотрудникаСервер")
Процедура Расш1_ПослеПересчитатьСотрудникаСервер(Сотрудник, ИдентификаторСтроки)
ТЗ_Буфер = Неопределено;
Если Не ЭтотОбъект.ПараметрыПересчета.Свойство("БуферДанных", ТЗ_Буфер) Тогда
Возврат;
КонецЕсли;
// Обходим новые строки и восстанавливаем значения
ПараметрыОтбора = Новый Структура("Сотрудник", Сотрудник);
НовыеСтроки = Объект.Начисления.НайтиСтроки(ПараметрыОтбора);
Для Каждого СтрокаТЧ Из НовыеСтроки Цикл
ОтборБуфера = Новый Структура("ВидРасчета", СтрокаТЧ.ВидРасчета);
СтрокиБуфера = ТЗ_Буфер.НайтиСтроки(ОтборБуфера);
Если СтрокиБуфера.Количество() > 0 Тогда
СтрокаТЧ.МойРеквизит = СтрокиБуфера[0].МойРеквизит;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важный нюанс: Поиск только по виду расчета может быть некорректным, если у сотрудника несколько одинаковых начислений (например, две надбавки). В этом случае рекомендуется использовать скрытые технические поля связи, такие как ИдентификаторСтрокиВидаРасчета, если они доступны в вашем релизе.
Проанализируем ситуацию глубже. Если ваша ячейка должна содержать данные, которые влияют на расчет или просто должны там храниться, возможно, добавление колонки в ТЧ — не лучший путь. В 1С:ЗУП 3.1 предусмотрен механизм показателей расчета зарплаты.
Если данные в ячейке — это число, которое должен вводить пользователь, лучше сделать следующее:
Начисление зарплаты и взносов в табличной части Начисления автоматически появится колонка для ввода этого показателя.Преимущество этого метода: Данные будут сохраняться типовым механизмом. При пересчете программа сама увидит введенный показатель и подставит его в расчет. Вам не придется писать ни одной строчки кода в расширении.
Если данные в вашей колонке носят справочный характер и не участвуют напрямую в математических формулах, рассмотрите вариант создания собственной табличной части в расширении документа.
Поскольку типовой механизм пересчета очищает только стандартную коллекцию Начисления, ваша кастомная ТЧ останется нетронутой. Вам останется только синхронизировать отображение данных на форме, связав строки основной ТЧ и вашей новой ТЧ по индексу или уникальному ключу сотрудника. Это более трудоемкий, но архитектурно «чистый» способ, не нарушающий логику работы типовых процедур обновления.
Выясним причину ошибки: данные обнуляются из-за того, что ЗУП 3.1 пересоздает строки «с чистого листа». Для решения задачи мы можем либо программно кэшировать данные в расширении, используя методы &Перед и &После, либо использовать типовой функционал показателей, что является более предпочтительным с точки зрения стабильности системы. Выбор метода зависит от того, должен ли ваш реквизит участвовать в формуле расчета или он просто выполняет роль комментария/метки.