Событийная модель Oracle Siebel CRM (Часть 3)

  • Tutorial

Введение


В предыдущих статьях (часть 1, часть 2) я рассмотрел особенности запуска и обработки основных событий бизнес-компонент: SetFieldValue и WriteRecord. Теперь я хочу обратиться к пользовательскому интерфейсу и посмотреть на то, как апплет обрабатывает нажатие на кнопку.



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

Принцип работы всех кнопок одинаковый, как стандартных, так и специфических. Фактически, каждая из них вызывает на апплете событие InvokeMethod, которому в качестве параметра передается тот метод, который заранее определен на конкретной кнопке:



Схема обработки события


Схема обработки события выглядит следующим образом:



1. Система проверяет, есть ли обработчик события на ветке Pre-Branch данного события на уровне апплета. Если этого обработчика нет, или он есть и отработал без ошибок, то система обращается к стандартному обработчику апплета.

2. Стандартный обработчик апплета смотрит, умеет ли он обрабатывать вызванный метод. Если не умеет, или умеет и обработчик отработал без ошибок, то стандартный обработчик апплета инициирует событие InvokeMethod на бизнес-компоненте, на которой основан апплет.

3. Система опять проверяет, есть ли обработчик на Pre-Branch данного события для данной бизнес компоненты. Уже после этого управление передается на уровень стандартного обработчика бизнес компоненты.

4. Стандартный обработчик смотрит на метод, который ему передали вместе с событием InvokeMethod, и, если он его не узнает, то система остановит обработку и отобразит ошибку. Если этот метод знаком бизнес-компоненте, то она обработает его, и после этого управление перейдет на ветку Post-Branch события InvokeMethod на уровне бизнес компоненты.

5. Если на данной ветке определен какой-то обработчик, то он сделает свою работу. В случае если тут не случилось никаких ошибок, то дальше управление перейдет уже на ветку Post Branch события InvokeMethod на уровне апплета.

Доступ к нажатию кнопки


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

Помимо этой проблемы, возникает ещё вопрос доступа к вызову события InvokeMethod для конкретного метода. По умолчанию Siebel, если он не знает метод, определённый на кнопке, то кнопка не доступна для нажатия.





Решить эту проблему можно несколькими способами. Одним из самых распространённых способов является скрипт на уровне апплета:

function WebApplet_PreCanInvokeMethod (MethodName, &CanInvoke)
{
	if (MethodName == "TestMethod")
	{
		CanInvoke = "TRUE";
		return (CancelOperation);
	}
 
	return (ContinueOperation);
}



Такое решение является достаточно гибким и позволяет писать сложную логику для определения доступа к данному методу, а, соответственно, и к нажатию кнопки. Тем не менее, есть более элегантные варианты решения. Например, это можно определить User Property на уровне апплета CanInvokeMethod: <Имя метода>. Значением этого свойства может быть любое логическое выражение, написанное на языке Siebel Query Language, включая использование функции ParentFieldValue для доступа к полям родительской бизнес-компоненты.





Ошибка стандартного обработчика


Как только кнопка становится доступной для нажатия, появляется возможность написать собственный обработчик. Тем не менее, как я указывал ранее, мы получим ошибку, которую возвращает стандартный обработчик события InvokeMethod на уровне бизнес-компоненты:



Есть два подхода к тому, как избежать этой ошибки. Первый основан на том, чтобы не дать системе дойти до стандартного обработчика на уровне бизнес-компоненты. Это можно сделать, если остановить обработку на Pre-Branch апплета либо бизнес-компоненты через скрипт:

function BusComp_PreInvokeMethod (MethodName)
{
	if (MethodName == "TestMethod")
	{
		// Do Something
 
		return (CancelOperation);
	}
 
	return (ContinueOperation);
}

Оператор return (CancelOperation); останавливает всю дальнейшую обработку.

Второй подход основан на том, чтобы сказать стандартному обработчику, что на данный метод никаких ошибок выводить не надо. Тут опять появляется два способа это сделать. Первый связан с использованием User Property “Named Method n” на уровне апплета или на уровне бизнес компоненты. Использование этого свойства я планирую рассмотреть в следующей статье. Здесь же мы посмотрим на самый простой и интересный способ, связанный с использованием префикса EventMethod в имени метода.

Суть очень простая: когда указываете название метода для кнопки, если он не является стандартным, его нужно начинать с EventMethod. Когда стандартный обработчик события InvokeMethod на бизнес компоненте получает такое название метода, он просто ничего сам не делает, а передает управление дальше по схеме. Если в рассмотренном здесь примере название метода изменить на EventMethodTestMethod, то получим следующую картину:





