Показаны сообщения с ярлыком batch input. Показать все сообщения
Показаны сообщения с ярлыком batch input. Показать все сообщения

пятница, 16 декабря 2016 г.

Вызываем FBLN1 с неколькими BELNR, BUKRS, LIFNR через пакетник

CLASS zcl_call_fbl1n DEFINITION
PUBLIC
ABSTRACT
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
TYPES:
tt_bukrs TYPE STANDARD TABLE OF bukrs WITH DEFAULT KEY .
TYPES:
tt_belnr TYPE STANDARD TABLE OF belnr_d WITH DEFAULT KEY .
TYPES:
tt_gjahr TYPE STANDARD TABLE OF gjahr WITH DEFAULT KEY .
TYPES:
tt_lifnr TYPE STANDARD TABLE OF lifnr WITH DEFAULT KEY .
CLASS-DATA st_bdc TYPE bdcdata_tab READ-ONLY .
CLASS-METHODS call
IMPORTING
!it_bukrs TYPE tt_bukrs OPTIONAL
!it_belnr TYPE tt_belnr OPTIONAL
!it_gjahr TYPE tt_gjahr OPTIONAL
!it_lifnr TYPE tt_lifnr OPTIONAL
VALUE(is_ctu_params) TYPE ctu_params OPTIONAL
EXPORTING
!et_msg TYPE tab_bdcmsgcoll .
CLASS-METHODS fill_bdc
IMPORTING
!it_bukrs TYPE tt_bukrs OPTIONAL
!it_belnr TYPE tt_belnr OPTIONAL
!it_gjahr TYPE tt_gjahr OPTIONAL
!it_lifnr TYPE tt_lifnr OPTIONAL .
protected section.
private section.
class-methods _SCREEN
importing
!IV_VALUE type CLIKE .
class-methods _FIELD
importing
!IV_VALUE type CLIKE .
class-methods _SELOPT
importing
!IT_DATA type STANDARD TABLE .
ENDCLASS.
CLASS ZCL_call_FBL1N IMPLEMENTATION.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_call_FBL1N=>CALL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_BUKRS TYPE TT_BUKRS(optional)
* | [--->] IT_BELNR TYPE TT_BELNR(optional)
* | [--->] IT_GJAHR TYPE TT_GJAHR(optional)
* | [--->] IT_LIFNR TYPE TT_LIFNR(optional)
* | [--->] IS_CTU_PARAMS TYPE CTU_PARAMS(optional)
* | [<---] ET_MSG TYPE TAB_BDCMSGCOLL
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD call.
FREE et_msg.
fill_bdc(
EXPORTING
it_bukrs = it_bukrs " Балансовая единица
it_belnr = it_belnr
it_gjahr = it_gjahr
it_lifnr = it_lifnr
).
IF is_ctu_params-dismode is INITIAL .
is_ctu_params-dismode = 'E'.
ENDIF.
IF is_ctu_params-nobinpt is INITIAL and sy-batch is INITIAL.
is_ctu_params-nobinpt = 'X'.
ENDIF.
CALL TRANSACTION 'FBL1N'
WITH AUTHORITY-CHECK
USING st_bdc
OPTIONS FROM is_ctu_params
MESSAGES INTO et_msg
.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_call_FBL1N=>FILL_BDC
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_BUKRS TYPE TT_BUKRS(optional)
* | [--->] IT_BELNR TYPE TT_BELNR(optional)
* | [--->] IT_GJAHR TYPE TT_GJAHR(optional)
* | [--->] IT_LIFNR TYPE TT_LIFNR(optional)
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD fill_bdc.
FREE st_bdc.
IF it_lifnr[] IS NOT INITIAL.
_screen('RFITEMAP 1000 X ').
_field('BDC_CURSOR KD_LIFNR-LOW').
_field('BDC_OKCODE =%004').
* _field(' KD_LIFNR-LOW').
* _field(' X_OPSEL X').
* _field(' PA_STIDA 16.12.2016').
* _field(' X_NORM X').
_field(' BDC_SUBSCR SAPLSSEL 2001%_SUBSCREEN_%_SUB%_CONTAINER').
_field(' BDC_SUBSCR SAPLSSEL 2002SUBSCREEN_CONTAINER2').
_selopt( it_lifnr ).
ENDIF.
IF it_bukrs[] IS NOT INITIAL.
_screen('RFITEMAP 1000 X').
_field(' BDC_CURSOR KD_LIFNR-LOW').
_field(' BDC_OKCODE =%005').
* _field(' KD_LIFNR-LOW 1').
* _field(' X_OPSEL X').
* _field(' PA_STIDA 16.12.2016').
* _field(' X_NORM X').
_field(' BDC_SUBSCR SAPLSSEL 2001%_SUBSCREEN_%_SUB%_CONTAINER').
_field(' BDC_SUBSCR SAPLSSEL 2002SUBSCREEN_CONTAINER2').
_selopt( it_bukrs ).
ENDIF.
IF it_belnr[] IS NOT INITIAL.
_screen('RFITEMAP 1000 X').
_field(' BDC_CURSOR KD_LIFNR-LOW').
_field(' BDC_OKCODE =DYNS').
* _field(' KD_LIFNR-LOW 1').
* _field(' KD_BUKRS-LOW 2000').
* _field(' X_OPSEL X').
* _field(' PA_STIDA 16.12.2016').
* _field(' X_NORM X').
_field(' BDC_SUBSCR SAPLSSEL 2001%_SUBSCREEN_%_SUB%_CONTAINER').
_field(' BDC_SUBSCR SAPLSSEL 2002SUBSCREEN_CONTAINER2').
_screen('RFITEMAP 1000 X').
_field(' BDC_CURSOR KD_LIFNR-LOW').
_field(' BDC_OKCODE =%02411060000707020').
* _field(' KD_LIFNR-LOW 1').
* _field(' KD_BUKRS-LOW 2000').
* _field(' X_OPSEL X').
* _field(' PA_STIDA 16.12.2016').
* _field(' X_NORM X').
_field(' BDC_SUBSCR SAPLSSEL 2001%_SUBSCREEN_%_SUB%_CONTAINER').
_field(' BDC_SUBSCR SAPLSSEL 2000SUBSCREEN_CONTAINER2').
_field(' BDC_SUBSCR SAPLSSEL 1106SUBSCREEN_CONTAINER').
_selopt( it_belnr ).
ENDIF.
_screen('RFITEMAP 1000 X').
_field(' BDC_OKCODE =ONLI').
_field(' BDC_CURSOR KD_LIFNR-LOW').
_field(' X_OPSEL X').
_field(' X_NORM X').
* _field(' X_SHBV X').
* _field(' X_MERK X').
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_call_FBL1N=>_FIELD
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_VALUE TYPE CLIKE
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD _field.
DATA ls_bdc TYPE bdcdata.
CHECK iv_value IS NOT INITIAL.
DATA(lv_value) = condense( iv_value ).
CHECK lv_value IS NOT INITIAL.
* SPLIT lv_value AT cl_abap_char_utilities=>horizontal_tab INTO ls_bdc-fnam ls_bdc-fval .
* SPLIT lv_value AT space INTO ls_bdc-fnam ls_bdc-fval .
FIND REGEX '^\s*(\S+)\s?(.*)$' IN lv_value SUBMATCHES ls_bdc-fnam ls_bdc-fval.
IF sy-subrc = 0.
CONDENSE ls_bdc-fval.
APPEND ls_bdc TO st_bdc.
ENDIF.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_call_FBL1N=>_SCREEN
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_VALUE TYPE CLIKE
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD _screen.
DATA ls_bdc TYPE bdcdata.
CHECK iv_value IS NOT INITIAL.
* SPLIT iv_value AT cl_abap_char_utilities=>horizontal_tab INTO ls_bdc-program ls_bdc-dynpro ls_bdc-dynbegin.
* SPLIT iv_value AT space INTO ls_bdc-program ls_bdc-dynpro ls_bdc-dynbegin.
FIND REGEX '^\s*(\S+)\s+(\d+)(.*)$' IN iv_value SUBMATCHES ls_bdc-program ls_bdc-dynpro DATA(lv_end).
IF sy-subrc = 0.
ls_bdc-dynbegin = condense( lv_end ).
APPEND ls_bdc TO st_bdc.
ENDIF.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_call_FBL1N=>_SELOPT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_DATA TYPE STANDARD TABLE
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD _selopt.
DATA lt_value TYPE STANDARD TABLE OF bdcdata-fval.
DATA lv_value TYPE bdcdata-fval.
DATA lv_index TYPE i.
DATA lv_ok_code TYPE string VALUE 'BDC_OKCODE /00'.
CONSTANTS cv_accept TYPE string VALUE 'BDC_OKCODE =ACPT'.
LOOP AT it_data ASSIGNING FIELD-SYMBOL(<ls_data>).
CHECK <ls_data> IS NOT INITIAL.
write <ls_data> to lv_value.
APPEND lv_value TO lt_value.
ENDLOOP.
CHECK lt_value[] IS NOT INITIAL.
SORT lt_value.
DELETE ADJACENT DUPLICATES FROM lt_value.
IF lines( lt_value ) < 9.
lv_ok_code = cv_accept.
ENDIF.
_screen('SAPLALDB 3000 X').
_field( lv_ok_code ).
_field(' BDC_SUBSCR SAPLALDB 3010SCREEN_HEADER').
_field(' BDC_CURSOR RSCSEL_255-SLOW_I(08)').
LOOP AT lt_value ASSIGNING FIELD-SYMBOL(<v_value>) FROM 1 TO 8.
_field( |RSCSEL_255-SLOW_I({ sy-tabix WIDTH = 2 PAD = '0' ALIGN = right }) { <v_value> }| ).
ENDLOOP.
LOOP AT lt_value FROM 9 TRANSPORTING NO FIELDS WHERE table_line IS NOT INITIAL.
if sy-tabix = lines( lt_value ).
lv_ok_code = cv_accept.
ENDif.
lv_index = sy-tabix - 8.
_screen('SAPLALDB 3000 X').
_field( lv_ok_code ).
_field(' BDC_SUBSCR SAPLALDB 3010SCREEN_HEADER').
_field(' BDC_CURSOR RSCSEL_255-SLOW_I(08)').
DO 8 TIMES.
ADD 1 TO lv_index.
READ TABLE lt_value ASSIGNING <v_value> INDEX lv_index.
_field( |RSCSEL_255-SLOW_I({ sy-index WIDTH = 2 PAD = '0' ALIGN = right }) { <v_value> }| ).
ENDDO.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

