При разработке в 1С часто возникает задача программного создания документов. Возьмем типовую ситуацию: вы пишете код для создания документа "Перемещение товаров" в конфигурации "Управление торговлей 11.4". Чтобы избавить пользователя от рутины, часто используется автоматический помощник перемещений, который корректно заполняет табличную часть. Однако при самостоятельном написании кода все реквизиты, казалось бы, заполнены верно, документ записывается, но при попытке проведения система выдает ошибку "Обнаружено нулевое количество при пересчете в единицу хранения". При этом, если открыть созданный документ и просто перевыбрать единицу измерения в строке, он начинает проводиться без проблем. Давайте разберемся, почему так происходит и как это исправить.
Корень проблемы кроется в разнице между интерактивной работой пользователя в форме и программным заполнением объекта документа. Когда пользователь работает с формой документа, она содержит множество обработчиков событий. Например, при изменении номенклатуры, упаковки или количества в упаковках, запускается специальный код, который выполняет пересчеты и заполняет связанные реквизиты. Правильное заполнение этих полей критически важно, особенно когда выполняется автоматическое выравнивание остатков в 1С по данным регистров.
В документе "Перемещение товаров" и многих других документах УТ 11 есть два ключевых реквизита для количества в табличной части "Товары":
КоличествоУпаковок — это количество товара в тех единицах (упаковках), которые видит и указывает пользователь. Например, "10 коробок".Количество — это расчетное количество товара в базовой единице измерения (единице хранения), например, в "штуках". Этот реквизит является ключевым для проведения документа и для всех движений по регистрам.Когда вы работаете в форме и указываете "10 коробок", система автоматически умножает это число на коэффициент упаковки (например, 12 шт в коробке) и записывает результат "120" в реквизит Количество. При программном создании документа этот автоматический пересчет не происходит. Вы заполняете только КоличествоУпаковок, а критически важное поле Количество остается равным нулю. Именно на это и ругается система при проведении.
Посмотрим на типичный код, который приводит к ошибке. Автор на форуме предоставил следующий фрагмент:
// ... код создания шапки документа ...
ТабличнаяЧасть = НовыйДокумент.Товары;
НоваяСтрокаТЧ = ТабличнаяЧасть.Добавить();
НоваяСтрокаТЧ.Номенклатура = стр.номенклатура;
НоваяСтрокаТЧ.КоличествоУпаковок = стр.КоличествоУпаковок;
Здесь мы видим, что разработчик заполнил номенклатуру и количество в упаковках. Но реквизиты Упаковка, Коэффициент и, самое главное, Количество остались незаполненными. Это и есть причина ошибки.
Самый простой и понятный способ решения — это вручную рассчитать и заполнить все необходимые реквизиты в табличной части. Это имитирует то, что делает форма документа, и обеспечивает полноту данных для проведения. Этот метод часто применяется, когда реализуется загрузка данных из внешних файлов в складские документы.
Порядок действий:
Номенклатура.ЕдиницаХранения).КоличествоУпаковок).Упаковка.Коэффициент).Количество = КоличествоУпаковок * Коэффициент.Посмотрим на исправленный код:
// ... код создания шапки документа ...
ТабличнаяЧасть = НовыйДокумент.Товары;
// Предположим, что в переменной "стр" у нас есть все необходимые данные:
// стр.номенклатура - ссылка на номенклатуру
// стр.КоличествоУпаковок - количество, которое нужно переместить
// стр.Упаковка - ссылка на упаковку (если есть, иначе Неопределено)
НоваяСтрокаТЧ = ТабличнаяЧасть.Добавить();
НоваяСтрокаТЧ.Номенклатура = стр.номенклатура;
НоваяСтрокаТЧ.КоличествоУпаковок = стр.КоличествоУпаковок;
// Определяем, какую упаковку использовать
ТекущаяУпаковка = ?(ЗначениеЗаполнено(стр.Упаковка), стр.Упаковка, стр.номенклатура.ЕдиницаХранения);
// Заполняем реквизиты, связанные с упаковкой
НоваяСтрокаТЧ.Упаковка = ТекущаяУпаковка;
НоваяСтрокаТЧ.Коэффициент = ТекущаяУпаковка.Коэффициент;
// Рассчитываем и заполняем главный реквизит - Количество в единицах хранения
НоваяСтрокаТЧ.Количество = НоваяСтрокаТЧ.КоличествоУпаковок * НоваяСтрокаТЧ.Коэффициент;
// Если для номенклатуры ведется учет по характеристикам или сериям, их также нужно заполнить
// НоваяСтрокаТЧ.Характеристика = стр.Характеристика;
// НоваяСтрокаТЧ.Серия = стр.Серия;
После такого заполнения всех связанных полей документ будет содержать корректные данные и успешно проведется.
Более правильным и надежным подходом является вызов процедур из общих модулей конфигурации. Разработчики 1С уже создали функции для всех стандартных расчетов. Например, такой подход реализован в решении для заполнения табличной части перемещения товаров остатками по складу. Использование этих функций гарантирует, что ваша логика будет работать так же, как и стандартный интерфейс, и не "сломается" после очередного обновления конфигурации.
Для пересчета количества можно найти соответствующую процедуру в общих модулях, например, УправлениеЗапасамиСервер или ЗаполнениеДокументов. Чтобы найти нужную процедуру, можно открыть форму документа "ПеремещениеТоваров" в конфигураторе и посмотреть, какой код вызывается в обработчике события ПриИзменении для полей "Упаковка" или "КоличествоУпаковок".
Пример вызова такой процедуры может выглядеть так:
// ... код создания шапки документа ...
НоваяСтрокаТЧ = НовыйДокумент.Товары.Добавить();
НоваяСтрокаТЧ.Номенклатура = стр.номенклатура;
НоваяСтрокаТЧ.Упаковка = ?(ЗначениеЗаполнено(стр.Упаковка), стр.Упаковка, стр.номенклатура.ЕдиницаХранения);
НоваяСтрокаТЧ.КоличествоУпаковок = стр.КоличествоУпаковок;
// Вызываем типовую процедуру для пересчета всех зависимых реквизитов
// Название модуля и процедуры может отличаться в разных версиях УТ!
УправлениеЗапасамиСервер.РассчитатьКоличествоВЕдиницахХранения(НоваяСтрокаТЧ);
Важно: Названия общих модулей и процедур могут меняться между версиями, поэтому всегда проверяйте их актуальность в вашей конфигурации. Этот подход, хоть и требует небольшого исследования, является наиболее профессиональным.
Если вы сталкиваетесь с подобной проблемой и не можете понять, какого реквизита не хватает, есть универсальный метод отладки, который посоветовали на форуме. В ситуациях, когда проведение блокируется из-за расхождений, иногда помогает временное проведение документов без контроля остатков, но для поиска причины лучше использовать сравнение:
Сравнение сразу покажет, какие поля ваш код не заполнил, а система заполнила автоматически при ручной работе. Это поможет избежать ошибок при таких сложных операциях, как выравнивание складских остатков по излишкам и недостачам. В нашем случае вы бы сразу увидели, что в "эталонном" документе заполнены реквизиты Количество, Упаковка и Коэффициент, а в "программном" они пустые. Это самый быстрый способ найти причину подобных ошибок.