При разработке учетных документов часто возникает задача ввода данных в виде матрицы: по строкам располагаются аналитические параметры, а по колонкам — дни месяца. Дополнительно может потребоваться возможность пометить определенные дни для автоматического расчета (например, по среднему значению за предыдущие периоды или дни месяца). Разберем архитектурные и технические решения этой задачи на платформе 1С:Предприятие 8.3.
Первое побуждение разработчика — добавить в табличную часть документа 31 реквизит для значений каждого дня и еще 31 реквизит-флаг для признака расчета. Однако создание жесткой структуры из десятков реквизитов имеет серьезные недостатки:
Рассмотрим правильный подход: разделение модели хранения данных и модели их отображения на форме. Этот паттерн применяется в типовых конфигурациях (например, в документе Установка цен номенклатуры или Табель учета рабочего времени).
В структуре метаданных документа табличную часть организуют в нормализованном (вертикальном) виде. Для этого достаточно небольшого набора реквизитов:
Параметр (или ссылка на аналитику, строку расчетов).ДеньМесяца (или Дата / Период).Значение (Число).ПоСреднему (Булево — признак расчета по среднему значению).Такая табличная часть скрывается на управляемой форме. При проведении документа данные из такой структуры считываются максимально быстро и прозрачно одной простой выборкой.
Для удобного ввода данных пользователем на форму документа выводится временная таблица значений, колонки которой формируются программно в зависимости от выбранного месяца.
Разберем по шагам алгоритм создания такой матрицы на сервере:
ИзменитьРеквизиты().Посмотрим на пример программного добавления колонок на форму:
&НаСервере
Процедура СформироватьКолонкиДнейНаСервере(КоличествоДней)
// 1. Удаляем старые динамические элементы и реквизиты (если были)
// 2. Описываем новые реквизиты
ДобавляемыеРеквизиты = Новый Массив;
Для День = 1 По КоличествоДней Цикл
ИмяРеквизита = "День_" + Формат(День, "ЧЦ=2; ЧВН=");
ДобавляемыеРеквизиты.Добавить(
Новый РеквизитФормы(ИмяРеквизита, Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)), "ТаблицаМатрицы")
);
КонецЦикла;
ИзменитьРеквизиты(ДобавляемыеРеквизиты);
// 3. Создаем элементы формы
ТаблицаЭлемент = Элементы.ТаблицаМатрицы;
Для День = 1 По КоличествоДней Цикл
ИмяКолонки = "День_" + Формат(День, "ЧЦ=2; ЧВН=");
ЭлементКолонка = Элементы.Добавить(ИмяКолонки, Тип("ПолеФормы"), ТаблицаЭлемент);
ЭлементКолонка.Вид = ВидПоляФормы.ПолеВвода;
ЭлементКолонка.ПутьКДанным = "ТаблицаМатрицы." + ИмяКолонки;
ЭлементКолонка.Заголовок = Строка(День);
КонецЦикла;
КонецПроцедуры
Частый вопрос разработчиков: как обратиться к ячейке таблицы, если имя колонки хранится в переменной? Попытка использовать точечную нотацию вроде Объект.ТЧ[НомерСтроки].ИмяПеременной приводит к ошибке компиляции. Для динамического доступа используется синтаксис квадратных скобок:
// Правильное обращение к колонке по имени переменной:
СтрокаДанных = ТаблицаМатрицы[НомерСтроки];
СтрокаДанных[ИмяКолонки] = РассчитанноеЗначение;
Чтобы не загромождать интерфейс двойным количеством колонок (число + флажок для каждого дня), можно применить более эргономичные подходы:
УсловноеОформление формы. Это дает наглядную картину без лишних флажков.Проанализируем места выполнения расчета:
ПередЗаписьюНаСервере формы: данные из динамической экранной таблицы сворачиваются обратно в строки реальной табличной части Объект.ИмяТабличнойЧасти.ПередЗаписью: дублируется проверка и контрольный пересчет значений, помеченных флагом расчета по среднему, чтобы обеспечить целостность данных при программном создании документов.Не рекомендуется откладывать расчет среднего исключительно на этап формирования отчетов или проведения по регистрам. Фиксация рассчитанных значений непосредственно в данных документа гарантирует воспроизводимость истории и позволяет пользователю сверить и проверить все показатели перед проведением.