Заполнение объектов в модели MVC

10.08.22

Разработка - Механизмы платформы 1С

Обычно объекты ИБ содержат избыточную информацию. Заполнение объекта может быть интерактивным или из модуля – алгоритмы должны быть одинаковые. Внешние системы должны определять основные реквизиты, а алгоритмы заполнения дополнять все остальные реквизиты зависимые, определяемые текущими бизнес-правилами, служебные.

Оглавление

Реквизиты объектов и работа с ними. 1

Откуда берется избыточность и нужно ли с ней бороться?. 2

Алгоритмы заполнения и MVC. 3

Обработчик заполнения. 4

Обработчик ПриИзменении. 5

Команды изменения / заполнения. 5

Вывод


Реквизиты объектов и работа с ними

Представим себе реализацию документа Заказ покупателя. Какой минимально необходимый реквизитный состав требуется для заказа? Ну, наверное, это Организация, Клиент, Номенклатура, Количество. Это так называемые входные параметры.

Для цельности заказа не хватает стоимостной оценки, номера и даты. Хорошо, что на счет стоимости заказа? Будет ли она определяться конкретными условиями договоренностей с клиентом или договоренность со всеми клиентами одинаковая? Скорее всего разная. Пусть эта договоренность оформлена в договоре между Организацией и Клиентом. Скорее всего такой договор с покупателем будет один, хотя не исключено что и много. Если договоров несколько, то нужно понимать критерии действия одного договора или другого. Зная договор можно определить цены и условия скидки.

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

Бизнес процессы организаций могут быть весьма разнообразны. В некоторых из них к заказу может потребоваться дополнительно определить тип отношений с клиентом. Клиент может быть физическим лицом или юридическим. Возможно даже, что для организации имеет значение является ли клиент аффилированным лицом или нет. Вся эта дополнительная информация может быть заполнена из дополнительных источников при тех же самых входных параметров, которые были определены в самом начале.

Добавьте к этому еще изменчивость бизнеса. Что если в какой-то момент началась акция и все цены заказа идут по особым условиям? А если скидки разные по разным группам товаров? Все это должно быть учтено в алгоритмах заполнения заказа.

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

Но что если заказ порождается из другой системы? Например это веб-заказ, где в качестве бэка используется 1С? Или это в рамках 1С в той же базе, но из альтернативных вариантов формирования: из АРМ или из почты или из телеграм-канала? Каждый из этих источников должен правильно заполнить данные заказа. Если каждый источник будет использовать собственный алгоритм формирования заказа, то это будет плохое архитектурное решение. Дублирование реализации очень быстро может привести к расхождению логики. Кроме того такой подход увеличивает сложность системы и затраты на её сопровождение.

Хорошо, в платформе 1С имеет подходящий обработчик заполнения - его и нужно использовать в нашем случае. При необходимости заполнить заказ из внешних алгоритмов нужно будет передать входящие параметры в этот обработчик. Остается согласовать формат входящих параметров. Идеальное решение, когда структура входящих параметров совпадает со структурой самого заказа. В таком варианте входящие параметры можно перенести 1=1 в заказ, а затем дозаполнить данные заказа, согласно текущему бизнес-процессу.

Еще одна задача, которая осталась нерешенной - как переиспользовать алгоритмы заполнения, которые были реализованы изначально под интерактивную работу с заказом? И здесь очень хорошо подходит шаблон MVC. Если бизнес-логика заказа отделена от представления, то появляется возможность её переиспользования в том числе и в неинтерактивных сценариях система-система.

 

Откуда берется избыточность и нужно ли с ней бороться?

Источниками избыточности не всегда является плохая архитектура. Дело в том, что информационный объект, такой как документ 1С – это объект-событие, привязанный к определенному моменту времени. Вся информация, которой он наполнен, также относится к этому моменту времени. Данные объекта условно можно поделить на ключевые, регистрационные и определяемые. Ключевые – это входящие параметры, которые определяются внешней системой или пользователем и характеризующие объект или его предназначение. Регистрационные – те, которые присваиваются объекту для регистрации в системе. Это могут быть номер, дата, ответственный исполнитель и т.д. Определяемые данные заполняет система исходя из текущих условий. Нужно стремиться, чтобы эти данные в большинстве своем определялись однозначно. При необходимости такие данные должны быть доопределены или изменены на другие допустимые значения или определены по-умолчанию. В первом случае решение принимается пользователем, а во втором – системой.

