BADI – Технология внедрения бизнес расширений / дополнений в код стандартных транзакций, данная техника доступна в любых модулях системы, фактически эта технология вышла для замены техники Customerexits, используя объектно-ориентированный подход к реализации расширений системы. Технология BADI призвана решить основную проблему использования точки расширения несколькими пользователями с изоляцией реализаций. Если проанализировать код системы и посмотреть места добавления вызовов BADI, то можно заменить, что вызовы добавлены до или после вызова Customerexits, т.е. функции вида CALL CUSTOMER-FUNCTION. Следовательно, в большинстве случаев можно использовать Customerexits или соответствующий ему BADI. Кстати, в таком случае в классе такого BADI перечень доступных для реализации методов, совпадает по количеству с перечнем функций в рамках компонента расширения Customerexits-а.
На данном этапе существуют два варианта реализации технологии BADI, это так называемы старые и новые BADI расширения. Различие между ними, это способ реализации класса расширения. В старых BADI, как я понимаю, реализация была сделана следующим образом, в программе в точке расширения реализовывался вызов соответствующего метода класса. Пользователю, фактически предлагалось, переопределять метод класса и таким образом выстраивалась цепочка независимых реализаций. Такая методика позволяла разнести разные реализации в свои расширения, однако проблемы в одной из наследуемых реализации могли поломать работу всех пользовательских расширений. Поэтому, через некоторое время компания перешла на новый тип BADI, теперь при реализации вы пишете класс, как наследник заранее предопределенного класса, реализующего расширение. В точке вызова система проверяет наличие всех созданных и активных инстанций – наследников от базового класса расширения и вызывает соответствующие методы всех зарегистрированных классов наследников. Перечень методов, которые будут вызваться и точки вызова, заранее определены в родительском классе. Для механизма реализации новых BADI в язык системы были введены две новые служебные команды GET BADI и CALL BADI.
Примечание: По заявлениям разработчиков SAP, новая техника BADI работает быстрее предыдущего используемого механизма. Хотя это и логично, так как новый механизм использует новые команды языка, а не вызов класса который определяет наличие расширения. Однако среднестатистический пользователь вряд ли заметит какое либо ускорение при вызовах новой или старой реализации.
На первый взгляд, для пользователя особо ничего не изменяется при реализации старых или новых BADI. Однако, на самом деле отличия существенные. Новая техника расширений решила проблему хранения глобальных переменных в рамках класса реализации, что было довольно проблематично реализовать используя механизмы наследования методов. Классы реализации полностью стали независимыми и соответственно разработчики получили раздельные объекты, которые можно независимо и параллельно обрабатывать. Именно новая технология BADI, предоставляет полную изоляцию каждой инстанции, не понимание этих различий, приводит к не правильному использованию новых BADI. Например, при переходе от старого типа реализации к новому набор методов остался старый, а вот параметры методов существенно изменились, что привело к полной дезориентации части разработчиков, особенно индусских. Простой пример, в системе существует BADI: MB_MIGO_BADI – Поля пользователя на экране MIGO. В старой реализации метода, если правильно помню (к сожалению старой системы, у меня уже нет), CHECK_ITEM вам передавалась позиция документа, которую вы могли проверить на ошибки и вернуть результат проверки в параметр ET_BAPIRET2. В новой реализации в данный метод передается только значение переменной I_LINE_ID – Unique Identification of Document Line, т.е. номер позиции которую надо проверить, но данных самой позиции вам не передается. Это привело к тому, что на куче индусских форумов и части русскоязычных, скопированных из индусских, реализуется механизм сохранения вводимых позиций через IMPORT TO MEMORY в методе IF_EX_MB_MIGO_BADI~LINE_MODIFY, чтобы потом в методе проверки сделать EXPORT FROM MENORY и далее проверить значения. Я так понимаю, все реализующие этот механизм, считают себя профессионалами, а вот разработчиков компании SAP полными идиотами, которые даже нормально не понимают, что забыли передать в метод проверки сам объект проверки – позицию документа. Они, видите ли, передали какую-то непонятную переменную I_LINE_ID, которая содержит просто число, причем это число даже не является порядковым номером позиции документа. В общем, совсем не понятно как теперь работать и поэтому люди пишут какие-то кривые обходные методики для получения доступа к позициям документа внутри BADI, но при этом не просто пишут, они еще и рекомендуют их как единственно верное решение. Лично я, когда впервые столкнулся с новым BADI, и почитал предложенные механизмы, решил что это я, что-то не понимаю, но вряд ли разработчики SAP, могли так ошибиться. На самом деле, достаточно было просмотреть рекомендуемую реализацию шаблона BADI, чтобы понять, что действительно заблуждаюсь я, и действительно, в методе проверки CHECK_ITEM, при использовании нового механизма BADI, не нужно передавать строку документа.
Рекомендация: Если вы не понимаете механизма работы, не отталкивайтесь от предположения, что реализовавший данный механизм, был идиотом, так как в 99% вы просто не разобрались в решении, а 1% я оставляю на пограничные случаи.
Создание расширения для транзакции MIGO
Пример работы с BADI, предлагаю рассмотреть на основе MB_MIGO_BADI, раз уже начал этот раздел с ее упоминания. Так как система новая то будем использовать механизм реализации нового BADI. Кстати, если вы выберете использовать старый или так называемый классический BADI, то все равно на определенном этапе реализации система скажет вам, что уже существует новая реализация для данного BADI, поэтому будет выполнена конвертация данных для нового механизма. Поэтому отсюда следует, что в системе не может существовать одновременно поддержка реализации старого и нового BADI для одного и того же объекта, как например MB_MIGO_BADI.
Создание точки расширения выполняется в транзакции SE19 – BAdI-Builder – внедрения, рисунок 1: badi-01.png. Транзакция работает или в режиме создания или в режиме изменения расширения. Если честно не очень распространенный вариант первого экрана транзакции. Для создания точки расширения требуется ввести имя существующей в системе точки расширения, в данном случае это MB_MIGO_BADI. Выбираем режим создания расширения.
Появится диалоговый экран с запросом создаваемой точки расширения, который будет реализовывать наше расширение. Так как основное имя MB_MIGO_BADI, то имя создаваемой точки пусть будет ZZ_MB_MIGO_BADI, имя может быть любое подходящее под соглашения по наименованию пользовательских объектов, рисунок 2: badi-02.png.
Для группировки нескольких точек расширений, которые реализуют один бизнес-процесс, можно создать групповое имя, которое будет объединять создаваемые расширения, для упрощения управления всеми реализациями. Если это просто локальная реализация, то можно не создавать групповое имя. После подтверждения создания появляется запрос на ввод имени реализации, указания класса реализации и выбора определения BADI, рисунок 3: badi-03.png, это все организовано таким образом, так как точка расширения может включать в себя несколько различных классов, фактически составляющих реализацию точки расширения. В данном случае точка расширения совпадает по имени с классом реализации, при этом класс реализации для точки только один.
После заполнения всех полей подтверждаем ввод. Система предложит нам вариант создания реализации (фактически наследуемого класса). Так как в данном случае у нас есть пример реализации и мы создаем расширение данного типа в первый раз, то лучшим выходом будет создание реализации на основе копирования примера класса. В противном случае, если вы знаете, как создавать расширение, то выбираете создание пустого класса, так как при создании копирования примера класса, создаваемый новый класс будет реализовывать все методы класса шаблона, хотя вам вполне может и не требуется реализация всех методов, рисунок 4: bapi-04.png.
Таким образом, мы получаем реализующий расширение класс с перечнем все доступных методов, которые уже изначально содержат пример правильного кода, который позволит вам написать свою реализацию по аналогии с примером. Сохраняем созданный класс и теперь можно перейти к просмотру/редактированию созданного класса расширения, рисунок 5: badi-05.png. После сохранения расширения его нужно активировать. Если расширение активно, то результат его работы можно увидеть в транзакции MIGO.
аботать с точкой расширения можно или используя и дальше транзакцию SE19 или же можно работать уже с реализующим классом используя транзакцию SE24 / SE80.
Сейчас транзакция MIGO не содержит закладки пользователя, рисунок 6: bapi-07.png, так как класс еще не активирован, но если выполнить активацию, то при просмотре документов будет доступна закладка с полями пользователя.
Так как, класс был создан на основе шаблона, то количество объектов подлежащих активации будет большим. Вы должны просто выделить все позиции и провести активацию всех объектов, рисунок 7: badi-06.png.
После активации данных в транзакции MIGO появятся закладки полей пользователя, рисунок 8: badi-08.png.
Если закладка не появилась или же при выполнении стандартной транзакции, которую вы расширили вы не попадаете в текст реализации расширения, то убедитесь что внедрение активировано и оно вызывается. Для этого в транзакции SE19 перейдите на закладку расширенные элементы внедрения и просмотрите статус расширения. Курсор должен стоять на имени BADI-внедрения, а не на реализующем классе, рисунок 9: badi-09.png.
Техника поиска BADI
Для просмотра существующих BADI, в системе существует транзакция просмотра SE18, которая позволят просмотреть параметры и методы существующих классов, реализующих BADI. Данная транзакция разделяет BADI, на два вида, собственно новые BADI, называемые в данный момент «Точка расширения» и стандартные старые BADI. Если вы попытаетесь найти BADI, который в данный момент уже мигрировал в новую реализацию, например приведенный выше MB_MIGO_BADI, то при просмотре такого BADI, будет видно, что нужно использовать новую технику точек расширения, рисунок 16: badi-16.png т.е. значит, что идем в просмотр точки расширения с таким же именем.
Примечание: Спасибо разработчикам системы, они не мудрили с именами реализаций и поэтому точка расширения, называется так же как и старый BADI. Хотя с другой стороны именно это возможно привело некоторых разработчиков к непониманию того, что имена старые, но механизмы работы значительно изменились.
Если же реализация осталась старой, т.е. это классический BADI, то при просмотре мы увидим классы, включенные в BADI, рисунок 17: badi-17.png.
Однако, искать BADI, таким образом, занятие не очень благодарное, да и результат может быть довольно не предсказуемым, т.е. скорее всего, будет найдено не то, особенно в том случае если имя точки расширения и описание, скажем так, слегка далеки от ее предназначения. Поэтому есть более простой метод поиска всех BADI, которые вызываются в ходе выполнения любой транзакции. Как мы помним, фактически BADI, это класс который создается в момент работы транзакции, таким образом, в системе существует программа, которая для любого выполняемого кода, если находит точку вызова BADI, должна проверить существование реализации данного BADI и если, такая реализация существует, то необходимо создать инстанцию реализующую класс.
В системе действительно есть реализация класса, который вызывается всегда, когда система пытается проверить существование реализации BADI. Это класс: CL_EXITHANDLER и его метод GET_INSTANCE. В транзакции SE24 переходим к просмотру кода реализации и на строке:
call method cl_exithandler=>get_class_name_by_interface
Устанавливаем точку останова, рисунок 18: badi-18.png.
Теперь идем в интересующую нас транзакцию и в те моменты, когда будет проверяться реализация/существование BADI, система будет попадать в данный класс и метод. В переменной exit_name, система будет возвращать имя BADI. Соответственно, выполнив транзакцию, вы получите все BADI, который вызываются при ее работе, рисунок 19: badi-19.png.
Другой метод поиска BADI так же связан с отладчиком и появлением новым команд в языке, а именно команды GET BADI и CALL BADI. Поэтому можно поставить точку останова на вызов команды CALL BADI и получить в отладчике перечень реализуемых в транзакции методов расширений, рисунок 20: badi-20.png или же поставить точку останова на команду GET BADI для получения списка расширений.
Применимость – Некоторые особенности использования BADI.
Компания SAP ограничивает возможности использования BADI, почему и зачем это делается? Иногда если честно лично мне не очень ясно. Например, есть такая BAPI-функция BAPI_INCOMINGINVOICE_CREATE1 – создание счета логистики, в данной функции есть структура для передачи полей, определенных пользователе. Стандартно данный механизм использует технику передачи параметров через структуры:
- EXTENSIONIN тип BAPIPAREX
- EXTENSIONOUT тип BAPIPAREX
В данной BAPI-функции такие структуры так же определены. Далее стандартно в системе реализуется BADI-расширение, которое должно позволить корректно передать пользовательские поля в таблицы документа. Однако, не все так просто. Для данной BAPI, класс, реализующий возможности такой передачи, по странной причине объявлен внутренним. Таким образом, использование данной BADI, невозможно.
В данный момент определены следующие параметры:
- Многоразовое – данный флаг определяет, каким образом выполняется реализация BADI внутри системы. Если данный флажок не установлен, то каждый разработчик определяет свою инстанцию класса и система последовательно их обработает. Что это дает? Во-первых, вы независимы по внутренним переменным класса реализующего BADI. Во-вторых, реализацию можно безболезненно отключить, если она устарела или вдруг возникли проблемы с ее работоспособностью. Если данный флажок не установлен, то по факту мы имеем аналог CUSTOMER-EXIT, т.е. все разработчики должны работать в рамках одной реализации и как следствие учитывать код, написанный предыдущими разработчиками, что не добавляет в BADI устойчивости к не правильной реализации.
- Реализуемо только внутри SAP – Данный флажок полностью блокирует использование BADI внешними разработчиками, т.е. данный тип BADI предназначен только для использования внутри компании SAP или внутри партнеров SAP которые участвуют в разработке ПО. В данном случае как раз на рисунке badi-21.png, показан такой тип BADI. Если вам попалось такое определение BADI, то переходите к технике Enhancement Spot, это BADI закрыто для внешнего использования.
- Огранич. использование фильтра – Тоже еще один из флажков компании SAP, который говорит нам, что реализация данного BADI возможно фильтруется по именам реализующих классов. Насколько я понимаю, компания может ограничить имена реализующих классов, что тоже в какой-то момент может полностью запретить использование такого BADI клиентами компании, просто потому, что вам не дадут использовать для реализации мена классов начинающиеся на Z или Y. Фильтрация имен выполняется классом CL_ENH_BADI_RUNTIME_FUNCTIONS, в котором реализован статический метод GET_IMPLS_FOR_LIMITED_BADI. Теоретически, используя не явную точку расширения в вызываемом методе GET_IMPLS_FOR_LIMITED_BADI, можно обойти данное ограничение, но это уже будет сфера вашей ответственности, в случае каких-либо глобальных проблем в системе после такой модификации. Так как компания SAP, надеюсь, когда запрещает использование функций расширения, исходит из каких-то внутренних правил или особенностей реализации функциональности.
Общий вывод из всего сказанного, очень неплохо, если в BADI стоит или не стоит флажок «Многоразовое», и совсем плохо, если стоят какие-либо следующие флажки. Это значит, что для вас как для клиента компании SAP, данное BADI закрыто для использования.