29 сентября 2011 г.

ABAP: как узнать размер окна SAP экрана в писелях

DATA: ref_consumer TYPE REF TO cl_gui_props_consumer,
      s_metric_factors TYPE CNTL_METRIC_FACTORS.


ref_consumer = cl_gui_props_consumer=>create_consumer( ).
s_metric_factors = ref_consumer->get_metric_factors( ).

s_metric_factors-screen-x - ширина
s_metric_factors-screen-y - высота

подсмотрено здесь. Подробнее...

13 сентября 2011 г.

Позновательно о TabStrip

Помимо того, что написано в ссылке:
Закладка также может быть полем вывода. То есть если объявить переменную с таким же именем и менять её значение - оно будет подставлять в заголовок закладки. Только саму галку "поле вывода" не забудьте поставить. Подробнее...

30 августа 2011 г.

Принудительное подтверждение изменений в ALV GRID

Проблема: В ALV GRID-е чтобы отработали события data_changed и data_changed_finished необходимо нажимать enter после редактирования. С числами и текстом это более менее ожидаемо и проблем не возникает. А вот со списками drop-down это совсем неочевидно. Поэтому следующее действие (например, сохранение введённых данных) отрабатывает без учёта этих изменений.

Решение:
IF l_grid_items IS NOT INITIAL.
CALL METHOD l_grid_items->check_changed_data.
ENDIF.
Этот код заканчивает редактирование ALV GRID-а. В моем случае его оказалось достаточно вписать в PAI до обработки параметра user-command.
Подробнее...

29 июля 2011 г.

Поиск в исходных кодах

Уже писал раньше про ФМ RPR_ABAP_SOURCE_SCAN, который помогает найти в исходных кода текст
Оказалось, что он ище далеко не везде. Зато RS_ABAP_SOURCE_SCAN ищет и в классах, и в расширениях cmod. Подробнее...

13 июля 2011 г.

Партии VS Виды оценки

Оказывается "партии" (charg) и "Виды оценки" (bwtar) - совсем не одно и то же, как меня когда-то убедил кто-то из консультантов.

На сбытовых заводах у нас они соответствуют 1к1, а, например, на балансовых - не соответствуют.

Соответствие можно восстановить в таблице mcha. Там по материалу/заводу/"партии" можно узнать вид оценки. Подробнее...

27 июня 2011 г.

Работа с блокировками

1. Найти Функции блокировки/разблокировки

Например, необходимо блокировать/разблокировать элемент таблицы vbak (сбытовой заказ).
   * В транзакции se11 в графе "ОбъектБлокировки" ищем "*vbak*" и находим "EVVBAKE".
   * Заходи внутрь и нажимаем "Перейти к" - "Модули блокировки"
   * Там видим:
DEQUEUE_EVVBAKE Снятие блок. постановки в очередь с объекта EVVBAKE
ENQUEUE_EVVBAKE Запрос блокировки постановки в очередь для объекта EVVBAKE
есть ещё две, но по ним видно, что это что-то специфическое, потому что там блокировка идёт не по vbak-vbeln, а по совершенно другому полю.

2. Снять все блокировки

Эти функции работают не как "блокировать" / "разблокировать", а "увеличить счётчик блокировок" / "уменьшить счетчик блокировок". В некоторых случаях это не очень удобно, например когда мы не можем или не хотим следить за количеством блокировок (в моём случае стандартные ФМ-ы непредсказуемо снимали или устанавливали блокировки).
Вот такой код вернёт в E_COUNT количество блокировок текущим пользователем по заказу l_vbeln:
data lt_enq type table of seqg3.
data ls_enq type seqg3.
data: GTARG TYPE EQEGTARG.

CONCATENATE SY-MANDT l_vbeln into GTARG.
CALL FUNCTION 'ENQUEUE_REPORT'
   EXPORTING
      GCLIENT = SY-MANDT
      GNAME = 'VBAK'
      GTARG = GTARG
      GUNAME = SY-UNAME
   TABLES
      ENQ = lt_enq
   EXCEPTIONS
      COMMUNICATION_FAILURE = 1
      SYSTEM_FAILURE = 2
      OTHERS = 3.
E_COUNT = 0.
LOOP AT lt_enq into ls_enq.
   E_COUNT = E_COUNT + ls_enq-GUSEVB.
ENDLOOP.
Соответственно для полной разблокировки надо запускать соответсвующий фм столько раз.
А при блокировании лучше проверить, а не заблокирован ли уже заказ.
Так же могут быть полезны другие модули группы функций SENT.