среда, 13 июня 2012 г.

Изменение позиций финансовых документов.

Финансы в SAP писали совсем другие люди, что писали например MM-SD. В последних есть какие-то BADI, BAPI, User-Exit и прочие технологии, которые позволяют внедрится в процесс создания/изменения логистических документов, либо просто их менять из своих программ. В FI для внедрения служат как правило замещения. Есть еще OpenFI, но в каких-то случаях он работает в каких-то нет. В любом случае если нужно поменять финансовый документ из своей программы, то как правило для этого нет никаких ФМ или BAPI, и вместо них приходится применять "пакетники" (batch input). Если кто не в курсе - это аналог макросов в продуктах  MS Office. "Пакетник" записывается на какую-то стандартную транзакцию и фактически эмулирует действия пользователя, когда он работает в этой транзакции. Это, конечно, относительно медленно, но других вариантов как правило нет. Вернее можно, конечно, напрямую обновлять BSEG, только это чревато получением неконсистентности данных.  Но основной минус "пакетников" - это то, что они, скажем так, однонаправленные. То есть, можно передать транзакции команды и тем самым сказать что делать, но невозможно прочитать из транзакции ее текущее состояние - то есть нельзя понять, что получилось в вычисляемых полях, получить данные списка в том порядке, как он выведен на экране (это часто нужно для позиционирования или выделения), даже нельзя получить номер экрана на котором мы находимся, если, например, следующий экран зависит от введенных данных. Вот последнее особенно портит нервы, поскольку команды в "пакетнике" привязаны к экрану.

Например, записали вы "пакетник" на изменение текста позиции FI-документа в транзакции FB02. Проверили на примерах - все вроде работает. Отдали в тест и выясняется, что когда то работает, а когда то нет.
Включили интерактивный режим, запустили пример на котором не сработало, выполнение дошло до нужного экрана как вам кажется и остановилось, причем текст не поменялся, сохранение не производится. Непонятно.

На самом деле объяснение банальное - команда у вас записана для выполнения на определенном экране, а транзакция вывела вам другой. С виду он может даже похож на изначальный, но по факту - другой. Сделала она это по одной ей известной логике - может тип документа другой, может получатель какой-то особенный, может что-то с датами.

Можно, конечно, провести пару незабываемых часов в отладке выясняя почему уже оно так. Но к счастью  для изменения позиций финансового документа есть ФМ
FI_ITEMS_MASS_CHANGE, в котором вся эта логика уже зашита. По факту он точно также выполняет пакетник, но все заморочки с экранами решает за вас.