Почему метод Заполнить() не срабатывает при создании Счета на оплату поставщика на основании Поступления?

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

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

Однако, используя стандартный метод платформы Заполнить(), можно столкнуться с неочевидным поведением системы: для одних документов (например, «Реализация товаров и услуг») он работает идеально, а для других (например, «Счет на оплату поставщика» на основании поступления) — оставляет документ пустым. В этой статье мы подробно разберем, почему так происходит, рассмотрим архитектуру ввода на основании в типовых конфигурациях и напишем правильный программный код для решения этой задачи.

Суть проблемы: асимметрия документооборота

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

  1. Создается РеализацияТоваровУслуг (РТУ). Вызов СчетНаОплату.Заполнить(РТУ.Ссылка) работает корректно.
  2. Создается ПоступлениеТоваровУслуг (ПТУ). Вызов СчетНаОплатуПоставщика.Заполнить(ПТУ.Ссылка) оставляет документ пустым.

Почему возникает эта "несправедливость"? Дело в том, как разработчики типовой конфигурации заложили логику бизнес-процессов.

Для продаж (РТУ): Типовой сценарий предполагает, что вы можете выписать счет клиенту на основании уже созданной реализации (пост-оплата или оформление документов задним числом). Поэтому в модуле документа «Счет на оплату покупателю» прописан обработчик события ОбработкаЗаполнения, который умеет "разбирать" данные из Реализации.

Для закупок (ПТУ): Типовой сценарий 1С предполагает цепочку: Счет от поставщика -> Оплата -> Поступление товара. То есть «Поступление» обычно вводится на основании «Счета», а не наоборот. Из-за этого в модуле документа СчетНаОплатуПоставщика отсутствует алгоритм заполнения на основании ПоступлениеТоваровУслуг. Метод Заполнить() отрабатывает штатно (не вызывает ошибок), но так как он не находит инструкции, как переносить данные из ПТУ, документ остается незаполненным.

Решение 1: Программное создание документа «с нуля»

Раз стандартный метод Заполнить() не поддерживается конфигурацией для данной пары документов, нам необходимо взять управление в свои руки. Мы не можем полагаться на автоматику, поэтому создадим документ и перенесем реквизиты явно.

Рассмотрим алгоритм действий, который мы должны реализовать в коде:

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

Ниже приведен пример кода, реализующий этот подход:


// Предположим, у нас есть ссылка на созданное поступление в переменной СсылкаНаПТУ

НовыйСчет = Документы.СчетНаОплатуПоставщика.СоздатьДокумент();

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

// Важный момент: Статус оплаты и комментарий
НовыйСчет.Комментарий = "Создан автоматически загрузкой на основании " + Строка(СсылкаНаПТУ);

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

// Аналогично обрабатываем услуги, если они есть
Для Каждого СтрокаПТУ Из СсылкаНаПТУ.Услуги Цикл
    НоваяСтрока = НовыйСчет.Товары.Добавить();
    НоваяСтрока.Номенклатура = СтрокаПТУ.Номенклатура;
    НоваяСтрока.Содержание = СтрокаПТУ.Содержание; 
    НоваяСтрока.Количество = 1; // Для услуг часто количество 1, если не указано иное
    НоваяСтрока.Цена = СтрокаПТУ.Сумма; // Цена равна сумме, если кол-во 1
    НоваяСтрока.Сумма = СтрокаПТУ.Сумма;
    НоваяСтрока.СтавкаНДС = СтрокаПТУ.СтавкаНДС;
    НоваяСтрока.СуммаНДС = СтрокаПТУ.СуммаНДС;
КонецЦикла;

// 3. Запись документа
НовыйСчет.Записать(РежимЗаписиДокумента.Запись);

Важный нюанс: Связывание документов

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

В отличие от связки «Счет -> Реализация», где Реализация ссылается на счет через реквизит СчетНаОплату, при обратном создании нам нужно обновить уже существующее Поступление.

Добавим этот шаг к нашему коду:


// ... код создания счета (см. выше) ...

// 4. Проставляем ссылку на созданный счет в документе Поступления
ПТУОбъект = СсылкаНаПТУ.ПолучитьОбъект();
ПТУОбъект.СчетНаОплатуПоставщика = НовыйСчет.Ссылка;
// Желательно записывать в режиме проведения, если документ уже был проведен,
// либо просто "Запись", если проведение не требуется
ПТУОбъект.Записать(РежимЗаписиДокумента.Проведение); 

Таким образом, мы восстанавливаем логическую целостность цепочки документов, даже если физически создавали их в обратном порядке.

Решение 2: Использование типовых механизмов (на примере Счета-фактуры)

В теме также был затронут вопрос создания счетов-фактур. Здесь подход кардинально отличается. Счета-фактуры — это регламентированные документы со сложной логикой, зависящей от законодательства. Для их создания не рекомендуется использовать прямое заполнение свойств (как мы делали выше для Счета на оплату).

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


// Пример создания Счета-фактуры выданного (на основании Реализации)

// 1. Подготовка параметров создания. Используем типовую функцию.
ПараметрыСоздания = УчетНДСКлиентСервер.НовыеПараметрыСозданияВыданногоСчетаФактуры();

// 2. Указываем документ-основание (нашу Реализацию)
ПараметрыСоздания.Основание = РТУ.Ссылка;

// 3. Можно указать GUID, если он нам известен или нужен специфический
ПараметрыСоздания.УникальныйИдентификатор = РТУ.Ссылка.УникальныйИдентификатор();

// 4. Структура отбора (обычно Неопределено, если создаем по одному документу)
ПараметрыСоздания.СтруктураОтбора = Неопределено;

// 5. Вызов серверного метода для создания документа
// Метод сам определит вид счета-фактуры, заполнит коды видов операций и проведет документ
СтруктураСФ = УчетНДСВызовСервера.СоздатьСчетФактуруВыданныйНаОсновании(ПараметрыСоздания);  

// Получаем ссылку на созданный документ
СсылкаНаСФ = СтруктураСФ.Ссылка;

Использование таких методов (API конфигурации) предпочтительнее ручного создания, так как разработчики 1С могут менять структуру документа СчетФактураВыданный в обновлениях, а экспортные методы общих модулей обычно сохраняют обратную совместимость или обновляются вместе с метаданными.

Резюме и рекомендации

При загрузке данных и программном создании документов в 1С всегда следует учитывать направление бизнес-процессов, заложенное в конфигурацию:

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