При разработке отчетов и печатных форм в среде 1С:Предприятие 7.7 разработчики нередко сталкиваются с ситуацией, когда секция таблицы выводит предупреждение (например, «Не указана цена»), даже если реквизит заполнен и значение отлично от нуля. Разберем по шагам, из-за чего возникает такое поведение, как локализовать скрытые ошибки в коде и как грамотно переписать логику формирования отчета.
Проанализируем типичные архитектурные и логические ошибки, приводящие к ложному выводу сообщений в печатную форму:
Если ... ИначеЕсли: если в блоке ИначеЕсли жестко прописано присвоение служебного текста без вложенной проверки самого значения цены, программа гарантированно выведет эту строку при невыполнении главного условия Если.Попытка ... Исключение: перехват ошибок без вывода сообщений маскирует реальные сбои (например, обращение к несуществующему реквизиту справочника вроде Спр.Механик). В результате выполнение блока прерывается на середине, а переменные остаются в неопределенном состоянии либо управление уходит по неверной ветке.ПечНаименование и ПечЗамечание не присваиваются пустые значения, в секцию попадают данные от предыдущей итерации цикла.Получить(ТекущаяДата()) для каждого реквизита создает избыточные запросы к базе данных и усложняет чтение кода.Рассмотрим последовательность действий, которая позволяет быстро выявить и устранить проблему в модуле отчета.
Попытка ... Исключение: убираем конструкцию перехвата ошибок, чтобы отладчик платформы сразу указал на строку с обращением к отсутствующему свойству или методу агрегатного объекта.Механик, Сотрудник, НаОбслуживании) действительно присутствуют в структуре справочника.Группировка и Строка и предотвращает рассинхронизацию условий.ИспользоватьДату().Выясним причину замедления и возможных сбоев при чтении периодических реквизитов справочников. При вызове Спр.Цена.Получить(ТекущаяДата()) на каждом шаге цикла система выполняет отдельное обращение к таблице периодики. Гораздо надежнее и быстрее зафиксировать рабочую дату для самого объекта выборки с помощью метода ИспользоватьДату(ТекущаяДата(), 1).
Посмотрим на пример установки контекста даты:
Спр = СоздатьОбъект("Справочник.Номенклатура");
Спр.ИспользоватьДату(ТекущаяДата(), 1);
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
// Теперь к периодическому реквизиту обращаемся напрямую через точку:
ТекущаяЦена = Спр.Цена;
Если ТекущаяЦена = 0 Тогда
// Обработка отсутствия цены
КонецЕсли;
КонецЦикла;
Если требуется гарантированно получить значение периодического реквизита через отдельный системный объект, можно воспользоваться объектом Периодический:
Период = СоздатьОбъект("Периодический");
Период.ИспользоватьОбъект("Цена", Спр.ТекущийЭлемент());
Период.Получить(ТекущаяДата());
ЗначениеЦены = Период.Значение;
Разберем готовое решение, в котором устранены логические ошибки ветвления, вынесен в процедуру вывод секций таблицы и корректно проверяются все реквизиты объекта.
Перем Спр, Заголовок;
// Процедура централизованного вывода шапки и строк таблицы
Процедура ВывестиЗамечание(ИмяПоля, ТекстЗамечания)
ПечНаименование = ИмяПоля;
ПечЗамечание = ТекстЗамечания;
Если Заголовок = 0 Тогда
Заголовок = 1;
ДоговорСО = СпрДоговоры.ТекущийЭлемент();
Таб.ВывестиСекцию("Группировка");
КонецЕсли;
Таб.ВывестиСекцию("Строка");
КонецПроцедуры
// Основной блок выборки и анализа данных
Процедура СформироватьОтчет()
Таб.ИсходнаяТаблица("Таблица");
Спр = СоздатьОбъект("Справочник.Оборудование");
Спр.ИспользоватьДату(ТекущаяДата(), 1);
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
// Пропускаем удаленные элементы и объекты не на обслуживании
Если (Спр.ПометкаУдаления() = 1) ИЛИ (Спр.НаОбслуживании = 0) Тогда
Продолжить;
КонецЕсли;
Заголовок = 0;
ПечОбъект = "Договор ТО №" + СокрЛП(СпрДоговоры.НомерДоговора) +
" (" + СпрДоговоры.Контрагент.Наименование + "), модель " +
Спр.Модель.Наименование + " (№" + СокрЛП(Спр.СерийныйНомер.ЗаводскойНомер) + ")";
// 1. Проверка телефонов
Если (Спр.Телефон1 = "8( ) - - ") И (Спр.Телефон2 = "8( ) - - ") И
(Спр.Телефон3 = "8( ) - - ") И (Спр.Телефон4 = "8( ) - - ") Тогда
ВывестиЗамечание(" Телефоны", "Не указан телефон.");
КонецЕсли;
// 2. Проверка даты замены ЭКЛЗ
Если ПустоеЗначение(Спр.ДатаЗаменыЭКЛЗ) = 1 Тогда
ВывестиЗамечание(" ЭКЛЗ", "Дата блокировки ЭКЛЗ не указана.");
ИначеЕсли Спр.ДатаЗаменыЭКЛЗ < ТекущаяДата() Тогда
ВывестиЗамечание(" ЭКЛЗ", "Просрочена дата замены ЭКЛЗ.");
КонецЕсли;
// 3. Проверка адреса эксплуатации
Если ПустоеЗначение(Спр.МестоУстановки.АдресФакт) = 1 Тогда
ВывестиЗамечание(" Адрес эксплуатации", "Не указан адрес места эксплуатации.");
КонецЕсли;
// 4. Проверка станции метро
Если ПустоеЗначение(Спр.МестоУстановки.Метро) = 1 Тогда
ВывестиЗамечание(" Метро", "Не указана станция метро места эксплуатации.");
КонецЕсли;
// 5. Проверка ИФНС
Если ПустоеЗначение(Спр.ИФНС) = 1 Тогда
ВывестиЗамечание(" ИФНС", "Не указан ИФНС.");
ИначеЕсли ПустоеЗначение(Спр.ИФНС.Адрес) = 1 Тогда
ВывестиЗамечание(" ИФНС", "Не указан адрес ИФНС.");
КонецЕсли;
// 6. Проверка цены (срабатывает строго при нулевой или незаполненной цене)
Если (ПустоеЗначение(Спр.Цена) = 1) ИЛИ (Спр.Цена = 0) Тогда
ВывестиЗамечание(" Цена", "Не указана цена.");
КонецЕсли;
КонецЦикла;
Таб.Показать("Отчет по замечаниям");
КонецПроцедуры
Такая структура модуля исключает ложное срабатывание проверок, делает алгоритм прозрачным для отладки и существенно повышает скорость формирования печатной формы за счет правильной выборки периодических реквизитов.