Почему не работает выборка из журнала расчетов в 1С 7.7 и как это исправить?

Программист 1С v7.7 Сфера услуг, туризм и социальный сектор
← На главную

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

Анализ исходного кода и поиск логической ошибки

Проанализируем фрагмент кода, представленный в вопросе. Автор пытается перебрать справочник клиентов и для каждого клиента найти записи в журнале расчетов «Квартплата», которые входят в определенную группу расчетов и имеют нулевой результат. Однако в коде допущена критическая ошибка, которая может привести к аварийному завершению работы цикла или всей процедуры.

Разберем этот фрагмент:


Пока ЖрнКв.ПолучитьЗапись() = 1 Цикл 
    Если ЖрнКв.ВидРасч.ВходитВГруппу("ВсеНачисления") = 1 Тогда 
        Если ЖрнКв.Результат = 0 Тогда
            Коммент = Коммент + ЖрнКв.ВидРасч + ", "; 
        КонецЕсли;                                                                                                   
    КонецЕсли;
    Коммент = Лев(Коммент, СтрДлина(Коммент)-2);
КонецЦикла;

Обратите внимание на строку Коммент = Лев(Коммент, СтрДлина(Коммент)-2);. Она находится внутри цикла получения записей журнала. Выясним причину, почему это фатально для алгоритма:

  1. Если при первой итерации цикла условие ЖрнКв.Результат = 0 не выполняется, переменная Коммент остается пустой строкой.
  2. Функция СтрДлина("") возвращает 0.
  3. Выражение СтрДлина(Коммент) - 2 дает результат -2.
  4. В платформе 1С 7.7 функция Лев(Строка, Длина) при отрицательном значении длины вызывает ошибку времени выполнения (Runtime Error).

В результате программа просто прерывает выполнение процедуры, и создается впечатление, что «в цикл не попадаем в принципе». Решение: вынесите обрезку лишней запятой за пределы цикла и обязательно добавьте проверку на заполненность строки.

Особенности метода ВыбратьЗаписиПоОбъекту

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

Также важно убедиться, что в конфигураторе для журнала расчетов «Квартплата» справочник «Клиенты» действительно назначен Объектом расчета. Если эта связь не установлена, метод ВыбратьЗаписиПоОбъекту всегда будет возвращать пустую выборку, даже если записи в базе физически существуют.

Проблема периодов журнала расчетов

В 1С 7.7 журналы расчетов жестко привязаны к понятию «Текущий период». Рассмотрим функции, использованные в коде: ЖрнКв.НачалоТекущегоПериода() и ЖрнКв.КонецТекущегоПериода(). Эти функции возвращают даты начала и конца того периода, который в данный момент установлен для журнала в системе (как правило, это текущий месяц).

Если пользователь пытается сформировать отчет за декабрь 2019 года, но текущий расчетный период в базе открыт, например, для января 2020 года, то выборка по текущему периоду не найдет старых записей. Посмотрим, как это проверить:

  1. Убедитесь, какой период в журнале является актуальным (меню «Операции» — «Журналы расчетов»).
  2. Если нужно выбрать данные за прошлые периоды, необходимо использовать метод УстановитьПериод() или передавать в ВыбратьЗаписиПоОбъекту явные даты начала и конца нужного интервала.

Проверка статуса расчета: «Рассчитана» или нет?

Автор ищет записи, где Результат = 0. Однако нулевой результат не всегда означает, что расчет не был выполнен. В 1С 7.7 запись журнала может иметь результат 0, будучи успешно рассчитанной (например, если нет данных для начисления). Если цель отчета — найти именно нерассчитанные записи (те, что помечены вопросительным знаком в интерфейсе), правильнее использовать метод Рассчитана().

Проанализируем пример исправленного условия:


Если ЖрнКв.Рассчитана() = 0 Тогда
    // Эта запись еще не рассчитывалась
    Коммент = Коммент + ЖрнКв.ВидРасч + ", ";
КонецЕсли;

Инициализация переменных и глобальный контекст

В коде встречается условие: Если ... асКлиенты.ПринадлежитГруппе(ВЫБЫВШИЕ) = 1 Тогда. В системе 1С 7.7 идентификатор ВЫБЫВШИЕ не может быть просто «написан» в коде, если это название группы в справочнике. Программа воспримет это как пустую переменную. Чтобы условие заработало, группу нужно сначала найти.

Разберем, как это сделать правильно:


ГрпВыбывшие = СоздатьОбъект("Справочник.Клиенты");
Если ГрпВыбывшие.НайтиПоНаименованию("ВЫБЫВШИЕ", 0, 1) = 1 Тогда
    ВЫБЫВШИЕ = ГрпВыбывшие.ТекущийЭлемент();
КонецЕсли;

Только после такой инициализации проверка ПринадлежитГруппе(ВЫБЫВШИЕ) станет корректной.

Оптимизация: переход от циклов к запросам

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

Выясним преимущества использования запроса:

Итоговый вариант исправленного кода

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


Процедура Сформировать()
    ЖрнКв = СоздатьОбъект("ЖурналРасчетов.Квартплата");
    асКлиенты = СоздатьОбъект("Справочник.Клиенты");
    
    // Определяем границы периода (можно также брать из реквизитов диалога)
    ДатаНач = ЖрнКв.НачалоТекущегоПериода();  
    ДатаКон = ЖрнКв.КонецТекущегоПериода();
    
    ТабДок = СоздатьОбъект("Таблица");
    ТабДок.ИсходнаяТаблица("СписокРасчетовНеВып");
    ТабДок.ВывестиСекцию("Шапка");
    
    сч = 0; 
    асКлиенты.ВыбратьЭлементы();
    Пока асКлиенты.ПолучитьЭлемент() = 1 Цикл
        // Пропускаем группы, помеченные на удаление и пустые ссылки
        Если (асКлиенты.ЭтоГруппа() = 1) Или (асКлиенты.ПометкаУдаления() = 1) Тогда
            Продолжить;
        КонецЕсли;
        
        Коммент = ""; 
        // Используем ТекущийЭлемент() для надежности выборки
        ЖрнКв.ВыбратьЗаписиПоОбъекту(асКлиенты.ТекущийЭлемент(), ДатаНач, ДатаКон);
        
        Пока ЖрнКв.ПолучитьЗапись() = 1 Цикл 
            Если ЖрнКв.ВидРасч.ВходитВГруппу("ВсеНачисления") = 1 Тогда 
                // Проверяем именно отсутствие расчета
                Если (ЖрнКв.Рассчитана() = 0) Или (ЖрнКв.Результат = 0) Тогда
                    Коммент = Коммент + СокрЛП(Строка(ЖрнКв.ВидРасч)) + ", "; 
                КонецЕсли;                                                                                                   
            КонецЕсли;
        КонецЦикла;
        
        // Обрезаем запятую только ЕСЛИ строка не пустая и ЗА пределами внутреннего цикла
        Если ПустаяСтрока(Коммент) = 0 Тогда
            невыпрасч = Лев(Коммент, СтрДлина(Коммент) - 2);
            сч = сч + 1;
            лс = асКлиенты.Код;
            ТабДок.ВывестиСекцию("Строка");
        КонецЕсли;
    КонецЦикла;
    
    ТабДок.ТолькоПросмотр(1);
    ТабДок.Показать();
КонецПроцедуры

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

← На главную