При разработке конфигураций и подсистем для производственных предприятий часто возникает задача расчета геометрических или технологических параметров изделий (например, площади воздуховодов, отводов, тройников или врезок). Каждое изделие обладает уникальным набором исходных размеров и собственной формулой расчета, однако в учете все они должны выступать позициями номенклатуры. Рассмотрим, как грамотно спроектировать структуру данных, организовать пользовательский интерфейс и оптимизировать математические расчеты в управляемом приложении 1С.
Перед тем как приступать к коду, проанализируем возможные варианты архитектуры и выясним, с какими проблемами можно столкнуться при неверном выборе:
Справочник.Отводы, Справочник.Заглушки, Справочник.Воздуховоды, то во всех документах конфигурации (заказах, накладных, спецификациях) придется использовать реквизиты составного типа. Это приводит к существенному замедлению работы СУБД, невозможности построения компактных индексов, затруднениям при контроле остатков и громоздким отчетам. Поэтому базовая сущность должна оставаться единым справочником Номенклатура.Если количество типов изделий ограничено (порядка 10–15 видов) и формулы расчета фиксированы, наиболее надежным и быстрым вариантом является размещение полей на скрытых страницах формы. Разберем по шагам, как это реализовать:
Номенклатура создаем реквизит ВидИзделия с типом перечисления (или ссылкой на фиксированный классификатор).ОтображениеЗакладок устанавливаем значение Не отображать.СтраницаОтводКруглый, СтраницаТройник, СтраницаЗаглушка.Элементы.Поле.Видимость = Ложь) переключаем всю страницу одной командой через свойство ТекущаяСтраница.Посмотрим на пример обработчика изменения вида изделия на клиенте:
&НаКлиенте
Процедура ВидИзделияПриИзменении(Элемент)
УстановитьСтраницуПараметров();
КонецПроцедуры
&НаКлиенте
Процедура УстановитьСтраницуПараметров()
Если Объект.ВидИзделия = ПредопределенноеЗначение("Перечисление.ВидыИзделий.ОтводКруглый") Тогда
Элементы.ГруппаСтраницПараметров.ТекущаяСтраница = Элементы.СтраницаОтводКруглый;
ИначеЕсли Объект.ВидИзделия = ПредопределенноеЗначение("Перечисление.ВидыИзделий.ТройникПрямоугольный") Тогда
Элементы.ГруппаСтраницПараметров.ТекущаяСтраница = Элементы.СтраницаТройникПрямоугольный;
ИначеЕсли Объект.ВидИзделия = ПредопределенноеЗначение("Перечисление.ВидыИзделий.Заглушка") Тогда
Элементы.ГруппаСтраницПараметров.ТекущаяСтраница = Элементы.СтраницаЗаглушка;
Иначе
Элементы.ГруппаСтраницПараметров.ТекущаяСтраница = Элементы.СтраницаПоУмолчанию;
КонецЕсли;
КонецПроцедуры
В управляемом интерфейсе платформа не выполняет отрисовку содержимого неактивных страниц, благодаря чему форма открывается мгновенно, а код остается простым и поддерживаемым.
Чтобы не создавать в таблице справочника десятки разреженных колонок (где для отвода заполнен диаметр, а высота и ширина остаются пустыми), рассмотрим два практичных метода хранения:
ПараметрыИзделия с колонками ИмяПараметра (Строка) и Значение (Число). При открытии формы значения из таблицы переносятся в реквизиты формы, а перед записью выгружаются обратно. Запись данных происходит в одной транзакции с самим объектом без обращения к сторонним регистрам.ПрочитатьJSON и ЗаписатьJSON. При открытии формы строка преобразуется в структуру, значения из которой заполняют поля на форме.Инженерные формулы часто содержат коэффициенты, зависящие от углов поворота или типоразмеров. Нагромождение условий Если ... ИначеЕсли снижает читаемость кода и провоцирует ошибки. Рассмотрим расчет площади круглого отвода, где промежуточные параметры определяются углом изделия:
&НаСервереБезКонтекста
Функция РассчитатьПлощадьОтводаКруглого(Диаметр, Угол) Экспорт
ЧислоПи = 3.1415926535;
// Подготовка таблицы технологических коэффициентов
ПараметрыУглов = Новый Соответствие;
ПараметрыУглов.Вставить(90, Новый Структура("ЧислоЗвеньев, ДелительШейки", 2, 2));
ПараметрыУглов.Вставить(60, Новый Структура("ЧислоЗвеньев, ДелительШейки", 2, 3));
ПараметрыУглов.Вставить(45, Новый Структура("ЧислоЗвеньев, ДелительШейки", 0, 4));
ПараметрыУглов.Вставить(30, Новый Структура("ЧислоЗвеньев, ДелительШейки", 0, 6));
ПараметрыУглов.Вставить(15, Новый Структура("ЧислоЗвеньев, ДелительШейки", 0, 12));
ДанныеУгла = ПараметрыУглов[Угол];
Если ДанныеУгла = Неопределено Тогда
ВызватьИсключение "Недопустимый угол отвода: " + Формат(Угол, "ЧГ=0");
КонецЕсли;
ЧислоЗвеньев = ДанныеУгла.ЧислоЗвеньев;
ДелительШейки = ДанныеУгла.ДелительШейки;
Шейка = (ЧислоПи / ДелительШейки * Диаметр / 2) / (ЧислоЗвеньев + 2) + 15;
Срез = (ЧислоПи / ДелительШейки * Диаметр) / (ЧислоЗвеньев * 2 + 2);
ПлощадьS2 = ЧислоПи * Диаметр / 1000 * 0.1;
ПлощадьS1 = (ЧислоПи * Диаметр * (2 * (Шейка + Срез / 2) + ЧислоЗвеньев * (Шейка + Срез))) / 1000000;
Возврат Окр(ПлощадьS1 + ПлощадьS2, 4);
КонецФункции
Важное архитектурное правило: расчетные функции следует размещать в модуле менеджера справочника или в общем серверном модуле. Это позволит повторно использовать алгоритм не только на форме элемента, но и при групповом пересчете спецификаций, импорте данных из CAD-систем или выполнении регламентных заданий без контекста клиентской формы.