3. Ожидание разблокировки стандартными FM-ами

Функции блокировки могут пригодиться в случае, когда по одному объекту (например, сбытовому заказу) необходимо последовательно выполнять разные BAPI-функции. Дело в том, что эти функции часто работаю асинхронно, и возвращают управление в вызывающую функцию раньше, чем закончат свою работу. Не помогает даже bapi_transaction_commit с признаком wait. То есть второй шаг обработки будет провален так как, первый шаг ещё не отработал.
В таких случаях может быть полезен следующий код:
* вызов первой функции, блокирующей заказ. например, SD_SALESDOCUMENT_CREATE.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING WAIT = 'X'.

is_ok = space.
DO 10 TIMES. " количество попыток, сколько раз пытаться блокировать заказ. не слишком много
* вызов фм блокирования
   IF SY-SUBRC = 0. " если удалось заблокировать
* вызов функции разблокирования
      is_ok = 'X'.
      exit.
   else.
      * если надо - запоминаем почему неудалось заблокировать. это хранится в sy-MSG*.
   ENDIF.
   WAIT UP TO 1 SECONDS. " делаем паузу перед следующей попыткой заблокировать
ENDDO.
if is_ok is not initial.
   * вызов второй функции, блокирующей заказ.
endif.
Подробнее...

26 июня 2011 г.

FM для вывода диалога с несколькими опциями

  DATA: lt_spopli TYPE TABLE OF SPOPLI,
        ls_spopli TYPE SPOPLI.
  DATA: lv_answer TYPE CHAR2.

  CLEAR ls_spopli.
  ls_spopli-VAROPTION = 'Предложение'.
  APPEND ls_spopli TO lt_spopli.
  CLEAR ls_spopli.
  ls_spopli-VAROPTION = 'Заказ с оплатой на месте'.
  APPEND ls_spopli TO lt_spopli.

  CALL FUNCTION 'POPUP_TO_DECIDE_LIST'
    EXPORTING
      CURSORLINE               = 1
      TEXTLINE1                = 'Сохранить документ как:'
      TITEL                    = 'Cохранить'
    IMPORTING
      ANSWER                   = lv_answer
    TABLES
      T_SPOPLI                 = lt_spopli
    EXCEPTIONS
      NOT_ENOUGH_ANSWERS       = 1
      TOO_MUCH_ANSWERS         = 2
      TOO_MUCH_MARKS           = 3
      OTHERS                   = 4
            .

  IF SY-SUBRC <> 0.
    MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
            WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
  ENDIF.

Результат:

Подробнее...

30 мая 2011 г.

Несколько полезных записей из внешнего интернета

Как найти что-то в исходных кодах
Для поиска чего либо в исходных кодах, очень помогает программа
RPR_ABAP_SOURCE_SCAN

Как запустить отладку в модальном окне
Вот так можно включить отладку в модальном окне:
Создаем текстовый файл со следующим содержанием, например, на рабочем столе

[FUNCTION]
Command=/H
Title=Debugger
Type=SystemCommand

Теперь просто перетаскиваем этот файл на ваше окошко и все.

Как редактировать данные в таблицах без диалога ведения, или в закрытых мандантах
Для того, что бы редактировать данные в таблицах без диалога ведения, или в закрытых мандантах необходимо:
В транзакции UASE16N выбрать таблицу, данные которой необходимо редактировать, ввести команду &SAP_EDIT в командную строку и нажать «Выполнить». Подробнее...

Вывести результат стандартных функций (BAPIRET2)



Красиво показать результат вызова стандартного ФМ:

CALL FUNCTION 'C14ALD_BAPIRET2_SHOW'
TABLES
I_BAPIRET2_TAB = RETURN.



Неожиданно приятная функция, не иначе как брахман писал. Подробнее...

20 мая 2011 г.

Быстрое создание ALV-таблицы

" например надо отобразить таблицу T_TCJ_POSITIONS
DATA: gc_alv_table TYPE REF TO cl_salv_table.
cl_salv_table=>factory( IMPORTING r_salv_table = gc_alv_table CHANGING t_table = T_TCJ_POSITIONS ).
" показать
gc_alv_table->display( ).

" если необходимо добавить события:
data: events_tb TYPE REF TO CL_SALV_EVENTS_TABLE.
CALL METHOD gc_alv_table->GET_EVENT
RECEIVING
VALUE = events_tb.

