La creación de fuentes desde SAP a BW puede ser variada, desde una simple vista replicada a BW, un infoset, una tabla, donde los datos pueden ser datos maestros, textos o bien transaccionales, es decir que conforman datos del día a día en una empresa ( Pedidos, facturas, ordenes compra, etc.), en este artículo intentare explicar el uso de uno de los más elaborados por no decir complejo, el de los creados a partir de un módulo de función, donde principalmente se utiliza ABAP como herramienta de desarrollo, esto se realiza del lado del emisor de datos en este caso SAP ECC.
Primero, necesitamos crear una estructura que será la base de la tabla que recibirá la información. Creamos la estructura por la SE11 y colocamos los campos que se van a obtener en la extracción.
Para crear la función que genera la extracción nos dirigimos primero a la SE80 y colocamos el módulo de funcion RSAX ahí, encontraremos dos módulos de funciones que podemos usar para generar una copia de la misma y migren las variables de dicha función, con el fin que se copien todos sus parámetros y no te genere error al momento de probar tu extractor.
Ubicamos la función RSAX_BIW_GET_DATA_SIMPLE presionamos el botón derecho del mouse y escogemos COPIAR
En la ventana que nos aparece completamos lo siguiente:
De: Es el nombre de la función que vamos a copiar
A: Colocamos el nombre de nuestra función
Grupo funciones: Colocamos el grupo de función donde lo vas a crear.
Nos dirigimos a nuestro módulo de función y verificamos en la pestaña IMPORT, TABLAS y COD FTE se haya generado sus respectivas variables.
En La pestaña TABLAS ubicamos E_T_DATA que es la tabla de salida y le cambiamos su tipo de referencia por la estructura que creamos que va tener nuestra tabla de salida. Para este caso ZMM_MOV_MER_BW
En la pestaña COD FTE ya está generado la lógica del extractor, es por ello que yo te recomiendo hacer la copia de la función de ejemplo, puesto que la base de lectura ya estaría desarrollada y solo quedaría plantear la lógica de obtención para la tabla de respuesta. Copia el siguiente código, ahí indico en un comentario donde deberías insertar tu programación.
FUNCTION ZMF_MM_MOV_MER_BW.
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*" IMPORTING
*" VALUE(I_REQUNR) TYPE SRSC_S_IF_SIMPLE-REQUNR
*" VALUE(I_DSOURCE) TYPE SRSC_S_IF_SIMPLE-DSOURCE OPTIONAL
*" VALUE(I_MAXSIZE) TYPE SRSC_S_IF_SIMPLE-MAXSIZE OPTIONAL
*" VALUE(I_INITFLAG) TYPE SRSC_S_IF_SIMPLE-INITFLAG OPTIONAL
*" VALUE(I_READ_ONLY) TYPE SRSC_S_IF_SIMPLE-READONLY OPTIONAL
*" VALUE(I_REMOTE_CALL) TYPE SBIWA_FLAG DEFAULT SBIWA_C_FLAG_OFF
*" TABLES
*" I_T_SELECT TYPE SRSC_S_IF_SIMPLE-T_SELECT OPTIONAL
*" I_T_FIELDS TYPE SRSC_S_IF_SIMPLE-T_FIELDS OPTIONAL
*" E_T_DATA STRUCTURE SFLIGHT OPTIONAL
*" EXCEPTIONS
*" NO_MORE_DATA
*" ERROR_PASSED_TO_MESS_HANDLER
*"----------------------------------------------------------------------
* Example: DataSource for table SFLIGHT
TABLES: SFLIGHT.
* Auxiliary Selection criteria structure
DATA: L_S_SELECT TYPE SRSC_S_SELECT.
* Maximum number of lines for DB table
STATICS: S_S_IF TYPE SRSC_S_IF_SIMPLE,
* counter
S_COUNTER_DATAPAKID LIKE SY-TABIX,
* cursor
S_CURSOR TYPE CURSOR.
* Select ranges
RANGES: L_R_CARRID FOR SFLIGHT-CARRID,
L_R_CONNID FOR SFLIGHT-CONNID.
* Initialization mode (first call by SAPI) or data transfer mode
* (following calls) ?
IF I_INITFLAG = SBIWA_C_FLAG_ON.
************************************************************************
* Initialization: check input parameters
* buffer input parameters
* prepare data selection
************************************************************************
*************************************************************
* NOTA 1
“ZBW_EXTRACTOR cámbialo por el nombre de tu fuente de datos
*************************************************************
* Check DataSource validity
CASE I_DSOURCE.
WHEN 'ZBW_EXTRACTOR'.
WHEN OTHERS.
IF 1 = 2. MESSAGE E009(R3). ENDIF.
* this is a typical log call. Please write every error message like this
LOG_WRITE 'E' "message type
'R3' "message class
'009' "message number
I_DSOURCE "message variable 1
' '. "message variable 2
RAISE ERROR_PASSED_TO_MESS_HANDLER.
ENDCASE.
APPEND LINES OF I_T_SELECT TO S_S_IF-T_SELECT.
* Fill parameter buffer for data extraction calls
S_S_IF-REQUNR = I_REQUNR.
S_S_IF-DSOURCE = I_DSOURCE.
S_S_IF-MAXSIZE = I_MAXSIZE.
* Fill field list table for an optimized select statement
* (in case that there is no 1:1 relation between InfoSource fields
* and database table fields this may be far from beeing trivial)
APPEND LINES OF I_T_FIELDS TO S_S_IF-T_FIELDS.
ELSE. "Initialization mode or data extraction ?
************************************************************************
* Data transfer: First Call OPEN CURSOR + FETCH
* Following Calls FETCH only
************************************************************************
* First data package -> OPEN CURSOR
IF S_COUNTER_DATAPAKID = 0.
*************************************************************
NOTA 2
ES ACA DONDE DEBES INGRESAR TU LOGICA, Y COMO EN ESTE EJEMPLO GENERAR TUS RANGOS QUE SERIAN LOS VALORES DE ENTRADA
* Fill range tables BW will only pass down simple selection criteria
* of the type SIGN = 'I' and OPTION = 'EQ' or OPTION = 'BT'.
LOOP AT S_S_IF-T_SELECT INTO L_S_SELECT WHERE FIELDNM = 'CARRID'.
MOVE-CORRESPONDING L_S_SELECT TO L_R_CARRID.
APPEND L_R_CARRID.
ENDLOOP.
LOOP AT S_S_IF-T_SELECT INTO L_S_SELECT WHERE FIELDNM = 'CONNID'.
MOVE-CORRESPONDING L_S_SELECT TO L_R_CONNID.
APPEND L_R_CONNID.
ENDLOOP.
* Determine number of database records to be read per FETCH statement
* from input parameter I_MAXSIZE. If there is a one to one relation
* between DataSource table lines and database entries, this is trivial.
* In other cases, it may be impossible and some estimated value has to
* be determined.
OPEN CURSOR WITH HOLD S_CURSOR FOR
SELECT (S_S_IF-T_FIELDS) FROM SFLIGHT
WHERE CARRID IN L_R_CARRID AND
CONNID IN L_R_CONNID.
ENDIF. "First data package ?
*************************************************************
* Fetch records into interface table.
* named E_T_'Name of extract structure'.
FETCH NEXT CURSOR S_CURSOR
APPENDING CORRESPONDING FIELDS
OF TABLE E_T_DATA
PACKAGE SIZE S_S_IF-MAXSIZE.
IF SY-SUBRC <> 0.
CLOSE CURSOR S_CURSOR.
RAISE NO_MORE_DATA.
ENDIF.
S_COUNTER_DATAPAKID = S_COUNTER_DATAPAKID + 1.
ENDIF. "Initialization mode or data extraction ?
ENDFUNCTION.
Adicionalmente, se debe crear un include para el método LOG_WRITE para que muestre un log cuando se conecte o no el cursor. Solo genera el include bajo el nombre ZLOGEXTRACTOR y copia esta lógica.
*& Include ZLOGEXTRACTOR
*&---------------------------------------------------------------------*
DATA: RSAL_SAVE_SUBRC LIKE SY-SUBRC,
RSAL_S_LOGPARMS LIKE RSLOGPARMS.
* --------------------------------------------------------------------
* Open application log
* --------------------------------------------------------------------
DEFINE LOG_OPEN.
RSAL_S_LOGPARMS-FUNCTION = &1.
RSAL_S_LOGPARMS-LOGSYS = &2.
RSAL_S_LOGPARMS-INFOSOURCE = &3.
RSAL_S_LOGPARMS-TYPE = &4.
CALL FUNCTION 'RSAL_LOG_OPEN'
EXPORTING
I_FUNCTION = RSAL_S_LOGPARMS-FUNCTION
I_LOGSYS = RSAL_S_LOGPARMS-LOGSYS
I_INFOSOURCE = RSAL_S_LOGPARMS-INFOSOURCE
I_TYPE = RSAL_S_LOGPARMS-TYPE.
END-OF-DEFINITION.
* --------------------------------------------------------------------
* Set logical system to log
* --------------------------------------------------------------------
DEFINE LOG_SET_LOGSYS.
RSAL_S_LOGPARMS-LOGSYS = &1.
CALL FUNCTION 'RSAL_LOG_SET_LOGSYS'
EXPORTING
I_LOGSYS = RSAL_S_LOGPARMS-LOGSYS.
END-OF-DEFINITION.
* --------------------------------------------------------------------
* Reset logical system to log
* --------------------------------------------------------------------
DEFINE LOG_RESET_LOGSYS.
CALL FUNCTION 'RSAL_LOG_RESET_LOGSYS'.
END-OF-DEFINITION.
* --------------------------------------------------------------------
* Set InfoSource to log
* --------------------------------------------------------------------
DEFINE LOG_SET_ISOURCE.
RSAL_S_LOGPARMS-INFOSOURCE = &1.
RSAL_S_LOGPARMS-TYPE = &2.
CALL FUNCTION 'RSAL_LOG_SET_ISOURCE'
EXPORTING
I_OBJECT = RSAL_S_LOGPARMS-INFOSOURCE
I_TYPE = RSAL_S_LOGPARMS-TYPE.
END-OF-DEFINITION.
* --------------------------------------------------------------------
* Reset InfoSource to log
* --------------------------------------------------------------------
DEFINE LOG_RESET_ISOURCE.
CALL FUNCTION 'RSAL_LOG_RESET_ISOURCE'.
END-OF-DEFINITION.
* --------------------------------------------------------------------
* Write log using specified message (using only first two message
* values)
* --------------------------------------------------------------------
DEFINE LOG_WRITE.
RSAL_SAVE_SUBRC = SY-SUBRC.
RSAL_S_LOGPARMS-MSGTY = &1.
RSAL_S_LOGPARMS-MSGID = &2.
RSAL_S_LOGPARMS-MSGNO = &3.
RSAL_S_LOGPARMS-MSGV1 = &4.
RSAL_S_LOGPARMS-MSGV2 = &5.
CALL FUNCTION 'RSAL_LOG_WRITE'
EXPORTING
I_MSGTY = RSAL_S_LOGPARMS-MSGTY
I_MSGID = RSAL_S_LOGPARMS-MSGID
I_MSGNO = RSAL_S_LOGPARMS-MSGNO
I_MSGV1 = RSAL_S_LOGPARMS-MSGV1
I_MSGV2 = RSAL_S_LOGPARMS-MSGV2.
SY-SUBRC = RSAL_SAVE_SUBRC.
END-OF-DEFINITION.
* --------------------------------------------------------------------
* Write message with all message parameters
* --------------------------------------------------------------------
DEFINE LOG_WRITE_FULL.
RSAL_SAVE_SUBRC = SY-SUBRC.
RSAL_S_LOGPARMS-MSGTY = &1.
RSAL_S_LOGPARMS-MSGID = &2.
RSAL_S_LOGPARMS-MSGNO = &3.
RSAL_S_LOGPARMS-MSGV1 = &4.
RSAL_S_LOGPARMS-MSGV2 = &5.
RSAL_S_LOGPARMS-MSGV3 = &6.
RSAL_S_LOGPARMS-MSGV4 = &7.
CALL FUNCTION 'RSAL_LOG_WRITE'
EXPORTING
I_MSGTY = RSAL_S_LOGPARMS-MSGTY
I_MSGID = RSAL_S_LOGPARMS-MSGID
I_MSGNO = RSAL_S_LOGPARMS-MSGNO
I_MSGV1 = RSAL_S_LOGPARMS-MSGV1
I_MSGV2 = RSAL_S_LOGPARMS-MSGV2
I_MSGV3 = RSAL_S_LOGPARMS-MSGV3
I_MSGV4 = RSAL_S_LOGPARMS-MSGV4.
SY-SUBRC = RSAL_SAVE_SUBRC.
END-OF-DEFINITION.
* --------------------------------------------------------------------
* Write log using last error message from 'sy' variables
* without closing log
* --------------------------------------------------------------------
DEFINE LOG_WRITE_ERROR.
RSAL_SAVE_SUBRC = SY-SUBRC.
CALL FUNCTION 'RSAL_LOG_WRITE'.
SY-SUBRC = RSAL_SAVE_SUBRC.
END-OF-DEFINITION.
* --------------------------------------------------------------------
* Write log using last error message from 'sy' variables
* and close log
* --------------------------------------------------------------------
DEFINE LOG_WRITE_ERROR_AND_CLOSE.
RSAL_SAVE_SUBRC = SY-SUBRC.
CALL FUNCTION 'RSAL_LOG_WRITE'
EXPORTING
I_CLOSE_LOG = 'X'.
SY-SUBRC = RSAL_SAVE_SUBRC.
END-OF-DEFINITION.
* --------------------------------------------------------------------
* Write log using last error message from 'sy' variables,
* close log and send message
* --------------------------------------------------------------------
define log_write_error_close_message.
rsal_save_subrc = sy-subrc.
call function 'RSAL_LOG_WRITE'
exporting
i_close_log = 'X'.
message id sy-msgid type sy-msgty number sy-msgno
with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 raising &1.
sy-subrc = rsal_save_subrc.
end-of-definition.
* --------------------------------------------------------------------
* Write internal log tables to database and close log
* --------------------------------------------------------------------
DEFINE LOG_CLOSE.
RSAL_SAVE_SUBRC = SY-SUBRC.
CALL FUNCTION 'RSAL_LOG_CLOSE'.
SY-SUBRC = RSAL_SAVE_SUBRC.
END-OF-DEFINITION.
* --------------------------------------------------------------------
* Rollback previous database operations write internal log
* tables to database and close log
* --------------------------------------------------------------------
DEFINE LOG_CLOSE_AND_ROLLBACK.
RSAL_SAVE_SUBRC = SY-SUBRC.
ROLLBACK WORK.
CALL FUNCTION 'RSAL_LOG_CLOSE'.
SY-SUBRC = RSAL_SAVE_SUBRC.
END-OF-DEFINITION.
Ahora guarda y activa el módulo de función. Hasta ahí, ya tenemos la parte ABAP culminada y procedemos a generar la fuente de dato del extractor
Creamos el origen de datos genérico en RSO2 recuerda que el nombre que escojas es lo que vas colocar en el código de la función.
Incluimos el componente de aplicación, es necesario que completes los campos de descripción y para incluir la estructura y nuestro módulo de función presionamos el botón EXTRACCION VIA MF
Presionamos el botón DELTA GENERICO para generar el extractor DELTA y marcamos las siguientes opciones. Para el caso del número de componente tienes que preguntar al funcional o según el detalle de la especificación.
La función del Delta Genérico en los extractores es definir un campo de la tabla que se va a utilizar como base para la obtención (extracción) de registros nuevos. Así si por ejemplo se define un campo “Fecha de Creación” para el delta genérico y los datos que se extraen cada vez que se ejecuta el extractor son los que se crearon desde la última fecha que se ejecuto, en vez de hacer un “full”, es decir obtener todos los datos de la tabla cada vez que se ejecuta el mismo. A este tipo de extracción se la denomina extracción “Delta”.