Los documentos de cambio protocolan automáticamente los cambios de datos en SAP. Permiten el seguimiento completo de cambios en objetos de negocio para auditoría y cumplimiento.
Conceptos de documentos de cambio
| Concepto | Descripción |
|---|---|
| Objeto de documento de cambio | Definición de las tablas a protocolar |
| Documento de cambio | Entrada de protocolo individual |
| CDHDR | Tabla de cabecera de documentos de cambio |
| CDPOS | Tabla de posiciones (cambios de campos) |
Transacciones importantes
| Transacción | Descripción |
|---|---|
| SCDO | Mantener objetos de documento de cambio |
| SCU3 | Mostrar documentos de cambio (genérico) |
| RSSCD100 | Evaluar documentos de cambio |
Ejemplos básicos
Escribir documento de cambio
DATA: ls_order_old TYPE zorder, ls_order_new TYPE zorder, lv_objectid TYPE cdhdr-objectid.
" Leer datos antiguos (antes del cambio)SELECT SINGLE * FROM zorder INTO ls_order_old WHERE order_id = '1000000001'.
" Establecer nuevos datosls_order_new = ls_order_old.ls_order_new-status = 'C'. " Modificadols_order_new-amount = 1500.
" Object-ID para documento de cambiolv_objectid = ls_order_old-order_id.
" Abrir documento de cambioCALL FUNCTION 'CHANGEDOCUMENT_OPEN' EXPORTING objectclass = 'ZORDER' objectid = lv_objectid planned_change_number = ' ' planned_or_real_changes = 'R'.
" Protocolar cambiosCALL FUNCTION 'CHANGEDOCUMENT_SINGLE_CASE' EXPORTING tablename = 'ZORDER' workarea_old = ls_order_old workarea_new = ls_order_new change_indicator = 'U'. " Update
" Cerrar y guardar documento de cambioCALL FUNCTION 'CHANGEDOCUMENT_CLOSE' EXPORTING objectclass = 'ZORDER' objectid = lv_objectid date_of_change = sy-datum time_of_change = sy-uzeit tcode = sy-tcode username = sy-uname EXCEPTIONS no_position_found = 1 OTHERS = 2.
IF sy-subrc = 0. " Cambiar datos realmente UPDATE zorder FROM ls_order_new. COMMIT WORK.ENDIF.Módulo de funciones generado
" Después de la definición SCDO se genera FB: ZORDER_WRITE_DOCUMENT
DATA: ls_order_old TYPE zorder, ls_order_new TYPE zorder, lt_xorder TYPE TABLE OF zorder, lt_yorder TYPE TABLE OF zorder.
" Cambio de registro individualCALL FUNCTION 'ZORDER_WRITE_DOCUMENT' EXPORTING objectid = ls_order_new-order_id tcode = sy-tcode utime = sy-uzeit udate = sy-datum username = sy-uname upd_zorder = 'U' " Update TABLES xzorder = lt_xorder " Datos nuevos yzorder = lt_yorder " Datos antiguos EXCEPTIONS OTHERS = 1.Cambios para Insert (Creación)
DATA: ls_order_new TYPE zorder.
" Crear nuevo pedidols_order_new-order_id = '1000000002'.ls_order_new-customer_id = 'CUST001'.ls_order_new-status = 'O'.ls_order_new-amount = 1000.
" Old-Record vacío indica InsertDATA(ls_order_old) = VALUE zorder( ).
CALL FUNCTION 'CHANGEDOCUMENT_OPEN' EXPORTING objectclass = 'ZORDER' objectid = ls_order_new-order_id.
CALL FUNCTION 'CHANGEDOCUMENT_SINGLE_CASE' EXPORTING tablename = 'ZORDER' workarea_old = ls_order_old workarea_new = ls_order_new change_indicator = 'I'. " Insert
CALL FUNCTION 'CHANGEDOCUMENT_CLOSE' EXPORTING objectclass = 'ZORDER' objectid = ls_order_new-order_id date_of_change = sy-datum time_of_change = sy-uzeit tcode = sy-tcode username = sy-uname.
INSERT zorder FROM ls_order_new.COMMIT WORK.Cambios para Delete (Eliminación)
DATA: ls_order_old TYPE zorder.
SELECT SINGLE * FROM zorder INTO ls_order_old WHERE order_id = '1000000001'.
" New-Record vacío indica DeleteDATA(ls_order_new) = VALUE zorder( ).
CALL FUNCTION 'CHANGEDOCUMENT_OPEN' EXPORTING objectclass = 'ZORDER' objectid = ls_order_old-order_id.
CALL FUNCTION 'CHANGEDOCUMENT_SINGLE_CASE' EXPORTING tablename = 'ZORDER' workarea_old = ls_order_old workarea_new = ls_order_new change_indicator = 'D'. " Delete
CALL FUNCTION 'CHANGEDOCUMENT_CLOSE' EXPORTING objectclass = 'ZORDER' objectid = ls_order_old-order_id date_of_change = sy-datum time_of_change = sy-uzeit tcode = sy-tcode username = sy-uname.
DELETE FROM zorder WHERE order_id = ls_order_old-order_id.COMMIT WORK.Protocolar múltiples tablas
DATA: ls_header_old TYPE zorder_head, ls_header_new TYPE zorder_head, lt_items_old TYPE TABLE OF zorder_item, lt_items_new TYPE TABLE OF zorder_item.
" Abrir documento de cambioCALL FUNCTION 'CHANGEDOCUMENT_OPEN' EXPORTING objectclass = 'ZORDER' objectid = ls_header_new-order_id.
" Protocolar datos de cabeceraCALL FUNCTION 'CHANGEDOCUMENT_SINGLE_CASE' EXPORTING tablename = 'ZORDER_HEAD' workarea_old = ls_header_old workarea_new = ls_header_new change_indicator = 'U'.
" Protocolar posicionesLOOP AT lt_items_new INTO DATA(ls_item_new). READ TABLE lt_items_old INTO DATA(ls_item_old) WITH KEY item_id = ls_item_new-item_id.
IF sy-subrc = 0. " Posición modificada CALL FUNCTION 'CHANGEDOCUMENT_SINGLE_CASE' EXPORTING tablename = 'ZORDER_ITEM' workarea_old = ls_item_old workarea_new = ls_item_new change_indicator = 'U'. ELSE. " Nueva posición CALL FUNCTION 'CHANGEDOCUMENT_SINGLE_CASE' EXPORTING tablename = 'ZORDER_ITEM' workarea_old = VALUE zorder_item( ) workarea_new = ls_item_new change_indicator = 'I'. ENDIF.ENDLOOP.
" Posiciones eliminadasLOOP AT lt_items_old INTO ls_item_old. READ TABLE lt_items_new TRANSPORTING NO FIELDS WITH KEY item_id = ls_item_old-item_id.
IF sy-subrc <> 0. CALL FUNCTION 'CHANGEDOCUMENT_SINGLE_CASE' EXPORTING tablename = 'ZORDER_ITEM' workarea_old = ls_item_old workarea_new = VALUE zorder_item( ) change_indicator = 'D'. ENDIF.ENDLOOP.
CALL FUNCTION 'CHANGEDOCUMENT_CLOSE' EXPORTING objectclass = 'ZORDER' objectid = ls_header_new-order_id date_of_change = sy-datum time_of_change = sy-uzeit tcode = sy-tcode username = sy-uname.Leer documentos de cambio
DATA: lt_cdhdr TYPE TABLE OF cdhdr, lt_cdpos TYPE TABLE OF cdpos.
" Leer datos de cabeceraSELECT * FROM cdhdr INTO TABLE lt_cdhdr WHERE objectclas = 'ZORDER' AND objectid = '1000000001' ORDER BY udate DESCENDING, utime DESCENDING.
" Leer datos de posiciónIF lt_cdhdr IS NOT INITIAL. SELECT * FROM cdpos INTO TABLE lt_cdpos FOR ALL ENTRIES IN lt_cdhdr WHERE objectclas = lt_cdhdr-objectclas AND objectid = lt_cdhdr-objectid AND changenr = lt_cdhdr-changenr.ENDIF.
" SalidaLOOP AT lt_cdhdr INTO DATA(ls_cdhdr). WRITE: / 'Cambio del:', ls_cdhdr-udate, ls_cdhdr-utime, 'por:', ls_cdhdr-username.
LOOP AT lt_cdpos INTO DATA(ls_cdpos) WHERE changenr = ls_cdhdr-changenr. WRITE: / ' Campo:', ls_cdpos-fname, 'Anterior:', ls_cdpos-value_old(20), 'Nuevo:', ls_cdpos-value_new(20). ENDLOOP.ENDLOOP.Documentos de cambio con clase
CLASS zcl_change_document DEFINITION. PUBLIC SECTION. METHODS log_change IMPORTING iv_objectid TYPE cdhdr-objectid is_old TYPE any is_new TYPE any iv_tablename TYPE tabname iv_operation TYPE cdchngind. " I/U/DENDCLASS.
CLASS zcl_change_document IMPLEMENTATION. METHOD log_change. CALL FUNCTION 'CHANGEDOCUMENT_OPEN' EXPORTING objectclass = 'ZORDER' objectid = iv_objectid.
CALL FUNCTION 'CHANGEDOCUMENT_SINGLE_CASE' EXPORTING tablename = iv_tablename workarea_old = is_old workarea_new = is_new change_indicator = iv_operation.
CALL FUNCTION 'CHANGEDOCUMENT_CLOSE' EXPORTING objectclass = 'ZORDER' objectid = iv_objectid date_of_change = sy-datum time_of_change = sy-uzeit tcode = sy-tcode username = sy-uname EXCEPTIONS no_position_found = 1 OTHERS = 2. ENDMETHOD.ENDCLASS.Mostrar documentos de cambio vía ALV
DATA: lt_display TYPE TABLE OF ty_change_display.
SELECT h~objectid, h~udate, h~utime, h~username, h~tcode, p~tabname, p~fname, p~chngind, p~value_old, p~value_new FROM cdhdr AS h INNER JOIN cdpos AS p ON h~objectclas = p~objectclas AND h~objectid = p~objectid AND h~changenr = p~changenr WHERE h~objectclas = 'ZORDER' AND h~udate BETWEEN @lv_from_date AND @lv_to_date INTO CORRESPONDING FIELDS OF TABLE @lt_display ORDER BY h~udate DESCENDING, h~utime DESCENDING.
" Mostrar ALVcl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) CHANGING t_table = lt_display ).
lo_alv->display( ).Protocolar cambios de texto
" Para textos largos (ej. notas)DATA: lv_text_old TYPE string VALUE 'Texto antiguo', lv_text_new TYPE string VALUE 'Texto nuevo más largo'.
CALL FUNCTION 'CHANGEDOCUMENT_OPEN' EXPORTING objectclass = 'ZORDER' objectid = lv_objectid.
" Protocolar cambio de textoCALL FUNCTION 'CHANGEDOCUMENT_TEXT_CASE' EXPORTING textcase = 'X' text_old = lv_text_old text_new = lv_text_new tablename = 'ZORDER' fieldname = 'NOTES' change_indicator = 'U'.
CALL FUNCTION 'CHANGEDOCUMENT_CLOSE' EXPORTING objectclass = 'ZORDER' objectid = lv_objectid date_of_change = sy-datum time_of_change = sy-uzeit tcode = sy-tcode username = sy-uname.Definir objeto de documento de cambio en SCDO
1. Llamar transacción SCDO2. Ingresar nombre de objeto: ZORDER3. Agregar tablas: - ZORDER_HEAD (Tabla de cabecera) - ZORDER_ITEM (Tabla de posiciones)4. Marcar campos a protocolar5. Generar módulo de funciones6. Activar y transportarProtocolización de cambios masivos
" Para cambios masivosCALL FUNCTION 'CHANGEDOCUMENT_OPEN' EXPORTING objectclass = 'ZORDER' objectid = '*MASS*'. " ID especial
LOOP AT lt_changes INTO DATA(ls_change). CALL FUNCTION 'CHANGEDOCUMENT_SINGLE_CASE' EXPORTING tablename = 'ZORDER' workarea_old = ls_change-old_data workarea_new = ls_change-new_data change_indicator = 'U' objectid = ls_change-order_id. " Por registroENDLOOP.
CALL FUNCTION 'CHANGEDOCUMENT_CLOSE' EXPORTING objectclass = 'ZORDER' objectid = '*MASS*' date_of_change = sy-datum time_of_change = sy-uzeit tcode = sy-tcode username = sy-uname.Indicadores de cambio
| Indicador | Descripción |
|---|---|
| I | Insert (Creación) |
| U | Update (Modificación) |
| D | Delete (Eliminación) |
| E | Cambio de campo individual |
Estructura CDPOS
| Campo | Descripción |
|---|---|
| OBJECTCLAS | Objeto de documento de cambio |
| OBJECTID | ID de objeto |
| CHANGENR | Número de cambio |
| TABNAME | Nombre de tabla |
| FNAME | Nombre de campo |
| CHNGIND | Indicador de cambio |
| VALUE_OLD | Valor anterior |
| VALUE_NEW | Valor nuevo |
Mejores prácticas
- Campos relevantes: Solo protocolar campos relevantes para el negocio
- Rendimiento: Escribir documentos de cambio en update task
- Object-ID: Usar ID único y descriptivo
- Archivado: Archivar documentos de cambio antiguos (SARA)
- Permisos: Proteger acceso de lectura a documentos de cambio
- Cumplimiento: Observar requisitos de períodos de retención
Temas relacionados
- Application Logging - Protocolización de aplicaciones
- Lock Objects - Gestión de bloqueos
- Verificación de autorizaciones - Control de acceso
- Desarrollo BAPI - Procesamiento de documentos