BADI – Технология внедрения бизнес расширений / дополнений
BADI – Технология внедрения бизнес расширений / дополнений в код стандартных транзакций; данная техника доступна в любых модулях системы, фактически эта технология, использующая объектно-ориентированный подход к реализации расширений системы, вышла для замены техники Customerexits.
Продолжение цикла статей "Техники расширений стандартной системы SAP".
Все статьи цикла приведены внизу публикации.
1. Общее описание технологии BADI.
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% я оставляю на пограничные случаи.
2. Пример расширения MB_MIGO_BADI для транзакции MIGO
Пример работы с BADI, предлагаю рассмотреть на основе работы с транзакцией MB_MIGO_BADI, раз уже начал этот раздел с ее упоминания. Так как система новая, то будем использовать механизм реализации нового BADI. Кстати, если вы попытаетесь использовать старый или так называемый классический BADI, то все равно на определенном этапе реализации система скажет вам, что уже существует новая реализация для данного BADI, поэтому будет выполнена конвертация данных для нового механизма. Отсюда следует, что в системе не может существовать одновременно поддержка реализации старого и нового механизмов BADI для одного и того же объекта, как например, для MB_MIGO_BADI.
Создание точки расширения выполняется в транзакции SE19 – BAdI-Builder – внедрения, Рис.1. Транзакция работает или в режиме создания, или в режиме изменения расширения. Если честно, не очень распространенный вариант первого экрана транзакции. Для создания точки расширения требуется ввести имя существующей в системе точки расширения, в данном случае это MB_MIGO_BADI. Выбираем режим создания расширения.
Рис.1
Появится диалоговый экран с запросом создаваемой точки расширения, который будет реализовывать наше расширение. Так как основное имя MB_MIGO_BADI, то имя создаваемой точки пусть будет ZZ_MB_MIGO_BADI, имя может быть любое подходящее под соглашения по наименованию пользовательских объектов, Рис.2.
Рис.2
Для группировки нескольких точек расширений, которые «обслуживают» один бизнес-процесс, можно создать групповое имя, которое будет объединять создаваемые расширения, для упрощения управления всеми реализациями. Если это просто локальная реализация расширения, то можно не создавать групповое имя. После подтверждения создания появляется запрос на ввод имени реализации, указания класса реализации и выбора определения BADI, Рис.3, это все организовано, так, потому как точка расширения может включать в себя несколько различных классов, в совокупности составляющих реализацию точки расширения. В нашем случае точка расширения совпадает по имени с классом реализации, при этом класс реализации для точки только один.
Рис.3
После заполнения всех полей подтверждаем ввод. Система предложит нам вариант создания реализации (фактически наследуемого класса). Так как у нас есть пример реализации, и мы создаем расширение данного типа в первый раз, то лучшим выходом будет создание реализации на основе копирования класса-примера Если же вы уже знаете, как создавать расширение, то выбираете создание пустого класса, так как при копировании класса-примера создаваемый новый класс будет реализовывать все методы класса-паррента (шаблона), хотя вам, может быть, и не требуется реализация всех методов, Рис.4.
Рис.4
Таким образом, мы получаем класс, реализующий расширение с перечнем все доступных методов, которые уже изначально содержат пример правильного кода, который позволит вам написать свою реализацию по аналогии с примером. Сохраняем созданный класс и теперь можно перейти к просмотру/редактированию созданного класса расширения, Рис.5. После сохранения расширения его нужно активировать. Если расширение активно, то результат его работы можно увидеть в транзакции MIGO.
Рис.5
Работать с точкой расширения можно или используя и дальше транзакцию SE19 или же можно работать уже с классом, реализующим расширение, используя транзакцию SE24 / SE80.
Сейчас транзакция MIGO не содержит закладки пользователя, Рис.6, так как класс еще не активирован, но если выполнить активацию, то при просмотре документов будет доступна закладка с полями пользователя.
Рис.6
Так как, класс был создан на основе шаблона, то количество объектов, подлежащих активации будет большим. Вы должны просто выделить все позиции и провести активацию всех объектов, Рис.7.
Рис.7
После активации данных в транзакции MIGO появятся закладки полей пользователя, Рис.8.
Рис.8
Если закладка не появилась или же при выполнении стандартной транзакции, которую вы расширили, вы не попадаете в текст реализации расширения, то убедитесь, что внедрение активировано и оно вызывается. Для этого в транзакции SE19 перейдите на закладку «Расширенные элементы внедрения» и просмотрите статус расширения. Курсор должен стоять на имени BADI-внедрения, а не на реализующем его классе, Рис.9.
Рис.9
3. Как это все работает?
Система «видит», что существует реализация расширения и «оформлен» наследник класса, поэтому в момент запуска транзакции она создает класс, отвечающий за реализацию. В вашем классе вам доступен метод INIT, который вызывается в конструкторе. Для каждого BADI-расширения возможны различные правила создания реализующего класса, именно поэтому, общая рекомендация при создании BADI, в первый раз, выполнять создание путем копирования из образца, если конечно это возможно. В методе INIT система должна вернуть имя вашей реализации. В данном случае имя реализации предлагается задать константой в рамках вашего класса и далее инкорпорировать эту константу в возвращаемые параметры метода инициализации класса, Рис.10.
Рис.10
Далее следует собственно реализация метода инициализации класса, Рис.11. В принципе это демонстрация правильного стиля программирования, когда имя класса реализации, по которому система будет в дальнейшем проводить идентификацию вашего класса, определяется через внутреннюю константу в рамках класса.
Рис.11
Далее при каждом добавлении строки в документ движения материала в транзакции MIGO, система будет вызвать метод LINE_MODIFY – Add / Change a Line (GOITEM), т.е. при каждом добавлении или изменении строки документа вы будете получать уведомление. Как образом предлагается реализовать данный метод? Так как фактически вы создали класс, то все необходимы для работы поля из позиции документа, предлагается хранить во внутренней приватной таблице класса. Структура, описывающая таблицу, создается в словаре данных и затем вы оформляете внутреннюю переменную в рамках класса, Рис.12.
Рис.12
В коде реализации, вы просто читаете необходимую строку позиции документа из этой таблицы по ключу I_LINE_ID, который обязательно должен быть включен в вашу внутреннюю структуру, так как это уникальный номер строки позиции документа. Если строка найдена, тогда вы модифицируете ее в своей таблице, так как пришли новые изменения, если же строки нет, тогда вы добавляете эту строку в свою внутреннюю таблицу. Таким образом, в рамках класса, реализующего расширение, вы всегда имеете таблицу строк документа. Именно поэтому в метод CHECK_ITEM – Check Item Data of Goods Movement система передает вам только уникальный номер строки, которую следует проверить, так как саму строку вы должны извлечь из внутренней таблицы строк своего класса реализации. Само собой, в этой таблице нужно сохранить не только поля, которые вы добавили на собственный экран, но и поля которые вам будут нужны для проверки введенных данных, Рис.13, поэтому вам не нужно выполнять какие-то телодвижения по сохранению позиций документа через память системы. Вы уже имеете класс, который может хранить все необходимые данные, вплоть до копии всех полей позиции документа, если это вам необходимо.
Примечание: Обратите внимание, что при реализации метода LINE_MODIFY, вы должны учесть также и ситуацию, когда документ уже сохранен в базу данных системы, поэтому транзакция MIGO вызвана в
Если хотите прочитать статью полностью и оставить свои комментарии присоединяйтесь к sapland
ЗарегистрироватьсяУ вас уже есть учетная запись?
Войти
Обсуждения 2
Комментарий от
Максим Казимирченко
| 09 февраля 2017, 10:16
1) Запускаем SE37 .
2) ФМ SXV_GET_CLIF_BY_NAME.
3) Ставим breakpoint.
4) Открываем новый режим.
5) Запускаем транзакцию, в которой хотим искать BADI.
6) Если в транзакии предусмотрена BADI, произойдет остановка в точке прерывания.
7) Смотрим значение переменной NAME.
8) Это и есть имя BADI.
Комментарий от
Алексей Герасименко
| 07 января 2022, 14:36
Подскажите, пожалуйста, не совсем понял: о какой проблеме хранения глобальных переменных, которую не решало Classic BAdI и смогло решить New BAdI, идёт речь.
И, если можно, более подробно вот об этом предложении про Classic BAdI: "...однако проблемы в одной из наследуемых реализаций могли поломать работу всех пользовательских расширений." Это же и для New BAdI справедливо, разве нет?