Данная техника используется практически в любой функциональности системы. Это наиболее широкий способ использования программных расширений. Реализация технологии заключается в использовании вызовов специальных функциональных модулей системы. Для этого в язык ABAP, был введен отдельный оператор вызова функции расширения: CALL CUSTOMER-FUNCTION “внутренний номер расширения”. Стандартно, если расширение не активно, система пропускает вызов пользовательской функции, даже если внутри содержится реализация. Пользовательские функции система группирует в так называемые компоненты расширений. Компонент может содержать как одну функцию, так и группу функций или экранов пользовательских расширений.
Для просмотра и поиска возможных расширений, доступных в системе можно воспользоваться несколькими вариантами поиска:
1. Использовать транзакцию просмотра существующих расширений, транзакция SMOD. Данная транзакция позволяет просмотреть содержимое компонента расширения, при этом она так же, обеспечивает поиск самих расширений в привязке к функциональности. Для поиска следует воспользоваться поиском компонентов для поля «Расширения», рисунок 1: SMOD-1.png.
Если вы запускаете транзакцию впервые, то нажав кнопку поиска допустимых значений, вы получите поиск компонентов по информационной системе репозитория, рисунок 2: SMOD-2.png, это не очень удобно, если вы даже приблизительно не знаете, как называется компонент, однако сразу переключить поиск на вариант «Приложения SAP» не получится.
Поэтому, для начала выполните поиска по системе репозитория, нажав кнопку F4, рисунок выше и в открывшемся окне найденных значений выберите любое первый попавшийся компонент. Например, у меня в системе это, какой-то: /CEECV/R – RO Material document item for goods receipt/issue slip. Затем зайдите в просмотр компонента, нажав кнопку "Просмотр" , после этого вернитесь на первый экран и снова выберите F4 в поле «Расширение». Теперь система покажет вам окно личного списка значений, из которого вы уже можете выполнить поиск по приложениям SAP, рисунок 3: SMOD-3.png.
Фактически будет выведено дерево компонентов системы, некий аналог транзакции SPRO, в данном дереве можно выполнить поиск необходимых расширений в привязке к функциональности системы, рисунок 4: SMOD-4.png. например компонент отвечающий за реализацию пользовательских данных в заявках на закупку функциональности управления материальными потоками.
2. Воспользоваться одной из Z-разработок, которых достаточно в интернете, которые позволяют найти компоненты расширений в привязке к транзакциям системы. Одним из недостатков таких решений является то, что при поиске будут найдены только расширения первого уровня, т.е. если при создании объекта А, он порождает зависимые объекты B и C, то такие программы обычно ищут только расширения доступные при создании объекта А.
3. Использовать инструменты отладки программы. Для этого запускаем интересующую нас транзакцию, после чего переходим в режим отладки системы. Далее устанавливаем точку прерывания по условию, рисунок 5:SMOD-5.png.
В открывшемся окне нужно задать обработку точек прерывания при выполнении оператора CALL CUSTOMER-FUNCTION, рисунок 6: SMOD-6.png
Теперь можно продолжить выполнение транзакции. Система будет останавливаться каждый раз, когда в тексте будет встречать вызов пользовательского расширения, причем это не зависит от того, активно оно или нет, рисунок 7: SMOD-7.png. Основная проблема при таком методе получения точки пользовательского расширения заключается в том, что вы получаете имя исходного текста, где находится точка, в данном случае это модуль: LBBPKU03, строка кода 79, однако не получаете имя компонента расширения которое нужно указать в транзакции ведения.
Для получения имени компонента следует перейти в просмотр найденного код, транзакция SE38, в которой нужно сделать двойной клик мышью на строке вызова пользовательского расширения, для перехода к реализации данной функции, рисунок 8: SMOD-8.png
Мы переходим в функциональный модуль, который вызывается, в данном случае для кода точки расширения 001, будет вызван функциональный модуль EXIT_SAPLBBPK_001, рисунок 9: SMOD-9.png.
Теперь, когда мы знаем реальное имя функционального модуля, можно достаточно просто найти имя компонента, который нужно активировать чтобы данное расширение вызвалось системой. Для этого переходим в транзакцию просмотра содержимого таблиц, транзакция SE16, затем указываем имя таблицы MODSAP и далее в поле MEMBER, вводим имя нашего функционального модуля, рисунок 10: SMOD-10.png.
Далее выполняем вывод значений и получаем имя компонента, который включает в себя найденное нами расширение, рисунок 11: SMOD-11.png.
Таким образом, получив имя расширения можно приступать к его реализации. Для активации расширений существует отдельная транзакция CMOD, которая служит для создания проектов расширений. Фактически проект расширения это объект, который включает в себя набор компонентов расширений, которые мы просматривали в транзакции SMOD или искали в стандартных программах системы. Обычно, в один проект, можно включить различные коды расширений объединяющих решение общей задачи.
Внимание: Одно расширение, можно включить только в один проект, поэтому если у вас расширение уже используется, то нужно найти проект, в котором оно находится, далее убедиться, что проект активирован и это значит, что вам остается только добавить свой код реализации расширения. Удалять и переносить расширения из чужого проекта в свой проект, наверное, не стоит..
В качестве практического примера воспользуемся расширением, которое позволяет генерировать инвентарный номер для объектов основных средств. Разработчики SAP определили расширение, которое позволяет пользователю реализовать собственный алгоритм генерации инвентарного номера карточки. Для этого в системе существует расширение AISA0001 – Присвоение инвентарного номера, рисунок 12: CMOD-1.png
Запускаем транзакцию CMOD, в появившемся окне вводим новое имя расширения на Z или Y, например, создаем расширение ZFIAA001. После ввода имени нажимаем кнопку "Создать", рисунок 13: CMOD-2.png.
Примечание: В принципе, имя проекта может начинаться на любую букву, тут нет жесткого ограничения по области наименования пользовательских объектов, так как проекты расширений это всегда только пользовательские объекты. Однако, лично мне привычнее, называть расширения, ориентируясь на стандартное соглашение по именам объектов SAP.
Система перейдет к экрану ведения атрибутов расширения, рисунок 14: CMOD-3.png. На экране ведения атрибутов проекта, требуется только ввести краткий текст, который описывает назначение создаваемого проекта. Затем нажимаем кнопку "Сохранить" вверху окна. Система спросит проект и запрос, в который необходимо сохранять данные.
После сохранения проекта требуется перейти к экрану присвоения расширений, на панели кнопок нажимаем кнопку "Присвоение расширения". Включаем в список наше расширение AISA0001. Если расширение не присвоено никакому проекту, то система просто выведет рядом с расширением краткий текст описания, рисунок 15: CMOD-4.png. В противном случае, будет выведено сообщение об ошибке, в котором будет указано имя проекта в котором уже включено расширение AISA0001.
Сохраняем данные присвоенных проекту компонентов и переходим к экрану просмотра присвоенных компонентов, для этого нажимаем кнопку "Компоненты", рисунок 15: CMOD-5.png. Так как проект не активирован, то светофоры, напротив расширений, будут красными. Это значит, что расширение не активно и даже если оно содержит код, система пропускает такие расширения. Это позволяет отключать расширения простой деактивацией проекта, например, если окажется, что текст пользовательского расширения содержит ошибку, которая генерирует ошибку времени выполнения, но требуется срочно провести документ.
Если сейчас выполнить активацию расширения, то создаваемый код будет выполнятся, при этом если код будет в этом момент не корректным, т.е. вы его в данный момент активно изменяете, то другие пользователи создающие карточки ОС, будут получать ошибку времени выполнения стандартной транзакции (системный дамп). Поэтому когда вы пишете новый код или правите его, деактивируйте расширение, чтобы не мешать другим пользователям в системе.
Итак, проект создан, компонент расширения включен в проект, можно перейти к реализации самого расширения. Для этого перейдем в проекте к реализации функции расширения, экран «Компоненты», рисунок 16: CMOD-5.png. Выполняем двойной клик мышью на имени функции расширения EXIT_SAPLAISA_001. Переходим в экран ведения функционального модуля, где всегда находится включение модуля начинающегося на Z, в данном случае это будет строка INCLUDE ZXAISU02, рисунок 17: CMOD-6.png. Так как имя расширения начинается на Z, то мы можем создать такой модуль без получения ключа на модификацию этого объекта. При этом создание объекта происходит следующим образом, делается двойной клик мышью на имени модуля, после чего будет получено сообщение о том, что модуль будет создан. Для подтверждения создания модуля нужно нажать мышью кнопку подтверждения вверху экрана или нажать клавишу ввода.
После подтверждения создания расширения, система запросит имя запроса, для переноса создаваемого объекта, включаем модуль в запрос, в который ранее включили создаваемый проект. Так как модуль пустой, то выполняем его генерацию. Ошибок быть не должно. Теперь можно приступить собственно к реализации самого кода, генерации инвентарных номеров при создании карточек ОС.
Перед написанием самого кода мы видим, что на вход передается структура I_ANLA типа ANLA, а на выходе от нас ожидается переменная E_INVNR типа ANLA-INVNR, т.е. содержащая инвентарный номер для создаваемой карточки ОС. Обычно, перед тем как что-то писать, в незнакомом мне расширении, я ставлю точку прерывания кода, типа break <имя пользователя>. Затем выполняю транзакцию, которая использует данное расширение, и анализирую содержимое переданных в функцию переменных. В данном случае выполняю транзакцию AS01 – Создание карточки ОС. Это довольно простое расширение, которое вызывается только одни раз при создании карточки ОС, но очень часто расширение может вызываться как при создании, так и изменении данных или их просмотре. Нужно понимать, что в зависимости от режима работы стандартной транзакции и вызова расширения, нужно реализовывать соответствующий код, иначе проблемы в работе стандартной транзакции будут обеспечены. Разработчики системы группируют пользовательские расширения в компоненты расширений, т.е. группа функций содержит набор взаимодействующих расширений. Например, расширение стандартной функциональности ведения дополнительных полей в заявках на закупку ММ, включает в себя 10 функциональных модулей, один пользовательский экран, а так же три структуры для ведения пользовательских данных, поэтому зачастую написание текста расширения является довольно не тривиальным заданием. Например, вернемся к нашему расширению генерации инвентарных номеров. В общем случае пусть инвентарный номер генерируется как номер карточки ОС + Субномер карточки, т.е. кажется простая операция формирования нового значения, на основании полученных в расширении данных:
CONCATENATE i_anla-anln1 '-' i_anla-anln2 INTO e_invnr.
Однако, такая реализация приводит к тому, что если пользователь введет инвентарный номер сам, на экране ввода стандартной транзакции, то его ввод будет принудительно заменен в расширении, что возможно не очень правильно. Поэтому я бы предложил в данном случае следующую реализацию:
IF i_anla-invnr IS INITIAL.
CONCATENATE i_anla-anln1 '-' i_anla-anln2 INTO e_invnr.
ELSE.
e_invnr = i_anla-invnr.
ENDIF.
Т.е. если значение пришло при вводе пользователя, то оно не замещается, кстати, обратите внимание, что обязательно нужно выполнить операцию присвоения поступившего значения в возвращаемую переменную, иначе, если это не сделать, то ввод пользователя будет затерт пустым значением. Если же поле не введено, т.е. будет получено пустое значение, то для него будет сгенерировано новое значение инвентарного номера.
После ввода кода, выполняем проверку кода на ошибки и если все нормально генерируем текст модуля. Затем возвращаемся на экран просмотра компонентов, рисунок 18: CMOD-5.png и активируем наш проект, нажав кнопку активации, на панели инструментов. Обычно, на этом шаге никакие ошибки возникнуть не должны, поэтому активация будет произведена, при этом светофоры переключатся на зеленый цвет, что говорит о том, что проект и включенные в него расширения активны, т.е. вызываются при работе стандартный транзакций, рисунок 18: CMOD-7.png.
Еще одной проверкой того, что расширение активировалось и будет вызваться в транзакции является эффект компилирования текстов при запуске бизнес транзакции, например в данном случае AS01.
И так, техника использования и поиска таких расширений довольно простая, однако не лишена серьезных недостатков:
1. Основная, по моему мнению, проблема данного типа расширений, это поддержка написанного кода несколькими разработчиками, т.е. если одно расширение потребовалось нескольким разработчикам / консультантам, то может возникнуть проблема взаимодействия, когда некоторые переменные окажутся по каким-либо причинам затертыми, так как текст реализации находится в одном, общем модуле. Так же может возникнуть проблема последовательности обработки, когда первый разработчик производит какие-то изменения полученных переменных, после чего второй разработчик тоже изменяет, эти же переменные. При таком подходе кто последний тот и прав, но вот как к этому отнесутся пользователи, получившие проблемы в системе, и хорошо, если это будет обнаружено достаточно на раннем этапе работы новой разработки, в идеале в ходе тестирования.
2. Невозможность «регламентированного» доступа к переменным вне функционального модуля системы, т.е. разработчики SAP, заранее определили набор переменных, которые передаются для анализа и набор переменных, которые можно изменить в данном типе расширения. Очень часто оказывается, что вроде как и расширение есть, а написать код невозможно, так как разработчик расширения не передал переменные, на основе которых, вы хотите построить анализ и реализацию данных или же наоборот, все переменные есть, но вот на выходе от вас хотя получить к примеру только инвентарный номер для основного средства, а вот текст заголовка карточки ОС, извините, но изменить не получится, так как от вас в этом расширении такого не ждут.
Примечание: Аналогично технике Field-Exit, существует техника обхода ограничения на доступ к переменным, т.е использование конструкции ASSIGN. Использование данной техники, полностью лежит на разработчике, ограничения такие же, как и описанные выше, т.е. нужно быть осторожным и если не уверены в том, что выполняете, никогда не меняйте значения переменных. Если доступ осуществляется к внутренним таблицам, то никогда не пересортировывайте их, так как это может привести к непредсказуемым результатам. Если вы изменяете, таким образом, какие-то значения переменных, то очень тщательно протестируйте такую разработку, хотя даже это может не спасти вас от проблем, особенно при обновлениях или миграции на новую версию.
Разработчики SAP не используют данный тип расширений, эта техника полностью отдана на откуп клиентам. В общем случае я встречал рекомендацию, если это возможно, то использовать именно этот механизм расширений.