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

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

При интерактивной работе в программе «1С:Бухгалтерия 8» (редакция 3.0) пользователь редко задумывается о подстановке счетов учета (например, 10.01, 41.01, 20, 26, 90.01.1). Достаточно выбрать номенклатурную позицию в табличной части документа ПоступлениеТоваровУслуг или РеализацияТоваровУслуг, как программа автоматически заполняет нужные счета бухгалтерского и налогового учета.

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

Почему счета учета не заполняются автоматически при программной записи?

Для начала выясним причину такого поведения системы. Когда пользователь выбирает номенклатуру в форме документа, на клиенте срабатывает событие поля ввода табличной части ПриИзменении. Оно запускает целую цепочку обработчиков, которые обращаются к серверу базы данных, считывают настройки из регистра сведений СчетаУчетаНоменклатуры и подставляют нужные значения в текущую строку.

Когда же мы пишем программный код, например:


НоваяСтрока = ДокументОбъект.Товары.Добавить();
НоваяСтрока.Номенклатура = СсылкаНаНоменклатуру;
НоваяСтрока.Количество = 10;

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

Разбор ошибки «Переменная не определена (РаботаСНоменклатуройКлиент)»

Пытаясь повторить интерактивное поведение формы, разработчики часто заглядывают в модуль формы документа и находят там вызовы функций из общих модулей, например, РаботаСНоменклатуройКлиент.СодержаниеПриИзменении. Попытка вызвать такой метод напрямую в серверном коде приводит к ошибке компиляции:

Переменная не определена (РаботаСНоменклатуройКлиент)

Рассмотрим подробнее, почему так происходит. В системе 1С существует строгое разделение контекстов выполнения кода:

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

Попытка вызвать процедуру модуля РаботаСНоменклатуройКлиент из модуля объекта документа, модуля менеджера или из серверной процедуры формы всегда завершится аварийной ошибкой компиляции, поскольку сервер ничего не знает о существовании этого клиентского модуля.

Правильный способ №1. Использование типового модуля «СчетаУчетаВДокументах» (Рекомендуется)

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

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

Вариант А. Заполнение счетов для всех строк документа

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


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

// Добавляем строку в табличную часть "Товары"
НоваяСтрока = НовыйДокумент.Товары.Добавить();
НоваяСтрока.Номенклатура = СсылкаНаТовар;
НоваяСтрока.Количество = 5;

// Подготавливаем структуру отбора для заполнения реквизитов
// Значение Истина означает, что мы заполняем только пустые (еще не заполненные) счета учета
ПараметрыЗаполнения = Новый Структура;
ПараметрыЗаполнения.Вставить("НеЗаполненныеРеквизиты", Истина);

// Вызываем типовой метод для всего объекта документа
СчетаУчетаВДокументах.Заполнить(НовыйДокумент, ПараметрыЗаполнения);

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

Вариант Б. Заполнение счетов для конкретной строки табличной части

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


// Допустим, у нас уже есть объект документа "ДокументОбъект"
НоваяСтрока = ДокументОбъект.Товары.Добавить();
НоваяСтрока.Номенклатура = СсылкаНаТовар;
НоваяСтрока.Количество = 1;

// Помещаем нашу новую строку в массив для обработки
МассивСтрок = Новый Массив;
МассивСтрок.Добавить(НоваяСтрока);

// Заполняем счета учета только для добавленной строки
СчетаУчетаВДокументах.ЗаполнитьСтроки(
    МассивСтрок, 
    "Товары", 
    ДокументОбъект.Ссылка, 
    Документы.ПоступлениеТоваровУслуг, 
    Истина
);

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

Альтернативный способ №2. Прямой запрос к регистру сведений (Почему это опасно?)

На форумах часто предлагают решить задачу «в лоб» — написать собственный запрос к регистру сведений СчетаУчетаНоменклатуры. Пример простого запроса может выглядеть так:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	СчетаУчета.СчетУчета КАК СчетУчета,
    |	СчетаУчета.СчетУчетаНДС КАК СчетУчетаНДС
    |ИЗ
    |	РегистрСведений.СчетаУчетаНоменклатуры КАК СчетаУчета
    |ГДЕ
    |	СчетаУчета.Номенклатура = &Номенклатура";

Запрос.УстановитьПараметр("Номенклатура", ВыбраннаяНоменклатура);
РезультатЗапроса = Запрос.Выполнить();

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

  1. Сначала ищется запись для конкретной Номенклатуры.
  2. Если ее нет, проверяется принадлежность к конкретной Группе номенклатуры (иерархический поиск вверх по дереву).
  3. Затем проверяются индивидуальные настройки для выбранного Склада (ведь на розничном и оптовом складах счета могут отличаться).
  4. Если настройки для склада не найдены, проверяются настройки для Вида номенклатуры (например, «Товары», «Материалы», «Услуги»).
  5. Учитывается специфика конкретной Организации (для разных юридических лиц в одной базе могут быть настроены свои правила).
  6. И только в самом конце, если совпадений не найдено, берется «дефолтное» общее правило (запись в регистре с пустыми измерениями).

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

Резюме

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

← На главную