data ALV_HANDLER_pay type ref to CL_ALV_HANDLER_pay.
create object ALV_HANDLER_pay.
set handler ALV_HANDLER_pay->handle_doubleclick for events_tb.


" Переименовать колонки:
gc_columns = gc_alv_table->get_columns( ).
gc_colwork ?= gc_columns->get_column( 'P_RECEIPTS' ).
gc_colwork->set_long_text( 'Оплата' ).
gc_colwork->set_medium_text( 'Оплата' ).
gc_colwork->set_short_text( 'Оплата' ).
" там же можно сделать прочие настройки, если надо

" добавим агрегацию
gc_aggr = gc_alv_table->get_aggregations( ).
gc_aggr->add_aggregation( 'P_RECEIPTS' ). Подробнее...

генерированные экраны в своих формах

Чтобы отобразить генерированные экраны в своих формах надо описать экран:

SELECTION-SCREEN BEGIN OF SCREEN 0101 AS SUBSCREEN.
SELECT-OPTIONS s_vkorg FOR vbak-vkorg.
SELECT-OPTIONS s_vkbur FOR vbak-vkbur.
SELECT-OPTIONS s_VKGRP FOR vbak-VKGRP.
SELECT-OPTIONS s_vtweg FOR vbak-vtweg.
SELECT-OPTIONS s_spart FOR vbak-spart.

SELECT-OPTIONS s_SUBMI FOR vbak-SUBMI.
SELECT-OPTIONS s_netwr FOR vbap-netwr.
SELECT-OPTIONS s_lifnr FOR vbpa-lifnr.
SELECTION-SCREEN END OF SCREEN 0101.

А в своём экране включить его в подэкран аналогично обычным экранам. Подробнее...

3 мая 2011 г.

Оптимизация запросов select

Ряд рекомендаций:
1. Отказаться от into corresponding fields of table в пользу into table. Причём выводить только нужные поля.
Очень хорошо помогает.
Однако для этого надо обеспечить, что порядок и тип полей в таблице-получателе совадал с порядком полей запроса.

2. Не смешивать в запросе буферизованные таблицы и не буферизованные: буферизация работать не будет. Лучше вынести получение в отдельные подзапросы - можно даже в цикле, работает быстро.
На примере заполнения имён заводов и складов:
select [...] from [...] into table RES_TB where [...].
FIELD-SYMBOLS <res_fs> TYPE res_tp.
LOOP AT RES_TB ASSIGNING <res_fs>.
SELECT SINGLE name1 into <res_fs>-werks_t from t001w where werks = <res_fs>-werks.
SELECT SINGLE LGOBE into <res_fs>-LGORT_t from t001l where werks = <res_fs>-werks and lgort = <res_fs>-lgort.

endloop.

3. Например, в конструкции where есть ограничения "fielndname <> 'X'". А список допустимых значений этого поля небольшой и известен или может получен взят из справочника. Лучше постараться заменить на "=" в каком-либо виден (in, for all entries). либо вообще получить избыточные данные и отбросить их программным кодом (delete [...] where "fielndname = 'X'").

4. Например, результат первого запроса (tab1) используется во втором запросе (tab2), а потом эти данные собираются в общую таблицу. Примерно так:
loop at tab1 assigning <tab1_fs>.
read table tab2 into ls_tab2 with key field1 = <tab1_fs>-fielnd1 [...].
<tab1_fs>-field5 = ls_tab2-field5.
" либо цикл по второй таблице с аналогичным фильтром
endloop.
На больших объёмах такая сборка может быть очень медленной.
В таких случаях бывает полезно объявить таблицу tab2 как hash, если это возможно.

5. В фильтрах и соединениях таблиц чтобы использовался индекс надо перечислить поля, стоящие выше в индексе. Даже если там константа.
Например, в таблице A512 ключ из полей: MANDT, KAPPL, KSCHL, VKORG, BWTAR, MATNR, KFRST, DATBI. А в фильтре используется только vkorg, BWTAR, matnr, а KAPPL, KSCHL - константы. Необходимо перечислить эти два поля. MANDT - необязательно, его подставит система.

см также по FOR ALL ENTRIES

to be continue... Подробнее...

Подводные камни FOR ALL ENTRIES

1. Если результаты одного запроса используются в конструкции for all entries второго - не забываем проверять, что таблица пустая. Иначе второй запрос не посчитает это ограничением.
select [...] into table table1 from [...] where [...].
if table1 is not initial.
select [...] into table table2 from [...] for all entries table1 where [...].
endif.


