При разработке собственных механизмов интеграции между конфигурациями 1С:Бухгалтерия предприятия (БП) и 1С:Зарплата и управление персоналом (ЗУП) часто возникает необходимость выгрузить накопленные первичные данные (например, учет питания сотрудников) и создать на их основании соответствующие расчетные документы. Разберем типичные ошибки, возникающие при написании подобной выгрузки, и рассмотрим правильную архитектуру переноса данных с разделением записей на два отдельных документа.
Выясним причину, почему исходный код автора не работает и вызывает ошибки выполнения:
Документы.РегистрацияРазовыхНачисленийРаботниковОрганизаций.СоздатьДокумент(), если данный документ принадлежит метаданным другой программы (ЗУП). В базе-источнике этого объекта метаданных попросту не существует.В тексте запроса указана секция СГРУППИРОВАТЬ ПО, однако не использованы агрегатные функции (например, СУММА(Сумма)). Кроме того, параметр Организация устанавливается в коде, но отсутствует в блоке ГДЕ.
Конструкция Если ТекСтрока = Поле пытается сравнить целую строку таблицы значений с неопределенной переменной. Для проверки булева признака необходимо обращаться к конкретному реквизиту строки: Если ТекСтрока.Поле Тогда.
Присваивание ТЗ.Сотрудники = ... ошибочно, так как обращение идет ко всей таблице значений, а не к строке формируемой табличной части документа.
Для передачи данных между разделенными конфигурациями выделим три основных подхода:
V83.COMConnector): база-источник подключается к базе-приемнику, находит необходимые элементы справочников и программно создает документы в ЗУП.Проанализируем правила сопоставления ссылочных типов. Нельзя напрямую передавать ссылки на физические лица или организации между базами, так как их уникальные идентификаторы (GUID) в разных информационных базах не совпадают. Сопоставление необходимо выполнять по бизнес-ключам:
ИНН и КПП.СНИЛС, ИНН или ФИО + Дате рождения.Сотрудники).Рассмотрим, как разделить таблицу значений на две группы по признаку флага Поле. Для этого создадим два отдельных документа и при обходе строк распределим начисления:
// Создаем два документа для разных условий
ДокументСПолем = БазаЗУП.Документы.РазовоеНачисление.СоздатьДокумент();
ДокументБезПоля = БазаЗУП.Документы.РазовоеНачисление.СоздатьДокумент();
Для Каждого СтрТЗ Из ТЗ Цикл
Если СтрТЗ.Поле Тогда
НоваяСтрока = ДокументСПолем.Начисления.Добавить();
Иначе
НоваяСтрока = ДокументБезПоля.Начисления.Добавить();
КонецЕсли;
// Заполнение реквизитов строки
НоваяСтрока.Сотрудник = НайденныйСотрудникВЗУП;
НоваяСтрока.Результат = СтрТЗ.Сумма;
КонецЦикла;
Разберем по шагам готовый код выгрузки данных из БП в ЗУП. Посмотрим на пример формирования корректного запроса и программного заполнения документов в подключенной базе:
Если НЕ ЗначениеЗаполнено(Организация) Тогда
Сообщить("Не выбрана организация!");
Возврат;
КонецЕсли;
// 1. Формируем выборку данных в базе-источнике (БП)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Питание.Сотрудник.ФизическоеЛицо.СтраховойНомерПФР КАК СНИЛС,
| Питание.Сотрудник.Код КАК ТабельныйНомер,
| Питание.Поле КАК ПризнакПоле,
| СУММА(Питание.Сумма) КАК Сумма
|ИЗ
| Документ.БС_ПитаниеСотрудников.Сотрудники КАК Питание
|ГДЕ
| Питание.Ссылка.Проведен = ИСТИНА
| И Питание.Ссылка.Организация = &Организация
| И Питание.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
|СГРУППИРОВАТЬ ПО
| Питание.Сотрудник.ФизическоеЛицо.СтраховойНомерПФР,
| Питание.Сотрудник.Код,
| Питание.Поле";
Запрос.УстановитьПараметр("Организация", Организация);
Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ПериодРегистрации));
Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ПериодРегистрации));
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Сообщить("Данные для выгрузки отсутствуют.");
Возврат;
КонецЕсли;
ТЗ = РезультатЗапроса.Выгрузить();
// 2. Подключаемся к базе-приемнику (ЗУП) через COM
Попытка
V8 = Новый COMОбъект("V83.COMConnector");
БазаЗУП = V8.Connect("File=""C:\Bases\ZUP"";Usr=""Admin"";Pwd=""123"";");
Исключение
Сообщить("Ошибка подключения к ЗУП: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// 3. Создаем два документа на стороне приемника
ДокФлагИстина = БазаЗУП.Документы.РегистрацияРазовыхНачисленийРаботниковОрганизаций.СоздатьДокумент();
ДокФлагИстина.Дата = ТекущаяДата();
ДокФлагИстина.ПериодРегистрации = НачалоМесяца(ПериодРегистрации);
ДокФлагИстина.Комментарий = "Загрузка из БП (Питание: Поле = Истина)";
ДокФлагЛожь = БазаЗУП.Документы.РегистрацияРазовыхНачисленийРаботниковОрганизаций.СоздатьДокумент();
ДокФлагЛожь.Дата = ТекущаяДата();
ДокФлагЛожь.ПериодРегистрации = НачалоМесяца(ПериодРегистрации);
ДокФлагЛожь.Комментарий = "Загрузка из БП (Питание: Поле = Ложь)";
// 4. Заполняем табличные части
Для Каждого Стр Из ТЗ Цикл
Если Стр.Сумма = 0 Тогда
Продолжить;
КонецЕсли;
// Ищем сотрудника в ЗУП по табельному номеру
СсылкаСотрудник = БазаЗУП.Справочники.СотрудникиОрганизаций.НайтиПоКоду(Стр.ТабельныйНомер);
Если НЕ ЗначениеЗаполнено(СсылкаСотрудник) Тогда
Сообщить("Не найден сотрудник с кодом: " + Стр.ТабельныйНомер);
Продолжить;
КонецЕсли;
Если Стр.ПризнакПоле Тогда
НовСтр = ДокФлагИстина.Начисления.Добавить();
Иначе
НовСтр = ДокФлагЛожь.Начисления.Добавить();
КонецЕсли;
НовСтр.Сотрудник = СсылкаСотрудник;
НовСтр.ФизЛицо = СсылкаСотрудник.Физлицо;
НовСтр.Результат = Стр.Сумма;
КонецЦикла;
// 5. Записываем заполненные документы
Если ДокФлагИстина.Начисления.Количество() > 0 Тогда
ДокФлагИстина.Записать();
Сообщить("Создан документ (Поле = Истина): " + Строка(ДокФлагИстина.Ссылка));
КонецЕсли;
Если ДокФлагЛожь.Начисления.Количество() > 0 Тогда
ДокФлагЛожь.Записать();
Сообщить("Создан документ (Поле = Ложь): " + Строка(ДокФлагЛожь.Ссылка));
КонецЕсли;
Рассмотренный подход позволяет четко разграничить контексты двух баз данных, избежать синтаксических ошибок при работе с коллекциями и корректно разделить итоговые начисления по двум документам.