Estimados SAPers,
SAP entregó un componente dedicado llamado Gestión de disputas dentro del módulo FSCM para gestionar las diferencias (es decir, disputas) que surgen durante la compensación de pagos recibidos y facturas de clientes. Gestión de disputas utiliza el componente Gestión de casos como base técnica para tramitar los casos de controversia. El propósito de esta publicación es explorar las opciones de mejora detrás de BADI SCMG_CHNG_BFR_STR_C. Esta publicación se centrará principalmente en el uso de este BAdI para la gestión de casos de disputa. Proporcionaré algunas recomendaciones sobre la arquitectura de las mejoras y algunos consejos útiles sobre cómo usar la interfaz de este BAdI de manera eficiente.
Este BAdI utiliza la interfaz IF_EX_SCMG_CHNG_BFR_STR_C con un método CHANGE. La siguiente captura de pantalla muestra la firma del método:
Este BAdI es un BAdI genérico dentro del marco de gestión de casos y se utiliza en muchos procesos. Sin embargo, este BAdI solo puede implementarse una vez, es decir, solo puede existir una implementación activa a la vez. La interfaz utiliza un parámetro de importación FLT_VAL para distinguir entre varios procesos que llaman a este BAdI. Los valores de filtro típicos son:
La siguiente captura de pantalla muestra la implementación de este BAdI:
Si desea usar este BAdI para la implementación de lógica personalizada, le recomiendo que use la clase de implementación para este BAdI solo como un controlador, mientras que la lógica principal debe implementarse en clases globales separadas. Permítanme aclarar lo que quiero decir.
La clase de implementación de BAdI ZCL_IM_SCMG_CHNG_BFR_ST, como se muestra a continuación, solo tiene un propósito: verifica el valor del filtro y enruta la ejecución a otras dos clases globales: ZCL_IM_SCMG_CHNG_BFR_ST_DC y ZCL_IM_SCMG_CHNG_BFR_ST_DCD. La primera clase implementa lógica personalizada para casos de disputa, la segunda para decisiones de crédito documentadas.
¿Cuáles son los beneficios de este enfoque? En mi opinión, el principal beneficio es que la lógica de mejora se divide en clases separadas. Cada clase sigue el principio de responsabilidad única y sabe cómo manejar los objetos de un solo tipo. Esta arquitectura asegura un menor impacto de regresión y significa un menor costo de mantenimiento a largo plazo: si necesita ajustar la lógica para un componente (por ejemplo, casos de disputa), puede estar seguro de que otras funcionalidades no se verán afectadas por estos cambios.
class zcl_im_scmg_chng_bfr_st definition
public
final
create public .
public section.
interfaces if_ex_scmg_chng_bfr_str_c .
protected section.
private section.
endclass.
class zcl_im_scmg_chng_bfr_st implementation.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_IM_SCMG_CHNG_BFR_ST->IF_EX_SCMG_CHNG_BFR_STR_C~CHANGE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_CASE TYPE REF TO IF_SCMG_CASE
* | [--->] FLT_VAL TYPE SCMGPROCESS
* | [!CX!] CX_SCMG_CASE_BADI
* +--------------------------------------------------------------------------------------</SIGNATURE>
method if_ex_scmg_chng_bfr_str_c~change.
constants:
begin of lc_filter,
dispute_case type scmgprocess value 'F_DM',
doc_cred_decision type scmgprocess value 'FDCD',
end of lc_filter.
case flt_val.
when lc_filter-dispute_case.
zcl_im_scmg_chng_bfr_st_dc=>change_dc( im_case ).
when lc_filter-doc_cred_decision.
zcl_im_scmg_chng_bfr_st_dcd=>change_dcd( im_case ).
when others.
return.
endcase.
endmethod.
endclass.
Las capturas de pantalla a continuación muestran cómo se implementó la nueva clase para casos de disputa:
Si eres un consultor funcional y analizas la interfaz de este BAdI por primera vez, puede que te confundas un poco: el método tiene solo un parámetro de importación IM_CASE y normalmente no puedes cambiar los parámetros de este tipo. Además, incluso si coloca un punto de interrupción en el código y verifica la variable IM_CASE en modo de depuración, no encontrará muchos detalles útiles. La siguiente captura de pantalla muestra cómo se ve este parámetro durante la depuración.
La explicación es simple: este método recibe una instancia del caso de disputa. Cada caso de controversia como instancia tiene ciertos atributos (es decir, valores asociados con él) y métodos (es decir, acciones que puede realizar en relación con la instancia). Veamos cómo acceder a estos atributos y cuáles son algunos métodos útiles que puede usar para obtener/establecer los valores de ciertos atributos.
Si desea verificar el valor de algún atributo, puede usar el método GET_SINGLE_ATTRIBUTE_VALUE. Recuperará el valor actual del atributo, por ejemplo, quién es el coordinador del caso de disputa. De manera similar, puede usar otro método GET_SINGLE_OLD_ATTR_VALUE para recuperar el valor del atributo antes de que se cambiara. Vea dos ejemplos a continuación:
try.
data lv_coordinator type udmcaseattr00-fin_coordinator.
lv_coordinator = im_case->get_single_attribute_value( 'FIN_COORDINATOR' ).
catch cx_srm_framework .
catch cx_scmg_case_attribute .
endtry.
try.
data lv_previous_coordinator type udmcaseattr00-fin_coordinator.
lv_previous_coordinator = im_case->get_single_old_attr_value( 'FIN_COORDINATOR' ).
catch cx_srm_framework .
catch cx_scmg_case_attribute .
endtry.
La lista de campos para estos métodos está esencialmente limitada por la lista de campos en las siguientes dos tablas:
(1) Atributos de casos genéricos, es decir, tabla SCMG_T_CASE_ATTR.
(2) Atributos de casos específicos de la aplicación: UDMCASEATTR00 – atributos de los casos de disputa, Reino UnidoM_DCD_ATTR – atributos de la decisión de crédito del documento, etc.
La primera tabla almacena atributos comunes, por ejemplo, tipo de caso, referencia externa, detalles administrativos (quién creó, quién cambió y cuándo, etc.). La segunda tabla almacena atributos que son específicos de un tipo de caso determinado (p. ej., caso de disputa).
Técnicamente hablando, la tabla específica de la aplicación depende de la configuración del perfil de atributo asociado con su caso. Puede consultar la configuración en la transacción S_SE3_50000032 o vista de mantenimiento SCMGVC_ATTRPROF (SM34).
Cuando hace referencia a estas variables en el código, puede utilizar diferentes enfoques. Según las reglas de su proyecto: puede hacer referencia al nombre de la variable directamente (p. ej., RESPONSABLE); puede usar una constante de la interfaz IF_SCMG_CASE o puede usar el atributo de caso directamente.
data lv_responsible type scmg_t_case_attr-responsible.
lv_responsible = im_case->get_single_attribute_value( 'RESPONSIBLE' ).
lv_responsible = im_case->get_single_attribute_value( if_scmg_case=>if_scmg_case_read~responsible ).
lv_responsible = im_case->get_single_attribute_value( im_case->responsible ).
Puede revisar la lista de constantes disponibles en la interfaz IF_SCMG_CASE a través de la transacción SE24:
Hay algunos otros métodos estándar para obtener ciertos atributos. Por ejemplo, hay métodos predefinidos para obtener el tipo de caso, crear el usuario, crear la fecha, el GUID del caso, la última fecha de cambio/usuario. Estos métodos son atajos útiles y no necesita reinventar la lógica desde cero.
Aquí también hay un consejo útil en el camino. A menudo es necesario verificar si BAdI se ejecuta durante la creación inicial del caso o en un modo de cambio. Puedes hacer una comprobación sencilla: obtener GUID del caso (es decir, identificador global) y seleccione cualquier atributo (p. ej., tipo de caso) de la tabla SCMG_T_CASE_ATTR. Cuando se ejecuta el BAdI durante la creación del caso, el GUID del caso ya está asignado, pero esta tabla aún está vacía. Si la selección falla, significa que el BAdI se ejecuta en modo creación.
" We already have a Case GUID at this point, but no entries in DB
data lv_guid type udmcaseattr00-case_guid.
lv_guid = im_case->get_guid( ).
data lv_case_type type scmg_t_case_attr-case_type.
select single case_type
from scmg_t_case_attr
into lv_case_type
where case_guid = lv_guid.
if sy-subrc <> 0.
" BAdI is executed in creation mode.
endif.
Otro requisito común es verificar si el usuario cambió el caso. ¿Por qué necesitarías hacer eso? La respuesta es bastante simple. La lógica de mejora a menudo se basa en la suposición de que el usuario cambia el caso y esta acción desencadena algunos cambios adicionales (por ejemplo, flujo de trabajo, notificación por correo electrónico, cambio de algunos atributos, etc.). Sin embargo, si simplemente abre el caso de disputa en modo de cambio a través de la transacción SAP GUI UDM_DISPUTE o a través de la aplicación Fiori F0702A “Administrar caso de disputa” y guarde el caso sin cambiar nada, esta acción también activará la ejecución de BAdI. Esto podría conducir a algunos cambios automáticos no deseados. Para evitar eso, puede usar el método estándar IS_CHANGED. Vea el código de muestra a continuación:
" Method definition
class-methods is_changed
importing
im_case type ref to if_scmg_case
returning
value(rv_yes) type abap_bool.
" Method implementation
method is_changed.
try.
if im_case->is_changed( ) = abap_true.
rv_yes = abap_true.
endif.
catch cx_srm_framework .
endtry.
endmethod.
" Use of the check in the main method
method change_dc.
" Check if dispute case was changed
if is_changed( im_case ) = abap_false.
return.
endif.
endmethod.
También hay un método setter que le permite cambiar el valor de los atributos de caso. Puede usar el método SET_SINGLE_ATTRIBUTE_VALUE para cambiar el valor del atributo de caso. El código fuente a continuación muestra cómo actualizar el valor del título del caso:
try.
im_case->set_single_attribute_value(
im_srmadid = im_case->case_title
im_value="Case Title: New Value" ).
catch cx_srm_framework .
catch cx_scmg_case_attribute .
endtry.
La gran ventaja de usar este BAdI es que puede actualizar muchos atributos diferentes dentro de la misma mejora. El módulo FSCM proporciona muchos BAdI diferentes que se pueden usar para actualizar solo un atributo específico (p. ej., prioridad de caso, referencias externas, procesador, etc.). La siguiente captura de pantalla muestra la lista de estos BAdI en el menú de configuración. En mi opinión, es mejor usar una mejora para administrar la lógica personalizada para los casos de disputa frente a muchas mejoras que actualizan solo un atributo. Con una mejora central, ahorra tiempo en la administración/documentación de los WRICEF y tiene mejor visibilidad/control sobre la lógica de mejora.
Cada caso de disputa tiene enlaces a una variedad de objetos en disputa que incluyen, entre otros, un socio comercial, un artículo residual y una factura de cliente. Vea la captura de pantalla a continuación:
Estos enlaces se almacenan en la tabla. FDM_DCOBJ. Vea la captura de pantalla a continuación con el contenido de muestra de la tabla:
Si necesita información adicional sobre el objeto en disputa para su lógica de mejora, puede implementar un método de utilidad dentro de la clase de implementación de BAdI que seleccionará la clave del objeto y la analizará en la partida del documento contable. El código fuente de muestra para este método se proporciona a continuación.
" Definition of the global type
types:
begin of ty_fidoc_key,
belnr type belnr_d,
bukrs type bukrs,
gjahr type gjahr,
buzei type buzei,
end of ty_fidoc_key.
" Definition of utility method
class-methods get_related_doc_key
importing
im_case type ref to if_scmg_case
iv_classification type fdm_classification
returning
value(rs_fidoc) type ty_fidoc_key.
" Implementation of utility method
method get_related_doc_key.
data lv_guid type udmcaseattr00-case_guid.
lv_guid = im_case->get_guid( ).
data lv_obj_key type fdm_dcobj-obj_key.
" Get object key of related payment documlent
select single obj_key
from fdm_dcobj
into lv_obj_key
where case_guid_loc = lv_guid
and obj_type="BSEG"
and classification = iv_classification.
" Parse object key into FI document key
if sy-subrc = 0 and strlen( lv_obj_key ) = 21.
rs_fidoc-bukrs = lv_obj_key(4).
rs_fidoc-belnr = lv_obj_key+4(10).
rs_fidoc-gjahr = lv_obj_key+14(4).
rs_fidoc-buzei = lv_obj_key+18(3).
endif.
endmethod.
" Use of utility method in the main method
method change_dc.
" Get the link to linked case object
data ls_fidoc_key type ty_fidoc_key.
ls_fidoc_key = get_related_doc_key(
im_case = im_case
iv_classification = fdmco_disp_residual ).
endmethod.
FDMCO_DISP_RESIDUAL – es una constante global definida por SAP para el campo FDM_DCOBJ-CLASSIFICATION, que se utiliza para indicar el elemento residual. El grupo de tipos FDMCO almacena la lista completa de estas constantes globales que se pueden usar en su mejora:
Estoy mencionando este aspecto sobre los objetos en disputa a propósito aquí. Hay una gran limitación con respecto a este BAdI. Cuando se ejecuta en modo creación, el GUID del caso de disputa ya está asignado, pero la tabla FDM_DCOBJ aún no está llena. Por lo tanto, no puede acceder a estos objetos durante la creación del caso de disputa, solo puede acceder a ellos en el modo de modificación. Si necesita acceder a los atributos de los objetos en disputa durante la creación del caso de disputa, le recomiendo usar BAdI FDM_AR_DISP_COMPLETE. Este BAdI se ejecuta antes que SCMG_CHNG_BFR_STR_C y ofrece muchas opciones de mejora. El método COMPLETE_DISPUTE del BAdI FDM_AR_DISP_COMPLETE tiene un parámetro T_OBJECTS, que almacena la lista de objetos en disputa.
Además de los atributos del caso y los objetos en disputa, es posible que también necesite acceder a los textos explicativos del caso. Antes de acceder a los textos largos, debe conocer el ID del texto. Puede verificar la configuración del perfil de texto asociado con el caso de disputa en la transacción S_SE3_50000056 (o vista de mantenimiento SCMGVC_TEXTPROF, SM34). Si no sabe qué perfil de texto se está utilizando, consulte la personalización del tipo de caso de disputa en la transacción S_SE3_50000059 (o vista de mantenimiento SCMGV_CTYPE_PPF, SM30). Vea la captura de pantalla del perfil de texto de muestra a continuación:
Puedes reutilizar la FM BDM_DISPUTE_NOTES_GET para obtener el texto asociado con el caso de disputa. Vea el código fuente de muestra a continuación:
" Get the value of case notes
data ls_return type bapiret2.
data lt_notes type bdm_t_notes.
call function 'BDM_DISPUTE_NOTES_GET'
exporting
im_guid = lv_guid
importing
es_return = ls_return
et_notes = lt_notes .
if lines( lt_notes ) = 0.
return.
endif.
data lv_text type string.
field-symbols <i> like line of lt_notes.
loop at lt_notes assigning <i> where tdobject="SCMG_CASE" and tdid = '0001'. " 0001 is a text ID
" Skip the first line
if sy-tabix = 1.
continue.
endif.
" Contcatenate the lines
if <i>-tdline="" or <i>-tdline na sy-abcde.
continue.
else.
lv_text = <i>-tdline && lv_text.
endif.
endloop.
Los datos de texto se almacenan en la tabla LT_NOTES. Se debe omitir la primera línea del texto. Este es un subtítulo generado automáticamente para el texto.
Nota: si está utilizando el sistema S4 HANA y la aplicación Fiori F0702A “Administrar caso de disputa” para mantener textos largos, no genera esta línea técnica. Por lo tanto, no hay necesidad de saltarse la primera línea.
Espero que no te arrepientas del tiempo que dedicaste si llegaste al final de esta publicación y aprendiste algo útil. Quedo atento a sus comentarios y observaciones.
Saludos,
Bohdan
Calle Eloy Gonzalo, 27
Madrid, Madrid.
Código Postal 28010
Paseo de la Reforma 26
Colonia Juárez, Cuauhtémoc
Ciudad de México 06600
Real Cariari
Autopista General Cañas,
San José, SJ 40104
Av. Jorge Basadre 349
San Isidro
Lima, LIM 15073