Почему не во всех случаях выводится периодический реквизит справочника в 1С 7.7

Программист 1С v7.7 Бухгалтерский учет
← На главную

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

Разбор типичной ошибки в коде

Проанализируем ситуацию, когда данные извлекаются из бухгалтерских итогов, а затем предпринимается попытка найти соответствующий элемент в справочнике для получения его периодического реквизита. Часто код выглядит следующим образом:


БИ = СоздатьОбъект("БухгалтерскиеИтоги");
БИ.ИспользоватьСубконто(ВидыСубконто.ОсновныеСредства);
БИ.ВыполнитьЗапрос(НачДата, КонДата, "01.1, 01.2");

СпрОС = СоздатьОбъект("Справочник.ОсновныеСредства");
СпрОС.ИспользоватьДату(РабочаяДата(), 1); 

БИ.ВыбратьСубконто(1);
Пока БИ.ПолучитьСубконто(1) = 1 Цикл
    ТекОС = БИ.Субконто(1);
    // Попытка найти элемент заново по коду
    Если СпрОС.НайтиПоКоду(ТекОС.Код) = 1 Тогда
        Сообщить("Подразделение: " + СпрОС.Подразделение);
    КонецЕсли;
КонецЦикла;

В данном примере мы видим избыточность: если ТекОС уже является объектом типа Справочник.ОсновныеСредства (полученным из субконто), то повторный поиск через НайтиПоКоду не имеет смысла и только замедляет работу программы. Однако основная проблема кроется в методах получения периодического значения.

Метод 1: Использование функции Получить(Дата)

Рассмотрим самый надежный способ получения значения периодического реквизита — использование метода .Получить(). Проанализируем его синтаксис: Объект.Реквизит.Получить(НужнаяДата). Этот метод позволяет явно указать, на какой момент времени нам требуется значение.

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

Правильный подход при работе в цикле:


Пока БИ.ПолучитьСубконто(1) = 1 Цикл
    ТекОС = БИ.Субконто(1);
    // Получаем подразделение на текущую дату или дату отчета
    ЗначениеПодр = ТекОС.Подразделение.Получить(КонДата);
    Сообщить("ОС: " + ТекОС + " - Подразделение: " + ЗначениеПодр);
КонецЦикла;

Метод 2: Использование ИспользоватьДату()

Метод ИспользоватьДату(Дата, Способ) устанавливает временной контекст для всего объекта справочника. Если второй параметр равен 1, то при обращении к любому периодическому реквизиту через точку (например, СпрОС.Подразделение), система автоматически будет возвращать значение на установленную дату.

Выясним причину, почему этот метод иногда "подводит":

  1. Если вы работаете с объектом, полученным из субконто (БИ.Субконто(1)), вам нужно вызвать ИспользоватьДату() именно для этого временного объекта.
  2. Если вы используете отдельный объект справочника (СоздатьОбъект), то после выполнения НайтиЭлемент() контекст даты сохраняется, но если объект был переинициализирован, настройки могут сброситься.

Конфликт аналитики: Субконто против Реквизита справочника

Проанализируем ситуацию, которая часто становится "невидимой" причиной отсутствия данных. В 1С 7.7 Подразделение может существовать в двух ипостасях одновременно:

  1. Как периодический реквизит в карточке Основного Средства (хранится в истории).
  2. Как субконто на счетах учета (например, на счете 01 или 02).

Выясним, в чем здесь подвох. В бухгалтерских итогах (объект БИ) подразделение фиксируется в момент проведения документа (принятия к учету или перемещения). Если бухгалтер изменил подразделение в карточке ОС (в справочнике), но не провел документ "Перемещение ОС", то в справочнике будет числиться новое подразделение, а в бухгалтерских итогах на счетах — старое.

Решение проблемы автора темы: при проверке выяснилось, что подразделение в базе было распределено по разным уровням субконто. На одних счетах оно было Субконто(1), на других — Субконто(2) или Субконто(3). При обходе итогов кодом, жестко привязанным к первому субконто, данные по остальным позициям просто игнорировались.

Оптимизация: Использование объекта "Периодический"

Если в вашем отчете тысячи записей, использование .Получить(Дата) внутри цикла приведет к существенным задержкам, так как каждый такой вызов — это отдельный запрос к базе данных (к таблице 1SCONST). Рассмотрим, как ускорить этот процесс.

Для массового получения периодических данных в 1С 7.7 рекомендуется использовать объект Периодический. Рассмотрим пример:


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

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

Проблема "битых" индексов (CDX)

Если код написан верно, история реквизита заполнена, но данные все равно не выводятся, проанализируем состояние базы данных. В файловых версиях (DBF) 1С 7.7 индексы периодических реквизитов могут повреждаться.

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

  1. Завершите работу всех пользователей в базе.
  2. Сделайте резервную копию.
  3. Удалите все файлы с расширением .cdx в каталоге базы данных.
  4. Запустите программу в монопольном режиме — индексы будут перестроены автоматически.
  5. Если проблема не исчезла, выполните процедуру "Тестирование и исправление" в Конфигураторе.

Итоги и рекомендации

Для стабильного вывода периодических реквизитов придерживайтесь следующих правил:

← На главную