2. При For all entries могут не выводиться дублирующиеся строки (как будто используется параметр distinct).
Необходимо перечислить в списке полей вывода все ключевые поля всех используемых в запрос таблиц (причём даже если значение каких-то из них фактически одинаковые).
Проблема похоже в том, что такой запрос преобразуется системой в набор запросов, объединённых через метрику UNION, а не UNION ALL.

3. Например в конструкции where запрос используется набор полей из таблицы конструкции for all entries, а значения эти неуникальные в таблице (например только номера документов, а в таблице встречаются и позиции).
Такой запрос можно ускорить:
data tab_copy like tab. " либо type с тем же типом
tab_copy = tab.
sort tab_copy by vbeln." список полей, используемых в for all entries
DELETE ADJACENT DUPLICATES FROM tab_copy COMPARING vbeln. " тот же список полей

И в запросе использовать эту таблицу.

4. Иногда полезно убрать лишние фильтр по значениям из таблицы for all entries (например, вместо vbeln+posnr[+etern] оставить только vbeln) и применить пункт 3.
Особенно когда известно, что скорее всего в таблице источнике перечислены все или многие значения исключаемых полей.
Пусть даже будет какая-то избыточность данных, но запрос отработает значительно быстрее. Подробнее...

ALV-контейнеры с одинаковыми именами

Проблема: В программе с ALV-контейнером на экране вызывается фм. В рамках ФМ-а открываются другие экраны с ALV-контейнерами. Один из которых называется также, как контейнер программы.
В результате при возврате из фм в программу ALV может не отрисовываться.

Выход: делать ALV-контейнеры с уникальными именами. Работает.
Возможно можно избежать такой проблемы подобрав параметры конструктора контейнера (указать программу-REPID и экран-DYNNR), но у меня не получилось. Подробнее...

28 апреля 2011 г.

Заполнение списка предлагаемых значений Listbox-а

На примере списка кредиторов
  types:
begin of vrm_value,
key(40) type c,
text(80) type c,
end of vrm_value,
VRM_VALUES TYPE VRM_VALUE OCCURS 0.
 
data: lifnr_values TYPE VRM_VALUES with header line.
FREE lifnr_values. " обязательно
data: lfa1_tb TYPE WSTN_LFA1_TAB, lfa1_ln TYPE LFA1.
" заполнить где-то lfa1_tb поставщиками
LOOP AT lfa1_tb into lfa1_ln.
lifnr_values-key = lfa1_ln-lifnr.
CONCATENATE lfa1_ln-NAME1 lfa1_ln-NAME2 lfa1_ln-NAME3 lfa1_ln-NAME4
into lifnr_values-text.
APPEND lifnr_values.
ENDLOOP.
call function 'VRM_SET_VALUES'
EXPORTING
id = 'LIFNR' " имя элемента
values = lifnr_values[]
EXCEPTIONS
others = 1.
Подробнее...

Sap Scripting

Проблема: необходимо автоматически запустить sap logon и выполнить какие-то действия автоматически.
1. Необходимо активировать у инстанции возможность Sap scripting-а
http://searchsap.techtarget.com/feature/Step-2-Activating-SAPGUI-scripting
2. Как генерировать скориптинг
Настройка локального формата .Запись и воспроизведение скрипта. Дальше там понятно что делать.
3. Пример скрипта:


 
dim session
StartApp
if WScript.Arguments.Count > 0 Then
if WScript.Arguments(0) = "Site" Then
SiteUpload
End if
End if
 
rem Выходим
session.findById("wnd[0]/tbar[0]/okcd").text = "/nex"
session.findById("wnd[0]").sendVKey 0
 
Sub SiteUpload
rem Запускаем программу
session.findById("wnd[0]/tbar[0]/okcd").text = "se38"
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]/usr/ctxtRS38M-PROGRAMM").text = "ZRSITE_UPLOAD"
session.findById("wnd[0]").sendVKey 8
session.findById("wnd[0]/usr/txtTUNE").text = "tyumen"
session.findById("wnd[0]/usr/txtMIN_C").text = "15"
session.findById("wnd[0]/usr/txtTEMP_DIR").text = "C:\"
session.findById("wnd[0]/usr/txtPR_VARI").text = "TYUMEN"
session.findById("wnd[0]").sendVKey 8
end sub
 
