Как получить дату документа из регистра в 1С 7.7 и выгрузить её в Таблицу Значений

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

Переход на платформу «1С:Предприятие 7.7» с классических языков программирования (например, C++, C# или чистый SQL) часто вызывает у разработчиков ступор. Логика построения локальных («черных») запросов и механизмы работы с базой данных здесь имеют свою специфику. Одной из типичных задач, вызывающих трудности у новичков, является получение даты документа, совершившего движение по регистру, и последующий вывод этой информации в Таблицу Значений (ТЗ) для сортировки или печати.

В этой статье мы подробно разберем, почему возникает ошибка «Неверно заданный путь», почему метод Выгрузить() может возвращать пустую таблицу значений и как правильно вытащить системные и пользовательские даты документов из регистров.

Различие между датой документа, датой создания и датой проведения

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

Давайте разберем, какие даты вообще могут фигурировать в контексте документа:

  1. ДатаДок (Дата документа): Это «бухгалтерская» дата, которую пользователь указывает вручную в форме документа или которая подставляется по умолчанию при вводе нового объекта. Именно она определяет, в какой период попадет документ и его движения. Ее легко получить стандартными средствами.
  2. Реальное время создания/записи: Физический момент времени, когда пользователь нажал кнопку «Записать». По умолчанию платформа не пишет эту дату в базу данных. Получить ее задним числом штатными средствами запросов невозможно.
  3. Реальное время проведения: Момент времени, когда транзакция проведения была зафиксирована в базе. Данная информация записывается только в Журнал регистрации (внешние файлы с расширением .elf). Обращаться к журналу регистрации из тяжелых отчетов динамически — крайне неэффективное решение, так как это сильно замедлит систему.

Практический совет: Если вашей компании критически важно контролировать реальное время создания и проведения документов в отчетах, необходимо заранее добавить в конфигураторе Общие реквизиты документов (например, ДатаСоздания, ВремяСоздания, АвторСоздания). Заполнять их следует в предопределенной процедуре ПриЗаписи() в модуле формы или в глобальном модуле:


Процедура ПриЗаписи()
    Если Выбран() = 0 Тогда // Документ записывается впервые
        ДатаСоздания = РабочаяДата();
        ВремяСоздания = ТекущееВремя();
        АвторСоздания = ИмяПользователя();
    КонецЕсли;
КонецПроцедуры

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

Причина ошибки «Неверно заданный путь...» в запросах 1С 7.7

Посмотрим на типичную ошибку, которую совершают программисты, привыкшие к синтаксису SQL или 1С 8.х. Попытка обратиться к реквизиту связанного объекта через точку непосредственно внутри тела запроса приведет к краху программы:


// ВНИМАНИЕ: Этот код вызовет ошибку "Неверно заданный путь ДатаДок"!
|ДатаДокумента = Регистр.Покупатели.ТекущийДокумент.ДатаДок;

Выясним причину этого поведения. Язык запросов 1С 7.7 («черные запросы») не умеет разыменовывать ссылочные поля на уровне текста самого запроса. Обращаться через точку к реквизитам объектов (будь то реквизиты документа или справочника) внутри текста запроса строго запрещено.

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

Разберем рабочий пример построения текста запроса:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = 
"//{{ЗАПРОС(ПолучитьДатуДокумента)
|Период с ДатаНачала по ДатаКонца;
|Клиент = Регистр.Покупатели.Договор.Владелец;
|Док = Регистр.Покупатели.ТекущийДокумент;
|СуммаДолга = Регистр.Покупатели.Сумма;
|Функция ПриходСуммы = Приход(СуммаДолга);
|Группировка Клиент без групп;
|Группировка Док;
|"//}}ЗАПРОС
;

Обратите внимание: мы объявили переменную Док, которая ссылается на ТекущийДокумент регистра. Теперь в цикле обработки мы сможем легко прочитать дату:


Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Пока Запрос.Группировка("Клиент") = 1 Цикл
        Пока Запрос.Группировка("Док") = 1 Цикл
            // Извлекаем дату документа напрямую из объекта группировки
            ТекДата = Запрос.Док.ДатаДок; 
            Сообщить("Документ " + Запрос.Док + " имеет дату: " + ТекДата);
        КонецЦикла;
    КонецЦикла;
КонецЕсли;

Почему метод Запрос.Выгрузить() возвращает пустые колонки?

Рассмотрим вторую частую проблему: разработчик выполняет метод Запрос.Выгрузить(ТЗ), но колонка с датами или самими документами в результирующей Таблице Значений оказывается пустой или вообще отсутствует.

Посмотрим на особенности работы метода Выгрузить() в 1С 7.7. Данный метод автоматически заполняет колонки Таблицы Значений только теми переменными запроса, по которым построены Группировки (строка Группировка ...) или рассчитаны Функции (строка Функция ...). Простые внутренние переменные запроса, объявленные через знак равенства (например, |ВидДолга = Регистр.Покупатели.ВидДолга;), но не участвующие в группировках, при автоматической выгрузке игнорируются.

Существует два надежных способа решить эту задачу.

Способ 1. Использование группировки по документу в запросе

Если мы группируем данные по документу, платформа автоматически выведет колонку Док в Таблицу Значений при выгрузке. После этого мы сможем обойти готовую ТЗ в цикле и заполнить колонку даты.

Разберем этот алгоритм по шагам:


// 1. Создаем и заполняем запрос с группировкой по документу
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = 
"|Период с ДатаНачала по ДатаКонца;
|Док = Регистр.Покупатели.ТекущийДокумент;
|СуммаДолга = Регистр.Покупатели.Сумма;
|Функция РасходСуммы = Расход(СуммаДолга);
|Группировка Док;";

ТЗ = СоздатьОбъект("ТаблицаЗначений");

Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    // Автоматически выгружаем группировки в ТЗ. 
    // В ТЗ появится колонка "Док" и колонка "РасходСуммы"
    Запрос.Выгрузить(ТЗ);
    
    // Добавляем новую колонку для даты документа
    ТЗ.НоваяКолонка("ДатаДок", "Дата");
    
    // Заполняем дату документа, перебирая строки ТЗ
    ТЗ.ВыбратьСтроки();
    Пока ТЗ.ПолучитьСтроку() = 1 Цикл
        Если ПолучитьПустоеЗначение(ТЗ.Док) = 0 Тогда
            ТЗ.ДатаДок = ТЗ.Док.ДатаДок;
        КонецЕсли;
    КонецЦикла;
КонецЕсли;

Способ 2. Ручное заполнение Таблицы Значений в цикле обхода

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

Рассмотрим пример реализации ручного заполнения:


// Создаем Таблицу Значений нужной структуры
ТЗ = СоздатьОбъект("ТаблицаЗначений");
ТЗ.НоваяКолонка("ДокументСсылка", "Документ");
ТЗ.НоваяКолонка("ДатаДокумента", "Дата");
ТЗ.НоваяКолонка("СуммаДвижения", "Число", 15, 2);

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = 
"|Период с ДатаНачала по ДатаКонца;
|Док = Регистр.Покупатели.ТекущийДокумент;
|СуммаДолга = Регистр.Покупатели.Сумма;
|Функция СуммаПриход = Приход(СуммаДолга);
|Группировка Док;";

Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Пока Запрос.Группировка("Док") = 1 Цикл
        // Проверяем, что документ существует и не пустой
        Если ПустоеЗначение(Запрос.Док) = 0 Тогда
            ТЗ.НоваяСтрока();
            ТЗ.ДокументСсылка = Запрос.Док;
            // Получаем дату документа напрямую из выборки запроса
            ТЗ.ДатаДокумента  = Запрос.Док.ДатаДок; 
            ТЗ.СуммаДвижения  = Запрос.СуммаПриход;
        КонецЕсли;
    КонецЦикла;
КонецЕсли;

Сортировка результатов по дате документа

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

Для сортировки ТЗ по возрастанию даты используем следующий метод:

ТЗ.Сортировать("ДатаДокумента+");

Если требуется отсортировать документы по убыванию даты (от самых свежих к более старым), укажем знак минус:

ТЗ.Сортировать("ДатаДокумента-");

Также помните, что сама платформа 1С 7.7 при группировке по документам в запросе (Группировка Док;) осуществляет обход по умолчанию в хронологическом порядке. Если вам нужно получить обратный порядок обхода непосредственно из запроса, вы можете управлять направлением обхода в методе Группировка():


// Параметр -1 указывает системе обходить группировку в обратном порядке
Пока Запрос.Группировка("Док", -1) = 1 Цикл 
    // Здесь документы будут обрабатываться от новых к старым
КонецЦикла;

Мы полностью разобрали логику извлечения дат документов при работе с регистрами в 1С 7.7, изучили причины возникновения ошибок адресации путей в запросах и научились правильно заполнять Таблицы Значений. Используя эти шаблоны кода, вы сможете избежать зависаний отчетов и некорректного вывода данных.

← На главную