Как исправить ошибку «Период не может быть пустым» и правильно сформировать движения документа в 1С?

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

При разработке механизмов проведения документов в системе «1С:Предприятие 8» программисты часто переходят от автоматического удаления и записи движений к ручному управлению через наборы записей. Этот метод более гибкий и производительный, однако он таит в себе ряд «подводных камней». Одной из самых распространенных проблем является системное сообщение «Период не может быть пустым», которое блокирует проведение документа. В этой статье мы подробно разберем, почему возникает эта ошибка, как правильно сопоставлять поля запроса с ресурсами регистра и как корректно обрабатывать данные из нескольких табличных частей документа.

Причина ошибки «Период не может быть пустым»

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

Если в вашем запросе вы выбираете дату документа под псевдонимом Дата, метод Загрузить() просто не увидит этого поля. Система попытается создать запись в регистре, обнаружит, что обязательное поле Период не заполнено, и выдаст ошибку. Проанализируем, как это исправить в тексте запроса.

Вместо простого выбора даты:


| ВЫБРАТЬ
|     ПриходТовара.Дата

Необходимо явно указать псевдоним Период:


| ВЫБРАТЬ
|     ПриходТовара.Дата КАК Период,
|     ПриходТовара.Склад КАК Склад,
|     ...

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

Сопоставление имен полей: почему не записываются ресурсы?

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

Проанализируем типичную структуру запроса для формирования движений:


| ВЫБРАТЬ
|     ПриходТовара.Склад КАК Склад,
|     Товары.Номенклатура КАК Номенклатура,
|     СУММА(Товары.Количество * Товары.Коэффициент) КАК КоличествоВБазовыхЕдиницах,
|     СУММА(Товары.Сумма) КАК Сумма

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

Работа с несколькими табличными частями: избегаем дублей

Часто один документ должен делать записи в один и тот же регистр из разных табличных частей (например, «Товары» и «Услуги»). Рассмотрим распространенную ошибку объединения таблиц через запятую в секции ИЗ. Это приводит к так называемому «картезианскому произведению» — строки перемножаются, и данные в регистре увеличиваются в геометрической прогрессии.

Для корректного решения этой задачи мы должны использовать оператор ОБЪЕДИНИТЬ ВСЕ. Рассмотрим пример правильного запроса, который собирает данные из двух табличных частей документа в единую таблицу для записи в регистр:


ВЫБРАТЬ
    Док.Склад КАК Склад,
    Док.Дата КАК Период,
    ТЧТовары.Номенклатура КАК Номенклатура,
    ТЧТовары.Количество КАК КоличествоВБазовыхЕдиницах,
    ТЧТовары.Сумма КАК Сумма
ИЗ
    Документ.ПриходТовара.Товары КАК ТЧТовары
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПриходТовара КАК Док ПО ТЧТовары.Ссылка = Док.Ссылка
ГДЕ
    Док.Ссылка = &Ссылка

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    Док.Склад,
    Док.Дата,
    ТЧУслуги.Номенклатура,
    ТЧУслуги.Количество,
    ТЧУслуги.Сумма
ИЗ
    Документ.ПриходТовара.Услуги КАК ТЧУслуги
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПриходТовара КАК Док ПО ТЧУслуги.Ссылка = Док.Ссылка
ГДЕ
    Док.Ссылка = &Ссылка

Обратите внимание, что при использовании ОБЪЕДИНИТЬ ВСЕ псевдонимы полей достаточно задать только в первом запросе. Все последующие части объединения будут автоматически сопоставлены по порядку следования колонок.

Алгоритм проведения в модуле объекта

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


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    // 1. Очищаем старые движения (если это предусмотрено логикой)
    Движения.ОстаткиНоменклатуры.Записывать = Истина;
    Движения.ОстаткиНоменклатуры.Очистить();
    
    // 2. Получаем данные для проведения через запрос
    // Предположим, функция ИнициализироватьДанные возвращает Таблицу Значений
    ТаблицаДвижений = ПолучитьТаблицуДляПроведения(Ссылка);
    
    // 3. Загружаем таблицу в набор записей регистра
    Движения.ОстаткиНоменклатуры.Загрузить(ТаблицаДвижений);
    
    // 4. Устанавливаем дополнительные свойства, если регистр - Остатки
    Для Каждого Запись Из Движения.ОстаткиНоменклатуры Цикл
        Запись.ВидДвижения = ВидДвиженияНакопления.Приход;
        Запись.Активность = Истина;
    КонецЦикла;
    
    // Важно: метод Записать() в ОбработкеПроведения вызывать не обязательно, 
    // если установлен флаг Записывать = Истина. Платформа сделает это сама.
    
КонецПроцедуры

Полезные советы для оптимизации

  1. Индексация: Если в запросе вы используете временные таблицы для предварительной обработки данных (например, для расчета себестоимости), всегда индексируйте поле Номенклатура. Это значительно ускорит выполнение запроса при больших объемах данных в документе.
  2. Менеджер временных таблиц: Используйте один МенеджерВременныхТаблиц для всех запросов в рамках одного проведения. Это позволит вам эффективно передавать промежуточные данные между разными функциями.
  3. Проверка на пустоту: Перед загрузкой таблицы в набор записей проверьте, есть ли в ней строки. Если таблица пуста, лишние циклы и обращения к регистру можно пропустить.
  4. Регистратор: Хотя при проведении из модуля объекта поле Регистратор заполняется автоматически, при использовании этого же кода во внешних обработках его необходимо добавлять в запрос: Документ.Ссылка КАК Регистратор.

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

← На главную