Расширение функционала
ERP можно расширять конфигурацией, JEXL-выражениями, динамическим Java-кодом, серверными сервисами, обработчиками событий и плагинами. Этот раздел помогает выбрать подходящий механизм и не обойти транзакции, события и проверки платформы.
Как выбрать механизм
| Задача | Предпочтительный механизм | Когда нужен следующий уровень |
|---|---|---|
Настроить тип процесса, форму или правило |
Конфигурация типа процесса и конструктор правил |
Если готового условия или действия недостаточно |
Вычислить условие или короткое значение |
JEXL |
Если выражение разрастается, требует повторного использования или сложного тестирования |
Изменить процесс, параметры или связанные объекты |
Сервисы из |
Прямой DAO допустим только внутри repository/DAO-слоя или в явно обоснованном исключении |
Обработать доменное событие |
|
Динамический listener нужен для инсталляционной логики, которую нельзя разместить в поставке |
Добавить крупную изолированную возможность |
Плагин или отдельный Gradle-модуль |
Динамический код подходит только для Java-классов, которые должны обновляться без сборки ERP |
Выполнять работу по расписанию |
Не создавайте собственные потоки и |
Сервисы в ServerContext
Сервисный слой является штатной точкой доступа к бизнес-операциям. Сервисы используют пользователя и соединения текущего ServerContext, участвуют в его транзакции, публикуют предусмотренные события и кешируются до закрытия контекста.
Основные страницы:
В Kotlin сервис получают типобезопасно:
import ru.bgcrm.context.core.ServerContext
import ru.bgcrm.context.core.getService
import ru.bgcrm.model.process.service.ProcessService
val processService = ServerContext.get().getService<ProcessService>()
val process = processService.getProcess(processId)
В Java используется интерфейс класса:
ProcessService processService = ServerContext.lookup(ProcessService.class);
Process process = processService.getProcess(processId);
ServerContext должен быть инициализирован для текущего потока. В HTTP-запросе, обработчике события и задаче платформы это уже сделано. Для самостоятельного запуска используйте withContext/runWithContext и явно определите пользователя и транзакционный режим.
|
JEXL
JEXL предназначен для коротких условий, вычислений и шаблонных фрагментов. ERP использует Apache Commons JEXL 3 в строгом режиме: неизвестная переменная или некорректный вызов завершают выполнение ошибкой.
Метод объекта вызывается через точку:
process.statusId == 39 && 1 =~ processParam.addressCityIds(90)
Статические вспомогательные методы доступны через стандартные пространства имён:
| Имя | Объект |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
Один или два перевода строки |
|
Буфер диагностических сообщений выражения |
Контекст зависит от точки запуска. Для событий процесса доступны process, user, event, form, processParam, processLink, processService, parameterService, processTaskService и другие объекты. Полный список приведён на странице Поддерживаемые объекты JEXL.
Для изменения данных используйте сервисы:
parameterService.updateText(process.id, 63, "Новое значение");
processService.addDescription(process.id, "Параметр обновлён");
paramRepo оставлен в контексте для совместимости со старыми выражениями. Новый код не должен использовать его для записи: прямой DAO обходит сервисные события и часть проверок.
Многострочный скрипт задаётся синтаксисом конфигурации <<END. Если вызывающая настройка ожидает результат, верните его оператором return:
someExpression=<<END
value = parameterService.getText(process.id, 63);
return !u.isBlankString(value);
END
Документация синтаксиса: Apache Commons JEXL.
Расширение JEXL-контекста
Дополнительные значения для процесса добавляются обработчиком BuildJexlContextEvent. Пользовательские значения объединяются со штатным контекстом, но штатные ключи имеют приоритет. Не переопределяйте имена process, user, context, processService, parameterService и другие системные ключи.
Динамический код
Динамический код — Java-исходники из настроенного каталога dyn, которые компилируются и загружаются без полной сборки ERP. Классы размещаются в пакете ru.bgcrm.dyn….
Через раздел администратора Динамический код можно:
-
открыть и изменить исходник;
-
скомпилировать выбранные классы или весь набор;
-
увидеть ошибки и предупреждения компиляции;
-
запустить класс, реализующий
Runnable.
После успешной компиляции применяется новый набор классов. Ошибка компиляции не должна рассматриваться как частичный успех: сначала устраните все ошибки, затем повторите сборку.
Динамический код пишется только на Java. Он компилируется против публичного API текущей версии ERP, поэтому после обновления системы его необходимо перекомпилировать и проверить.
Конфигурация, lifecycle компиляции, classloader, административные операции и диагностика описаны на странице Динамический Java-код.
Обработчики событий
Класс динамического обработчика наследуется от ru.bgcrm.event.listener.DynamicEventListener. Имя обработчика задаётся в конфигурации соответствующего типа процесса или параметра. Для новых обработчиков со статически известным составом событий предпочтителен AnnotatedEventListener.
Из обработчика получайте бизнес-сервисы через активный ServerContext. Не создавайте JDBC-соединения самостоятельно и не вызывайте DAO для операций, уже представленных сервисом.
Запуск при старте
Настройка createOnStart создаёт перечисленные классы при старте сервера и тем самым позволяет им зарегистрировать обработчики. Для фоновой периодической работы используйте штатный планировщик или модуль Task, а не runOnStart и бесконечный цикл.
HTTP-вызов динамического класса
/admin/dynamic.do?action=runDynamicClass является внутренним административным действием. Оно требует обычной авторизации и прав ERP. Не публикуйте его как интеграционный API и не передавайте логин с паролем в URL. Для внешней интеграции используйте справочник интеграций, отдельное Struts-действие или HTTP-клиент платформы.
JSP и клиентские расширения
JSP остаётся частью серверного интерфейса и печатных форм. Пользовательские JSP-фрагменты размещайте в каталогах WEB-INF/jspf/…/custom/, чтобы отделить их от штатных шаблонов.
Новый интерактивный интерфейс следует реализовывать во frontend-исходниках frontend/src/main/resources/webapps/. Каталоги app/webapps/ и build/ содержат результаты сборки и не являются источником.
JSP не должен содержать SQL или сложную бизнес-логику. Подготовьте данные в action/service и передайте их в request; в шаблоне оставьте отображение.
Схема обработки запроса: фильтр SetRequestParamsFilter добавляет в request контекст, action дополняет его данными, JSP формирует результат.
Логирование
ERP использует Log4j 2, конфигурация находится в app/log4j.properties. В коде используйте фасад ru.bgcrm.logging.Logger, а не System.out, java.util.logging, SLF4J или Log4j напрямую.
private val log = Logger.of(MyService::class.java)
log.info { "Обработан процесс $processId" }
Основные файлы — log/all.log и log/errors.log; отдельные подсистемы могут иметь собственные appenders. Не записывайте в лог пароли, токены, содержимое файлов и персональные данные.
Проверка расширения
Минимальная проверка перед поставкой:
-
код компилируется на JDK 21;
-
операции записи выполняются через сервисы и в ожидаемой транзакции;
-
проверены события до и после изменения;
-
повторный вызов не создаёт неожиданные дубли;
-
ошибки содержат безопасное и понятное сообщение;
-
для новой логики есть unit-тесты, а для JEXL — примеры входных данных и граничных значений;
-
документация содержит точку подключения, необходимые права, конфигурацию и способ отката.