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