Как программно заполнить счета учета номенклатуры в новом документе "РеализацияТоваровУслуг", созданном внешней обработкой в 1С:Бухгалтерии 3.0?

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

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

Давайте разберем, как эффективно заполнить счета учета (СчетУчета, СчетДоходов, СчетРасходов и другие) в табличной части документа "РеализацияТоваровУслуг", который был создан программно внешней обработкой и еще не сохранен в информационной базе.

Основные сложности и попытки решения

Изначально разработчики сталкиваются с несколькими препятствиями при попытке использовать стандартные механизмы заполнения счетов учета:

  1. Невозможность передачи формы на сервер: Мы не можем напрямую передать объект ФормаКлиентскогоПриложения с клиента на сервер. Это связано с архитектурой 1С:Предприятия, где клиент и сервер обмениваются только сериализуемыми данными (такими как примитивные типы, структуры, коллекции, ссылки на объекты базы данных, но не сами объекты форм).
  2. Пустая ссылка для нового документа: Для только что созданного, но еще не записанного документа, его свойство Ссылка будет пустым или Неопределено. Многие стандартные процедуры конфигурации, предназначенные для работы с существующими документами, ожидают в качестве параметра именно ссылку на записанный объект.

Рассмотрим типовые попытки, предпринятые в ходе решения данной проблемы, и выясним, почему они оказались неэффективными:

Попытка 1: Использование экспортной процедуры формы документа

Одной из первых идей может быть попытка вызова экспортной процедуры из модуля формы самого документа, например, РеализацияТоваровУслугФормы.СкладПриИзменении(ЭтотОбъект). Эта процедура в конфигурации обычно отвечает за пересчет или заполнение данных при изменении склада, и в ее коде может содержаться логика заполнения счетов учета.

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


Ошибка отображения типов:
Отсутствует отображение для типа 'ФормаКлиентскогоПриложения'
{ВнешняяОбработка.МенеджерПродаж.Форма.Форма.Форма(1979)}:    ЗаполнитьСчетаУчета(ФормаРеализации);
по причине:
Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа.

Это подтверждает, что прямая передача формы на сервер невозможна. Процедура СкладПриИзменении, как правило, ожидает в качестве параметра именно объект формы со свойством Объект, а не просто данные документа.

Попытка 2: Использование общего модуля СчетаУчетаВДокументах.Заполнить()

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

В случае с новым, незаписанным документом, ДанныеФормы.Ссылка будет пустой. Это приводит к тому, что процедура не может корректно определить контекст документа и, возможно, попытается записать изменения в отсутствующий объект или некорректно применит отбор. В сообщении форума автор также столкнулся с тем, что даже с отбором по конкретной табличной части (например, "Товары"), процедура все равно затрагивала другие реквизиты, что приводило к ошибкам.

Даже если мы передадим в серверную процедуру обработанный на клиенте объект ДанныеФормы (который является копией данных документа, а не самой формой), при вызове РеализацияТоваровУслугФормы.СкладПриИзменении(ДанныеФормы) мы столкнемся с ошибкой:


{ОбщийМодуль.РеализацияТоваровУслугФормы.Модуль(229)}: Поле объекта не обнаружено (Объект)
    Объект = Форма.Объект;

Эта ошибка возникает потому, что ДанныеФормы, переданные в качестве параметра, уже являются самим объектом документа (или его структурой), а не объектом формы, который имеет свойство Объект.

Правильный подход: использование СчетаУчетаВДокументах.ЗаполнитьСтроки()

Для корректного заполнения счетов учета номенклатуры в табличной части нового, незаписанного документа, созданного внешней обработкой, необходимо использовать специализированную процедуру из общего модуля СчетаУчетаВДокументах, которая предназначена для работы с отдельными строками табличной части и умеет обрабатывать новые документы.

Такой процедурой является СчетаУчетаВДокументах.ЗаполнитьСтроки().

Реализация серверной процедуры

В модуле формы вашей внешней обработки (или в общем модуле, если это уместно) создадим серверную процедуру. Мы будем передавать в неё объект ДанныеФормы, который на клиенте представляет собой данные нового документа, полученные через ФормаРеализации.Объект.


&НаСервере
Процедура ЗаполнитьСчетаУчета(ДанныеФормы)
    
    СтрокиДляДополнительнойОбработки = ДанныеФормы.Товары;
    СчетаУчетаВДокументах.ЗаполнитьСтроки(
        СтрокиДляДополнительнойОбработки,
        "Товары",
        ДанныеФормы.Ссылка,
        Документы.РеализацияТоваровУслуг,
        Истина // Важный параметр: указывает, что документ новый
    );
    
    // Если есть табличная часть "Услуги", аналогично заполним и ее:
    Если ДанныеФормы.Услуги.Количество() > 0 Тогда
        СтрокиДляДополнительнойОбработки = ДанныеФормы.Услуги;
        СчетаУчетаВДокументах.ЗаполнитьСтроки(
            СтрокиДляДополнительнойОбработки,
            "Услуги",
            ДанныеФормы.Ссылка,
            Документы.РеализацияТоваровУслуг,
            Истина
        );
    КонецЕсли;

КонецПроцедуры

