При работе с системой компоновки данных (СКД) разработчики часто сталкиваются с ситуацией, когда в отчете определенные поля (например, Вес, Объем или Сумма) отображаются через раз или вовсе остаются пустыми, хотя при открытии самого документа в интерфейсе значения прекрасно видны. Особенно часто такая проблема встречается в конфигурации 1С:Управление нашей фирмой (УНФ) и других современных решениях на управляемых формах. Рассмотрим подробно, почему это происходит и как заставить СКД видеть нужные нам данные.
Первое, что нам необходимо сделать, — это четко разделить понятия "Данные в базе данных" и "Данные в форме объекта". СКД работает напрямую с таблицами базы данных (SQL или файловой), выполняя запросы к физически записанным значениям. Форма же документа — это динамический инструмент, который может изменять данные "на лету" перед показом пользователю.
Проанализируем типичную ситуацию в УНФ. В этой конфигурации реквизит Вес в табличной части Запасы документа ЗаказПокупателя часто является кэширующим. Для оптимизации работы он может заполняться не в момент выбора товара, а при открытии формы или программно при выполнении определенных действий. Если документ был создан сторонней обработкой и записан без вызова специальных процедур пересчета, физическое поле в таблице БД останется пустым (со значением 0 или NULL).
Выясним причину такого поведения. В модуле формы документа часто присутствуют процедуры типа ПриЧтенииНаСервере, внутри которых вызывается функционал по дозаполнению веса и объема, например, ПрочитатьВесИОбъемЕдиницыТовара(). Когда пользователь открывает такой документ, программа видит, что вес в строках равен нулю, лезет в справочник Номенклатура, вычисляет вес и подставляет его в форму. Пользователь видит заполненную колонку, закрывает документ (часто без сохранения, так как программа не считает это модификацией), и в базе данных по-прежнему остается пустота.
Чтобы убедиться, что проблема именно в отсутствии данных в БД, воспользуемся консолью запросов. Напишем простой запрос к табличной части документа:
ВЫБРАТЬ
ЗаказПокупателяЗапасы.Ссылка КАК Заказ,
ЗаказПокупателяЗапасы.Номенклатура КАК Номенклатура,
ЗаказПокупателяЗапасы.Вес КАК Вес
ИЗ
Документ.ЗаказПокупателя.Запасы КАК ЗаказПокупателяЗапасы
ГДЕ
ЗаказПокупателяЗапасы.Ссылка = &Ссылка
Если консоль выдает пустые значения или нули, значит, СКД ведет себя абсолютно корректно — ей просто нечего суммировать. В этом случае проблему нужно решать на уровне записи данных в документ, а не в настройках отчета.
Иногда проблема кроется в особенностях Определяемых типов. В СКД определяемый тип, базирующийся на числе, может восприниматься системой неоднозначно, особенно если в поле попадают пустые значения. Рассмотрим, как правильно обработать такие поля в тексте запроса СКД, чтобы исключить ошибки суммирования.
Разберем пример использования функции ЕСТЬNULL или конструкции ВЫБОР. Это гарантирует, что даже если в базе данных значение не заполнено, система получит числовой ноль, который корректно участвует в агрегатных функциях (Сумма):
ВЫБРАТЬ
ЗаказПокупателяЗапасы.Ссылка КАК Заказ,
ЗаказПокупателяЗапасы.Номенклатура КАК Номенклатура,
// Способ 1: Использование ЕСТЬNULL
ЕСТЬNULL(ЗаказПокупателяЗапасы.Вес, 0) КАК ВесЧислом,
// Способ 2: Явное приведение через ВЫРАЗИТЬ
ВЫРАЗИТЬ(ЗаказПокупателяЗапасы.Вес КАК ЧИСЛО(15, 3)) КАК ВесТипизированный,
// Способ 3: Проверка на тип и NULL через ВЫБОР
ВЫБОР
КОГДА ЗаказПокупателяЗапасы.Вес ЕСТЬ NULL ТОГДА 0
ИНАЧЕ ЗаказПокупателяЗапасы.Вес
КОНЕЦ КАК ВесИтоговый
ИЗ
Документ.ЗаказПокупателя.Запасы КАК ЗаказПокупателяЗапасы
Обратите внимание на сообщение 16 из нашего обсуждения: если поле имеет составной тип, оно может содержать значение Неопределено. В этом случае проверка ЕСТЬ NULL может не сработать, и потребуется проверка ТипЗначения().
Если мы выяснили, что документы, созданные программно, "пустые" в части веса, нам необходимо изменить код обработки, которая их создает. В типовых конфигурациях (УНФ, ERP, КА) нельзя просто присвоить значение номенклатуры в строку ТЧ. Необходимо инициировать цепочку типовых процедур пересчета.
Посмотрим на пример правильного заполнения документа в коде:
// Создаем новый документ
НовыйДокумент = Документы.ЗаказПокупателя.СоздатьДокумент();
// ... заполнение шапки ...
Для Каждого СтрокаДанных Из ТаблицаИсточника Цикл
НоваяСтрока = НовыйДокумент.Запасы.Добавить();
НоваяСтрока.Номенклатура = СтрокаДанных.Номенклатура;
// ВАЖНО: В УНФ для заполнения веса, объема и цен
// необходимо вызывать экспортные методы объекта или менеджера.
// Например, можно вызвать процедуру из модуля документа:
НовыйДокумент.ЗаполнитьВесИОбъемПоСтроке(НоваяСтрока);
КонецЦикла;
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
Проанализируем ситуацию: если в вашей конфигурации нет прямой экспортной процедуры ЗаполнитьВесИОбъемПоСтроке, изучите модуль формы документа, найдите там процедуру ПриИзмененииНоменклатуры. Посмотрите, какие серверные методы она вызывает. Обычно это методы в модуле менеджера или общем модуле, которые принимают строку ТЧ или весь объект и рассчитывают параметры на основе данных справочника Номенклатура.
Даже если данные в базе есть, СКД может не считать итоги по полю с определяемым типом из-за неверных настроек на закладке "Ресурсы". Рассмотрим алгоритм правильной настройки:
Вес.Число с нужной точностью (например, 15.3). Это подскажет СКД, как обрабатывать данные в памяти.Вес в список ресурсов. В колонке "Выражение" должно стоять Сумма(Вес).Все иерархии).Если чудо не произошло и после "ручного перебивания" веса в документе он считается, а в новых — нет, проверьте подписки на события. Иногда расчет веса происходит в подписке ПередЗаписью, которая может игнорироваться при записи объекта с признаком ОбменДанными.Загрузка = Истина. Если ваша внешняя обработка использует этот признак для ускорения записи, типовые механизмы расчета веса могут просто не запускаться.
Резюме: проблема "исчезающего" веса в СКД почти всегда связана с тем, что конфигурация рассчитывает эти данные визуально в форме, но не сохраняет их физически в таблицу Документ.ЗаказПокупателя.Запасы при программном формировании. Используйте консоль запросов для подтверждения наличия данных и вызывайте типовые процедуры заполнения реквизитов в своих обработках.