Как программно создать договор контрагента и связать его с документом Поступление товаров и услуг в 1С

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

При разработке обработок загрузки данных из внешних источников (например, Excel) программисты часто сталкиваются с необходимостью автоматического создания не только документов, но и сопутствующих элементов справочников. Одной из самых частых задач является создание договора контрагента «на лету», если он отсутствует в базе. В этой статье мы разберем типичные ошибки при реализации этой логики и составим правильный алгоритм работы.

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

Рассмотрим ситуацию: при загрузке строк из файла Excel программа должна создать документ ПоступлениеТоваровУслуг. Для этого документа обязательным реквизитом является ДоговорКонтрагента. Если договора нет, его нужно создать программно. Посмотрим на критические ошибки, которые часто допускают новички (на основе примера из обсуждения):

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

Шаг 1: Подготовка и поиск контрагента

Прежде чем приступать к созданию договора, мы должны убедиться, что контрагент найден. Рассмотрим фрагмент кода, где выполняется поиск по наименованию из ячейки Excel. Обратите внимание, что поиск по наименованию — не самый надежный способ (лучше использовать ИНН/КПП), но в рамках учебного примера воспользуемся им.


КонтрагентСсылка = Справочники.Контрагенты.НайтиПоНаименованию(Excel.Cells(СтрокаОтсчета, 23).Text, Истина);

Если КонтрагентСсылка.Пустая() Тогда
    Сообщить("Контрагент не найден в строке " + СтрокаОтсчета);
    Продолжить; // Переходим к следующей итерации цикла
КонецЕсли;

Шаг 2: Проверка наличия договора (предотвращение дублей)

Проанализируем ситуацию: нам нужно создать договор с названием «Основной». Чтобы не плодить дубли, воспользуемся методом НайтиПоНаименованию, но обязательно укажем владельца (контрагента).


// Ищем существующий договор у конкретного контрагента
ДоговорСсылка = Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию("Основной", Истина, , КонтрагентСсылка);

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

Шаг 3: Создание документа и привязка договора

После того как мы получили ДоговорСсылка (либо найденный старый, либо только что созданный), мы можем переходить к заполнению документа ПоступлениеТоваровУслуг. Выясним причину, по которой у автора вопроса документы создавались, но договор в них был пустой: это происходило потому, что переменная договора не обновлялась внутри цикла создания документа.


НовыйДокумент = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.Организация = Объект.Организация;
НовыйДокумент.Контрагент = КонтрагентСсылка;
НовыйДокумент.ДоговорКонтрагента = ДоговорСсылка; // Присваиваем ссылку!
НовыйДокумент.ВидОперации = Перечисления.ВидыОперацийПоступлениеТоваровУслуг.Товары;
НовыйДокумент.Склад = ОсновнойСклад;

Шаг 4: Заполнение табличной части и счетов учета

Разберем подробнее заполнение табличной части «Товары». Важный нюанс для бухгалтерии: недостаточно просто заполнить номенклатуру и количество. Необходимо также указать счета учета (например, 10.01 или 41.01). В типовых конфигурациях для этого используются специальные процедуры в модуле объекта, но при программном заполнении счета часто прописывают явно.


НСтрк = НовыйДокумент.Товары.Добавить();
НСтрк.Номенклатура = Объект.Номенклатура; // В примере автора берется из реквизита обработки
НСтрк.Количество = ТекущееЗначениеКол;
НСтрк.Цена = ТекущееЗначениеЦена;
НСтрк.Сумма = НСтрк.Количество * НСтрк.Цена;
НСтрк.СтавкаНДС = Перечисления.СтавкиНДС.БезНДС;

// Прописываем счет учета вручную или через поиск
НСтрк.СчетУчета = ПланыСчетов.Хозрасчетный.НайтиПоКоду("10.01"); 

Итоговый алгоритм решения

Сведем все действия в единую логическую цепочку, которую необходимо реализовать в коде:

  1. Инициализация констант: Находим Склады, Валюты и счета учета до начала цикла обхода Excel, чтобы не нагружать базу лишними запросами.
  2. Цикл по строкам Excel: Начинаем перебор данных.
  3. Поиск контрагента: Если контрагент не найден, фиксируем ошибку и идем дальше.
  4. Работа с договором: Внутри цикла проверяем наличие договора «Основной» у этого контрагента. Если нет — создаем, обязательно записываем и получаем ссылку.
  5. Создание/Поиск документа: Проверяем, создан ли уже документ для этого контрагента (используя структуру Соответствие).
  6. Наполнение документа: Добавляем строки в табличную часть.
  7. Завершение: После окончания цикла Excel, делаем еще один цикл по коллекции СозданныеДокументы и записываем каждый документ в базу.

Важный совет: При программном создании объектов всегда используйте блок Попытка...Исключение при вызове метода Записать(). Это защитит вашу обработку от внезапной остановки, если, например, в системе настроен запрет на создание договоров определенного вида или не заполнены обязательные дополнительные реквизиты.

Проанализировав ситуацию, мы видим, что главная тонкость работы с объектами 1С заключается в понимании разницы между Объектом (набором данных в памяти, который мы редактируем) и Ссылкой (уникальным идентификатором записи в базе данных). Помните: в реквизиты других объектов (например, в поле «Договор» документа) можно записывать только Ссылку.

← На главную