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