Как исправить ошибку "Обнаружено нулевое количество при пересчете в единицу хранения" при программном создании "Перемещения товаров" в УТ 11?

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

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

Выясним причину ошибки

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

В документе "Перемещение товаров" и многих других документах УТ 11 есть два ключевых реквизита для количества в табличной части "Товары":

  1. КоличествоУпаковок — это количество товара в тех единицах (упаковках), которые видит и указывает пользователь. Например, "10 коробок".
  2. Количество — это расчетное количество товара в базовой единице измерения (единице хранения), например, в "штуках". Этот реквизит является ключевым для проведения документа и для всех движений по регистрам.

Когда вы работаете в форме и указываете "10 коробок", система автоматически умножает это число на коэффициент упаковки (например, 12 шт в коробке) и записывает результат "120" в реквизит Количество. При программном создании документа этот автоматический пересчет не происходит. Вы заполняете только КоличествоУпаковок, а критически важное поле Количество остается равным нулю. Именно на это и ругается система при проведении.

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

Посмотрим на типичный код, который приводит к ошибке. Автор на форуме предоставил следующий фрагмент:


// ... код создания шапки документа ...
ТабличнаяЧасть = НовыйДокумент.Товары;
НоваяСтрокаТЧ = ТабличнаяЧасть.Добавить();
НоваяСтрокаТЧ.Номенклатура = стр.номенклатура;  
НоваяСтрокаТЧ.КоличествоУпаковок = стр.КоличествоУпаковок;

Здесь мы видим, что разработчик заполнил номенклатуру и количество в упаковках. Но реквизиты Упаковка, Коэффициент и, самое главное, Количество остались незаполненными. Это и есть причина ошибки.

Решение 1: Прямой расчет и заполнение всех реквизитов

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

Порядок действий:

  1. Заполнить номенклатуру.
  2. Указать упаковку. Если у товара нет специфических упаковок, следует использовать его базовую единицу хранения (Номенклатура.ЕдиницаХранения).
  3. Заполнить количество в указанных упаковках (КоличествоУпаковок).
  4. Заполнить коэффициент пересчета из данной упаковки в базовую единицу. Его можно взять прямо из реквизита упаковки (Упаковка.Коэффициент).
  5. Рассчитать и заполнить итоговое количество в базовых единицах по формуле: Количество = КоличествоУпаковок * Коэффициент.

Посмотрим на исправленный код:


// ... код создания шапки документа ...
ТабличнаяЧасть = НовыйДокумент.Товары;

// Предположим, что в переменной "стр" у нас есть все необходимые данные:
// стр.номенклатура - ссылка на номенклатуру
// стр.КоличествоУпаковок - количество, которое нужно переместить
// стр.Упаковка - ссылка на упаковку (если есть, иначе Неопределено)

НоваяСтрокаТЧ = ТабличнаяЧасть.Добавить();
НоваяСтрокаТЧ.Номенклатура = стр.номенклатура;
НоваяСтрокаТЧ.КоличествоУпаковок = стр.КоличествоУпаковок;

// Определяем, какую упаковку использовать
ТекущаяУпаковка = ?(ЗначениеЗаполнено(стр.Упаковка), стр.Упаковка, стр.номенклатура.ЕдиницаХранения);

// Заполняем реквизиты, связанные с упаковкой
НоваяСтрокаТЧ.Упаковка = ТекущаяУпаковка;
НоваяСтрокаТЧ.Коэффициент = ТекущаяУпаковка.Коэффициент;

// Рассчитываем и заполняем главный реквизит - Количество в единицах хранения
НоваяСтрокаТЧ.Количество = НоваяСтрокаТЧ.КоличествоУпаковок * НоваяСтрокаТЧ.Коэффициент;

// Если для номенклатуры ведется учет по характеристикам или сериям, их также нужно заполнить
// НоваяСтрокаТЧ.Характеристика = стр.Характеристика;
// НоваяСтрокаТЧ.Серия = стр.Серия;

После такого заполнения всех связанных полей документ будет содержать корректные данные и успешно проведется.

Решение 2: Использование типовых механизмов конфигурации

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

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

Пример вызова такой процедуры может выглядеть так:


// ... код создания шапки документа ...
НоваяСтрокаТЧ = НовыйДокумент.Товары.Добавить();
НоваяСтрокаТЧ.Номенклатура = стр.номенклатура;
НоваяСтрокаТЧ.Упаковка = ?(ЗначениеЗаполнено(стр.Упаковка), стр.Упаковка, стр.номенклатура.ЕдиницаХранения);
НоваяСтрокаТЧ.КоличествоУпаковок = стр.КоличествоУпаковок;

// Вызываем типовую процедуру для пересчета всех зависимых реквизитов
// Название модуля и процедуры может отличаться в разных версиях УТ!
УправлениеЗапасамиСервер.РассчитатьКоличествоВЕдиницахХранения(НоваяСтрокаТЧ);

Важно: Названия общих модулей и процедур могут меняться между версиями, поэтому всегда проверяйте их актуальность в вашей конфигурации. Этот подход, хоть и требует небольшого исследования, является наиболее профессиональным.

Полезный совет по отладке

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

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

Сравнение сразу покажет, какие поля ваш код не заполнил, а система заполнила автоматически при ручной работе. Это поможет избежать ошибок при таких сложных операциях, как выравнивание складских остатков по излишкам и недостачам. В нашем случае вы бы сразу увидели, что в "эталонном" документе заполнены реквизиты Количество, Упаковка и Коэффициент, а в "программном" они пустые. Это самый быстрый способ найти причину подобных ошибок.

← На главную