Кнопка активна, и нажатие на неё не приводит к ошибкам. Можно ещё заметить тот факт, что я никаким образом не менял логику активации кнопки: скрипта никакого нет, свойство CanInvokeMethod занимается активацией строго метода TestMethod. Таким образом, это решение сразу двух проблем.

Используя такой подход, мы меняем основную парадигму. Теперь всё, что не запрещено, разрешено. Значит, после добавления такой кнопки нужно обязательно задуматься на тему того, как ограничить доступ к данной кнопке. Для этого можно использовать уже рассмотренный выше CanInvokeMethod.

Важное замечание: для того, чтобы трюк с EventMethod работал правильно, необходимо, чтобы класс бизнес-компоненты, на котором основан апплет, был равен либо CSSBCBase, либо любому унаследованному от него. Это означает, что для класса CSSBusComp, который по умолчанию прописывается для каждой новой бизнес-компоненты, такое решение работать не будет.

Выводы


1. При создании новых бизнес-компонент всегда указывайте имя класса CSSBCBase. Он дает достаточно много полезных вещей, в том числе функциональность, связанную с EventMethod.

2. При создании кнопок, которые автоматизируют функционал системы, рекомендую использовать в названии метода EventMethod для её активации и CanInvokeMethod для разграничения правил доступа. Это существенно поможет сократить количество скриптов и облегчит процесс разработки.

3. При условии соблюдения предыдущего пункта, обработчики нажатия кнопок можно вешать на любую ветку, как на Pre-Branch, так и на Post-Branch. Желательно задавать логику именно на уровне апплета.

4. С помощью свойства CanInvokeMethod можно ограничивать по заранее заданному условию доступ к стандартным методам апплета: NewRecord, DeleteRecord, NewQuery, ExecuteQuery. При этом при ограничении доступа к методу NewRecord не стоит использовать поля текущей сущности. Скорее всего, там будет обращение к профильным атрибутам через функцию GetProfileAttr() или к полям родительской записи через функцию ParentFieldValue().
Инфосистемы Джет
486,52
Системный интегратор
Поделиться публикацией

Комментарии 6

    0
    Спасибо, продолжайте и дальше публиковать статьи, они найдут своего читателя.
    Про трюк с EventMethod не знал, пополнил копилку. Стоило отметить минус кастомных методов в том, что кнопки остаются активными, даже тогда когда не надо (например вью РО в респонсибилити) и приходится писать скрипт на апплете:
    function WebApplet_PreCanInvokeMethod (MethodName, &CanInvoke)
    {
    	if(MethodName == "Test")
    	{
    		CanInvoke = TheApplication().InvokeMethod("IsViewReadOnly", TheApplication().GetProfileAttr("ActiveViewName"));
    		return (CancelOperation);
    	}
    	return (ContinueOperation);
    }
    

    NullScript способа не знаю.
      0
      Спасибо за комментарий! Методом IsViewReadOnly на уровне приложения никогда не пользовался, спасибо за
        0
        Методом IsViewReadOnly на уровне приложения никогда не пользовался. Штука очень интересная. Только я не рекомендую пользоваться RO Flag на уровне View. Такой запрет слишком жесткий, нет возможности задать условие или определить область действия, то есть на каком именно апплете нужно закрыть редактирование. У меня были требования, что на кредитной заявке нужно было закрыть возможность редактирования всех Detail View, кроме одной. При этом надо, чтобы в верхнем апплете с формой КЗ можно было изменять одно поле. Такую задачу сначала решали с помощью RO Flag. Но оказалось это очень неудобно для пользователей.

        Я могу посоветовать пользоваться свойством CanInvokeMethod, где в условии использовать функции InList и GetProfileAttrAsList. Например, вот так:

        InList(«Can Press Button Responsibility», GetProfileAttrAsList(«User Responsibilities»))
          0
          У нас на проекте используется РО на уровне вью. InList хорош когда в названии респ бывает что-то общее. На практике часто оказывается ничего общего кроме префикса. В таких случаях приходится писать скрипты.
            0
            А так да, когда появляется требование чтобы одно поле стало не РО — это самая печаль. Был как-то форм апплет с >50 полей, и для каждого настраивать UP Field Read Only Field то ещё развлечение.
              0
              Был как-то форм апплет с >50 полей, и для каждого настраивать UP Field Read Only Field то ещё развлечение.

              В таких случаях лучше делать отдельный форм апплет. Показывать его можно либо через переключение (Toggle), либо новую View нарисовать. Всё зависит от требований.

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое