Solicitud de Pedido – Obtener liberador y fecha de liberación

Caso: Se desea obtener el usuario que liberó una solicitud de pedido de compras, junto a la fecha de realizada la liberación.

Solución: Se obtiene la info de las tablas de documentos de modificación (CDHDR y CDPOS), se debe tener en cuenta que podrían haber más de una liberación de la solicitud en este log, ya que puede un usuario liberar, otro desliberar (cancelar la liberación anterior) y luego liberar nuevamente, pero lo dejo como ejemplo para ver el tema.

Asimismo puede hacerse para otros documentos de modificación, puede verse el listado en la transacción SCDO. Para nuestro ejemplo utilizaremos BANF.

FORM obtener_liberador USING    p_banfn  TYPE banfn
					   p_bnfpo  TYPE bnfpo  
					   p_afnam  TYPE afnam  
 
                       CHANGING p_username TYPE cdhdr-username
					   p_udate    TYPE cdhdr-udate.
 
  DATA: lv_tabix       TYPE sy-tabix,
        lv_tabkey      TYPE cdpos-tabkey,
        lt_cdhdr       TYPE TABLE OF cdhdr,
        wa_cdhdr       TYPE cdhdr,
        lt_cdpos       TYPE TABLE OF cdpos,
        wa_cdpos       TYPE cdpos.
 
      REFRESH: lt_cdhdr[],
               lt_cdpos[].
 
      TRANSLATE p_afnam TO UPPER CASE.
 
      SELECT *
        INTO TABLE lt_cdhdr
        FROM cdhdr
        WHERE objectclas  = 'BANF'
          AND objectid    = lw_solpe-banfn
          AND langu       = sy-langu.
 
      IF lt_cdhdr IS NOT INITIAL.
        SELECT *
          INTO TABLE lt_cdpos
          FROM cdpos
          FOR ALL ENTRIES IN lt_cdhdr
          WHERE objectclas      = lt_cdhdr-objectclas
            AND objectid        = lt_cdhdr-objectid
            AND changenr        = lt_cdhdr-changenr
            AND chngind         = lt_cdhdr-change_ind
            AND tabname         = 'EBAN'
            AND fname           = 'FRGKZ'
            AND value_new       = '2'.
 
        IF sy-subrc EQ 0.
          CONCATENATE sy-mandt 
			    p_banfn
                      p_bnfpo
                      INTO lv_tabkey.
 
          READ TABLE lt_cdpos INTO wa_cdpos WITH KEY tabkey = lv_tabkey.
          IF sy-subrc EQ 0.
            READ TABLE lt_cdhdr INTO wa_cdhdr WITH KEY objectclas = wa_cdpos-objectclas
                                                       objectid   = wa_cdpos-objectid
                                                       changenr   = wa_cdpos-changenr.
            IF sy-subrc EQ 0.
              p_username  = wa_cdhdr-username.
              p_udate     = wa_cdhdr-udate.
            ENDIF.
          ENDIF.
        ENDIF.
 
      ENDIF.
 
    ENDLOOP.
 
  ENDIF.
 
ENDFORM.                    "obtener_liberador

 

Nota: el SELECT a la CDPOS debe evaluarse con respecto al campo “value_new” ya que el código de liberacón puede ser distinto según como esté configurada la estrategia de liberación. En mi caso estaba el 2 como “Liberado”. Verificarlo buscando en la tabla CDPOS con un ejemplo de Solicitud de Pedido ya liberada.

También pueden usar las funciones que aparecen en:

http://help.sap.com/saphelp_nw04/helpdata/EN/2a/fa01dd493111d182b70000e829fbfe/content.htm

O ver el código del programa estándar CHANGEDOCU_READ

Categorías:ABAP/4 Etiquetas: , , , , , , , , ,

MB52 – Agregar campo en ALV

Caso: se desea agregar el campo ubicación (MARD-LGPBE) al reporte ALV de la transacción estándar MB52.

Solución:

El reporte tiene dos visualizaciones: jerárquica y no jerárquica. Para el primer caso, dejo el campo oculto (para que el usuario lo pueda agregar si lo desea) y en el segundo caso lo agregaré visible, antes del campo Lote.

1. Crear la implementación, modificando el fieldcat

a. Para reporte no-jerárquico

Vamos al report RM07MLBS y buscar el ENHANCEMENT-SECTION RM07MLBS_11 SPOTS ES_RM07MLBS y crear una implementación como se muestra en la imagen (en este caso el campo lo agrega luego del campo “Material”), agregando una llamada a macro_fill_fieldcat con el nuevo campo.

Yo agregué el campo luego del campo lote y para eso lo hice sin usar la macro, agregándolo al fieldcat directamente con código -ya que el col_pos está fijo sumando 1 en la macro-). O sea:

fieldcat-COL_POS = '9'.
fieldcat-fieldname = 'LGPBE'.
fieldcat-tabname = 'BESTAND'.
fieldcat-ref_tabname = 'MARD'.
fieldcat-no_out = space.
 
if not fieldcat-seltext_l is initial.
move : fieldcat-seltext_l to fieldcat-seltext_m,
fieldcat-seltext_l to fieldcat-seltext_s.
endif.
append fieldcat. clear fieldcat.

b. Para reporte jerárquico

Vamos al report RM07MLBS y buscamos el ENHANCEMENT-POINT RM07MLBS_1 SPOTS ES_RM07MLBS. Creamos una implementación y agregamos un nuevo campo al catálogo:

CLEAR fieldcat.
fieldcat-fieldname = 'LGPBE'.
fieldcat-tabname = 'BESTAND'.
fieldcat-ref_tabname = 'MARD'.
fieldcat-no_out = 'X'.
APPEND fieldcat.

Nota: si queremos modificar los datos de cabecera del reporte jerárquico modificamos el HEADER

2. Buscamos el FORM list_output

Nos posicionamos con el cursor al principio del FORM y vamos al menú “Tratar” -> Operaciones ampliación -> Insertar puntos de ampliación implícitos

Nos deja el código así:

Hacemos click con el botón derecho en las comillas y elegimos ->Implementación ampliación -> Crear implementación. Nos aparece la siguiente pantalla, elegimos “Cod. Fuente”.

3. Copiar el FORM completo

Allí hacemos copy&paste del contenido completo del FORM list_output en la implementación creada y al final ponemos la instrucción:

CHECK 1 = 2.

De esta forma luego de la ejecución de la implementación no se ejecutará el código original

4. Comentar código

Al compilar dará algunos errores, les doy algunos tips:

Comentar los ENHANCEMENT-SECTION y END-ENHANCEMENT-SECTION:

* ENHANCEMENT-SECTION     RM07MLBS_09 SPOTS ES_RM07MLBS.

* END-ENHANCEMENT-SECTION.

* ENHANCEMENT-SECTION     RM07MLBS_10 SPOTS ES_RM07MLBS.

* END-ENHANCEMENT-SECTION.

Yo comenté también esta parte (verificar si está OK):

* ENHANCEMENT-POINT RM07MLBS_2 SPOTS ES_RM07MLBS.
**$*$-Start: RM07MLBS_2————————————————————————–$*$*
* ENHANCEMENT 14  MGV_MATNR_LAMA_RM07MLBS.    “active version
** Modification for PIC-Supersession/MPN
*
*      IF SHOW_EXT_MANUFACTURER EQ ‘X’.
*             CLEAR EMNFR.
*             CALL FUNCTION ‘MPN01_READ_MPN_VIA_MATNR’
*                EXPORTING
**                     I_MATNR            = HEADER-MATNR “DI note 762421
*                     I_MATNR            = bestand-MATNR “DI note 762421
*               IMPORTING
**                    E_MFRPN            =
*                     E_EMNFR            = EMNFR
*                EXCEPTIONS
*                     MATERIAL_IS_NO_MPN = 1.
*
*         IF SY-SUBRC EQ 0.
*            MOVE EMNFR TO HEADER-EMNFR.
*         ENDIF.
*       ENDIF.
* ENDENHANCEMENT.

 

Asimismo modificar el nombre de la variable l_f_check.

*  data : l_f_check_(01)       type c.
data : l_f_check_new(01)       type c.              ” <–

y reeemplazar su uso en:

CALL FUNCTION ‘REUSE_ALV_HIERSEQ_LIST_DISPLAY’
EXPORTING
*            I_INTERFACE_CHECK  = l_f_check
I_INTERFACE_CHECK  = l_f_check_new         ” <–

 

CALL FUNCTION                  alv_detail_func
EXPORTING
*        I_INTERFACE_CHECK          = l_f_check
I_INTERFACE_CHECK          = l_f_check_new     ” <–

5. Crear una nueva tabla interna con los campos nuevos a agregar

Creamos una nueva tabla interna con el/los nuevos campos a agregar (en nuestro caso sólo es el campo MARD-LGPBE) y lo usamos en la llamada del ALV. Para nuestro ejemplo para el reporte jerárquico y no-jerárquico, debo crear una tabla BESTAND_NEW para agregar el campo LGPBE:

 

DATA: BEGIN OF bestand_new OCCURS 0,
*        Key fields
matnr LIKE mara-matnr,
werks LIKE t001w-werks,
lgort LIKE mard-lgort,
         LGPBE               like mard-LGPBE,    ”  Campo ubicación
         sobkz LIKE mkol-sobkz,
ssnum               like  bickey-ssnum,            “n531604
pspnr               like  mspr-pspnr,              “n531604
vbeln               like  mska-vbeln,              “n531604
posnr               like  mska-posnr,              “n531604
lifnr LIKE mkol-lifnr,
kunnr LIKE msku-kunnr,
kzbws LIKE mssa-kzbws,
charg LIKE mchb-charg,
*        Additional data (texts, unit, …)
maktx LIKE marav-maktx,
bwkey LIKE mbew-bwkey,
mtart LIKE marav-mtart,
matkl LIKE marav-matkl,
meins LIKE marav-meins,
bwtty LIKE marc-bwtty,
xchar LIKE marc-xchar,
lgobe LIKE t001l-lgobe,
bwtar LIKE mcha-bwtar,
waers LIKE t001-waers,
name1 LIKE t001w-name1,
*        Quantities and currencies
labst LIKE mard-labst,
wlabs LIKE mbew-salk3,
insme LIKE mard-insme,
winsm LIKE mbew-salk3,
speme LIKE mard-speme,
wspem LIKE mbew-salk3,
einme LIKE mard-einme,
weinm LIKE mbew-salk3,
retme LIKE mard-retme,
wretm LIKE mbew-salk3,
umlme LIKE mard-umlme,
wumlm LIKE mbew-salk3,
glgmg LIKE marc-glgmg,                             “n912093
wglgm LIKE mbew-salk3,                             “n912093
trame LIKE marc-trame,                             “n912093
wtram LIKE mbew-salk3,                             “n912093
umlmc LIKE marc-umlmc,                             “n912093
wumlc LIKE mbew-salk3,                             “n912093
*        Dummy field
dummy               TYPE  ALV_DUMMY,
*        Colour
farbe TYPE slis_t_specialcol_alv,
lvorm               like  mard-lvorm,
*        valuated blocked GR stock                       “AC0K020254
bwesb               like  marc-bwesb,           “AC0K020254
wbwesb              like  mbew-salk3,           “AC0K020254
matnr_40            type text40,                “DI note 1160649
END OF bestand_new.

 

6. Agregar el código para obtener el nuevo campo

Finalmente antes de la llamada del ALV, copio los valores de BESTAND a BESTAND_NEW y le agrego el campo nuevo, agregando la lógica luego del BREAK-POINT ID MMIM_REP_MB52:

 

BREAK-POINT ID MMIM_REP_MB52.                             "n912093
 
DATA: BEGIN OF ubicacion OCCURS 0,
matnr LIKE mara-matnr,
werks LIKE t001w-werks,
lgort LIKE mard-lgort,
LGPBE like mard-LGPBE,
END OF ubicacion.
REFRESH: ubicacion[],
bestand_new[].
 
SELECT matnr werks lgort lgpbe
INTO CORRESPONDING FIELDS OF TABLE ubicacion
FROM mard
FOR ALL ENTRIES IN bestand
WHERE matnr = bestand-matnr
AND werks = bestand-werks
AND lgort = bestand-lgort.
 
LOOP AT bestand.
CLEAR bestand_new.
MOVE-CORRESPONDING bestand TO bestand_new.
 
READ TABLE ubicacion WITH KEY matnr = bestand-matnr
werks = bestand-werks
lgort = bestand-lgort.
IF sy-subrc EQ 0.
bestand_new-lgpbe = ubicacion-lgpbe.
ENDIF.
 
APPEND bestand_new.
ENDLOOP.

7. Modificar la tabla interna en las llamadas al ALV

Finalmente en las llamadas al ALV ahora cambia la tabla interna:

TABLES
t_outtab_item      = bestand_new “bestand

y

TABLES
T_OUTTAB                   = bestand_new ” bestand

 

PD: en lugar de agregar la nueva estructura BESTAND_NEW no me fijé, pero capaz podía ampliarse la actual BESTAND agregando el nuevo campo.
Link: http://scn.sap.com/thread/2072130

Enviar Mail simple con SO_DOCUMENT_SEND_API1

Caso: Se desea enviar un mail en formato HTML.

Solución: se define un form ENVIAR_MAIL, que recibe como parámetros una lista de destinatarios y un texto adicional para incluir en el cuerpo del mensaje.

*&———————————————————————*
*&      Form  ENVIAR_MAIL
*&———————————————————————*
*       Envía un aviso al usuario que ejecutó el reporte indicando que el proceso terminó
*———————————————————————-*
FORM enviar_mail USING p_mails TYPE char100       ” Destinatarios
p_texto TYPE char255.      ” Texto dinámico para el cuerpo del mail

DATA: lt_docs            TYPE TABLE OF docs,
ls_doc_chng        LIKE sodocchgi1,
ld_tab_lines       LIKE sy-tabix,
lt_objtxt          LIKE solisti1 OCCURS 0 WITH HEADER LINE,
lt_objpack         LIKE sopcklsti1 OCCURS 6 WITH HEADER LINE,
ls_body            TYPE solisti1,
lt_body            TYPE TABLE OF solisti1,
lt_recipients      TYPE TABLE OF somlreci1 WITH HEADER LINE,
ls_recipients      TYPE somlreci1.
DATA ld_subject(50)      TYPE c VALUE ‘Asunto del mail!!!’.
DATA ld_body(255)        TYPE c.
DATA lv_sender           TYPE soextreci1-receiver.
DATA lv_len              TYPE          i.
DATA lv_ofset            TYPE          i.
DATA lv_char(1).

CLEAR: ls_doc_chng, ls_body, lt_recipients, ld_tab_lines, lv_sender.
REFRESH: lt_body, lt_recipients, lt_objpack, lt_objtxt.

*———————————————————————-*
* CONTROL DATA (Datos de cabecera del mail)
*———————————————————————-*
ls_doc_chng-obj_name = ‘URGENT’.
ls_doc_chng-sensitivty = ‘P’.
ls_doc_chng-no_change = ‘X’.
ls_doc_chng-priority = ’1′.
ls_doc_chng-obj_prio = ’1′.
ls_doc_chng-obj_langu = sy-langu.
ls_doc_chng-no_change = ‘X’.

*———————————————————————-*
* SUBJECT (Asunto del mail)
*———————————————————————-*
**    Email Subject
ls_doc_chng-obj_descr = ld_subject.     ” Ver variable definida con valor constante arriba

*———————————————————————-*
* BODY (Cuerpo del mail, en HTML)
*———————————————————————-*
CLEAR ls_body.
MOVE ‘<html><body>’ TO ls_body-line.
APPEND ls_body TO lt_body.

CLEAR ls_body.
CONCATENATE ‘<p>’ ‘Resultados de la ejecución del reporte</p>’
INTO ls_body-line.
APPEND ls_body TO lt_body.

CLEAR ls_body.
APPEND ls_body TO lt_body.
CLEAR ls_body.
CONCATENATE ‘<p>’ p_texto ‘</p>’
INTO ls_body-line SEPARATED BY space.
APPEND ls_body TO lt_body.

CLEAR ls_body.
APPEND ls_body TO lt_body.
CLEAR ls_body.
CONCATENATE ‘<p>’ ‘Este correo se ha generado en forma automática, por favor no responder</p>’
INTO ls_body-line SEPARATED BY space.
APPEND ls_body TO lt_body.

CLEAR ls_body.
MOVE  ‘</body></html>’ TO ls_body-line.
APPEND ls_body TO lt_body.

* Armo el HTML
lt_objtxt[] = lt_body[].
CLEAR lt_objtxt.
DESCRIBE TABLE lt_objtxt LINES ld_tab_lines.

IF ld_tab_lines GT 0.
READ TABLE lt_objtxt INDEX ld_tab_lines.
ls_doc_chng-doc_size =  ( ld_tab_lines - 1 ) * 255 + STRLEN( lt_objtxt ).
CLEAR lt_objpack-transf_bin.
lt_objpack-head_start = 1.
lt_objpack-head_num = 0.
lt_objpack-body_start = 1.
lt_objpack-body_num = ld_tab_lines.
lt_objpack-doc_type = ‘HTM’.
APPEND lt_objpack.
ENDIF.

*———————————————————————-*
*RECIPIENTS (Destinatarios del mail separados por ;)
*———————————————————————-*
lv_sender = ‘aaaa@aaaaa.com’.       ” Indicar el mail origen

CLEAR lt_recipients.
lv_len = STRLEN( p_mails ).          ” p_mails tiene direcciones de correo separadas por “;”
DO lv_len TIMES.
lv_ofset = sy-index - 1.
lv_char = p_mails+lv_ofset(1).
CHECK lv_char IS NOT INITIAL.
IF lv_char = ‘;’.
CONDENSE lt_recipients-receiver.
lt_recipients-rec_type    = ‘U’.
lt_recipients-rec_date    = sy-datum.
APPEND lt_recipients.
CLEAR lt_recipients.
CONTINUE.
ENDIF.
CONCATENATE lt_recipients-receiver lv_char INTO lt_recipients-receiver.
IF lv_len = sy-index.
CONDENSE lt_recipients-receiver.
lt_recipients-rec_type    = ‘U’.
lt_recipients-rec_date    = sy-datum.
APPEND lt_recipients.
ENDIF.
ENDDO.

CALL FUNCTION ‘SO_DOCUMENT_SEND_API1′
EXPORTING
document_data              = ls_doc_chng
put_in_outbox              = ‘X’
sender_address             = lv_sender
sender_address_type        = ‘SMTP’
commit_work                = ‘X’
TABLES
packing_list               = lt_objpack
contents_txt               = lt_objtxt
receivers                  = lt_recipients
EXCEPTIONS
too_many_receivers         = 1
document_not_sent          = 2
document_type_not_exist    = 3
operation_no_authorization = 4
parameter_error            = 5
x_error                    = 6
enqueue_error              = 7
OTHERS                     = 8.

IF sy-subrc EQ 0.
FORMAT: COLOR COL_POSITIVE, INTENSIFIED ON.
WRITE: /1 ‘El mail fue enviado con éxito’.
ELSE.
FORMAT: COLOR COL_NEGATIVE, INTENSIFIED ON.
WRITE: /1 ‘No se pudo enviar mail’.
ENDIF.

ENDFORM.                    ” ENVIAR_MAIL

[end]

Debug de Proceso de Fondo / JOB

Caso: Se desea ejecutar un reporte como proceso de fondo (JOB) y luego debuggearlo.

Solución: Previamente necesitamos permisos para el debug de jobs activos , más precisamente el objeto S_ADMI_FCD (PADM – Process administration para las transacciones SM04 y SM50).

Si tenemos los permisos, entonces:

1. Si el JOB está corriendo, vamos a la transacción SM50 y marcamos el checkbox del proceso que corre nuestro JOB y vamos a la opción del menú Program/Mode->Program->Debugging.

Allí comenzará el debug.

2.- Si el job ya finalizo podemos debugearlo desde la SM37 seleccionando el job y escribiendo la transacción JDBG.

Si el job es demasiado rápido para poder pillarlo por la SM50 un truco es programar el job por SM36 usando dos pasos y siendo el primer paso el report de bucle standard BTCLOOP, al comenzar el debug solo tendremos que salir del bucle de este report.

Fuente: http://www.mundosap.com/foro/showthread.php?t=5154

Buscar errores en SAP

Caso: a veces nos reportan un error o incidencia en SAP y no nos indican el código de error e intuimos que es un mensaje o estándar o Z que se puede encontrar en la SE91.

Solución: podemos ingresar a la tabla T100, buscando parte del nombre del error (recordar que con & se muestran los datos variables)

Allí podemos encontrar los distintos tipos de error que poseen el string buscado…

Categorías:ABAP/4 Etiquetas: , , , , , ,

GGB1 – Sustitución Bloqueo de Pago (BSEG-ZLSPR)

Caso: se desea que para algunos casos, el bloqueo de pago en la MIRO se desactive, es decir: por defecto existe un bloqueo de pago (A – Bloqueado el pago) para todos documentos ingresados por la MIRO, pero se desea que en algunos casos ese campo (BSEG-ZLSPR) sea vacío (“” Autorizado el pago)

Datos adicionales:

1. Se debe revisar el bloqueo de pago en la rama del árbol indicada en la siguiente imagen, ya que en la primera opción se indica si ese campo puede ser modificable en pantalla o no y la segunda opción los valores por defecto por condición de pago.

a. En Definir causas del bloqueo de pago (OB27)

b. En Definir valores propuestos para bloqueo de pago

2. Asimismo se debe verificar el bloqueo de pago que posea el proveedor, ya que puede tener uno por defecto también.

Solución: Intenté activar la sustitución por documento completo, pero parece que hay que hacerlo a nivel de posición.

Para ello:

1. Ingresar a la transacción SM30 y actualizar la vista VWTYGB01. Va a salir el mensaje ” Atención, la tabla es válida en todos los mandantes” darle OK.

Buscar el campo BSEG-ZLSPR y destildarle la opción “Excluir”. Grabar el cambio (va a solicitar orden de transporte). Con esto dejamos que en las sustituciones se pueda seleccionar este campo.

PD: Ver la transacción OB32. No la revisé bien, pero ahí también parece que se puede determinar el campo ZLSPR como modificable, aunque parece que para FI y no para aplicar una sustitución.

2. Ingresar a la transacción GGB1 para crear la sustitución

Creamos una sustitución de valor constante, agregando un paso en “Posición documento”, indicando la condición necesaria y en Sustitución agregando el campo BSEG-ZLSPR que aparecerá gracias al paso anterior (en el ejemplo es el paso 003).

Grabamos, para transportar hay que posicionarse en la Sustitución creada (en este caso Z000001) e ir al menú “Sustitución-Transportar” mediante orden de transporte.

3. Ingresar a la transacción GGB4 y seleccionar la opción “Activación valid./sust”.

Luego seleccionar “Contabilidad Financiera” y “Sustitución”

Para el caso se debe verificar que para la sociedad requerida, la sustitución está activa (con el valor 1).

4. Finalmente probamos la sustitución. Recuerden que si lo prueban en Desarrollo deben pasar las órdenes con la SCC1.

Ingresamos a la MIRO, completamos los datos, vemos que por defecto aparece el bloqueo de pago A (bloqueado el pago) ya que la condición que yo tenía en el sistema era Z030 y esa indica que corresponde ese bloqueo.

Luego de contabilizar el documento, ingreso a revisarlo por la MIR4 y…

Posdata: revisar que la condición de pago ha quedado vacía, supongo que al sustituir el bloqueo termina borrando la condición de pago…

Links:

http://sapinfohelps.blogspot.com/2009/04/substitution-payment-block-bseg-zlspr.html

http://scn.sap.com/thread/1288094

 

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.