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