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