Как программно создавать договоры контрагентов в 1С:Бухгалтерия 3.0 при их отсутствии в документах?

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При интеграции различных систем, например, при ежедневной загрузке данных из 1С:Управление торговлей в 1С:Бухгалтерия предприятия 3.0, часто возникает ситуация, когда в пришедших документах (например, в «Счетах на оплату покупателю») не заполнен договор. Это происходит, если в учетной системе-источнике договоры не ведутся или их структура отличается. Для корректного ведения бухгалтерского учета и последующего проведения документов в БП 3.0 договоры необходимы. В данной статье мы разберем, как автоматизировать процесс создания недостающих договоров программным способом, избегая дублирования и ошибок заполнения реквизитов.

Анализ исходной проблемы и типичных ошибок

Рассмотрим типичную ситуацию: программист пытается выбрать все документы с пустым договором и в цикле создать новые элементы справочника ДоговорыКонтрагентов. Однако на этом пути часто встречаются следующие препятствия:

  1. Неправильное обращение к владельцу: В справочнике ДоговорыКонтрагентов владельцем является Контрагент. Попытка присвоить владельцу код (строку) вместо ссылки приводит к ошибке записи.
  2. Ошибки в типах перечислений: В разных конфигурациях перечисления видов договоров могут называться по-разному. Например, Перечисления.ВидыДоговоров или Перечисления.ВидыДоговоровКонтрагентов.
  3. Проблема дублей: Если у одного контрагента есть несколько счетов без договора, простая обработка в цикле может создать новый договор на каждый счет, что недопустимо.
  4. Различие между Ссылкой и Объектом: При попытке записать созданный договор в документ необходимо помнить, что документ в выборке запроса представлен ссылкой, которую нельзя изменять без получения объекта.

Шаг 1: Формирование правильного запроса

Проанализируем структуру запроса. Нам необходимо выбрать документы СчетНаОплатуПокупателю, у которых не заполнен реквизит ДоговорКонтрагента. Выясним причину, по которой простое сравнение с НЕОПРЕДЕЛЕНО может не сработать: в 1С для ссылочных типов правильнее использовать проверку на пустую ссылку конкретного типа.

Рассмотрим оптимальный текст запроса, где мы сразу подготавливаем псевдонимы полей, совпадающие с именами реквизитов справочника ДоговорыКонтрагентов. Это позволит нам в дальнейшем использовать метод ЗаполнитьЗначенияСвойств.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	СчетНаОплатуПокупателю.Ссылка КАК Ссылка,
    |	СчетНаОплатуПокупателю.Контрагент КАК Владелец,
    |	СчетНаОплатуПокупателю.Контрагент.Наименование КАК Наименование,
    |	СчетНаОплатуПокупателю.Организация КАК Организация,
    |	ЗНАЧЕНИЕ(Перечисление.ВидыДоговоровКонтрагентов.СПокупателем) КАК ВидДоговора
    |ИЗ
    |	Документ.СчетНаОплатуПокупателю КАК СчетНаОплатуПокупателю
    |ГДЕ
    |	СчетНаОплатуПокупателю.ДоговорКонтрагента = ЗНАЧЕНИЕ(Справочник.ДоговорыКонтрагентов.ПустаяСсылка)";

Обратите внимание на использование ЗНАЧЕНИЕ(Перечисление.ВидыДоговоровКонтрагентов.СПокупателем) прямо в тексте запроса. Это избавляет нас от необходимости определять тип перечисления внутри цикла обработки.

Шаг 2: Алгоритм создания договора с проверкой на дубли

Разберем, как избежать создания нескольких договоров для одного и того же клиента. Перед созданием нового элемента мы должны проверить, не был ли он уже создан ранее в этом же сеансе работы или другими документами. Посмотрим на пример кода, который реализует поиск существующего договора по ключевым реквизитам: Владелец, Организация и Вид договора.


РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    
    // Пытаемся найти уже существующий договор, чтобы не плодить дубли
    ДоговорСсылка = Справочники.ДоговорыКонтрагентов.НайтиПоРеквизиту("ВидДоговора", 
                        Выборка.ВидДоговора, , Выборка.Владелец);
    
    // Если договор не найден, создаем новый
    Если ДоговорСсылка.Пустая() Тогда
        НовыйДоговор = Справочники.ДоговорыКонтрагентов.СоздатьЭлемент();
        
        // Используем механизм заполнения по именам полей из запроса
        ЗаполнитьЗначенияСвойств(НовыйДоговор, Выборка);
        
        // Дозаполняем обязательные реквизиты, которых не было в запросе
        НовыйДоговор.УстановитьНовыйКод();
        
        // В БП 3.0 важно заполнить валюту взаиморасчетов
        НовыйДоговор.ВалютаВзаиморасчетов = Справочники.Валюты.НайтиПоКоду("643"); 
        
        Попытка
            НовыйДоговор.Записать();
            ДоговорСсылка = НовыйДоговор.Ссылка;
            Сообщить("Создан новый договор: " + ДоговорСсылка);
        Исключение
            Сообщить("Не удалось создать договор для " + Выборка.Владелец + ": " + ОписаниеОшибки());
            Продолжить;
        КонецПопытки;
    КонецЕсли;

    // Шаг 3: Обновление документа
    Если НЕ ДоговорСсылка.Пустая() Тогда
        Попытка
            ОбъектДокумента = Выборка.Ссылка.ПолучитьОбъект();
            ОбъектДокумента.ДоговорКонтрагента = ДоговорСсылка;
            ОбъектДокумента.Записать();
        Исключение
            Сообщить("Ошибка при записи документа " + Выборка.Ссылка + ": " + ОписаниеОшибки());
        КонецПопытки;
    КонецЕсли;
    
КонецЦикла;

Разберем важные нюансы программного создания объектов

Использование метода ЗаполнитьЗначенияСвойств: Это крайне эффективный метод. Он сопоставляет имена полей в источнике (наша Выборка из запроса) и приемнике (объект НовыйДоговор). Чтобы он сработал для реквизита Владелец, в запросе мы специально указали псевдоним Контрагент КАК Владелец. Если бы мы оставили просто Контрагент, система бы не поняла, в какой реквизит справочника нужно записать ссылку на клиента.

Обработка транзакций: Если документов сотни или тысячи, запись каждого объекта по отдельности может замедлить работу. Рассмотрим возможность использования транзакций. Однако помните: если внутри транзакции произойдет критическая ошибка, изменения не зафиксируются вовсе. Для разовых обработок по созданию справочников использование НачатьТранзакцию() и ЗафиксироватьТранзакцию() оправдано для ускорения процесса в 2-5 раз.

Установка основного договора: В 1С:Бухгалтерия 3.0 недостаточно просто создать договор. Чтобы он подставлялся автоматически в будущие документы, его желательно назначить "Основным". Это делается через менеджер справочника или путем записи в соответствующий регистр сведений (в зависимости от версии конфигурации). Посмотрим на упрощенный пример:


// Пример установки основного договора для контрагента (упрощенно)
КонтрагентОбъект = Выборка.Владелец.ПолучитьОбъект();
// Проверяем, есть ли у контрагента уже основной договор
// Если нет - назначаем наш новый
// В современных БП это может регулироваться через отдельные процедуры БСП

Проблема "Объект не найден" и битых ссылок

Проанализируем ситуацию, когда договор в документе вроде бы пуст, но запрос по ЗНАЧЕНИЕ(Справочник.ДоговорыКонтрагентов.ПустаяСсылка) его не находит. Это происходит при наличии "битых ссылок" (когда объект был удален из базы без контроля ссылочной целостности). В таком случае в поле договора отображается текст вида <Объект не найден>.... Чтобы обработка была максимально надежной, в условие запроса можно добавить проверку:

ГДЕ СчетНаОплатуПокупателю.ДоговорКонтрагента.Ссылка ЕСТЬ NULL

Этот прием позволяет выловить записи, ссылки которых указывают на несуществующие в справочнике объекты.

Резюме

Подводя итоги, мы выяснили, что для успешного автоматического создания договоров необходимо:

  1. Использовать запросы с четко определенными псевдонимами полей.
  2. Обязательно проверять наличие договора перед созданием, чтобы избежать дублей.
  3. Работать с объектом документа (ПолучитьОбъект()), если требуется записать в него созданную ссылку.
  4. Следить за правильным именованием перечислений (ВидыДоговоровКонтрагентов в БП 3.0).

Следуя этой структуре, вы сможете написать надежную обработку, которая приведет базу 1С:Бухгалтерия в порядок после импорта данных из внешних систем.

← На главную