При разработке механизмов проведения документов в системе «1С:Предприятие 8» программисты часто переходят от автоматического удаления и записи движений к ручному управлению через наборы записей. Этот метод более гибкий и производительный, однако он таит в себе ряд «подводных камней». Одной из самых распространенных проблем является системное сообщение «Период не может быть пустым», которое блокирует проведение документа. В этой статье мы подробно разберем, почему возникает эта ошибка, как правильно сопоставлять поля запроса с ресурсами регистра и как корректно обрабатывать данные из нескольких табличных частей документа.
Рассмотрим ситуацию: вы используете объект НаборЗаписей и метод Загрузить(), чтобы передать результат запроса напрямую в регистр накопления. Платформа 1С ожидает, что в передаваемой таблице значений (результате запроса) колонки называются точно так же, как измерения и ресурсы в метаданных регистра. Поле Период является стандартным и обязательным для любого периодического регистра.
Если в вашем запросе вы выбираете дату документа под псевдонимом Дата, метод Загрузить() просто не увидит этого поля. Система попытается создать запись в регистре, обнаружит, что обязательное поле Период не заполнено, и выдаст ошибку. Проанализируем, как это исправить в тексте запроса.
Вместо простого выбора даты:
| ВЫБРАТЬ
| ПриходТовара.Дата
Необходимо явно указать псевдоним Период:
| ВЫБРАТЬ
| ПриходТовара.Дата КАК Период,
| ПриходТовара.Склад КАК Склад,
| ...
Важный нюанс: при проведении документа в качестве периода лучше всего использовать МоментВремени документа. Это гарантирует правильную последовательность движений в базе данных, особенно если несколько документов проводятся в одну и ту же секунду.
После того как ошибка с периодом устранена, разработчики часто сталкиваются со следующей проблемой: записи в регистре появляются, но суммы или количества в них равны нулю. Выясним причину этого поведения. Метод Загрузить() работает по принципу жесткого соответствия имен. Если в регистре ресурс называется КоличествоВБазовыхЕдиницах, а в вашем запросе колонка названа просто Количество, данные не будут перенесены.
Проанализируем типичную структуру запроса для формирования движений:
| ВЫБРАТЬ
| ПриходТовара.Склад КАК Склад,
| Товары.Номенклатура КАК Номенклатура,
| СУММА(Товары.Количество * Товары.Коэффициент) КАК КоличествоВБазовыхЕдиницах,
| СУММА(Товары.Сумма) КАК Сумма
Золотое правило: всегда проверяйте имена измерений и ресурсов в дереве конфигурации. Псевдонимы в запросе (то, что идет после ключевого слова КАК) должны буква в букву совпадать с именами в объекте РегистрНакопления.
Часто один документ должен делать записи в один и тот же регистр из разных табличных частей (например, «Товары» и «Услуги»). Рассмотрим распространенную ошибку объединения таблиц через запятую в секции ИЗ. Это приводит к так называемому «картезианскому произведению» — строки перемножаются, и данные в регистре увеличиваются в геометрической прогрессии.
Для корректного решения этой задачи мы должны использовать оператор ОБЪЕДИНИТЬ ВСЕ. Рассмотрим пример правильного запроса, который собирает данные из двух табличных частей документа в единую таблицу для записи в регистр:
ВЫБРАТЬ
Док.Склад КАК Склад,
Док.Дата КАК Период,
ТЧТовары.Номенклатура КАК Номенклатура,
ТЧТовары.Количество КАК КоличествоВБазовыхЕдиницах,
ТЧТовары.Сумма КАК Сумма
ИЗ
Документ.ПриходТовара.Товары КАК ТЧТовары
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПриходТовара КАК Док ПО ТЧТовары.Ссылка = Док.Ссылка
ГДЕ
Док.Ссылка = &Ссылка
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Док.Склад,
Док.Дата,
ТЧУслуги.Номенклатура,
ТЧУслуги.Количество,
ТЧУслуги.Сумма
ИЗ
Документ.ПриходТовара.Услуги КАК ТЧУслуги
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПриходТовара КАК Док ПО ТЧУслуги.Ссылка = Док.Ссылка
ГДЕ
Док.Ссылка = &Ссылка
Обратите внимание, что при использовании ОБЪЕДИНИТЬ ВСЕ псевдонимы полей достаточно задать только в первом запросе. Все последующие части объединения будут автоматически сопоставлены по порядку следования колонок.
Теперь разберем, как должен выглядеть итоговый код в процедуре ОбработкаПроведения. Мы подготовим набор записей, заполним его данными из запроса и укажем платформе, что эти данные нужно сохранить.
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// 1. Очищаем старые движения (если это предусмотрено логикой)
Движения.ОстаткиНоменклатуры.Записывать = Истина;
Движения.ОстаткиНоменклатуры.Очистить();
// 2. Получаем данные для проведения через запрос
// Предположим, функция ИнициализироватьДанные возвращает Таблицу Значений
ТаблицаДвижений = ПолучитьТаблицуДляПроведения(Ссылка);
// 3. Загружаем таблицу в набор записей регистра
Движения.ОстаткиНоменклатуры.Загрузить(ТаблицаДвижений);
// 4. Устанавливаем дополнительные свойства, если регистр - Остатки
Для Каждого Запись Из Движения.ОстаткиНоменклатуры Цикл
Запись.ВидДвижения = ВидДвиженияНакопления.Приход;
Запись.Активность = Истина;
КонецЦикла;
// Важно: метод Записать() в ОбработкеПроведения вызывать не обязательно,
// если установлен флаг Записывать = Истина. Платформа сделает это сама.
КонецПроцедуры
Номенклатура. Это значительно ускорит выполнение запроса при больших объемах данных в документе.МенеджерВременныхТаблиц для всех запросов в рамках одного проведения. Это позволит вам эффективно передавать промежуточные данные между разными функциями.Регистратор заполняется автоматически, при использовании этого же кода во внешних обработках его необходимо добавлять в запрос: Документ.Ссылка КАК Регистратор.Подводя итог, можно сказать, что корректная работа с движениями документа требует внимательности к метаданным. Ошибка Период не может быть пустым — это лишь сигнал о том, что интерфейс между вашим кодом (запросом) и структурой базы данных (регистром) нарушен. Исправив псевдонимы полей и правильно объединив таблицы, вы обеспечите надежную и быструю работу системы учета.