Системный подход к реализации замещений SAP FI. Часть I
Введение. Виды реализации SAP-расширений.
Для лучшего понимания цели написания данной статьи следует рассмотреть существующие стандартные виды реализации расширений.
Существуют следующие виды реализации SAP- расширений для соответствующих типов расширений:
Внешний Perform - в стандарте реализация оформлена как вызов подпрограмм из пула подпрограмм FI. Подвидом такого расширения являются подпрограммы пользователя,обслуживающие события стандартного диалога ведения таблиц.
Customer-Exit – реализуется как вызов ФМ, в теле которого прописан includ из области имен клиента.
Business Transaction Events (BTE) - тип расширения с кратким названием OpenFI. Реализуется в виде вызова ФМ, который создаётся по образцу, со строго определенным интерфейсом. ФМ разделяются на два подвида : модули P/S и модули интерфейса.
BADI (Business-Add-Ins) - тип расширения, который реализуется в стандарте как вызов методов пользовательского класса, создаваемого на основе стандартного интерфейса.
RWIN - тип расширения, который реализуется как вызов ФМ для предопределенных бизнес-процессов системы.
Цели написания статьи.
Настоящая статья является описанием моего личного подхода к реализации задач по развитию и адаптации стандартного решения SAP FI к задачам конкретной организации и предназначена для разработчиков, которые уже имеют опыт работы с типами расширений, указанных в начале статьи.
Пятилетний опыт сопровождения и реализации проектов по замещениям позволил мне сформировать некоторые приемы программирования, которыми я намерен поделиться с вами. Я ни в коей мере не претендую на оригинальность предлагаемого мною метода реализации расширений . Более того, в моём решении все достаточно банально. Но я попытаюсь показать Вам системный подход в разработке архитектуры такого рода проектов, в той коннотации, в которой я понимаю термин 'системно'.
Системность - это такой результат специальной организации элементов системы, когда целое становится больше простой суммы частей. Эффективность такого подхода заключается в сокращении издержек на сопровождение проекта.
Недостатки стандартного решения SAP.
Рассмотрим недостатки стандартного решения предлагаемого SAP, в части реализации SAP-расширений. Эти решения достаточно хорошо документированы. (См список публикаций в конце статьи). Естественно, описание этих "недостатков" выражает моё сугубо личное мнение:
Манданто - зависимость.
На мой взгляд, манданто - зависимость в замещениях не нужна. Также совсем не понятна такая избирательность: Внешний Perform и BTE - манданто-зависимы, а Customer-Exits, User-Exits, Badi - нет. Очевидно, SAP, предоставляя эти механизмы реализации разработчикам, пытался таким образом разделить консультантов на умеющих писать код и тех, которые кодировать не могут, но которым нужна возможность вносить изменения в функциональность. Но нужна ли консультантам такая возможность? Я думаю - нет.
Если бы речь шла о десятке другом проверок, то - может быть. Но ведь речь идет о сотнях подпрограмм (этапов Внешних Perform), десятков задач по проверкам и замещениям в каждом событии BTE, которыми полностью перекраивается стандартное решение SAP. В результате мы имеем громоздкий, трудоемкий механизм предназначенный для консультантов, которым разработчики пользуются для реализации поставленных задач замещений.
Трудоемкость регламентных действий.
Рассмотрим для примера регламентные действия по реализации такого расширения, как "Внешний Perform"
Регламент определяет следующую последовательность действий:
- Зарегистрировать подпрограмму в пуле подпрограмм, чтобы она была доступна на уровне этапа.
- Создать программу в специальном инклуде.
- Создать этап (проверки/замещения), прописать предпосылки и привязать созданную подпрограмму к данному этапу.
- Реализовать подпрограмму.
- Сформировать транспортный запрос. Интересно, что возможности транспорта этапов нет. Возможен только транспорт всего замещения или проверки, а это иногда сотни этапов. Вот такая вот манданто зависимость - из за одного этапа поедут все этапы замещения/проверки. То есть, даже если теоретически предположить наличие такой необходимости - иметь различные данные этапов проверок/замещений в разных мандантах, то первый же транспорт их выровняет.
- Через транзакцию SCC1 перенести запрос в мандант тестирования. Или повторить п.2 в нужном манданте.
- Если вдруг обнаружилась ошибка в предпосылках этапа при тестировании, следует - повторить п.3 (изменить), п.4., п.5. И так - несколько итераций. (Пару раз ошибся разработчик, пару раз консультант, пару раз пользователь был неточен в своих «хотелках»).
А такая простая задача, как например:"...или заместить значение поля BSEG-HKONT или выдать ошибку 'Счет не изменен...', вообще удвоит число этих итераций. Ведь замещение нужно делать в этапах GGB1, а сообщения по проверкам выдавать в этапах GGB0.
А ведь что может быть проще: реализовать один этап с предпосылкой TRUE и единую программу для вызова всех задач замещения в едином пуле подпрограмм (и прописать ее вызов). И для всех последующих замещений/проверок нужна будет всего одна строчка вызова.
Тестируемость
Представьте, что одновременно вам одновременно поступают на реализацию несколько небольших задач проверок/замещений от разных консультантов. Вы их быстро (насколько позволяет п.2) реализуете и рапортуете консультантам о том что их задачи реализованы. И тут начинается: один говорит мне нужно срочно нести в продуктив, другой вообще не отвечает, третий говорит что нужно нести через неделю, четвертый говорит что замещение стало не нужно и т.д. А все включено в один запрос и это, если по хорошему. По плохому - это когда задачи реализуют разные разработчики и их объекты сидят в запросах друг у друга....
А ведь все решается просто: использованием механизма активности задач. Достаточно снять галку активности у задачи в настроечной таблице, и можно задачу нести в продуктив. И пусть она там дожидается тестирования консультантом в неактивном состоянии.
Непрозрачность.
Все типы расширений в системе отделены друг от друга. Зачастую, одну поставленную задачу замещения разработчик выполняет используя разные типы расширений. И впоследствии, находясь например в контексте замещений позиций, если мы видим, что некий этап "Внешнего Perform" что-то замещает, то совсем не факт, что это все, что ставилось в постановке замещения. Хорошо, если после поисков в документации (если это документировано) удастся определить, что еще задействовано в данной задаче (RWIN,BTE,BADI,CUSTOMER-EXITs). Я видел такие разработки - сотни подпрограмм этапов Внешних Performs, абсолютно никак не связанных с кодом десятков модулей BTE, изменяющих данные...
Очевидно, что подпрограмма задачи замещения должна объединять реализации всех типов расширений, являться центром - два клика по имени которой покажут все возможные ссылки на расширения. Будь то BTE или ENHANCEMENTS, или что-то другое. Вот когда становится необходимой возможность включать и отключать замещение. Один клик консультантом, имеющим соответствующие полномочия по настроечной таблице в продуктивной системе, - и замещение отключено вместе со всеми своими вызовами отовсюду (см. раздел Активность замещений), а изменение в настройке запротоколировано документами изменений. А какой толк, в предпосылке этапа "Внешнего Perform" ставить FALSE, если имеется связанная с этим этапом правка данных в событии 1025 BTE и активность продукта в FIBF отключить нельзя, ведь в этом событии есть и другие задачи замещения. Правда находятся такие "трудяги", которые на каждую задачу замещения в BTE делают свой ФМ и свою ГФ.....
Мы видим отсутствие единого подхода у SAP к реализации типов расширений. Скорее всего реализации этих типов представляют собой этапы развития системы SAP. Сначала был RWIN, следом пошел OpenFi (BTE), затем внешний Perform, потом BADI и ENHANCEMENTS.
Таким образом, можно сделать вывод, что стандартные виды реализации SAP-расширений в системе - это всего на всего набор несвязанных между собой инструментов. Ну например, как рейсфедер, ватман, циркуль и т.д - для инженера проектировщика. Однако решая задачу внедрения SAP FI в конкретной организации, необходимо иметь проект архитектуры системы реализции SAP-расширений, а не просто набор инструментов.
В настоящей статье я представляю мое видение такой архитектуры в общем плане. Впрочем, не только видение. Она мной реализована и успешно функционирует уже на двух проектах в одной крупной корпорации. Более детальное рассмотрение данного вопроса с конкретными и подробными примерами - это тема отдельной статьи, которая будет актуальной в том случае, если данная статья вызовет интерес.
Рис.1. Структура вызовов задачи замещения.
Концепция программы ZRGGB_ADD. Аспекты разработки программы
Как уже говорилось, типы расширений и соответственно, виды реализации в системе отделены друг от друга. Попытаемся устранить этот недостаток с помощью программы, организованной специальным образом. Назовем её ZRGGB_ADD. На схеме (Рис. 1) показано, как может выглядеть структура вызовов задач замещения.
На схеме мы видим, что наша программа ZRGGB_ADD является центром всех модификаций стандартного решения SAP FI-CO.
Также можно видеть, как разделяются главные вызовы и вспомогательные вызовы, и как их объединяют таблицы памяти.
Видыреализации расширений SAP, представленые в блоке главных вызовов, передают свой интерфейс в программу ZRGGB_ADD через подпрограммы инициализации. Далее подпрограмма задачи замещения проверяет предпосылки и выполняет четыре действия:
- Отказ от замещения/проверки, на основании не пройденных предпосылок.
- Модифицирует контекст главных вызовов или выдает сообщение в случае проверки.
- Запоминает в таблицах памяти принятое решение для вспомогательных вызовов.
- Модифицирует контекст вспомогательных вызовов на основании данных в таблицах памяти.
Теперь рассмотрим более подробно концепцию программы ZRGGB_ADD.
Логика программы ZRGGB_ADD.
Во внутренней сессии SAP создается область памяти программы ZRGGB_ADD путем обращения к любой из ее подпрограмм. Обращение может быть из разных мест ( RWIN, BTE, BADI, внешних PERFORM и т.д ). В дальнейшем будем их называть EXITS. Обращение организуется по коду задачи, полученной от постановщика (Например, perform rh0019_10_20(zrggb_add)). Одна задача - это одна подпрограмма ZRGGB_ADD. В дальнейшем будем их называть ЗАДАЧИ ЗАМЕЩЕНИЯ.
В каждом месте вызова происходит инициализация глобальных переменных программы ZRGGB_ADD необходимыми для конкретного замещения данными. Инициализация не затрагивает Таблицы памяти.
Такого рода организация обеспечивает такие важные характеристики данной архитектуры как:
Централизация.
Одна задача может потребовать использования множества механизмов пользовательских расширений. Например в событии BTE 1025 перед сохранением документа FI мы определяем на какой счет заменить BSEG-HKONT и «подменяем» его. Но для правильного функционирования замещения этого мало. Ведь в контроллинге, в таблице COEP-KSTAR счет не обновится. Также не обновится счет в поле таблицы контроллинга ce17200-wwhkt. Таким образом, реализация подпрограммы для этой задачи потребует как минимум трех частей. Каждая для своего места вызова.
Для разграничения источников вызова в программе ZRGGB_ADD предусмотрена переменная g_ch и вспомогательная переменная g_check. Посмотрите в разделе примеров - пример 1. Как видно из примера, подпрограмма, где реализована задача, является центром всех обращений. Такой реализацией очень легко управлять. Можно включать или отключать ее выполнение пользователям с соответствующими правами (будем это рассматривать в разделе «Активность задач»), можно отслеживать модификации задачи по версиям кода. Облегчается дальнейшее сопровождение этой задачи. Облегчается "читабельность" кода, особенно для консультантов, которые наглядно видят всю ее реализацию практически на одном экране.
Таким образом соблюдается главный принцип программы ZRGGB_ADD - весь алгоритм задачи должен быть сосредоточен внутри одной подпрограммы задачи. Вызвав ссылку на данную подпрограмму, можно будет видеть всю иерархию вызовов данной задачи.
Единообразие.
Подпрограмма, где реализована задача, не предусматривает параметров. (эту ситуацию будем рассматривать в разделе «Передача параметров» )
Все параметры необходимые для реализации любой задачи замещения определены глобально в ZRGGB_ADD и наполняются указателями на исходные данные при инициализации из места вызова задачи. Таким образом, задача модифицирует оригинальные данные. Такая конструкция вносит единообразие в вызовы задач и упрощает написание кода для последующих задач. В месте вызова в самом начале происходит передача указателей на все доступные (необходимые для замещения) этому месту данные в память ZRGGB_ADD. И для последующих задач разработчику уже не нужно описывать передачу. (См. Пример 1 в конце статьи)
Оптимизация.
Некоторые замещения могут вызываться десятки раз при проводке одного документа. И повторные обращения к таблицам BKPF и BSEG могут быть излишними. Концепция программы ZRGGB_ADD подразумевает одноразовое обращение к БД для конкретного документа. Все последующие обращения будут направлены в соответствующие внутренние таблицы, что значительно снижает нагрузку на сервер БД.
Возможности.
Прежде, чем приступить к описанию предлагаемого мною проекта, укажу возможности которые появятся в результате его реализации.
- Возможность включать и отключать задачи замещений консультантами со специальными полномочиями и с протоколированием их действий документами изменений.
- Возможность построения "каскадных" проверок. Например, в ситуации когда задачи замещения по предупреждающим проверкам 1,2,3 - все не успешны, то программа выдаёт ошибку.
- Возможность создания рекурсивных предпосылок.
- Возможность оптимизировать выборки из БД.
- Возможность теста сложных задач прямо в продуктивной системе. Возможность построения тестовых систем.
Инициализация ZRGGB_ADD.
Каждому вызову задач замещения должна предшествовать инициализация глобальных данных пула подпрограмм ZRGGB_ADD данными «своего» контекста, и только после этого можно делать вызов задач замещения.
Вызов задач замещения осуществляется без передачи параметров. Весь необходимый контекст - уже передан при инициализации и будет доступен внутри задачи замещения.
При инициализации в программу ZRGGB_ADD передаются:
- Код вызова в переменную g_ch. Задача кода вызова - обеспечить разграничение кода подпрограммы задачи замещения в зависимости от вызовов данной задачи из разных мест EXIT-ов с разными контекстами данных.
- Все необходимые и доступные для модификации данные контекста EXITa.(Рис. 2)
FUNCTION zgf_sbt_interface_00001025. "Событи BTE 1025
DATA: ref_bkpf TYPE REF TO data,
ref_bseg TYPE REF TO data.
****
READ TABLE t_bkpf INDEX 1.
*Инициализация ZRGGB_ADD
*Получаем указатели на данные контекста
GET REFERENCE OF t_bkpf INTO ref_bkpf.
GET REFERENCE OF t_bseg[] INTO ref_bseg.
*Установим флаг источника вызова.Для события BTE 1025 пусть будет 'N'
PERFORM set_data(zrggb_add) USING 'g_ch' 'N'.
*Передадим
Если хотите прочитать статью полностью и оставить свои комментарии присоединяйтесь к sapland
ЗарегистрироватьсяУ вас уже есть учетная запись?
Войти
Обсуждения 1
Комментарий от
Александр Рыбин
| 28 апреля 2016, 06:08
Хорошая статейка, спасибо!
Поправочка только есть: ENHANSMENTS -> ENHANCEMENTS