Дополнительные реквизиты объекта не всегда могут определяться внешними данными в моменте. Это также могут быть данные из связанных таблиц. Цель таких реквизитов в упрощении алгоритмов работы с объектом, а также производительность. В демо-базе есть документ Демо: Заявка на операцию, в котором ключевым параметром является вид операции. По виду операции система определяет связанные данные: тип операции, форму оплаты. Тип операции берется из элемента справочника Демо Виды операций, а вот форма оплаты задается алгоритмически: по дефолту безналичная, однако если вид операции ограничен конкретной формой оплаты, то этим конкретным значением. Возможно, также оплата может быть любой, но у клиента может отсутствовать расчетный счет, тогда оплата будет наличными.

В приведенном примере Тип операции не может быть переопределен и введен в качестве реквизита документа «Демо Заявка на операцию» для простоты алгоритмов и работы отборов. Форма оплаты напротив, может быть изменена при необходимости в рамках доступных значений. Это пример зависимых или расчетных данных.

Может встречаться очень сложная бизнес-логика, которая определяет признаки расчетным путем. Для того, чтобы эту сложность не экспортировать за пределы объекта в самом объекте добавляются реквизиты, в которых сохраняется результат сложных расчетов. А это уже будет служебный реквизит, который хранит результат сложной бизнес-логики и является вспомогательным.

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

Рассмотренная избыточность имеет свои недостатки. Так несмотря на целостность отдельного объекта, данные тем ни менее могут стать несогласованными с внешними источниками. Однако если рассматривать зоны ответственности, то в своей зоне ответственности объект будет сохранен целостным. Также к рассчитанным значениям можно обращаться без необходимости тратить ресурсы на повторные вычисления. Кроме того обращаться к сохраненным данным можно стандартным образом, в отличии от расчетных. Сохраненные данным можно использовать в отборах и в отчетах, передавать в другие системы.

 

Алгоритмы заполнения и MVC

В основе идеи MVC лежит разделение слоев приложения, когда бизнес-логика имеет отдельный слой реализации. В таком разделении не важно, что является источником изменения данных. Заполнение может быть в обработчике заполнения, а может быть и в интерактивной команде заполнения. Более того, источником изменения может быть также команды в самом документе или обработчики изменения реквизитов, изменение которых может приводит к изменению других, зависимых реквизитов.

Другой вопрос, как в модель передать данные по изменениям? В первоначальном варианте подсистемы «Модель состояния» был реализован вариант, когда реквизиты объекта заполнялись непосредственно в алгоритме, а затем изменения передавались в модель. Этот вариант был осложнен необходимостью решать задачи: определение изменений, накопление изменений. Лучший вариант решения я увидел в учебном видео автора Черненко Виталия (Эффективная архитектура 1С. Ep.2. Сложность). Там предлагался вариант автозаполнения по шаблону. Идея мне показалась простой и эффективной, а в применении MVC очень хорошо применима для передачи в модель.

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

Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
    МодельОбъекта = Документы._ДемоЗаявкаНаОперацию.МодельСостояния(ЭтотОбъект).ПрименитьМодель();
    ФормаОплаты = Перечисления._ДемоВидыДенежныхСредств.Безналичные;
    ПриходРасход = Перечисления._ДемоПриходРасход.Расход;
    //  Для внешней операции
    ВидОперации = Справочники._ДемоВидыОперацийБюджетирование.НайтиПоНаименованию("Расчеты с контрагентами", Истина);
    //  Для внутренней операции
    //ВидОперации = Справочники._ДемоВидыОперацийБюджетирование.НайтиПоНаименованию("Внутреннее перемещение", Истина);
    КурсРасчетов = 1;
    СуммаВзаиморасчетов = 100;
    РаботаСМодельюОбъектаКлиентСервер.ПриИзмененииПараметра(МодельОбъекта, "ФормаОплаты");
    РаботаСМодельюОбъектаКлиентСервер.ПриИзмененииПараметра(МодельОбъекта, "ПриходРасход");
    РаботаСМодельюОбъектаКлиентСервер.ПриИзмененииПараметра(МодельОбъекта, "ВидОперации");
    РаботаСМодельюОбъектаКлиентСервер.ПриИзмененииПараметра(МодельОбъекта, "КурсРасчетов");
    РаботаСМодельюОбъектаКлиентСервер.ПриИзмененииПараметра(МодельОбъекта, "СуммаВзаиморасчетов");
    РаботаСМодельюОбъектаКлиентСервер.Рассчитать(ЭтотОбъект, МодельОбъекта.ИзмененныеПараметры);
КонецПроцедуры

Что здесь происходит? Вначале инициализируется подсистема состояния. Затем заполняются непосредственно данные объекта. Измененные реквизиты регистрируются с помощью вызова процедуры ПриИзмененииПараметра. Вызов этой процедуры приводит к накоплению данных об измененных реквизитах объекта. Измененные реквизиты хранятся в массиве из структур формата расчетного параметра. Накопленные изменения передаются в функцию Рассчитать. Результатом расчета будет измененный объект, сама функция вернет массив измененных параметров.

Способ заполнения по шаблону кардинально отличается от заполнения при интерактивной работе, но идеально подходит для формирования изменений в объекте для передачи их в модель. Все последующие примеры будут с использованием этого способа.

Далее будут рассмотрены следующие сценарии:

  1. Создание нового объекта
  2. Обработчик ПриИзменении для реквизита объекта
  3. Команда изменения / заполнения объекта

 

Обработчик заполнения

Обработчик заполнения объекта может выглядеть вот так:

Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
    //  Заполнение шаблона
    ШаблонОбъекта = Новый Структура;
    ШаблонОбъекта.Вставить("ФормаОплаты", Перечисления._ДемоВидыДенежныхСредств.Безналичные);
    ШаблонОбъекта.Вставить("ПриходРасход", Перечисления._ДемоПриходРасход.Расход);
    //  Для внешней операции - "Расчеты с контрагентами", для внутренней - "Внутреннее перемещение"
    //ШаблонОбъекта.Вставить("ВидОперации", Справочники._ДемоВидыОперацийБюджетирование.НайтиПоНаименованию("Расчеты с контрагентами", Истина));
    ШаблонОбъекта.Вставить("ВидОперации", Справочники._ДемоВидыОперацийБюджетирование.НайтиПоНаименованию("Внутреннее перемещение", Истина));
    ШаблонОбъекта.Вставить("КурсРасчетов", 1);
    ШаблонОбъекта.Вставить("СуммаВзаиморасчетов", 100);
    //  Расчет по шаблону
    Документы._ДемоЗаявкаНаОперацию.МодельСостояния(ЭтотОбъект).ПрименитьМодель();
    РаботаСМодельюОбъектаКлиентСервер.ЗаполнитьИРассчитать(ЭтотОбъект, ШаблонОбъекта);
КонецПроцедуры

В этом примере из демо-базы заполнение производится по следующей схеме. Вначале создается структура, подобно заполняемому объекту, затем эта структура передается в модель. Особенность данного примера в том, что здесь модель объекта документа реализована с использованием модели состояния. Использование модели состояния подразумевает создание модель объекта и уже затем использование подсистемы для расчета изменений по модели.

 

Обработчик ПриИзменении

Тот же прием можно использовать и в обработчике изменения для реквизита формы:

&НаСервере
Процедура ВалютаВзаиморасчетовПриИзмененииНаСервере()
    Если ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Объект.ДоговорКонтрагента, "ВалютаРасчетов") = Объект.ВалютаВзаиморасчетов Тогда
        Возврат;
    КонецЕсли;
    //  Определение значение договора
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ
    |    _ДемоДоговорыКонтрагентов.Ссылка
    |ИЗ
    |    Справочник._ДемоДоговорыКонтрагентов КАК _ДемоДоговорыКонтрагентов
    |ГДЕ
    |    _ДемоДоговорыКонтрагентов.Владелец = &Владелец
    |    И _ДемоДоговорыКонтрагентов.Организация = &Организация
    |    И _ДемоДоговорыКонтрагентов.ВалютаРасчетов = &ВалютаРасчетов";
    Запрос.УстановитьПараметр("Организация", Объект.Организация);
    Запрос.УстановитьПараметр("Владелец", Объект.Контрагент);
    Запрос.УстановитьПараметр("ВалютаРасчетов", Объект.ВалютаВзаиморасчетов);
    Выборка = Запрос.Выполнить().Выбрать();
    ШаблонОбъекта = Новый Структура;
    Если Выборка.Следующий() И Выборка.Количество() = 1 Тогда
        ШаблонОбъекта.Вставить("ДоговорКонтрагента", Выборка.Ссылка);
    Иначе
        ШаблонОбъекта.Вставить("ДоговорКонтрагента", Неопределено);
    КонецЕсли;
    ИзмененныеПараметры = РаботаСМодельюОбъектаКлиентСервер.Заполнить(ЭтотОбъект, ШаблонОбъекта);
    ПриИзмененииНаСервере(ИзмененныеПараметры);
КонецПроцедуры

В этом примере демонстрируется работа с шаблоном объекта. Сформированный шаблон передается в подсистему для изменения объекта. Результатом изменения будет сам измененный объект, а также массив измененных параметров. Массив измененных параметров затем передается в обработчик формы ПриИзменении, где производится расчёт нового состояния объекта и обновление формы.

В отличие от обработчика заполнения в этом примере объект вначале изменяется по шаблону, а затем производится расчёт по изменениям. Дело в том, что при работе в форме производится оптимизация клиент-серверного взаимодействия, а также необходимо обновить саму форму. Оптимизация клиент-серверного взаимодействия производится как при расчёте объекта, так и при обновлении формы.

 

Команды изменения / заполнения

Вот так может выглядеть гипотетическая команда изменения документа в форме:

    ШаблонОбъекта = Новый Структура;
    ШаблонОбъекта.Вставить("Дата", '20220101');
    ШаблонОбъекта.Вставить("ВалютаДокумента", Справочники.Валюты.НайтиПоНаименованию("USD"));
    //  Использовать контекст формы
    ИзмененныеПараметры = РаботаСМодельюОбъектаКлиентСервер.Заполнить(ЭтотОбъект, ШаблонОбъекта);
    ПриИзмененииНаСервере(ИзмененныеПараметры);

Здесь также, как и в примере обработчика ПриИзменении, вначале формируется шаблон объекта, затем он передается в подсистему для заполнения объекта. Результатом заполнения объекта будет массив измененных параметров, которые передаются уже в обработчик формы для расчёта нового состояния объекта и обновления формы.

 

Вывод

Проблема заполнения объектов существует по причине того, что ключевые входящие параметры не определяют полного состояния объекта. В формировании целостного объекта участвуют различные данные:

  1. Основные или ключевые
  2. Зависимые или расчетные
  3. Служебные

При интерактивном заполнении объекта система должна заполнять зависимые данные или служебные по мере ввода данных. Если заполнение объекта осуществляют внешние алгоритмы или внутренние, то это должны быть те же самые алгоритмы, которые работают при интерактивном вводе. В качестве входящих данных для этих алгоритмов можно использовать шаблон объекта, представляющий собой структуру свойств объекта. Используя шаблон модель сможет вычислить изменения и дополнить данные объекта: зависимые и служебные.

Демо-базу можно скачать в приложении к статье "Модель состояния для MVC" или в релизе на github.

MVC форма модель заполнение

См. также

Сервисы интеграции без Шины и интеграции

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    2767    dsdred    16    

60

Поинтегрируем: сервисы интеграции – новый стандарт или просто коннектор?

Перенос данных 1C Администрирование СУБД Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.17 появился замечательный механизм «Сервисы интеграции». Многие считают, что это просто коннектор 1С:Шины. Так ли это?

11.03.2024    6392    dsdred    59    

86

Как готовить и есть массивы

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    6288    YA_418728146    25    

68

Планы обмена VS История данных

Перенос данных 1C Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    7245    dsdred    36    

114

1С-ная магия

Механизмы платформы 1С Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    19407    SeiOkami    46    

121

Дефрагментация и реиндексация после перехода на платформу 8.3.22

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    13157    human_new    27    

76

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    9704    YA_418728146    6    

146

Внешние компоненты Native API на языке Rust - Просто!

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Внешние компоненты для 1С можно разработывать очень просто, пользуясь всеми преимуществами языка Rust - от безопасности и кроссплатформенности до удобного менеджера библиотек.

20.08.2023    6657    sebekerga    54    

96
Оставьте свое сообщение