Разберем параметры процедуры СчетаУчетаВДокументах.ЗаполнитьСтроки():

  1. СтрокиДляДополнительнойОбработки (первый параметр):

    Это коллекция строк табличной части, для которой мы хотим заполнить счета учета. В нашем случае это ДанныеФормы.Товары или ДанныеФормы.Услуги. Обратите внимание, что мы передаем именно коллекцию строк, а не весь объект документа.

  2. "Товары" (второй параметр):

    Имя табличной части, с которой мы работаем. Это строковое представление имени табличной части документа, например, "Товары", "Услуги" и т.п. Оно используется для корректной обработки метаданных.

  3. ДанныеФормы.Ссылка (третий параметр):

    Ссылка на документ. Как мы уже упоминали, для нового, незаписанного документа это свойство будет пустым (пустая ссылка или Неопределено). Однако, процедура ЗаполнитьСтроки специально разработана таким образом, чтобы корректно обрабатывать это значение, если ей явно указать, что документ новый (см. последний параметр).

  4. Документы.РеализацияТоваровУслуг (четвертый параметр):

    Объект метаданных документа. Это позволяет процедуре получить доступ к структуре и свойствам документа, а также к правилам заполнения счетов учета, специфичным для данного вида документа. Мы используем предопределенное значение Документы.РеализацияТоваровУслуг, чтобы указать тип документа.

  5. Истина (пятый параметр):

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

Клиент-серверное взаимодействие и обновление формы

Теперь давайте посмотрим, как эта серверная процедура вызывается из клиентского кода вашей внешней обработки.

  1. Подготовка объекта ДанныеФормы:

    На клиенте мы сначала получаем форму нового документа и ее объект, который будем изменять:

    
    &НаКлиенте
    Процедура СоздатьНакладнуюТоварыУслуги(Команда)
        
        // Получаем параметры для создания формы документа
        СтруктураПараметров = ПолучитьПараметрыФормыДокумента(ПредопределенноеЗначение("Перечисление.ВидыОперацийРеализацияТоваров.ПродажаКомиссия"));
        // Открываем форму нового документа, но пока не отображаем
        ФормаРеализации = ПолучитьФорму("Документ.РеализацияТоваровУслуг.ФормаОбъекта", СтруктураПараметров, ЭтотОбъект);
        
        // Получаем данные документа из формы. Это будет объект типа ДанныеФормыСтруктура,
        // который можно передавать на сервер.
        ДанныеФормы = ФормаРеализации.Объект;
        
        // Заполняем основные реквизиты документа
        ЗаполнитьЗначенияСвойств(ДанныеФормы, Новый Структура("СуммаВключаетНДС,Комментарий", СуммаВключаетНДС, "Создано обработкой 'Рабочее место менеджера'"));
        
        // Копируем изменения обратно в объект формы, чтобы они были видны
        КопироватьДанныеФормы(ДанныеФормы, ФормаРеализации.Объект);
        
        // Заполняем табличные части Товары и Услуги данными
        ЗаполнитьТабличнуюЧасть(ДанныеФормы, "Накладная", "Товары", СтруктураПараметров);
        ЗаполнитьТабличнуюЧасть(ДанныеФормы, "Накладная", "Услуги", СтруктураПараметров);
        
        // *Важный шаг:* Вызываем серверную процедуру для заполнения счетов учета
        ЗаполнитьСчетаУчета(ДанныеФормы);
        
        // *Важный шаг:* После изменений на сервере, снова копируем данные обратно в объект формы.
        // Это обеспечивает синхронизацию изменений, произошедших на сервере.
        КопироватьДанныеФормы(ДанныеФормы, ФормаРеализации.Объект);
        
        // ... дальнейшая логика по заполнению надписей и подготовке формы ...
        
        // Открываем форму для пользователя
        ФормаРеализации.Открыть();
        
        // *Важный шаг:* После открытия формы, обновляем ее итоги и готовим к отображению.
        ФормаРеализации.ОбновитьИтогиНаСервере();
        ФормаРеализации.ПодготовитьФормуНаСервере();
        
    КонецПроцедуры
    
  2. Вызов серверной процедуры:

    Мы вызываем нашу серверную процедуру ЗаполнитьСчетаУчета(), передавая ей ДанныеФормы. Этот объект является сериализуемым и успешно передается на сервер.

  3. Копирование данных обратно:

    После того как серверная процедура ЗаполнитьСчетаУчета() внесла изменения в ДанныеФормы, нам необходимо скопировать эти изменения обратно в объект формы на клиенте. Для этого используется стандартная функция КопироватьДанныеФормы(Источник, Приемник). Это гарантирует, что все программные изменения, сделанные на сервере, будут отображены в клиентской форме.

  4. Обновление и подготовка формы:

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

    • ФормаРеализации.ОбновитьИтогиНаСервере();: Этот метод вызывает серверную процедуру для пересчета итогов по табличным частям и другим зависимым данным документа. Это важно для корректного отображения сумм, НДС и других расчетных показателей.
    • ФормаРеализации.ПодготовитьФормуНаСервере();: Этот метод выполняет дополнительную подготовку формы к работе, которая может включать настройку видимости элементов, установку активности полей и другие действия, характерные для данной формы. Это помогает обеспечить, чтобы форма выглядела и вела себя так, как если бы она была создана и заполнена вручную пользователем.

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

Подводя итоги

Для успешного программного заполнения счетов учета номенклатуры в незаписанном документе "РеализацияТоваровУслуг" из внешней обработки мы должны:

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

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

← На главную