rem Подпрограма запуска приложения
Sub StartApp
rem запускаем саплогон
Set WshShell = CreateObject("WScript.Shell") 
WshShell.Run "C:\Progra~1\SAP\FrontEnd\SAPgui\saplogon.exe", 1, False
rem ждём открытия
WScript.Sleep(10000)
rem Открываеем сессию
If Not IsObject(application) Then
Set SapGuiAuto  = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
rem application.OpenConnection("RD1")   
application.OpenConnectionByConnectionString("rosasap09 00")
Set connection = application.Children(application.Children.Count - 1) rem свежеоткртое окно
Set session    = connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session,     "on"
WScript.ConnectObject application, "on"
End If
rem Авторизация
session.findById("wnd[0]").maximize
session.findById("wnd[0]/usr/txtRSYST-MANDT").text = "800"
session.findById("wnd[0]/usr/txtRSYST-BNAME").text = "alexeys"
session.findById("wnd[0]/usr/pwdRSYST-BCODE").text = ""
session.findById("wnd[0]/usr/txtRSYST-LANGU").text = "ru"
session.findById("wnd[0]").sendVKey 0
 
rem Если открылось окно, что чувак уже залогинен - закрыть? а может не закрывать? Тогда вместо OPT1 - OPT2
set log_opt = session.findById("wnd[1]/usr/radMULTI_LOGON_OPT1",  False)
If not log_opt Is Nothing Then
log_opt.select
session.findById("wnd[1]/tbar[0]/btn[0]").press
End If
 
End Sub
 

Подробнее...

Вызов PBO из событий ALV

Проблема: в событии ALV изменились какие-либо значения, отображаемые экраном DynPro, но так как события PBO не было - пользователь видит старые значения.
Подобрал два варианта:
1. Имитировать событие PBO.

CALL FUNCTION 'SAPGUI_SET_FUNCTIONCODE'EXPORTINGFUNCTIONCODE           = '='EXCEPTIONSFUNCTION_NOT_SUPPORTED = 1OTHERS                 = 2.

Работает, но медленно. Возможно если использовать другой FUNCTIONCODE, будет лучше. знак равенства предлагался как значение по умолчанию.

2. Обновить значение самостоятельно.

Пробовал использовать функции DYNP_VALUES_READ и DYNP_VALUES_UPDATE, но не получилось. зато получилось с

DATA: dynpfields_tb  TYPE TABLE OF dynpread,
dynpfields_ln  TYPE dynpread. 
DEFINE AddField.
dynpfields_ln-fieldname  = '&1'.
dynpfields_ln-fieldvalue = &1.
APPEND dynpfields_ln to dynpfields_tb.
END-OF-DEFINITION.
AddField MAT_INFO_STR-MATNR.
AddField MAT_INFO_STR-MATERIAL_NAME.
CALL FUNCTION 'DYNP_UPDATE_FIELDS'
EXPORTING
DYNAME               = sy-repid
DYNUMB               = '1210'
TABLES
DYNPFIELDS           = dynpfields_tb
EXCEPTIONS
INVALID_ABAPWORKAREA = 1
INVALID_DYNPROFIELD  = 2
INVALID_DYNPRONAME   = 3
INVALID_DYNPRONUMMER = 4
INVALID_REQUEST      = 5
NO_FIELDDESCRIPTION  = 6
UNDEFIND_ERROR       = 7
OTHERS               = 8.

Работает, быстро, но есть казусы (возможно имеют решения, но я пока их не знаю):
- иногда теряются часть текста после переключения закладок с этими данными.
- не получилось использовать для чисел - пришлось менять тип на текстовый, что не всегда допустимо.
- пришлось отказаться от программ преобразования - вызываю их сам в коде, что тоже не всегда удобно.

3. У конструктора ALV GRID-а есть параметр i_appl_events. если его взвести - при нажатии вызывается PAI, а после PBO. Но тоже медленно всё работает. Возможно у других объектов есть такой же способ.

4. cl_gui_cfw=>set_new_ok_code. Тоже медленно.
CALL METHOD cl_gui_cfw=>set_new_ok_code
EXPORTING
new_code = 'DUMMY'.
CL_GUI_CFW=>FLUSH. Подробнее...

27 апреля 2011 г.

ABAP: добавление своей кнопки в TOOLBAR ALV GRID

Для этого надо создать класс обработчик для обработки событий toolbar и user_command для ALV GRID.

Пример:

CLASS cl_trans_g_event_receiver DEFINITION.
  PUBLIC SECTION.
  METHODS:
    handle_toolbar
      FOR EVENT toolbar OF cl_gui_alv_grid
        IMPORTING e_object e_interactive,
    handle_user_command
      FOR EVENT user_command OF cl_gui_alv_grid
        IMPORTING e_ucomm.
ENDCLASS.

CLASS cl_trans_g_event_receiver IMPLEMENTATION.
  METHOD handle_toolbar.
    PERFORM method_trans_toolbar USING e_object.
  ENDMETHOD.

  METHOD handle_user_command.
    PERFORM method_trans_user_command USING e_ucomm.
  ENDMETHOD.
ENDCLASS.

* Добавление кнопки в тулбар
FORM METHOD_TRANS_TOOLBAR USING P_E_OBJECT TYPE REF TO CL_ALV_EVENT_TOOLBAR_SET.
  DATA: ty_toolbar TYPE stb_button.

* разделитель
  CLEAR ty_toolbar.
  ty_toolbar-butn_type = 3.
  APPEND ty_toolbar TO p_e_object->mt_toolbar.

* кнопка
  CLEAR ty_toolbar.
  ty_toolbar-function = 'MYBUTT'.
  ty_toolbar-icon = ICON_HISTORY.
  ty_toolbar-butn_type = 0.
  ty_toolbar-text = 'Моя кнопка'.

  APPEND ty_toolbar TO p_e_object->mt_toolbar.
ENDFORM.

* Обработка команд
FORM METHOD_TRANS_USER_COMMAND USING P_E_UCOMM TYPE SY-UCOMM.
  CASE p_e_ucomm.
    WHEN 'MYBUTT'.
*     ЧТО-ТО ДЕЛАЕМ
  ENDCASE.
ENDFORM.

Ну и надо незабыть инициализировать все это после создания грида:

  DATA: trans_g_event_receiver TYPE REF TO cl_trans_g_event_receiver.

  CREATE OBJECT trans_g_event_receiver.

  SET HANDLER trans_g_event_receiver->handle_toolbar FOR trans_grid.
  SET HANDLER trans_g_event_receiver->handle_user_command FOR trans_grid.
Подробнее...

ABAP: стили ячеек в ALV GRID.

Список возможных значений стилей можно или даже нужно брать из инклуда <CL_ALV_CONTROL>.

Вариант 1:
Стиль для столбца можно указать в филд-каталоге (LVC_T_FCAT) в полях:
    STYLE
    STYLE2
    STYLE3
    STYLE4

Пример:
  ls_fcat-style = ALV_STYLE_COLOR_INT_BACKGROUND + ALV_STYLE_ALIGN_CENTER_CENTER.

Вариант 2:
Если необходимо чтобы разные стили были у разных произвольных ячеек, то в стуктуру вашей внутренней таблицы для ALV придется ввести поле типа LVC_T_STYL. В нем будет заполняться таблица стилей для каждой ячейки выбранной строки.

Структура этой таблицы выглядит так:
    FIELDNAME TYPE LVC_FNAME,
    STYLE     TYPE LVC_STYLE,
    STYLE2    TYPE LVC_STYLE,
    STYLE3    TYPE LVC_STYLE,
    STYLE4    TYPE LVC_STYLE,
    MAXLEN    TYPE INT4.

И собственно заполняется так же как и в филд-каталоге, только для каждой ячейки каждой строки вашей внутренней таблицы для ALV. Важно, таблица стилей должна заполняться так, чтобы в результате получилась таблица отсортированная по FIELDNAME.

Ну и в конце концов необходимо указать имя поля с таблицей стилей в лэйаут ALV (LVC_S_LAYO).

Пример:
  tcalend_g_layo-sel_mode = 'A'.
  tcalend_g_layo-stylefname = 'CELLTAB'.
Подробнее...

ABAP: FM для вычисления даты +/- определенное кол-во дней

ФМ – DATE_IN_FUTURE, во входных параметрах дата должна быть в формате “ddmmyyyy”

Пример:

lv_datum+0 = sy-datum+6(2).
lv_datum+2 = sy-datum+4(2).
lv_datum+4 = sy-datum(4).


CALL FUNCTION 'DATE_IN_FUTURE'
  EXPORTING
    ANZAHL_TAGE             = -10
    IMPORT_DATUM            = lv_datum
  IMPORTING
*   EXPORT_DATUM_EXT_FORMAT =
    EXPORT_DATUM_INT_FORMAT = lv_fdmdt.

А то все время забываю как он называется. Подробнее...

3 марта 2011 г.

ABAP: Печать штрих-кодов в SAP с помощью Smartforms

Ссылка на неплохой туториал по печати штрих-кодов в Smartforms, там все хорошо описано, с картинками и примерами. Подробнее...