Enviar mails desde R/3

Introducción

Enviar correos electrónicos desde R/3 es una tarea sencilla… si sabes cómo. Si no, puede ser algo muy lioso.

El requisito básico es configurar, en la transacción SCOT, un servidor SMTP. Debemos añadir al árbol INT (internet) un objeto SMTP y posteriormente configurarlo: basta con darle un nombre, activar la casilla “Nodo en operación” y especificar en Host y Puerta el nombre o IP del servidor SMTP y el puerto (normalmente el 25).

Pon también, en los tipos de dirección soportados, un * dentro del botón adyacente a la casilla “Internet”. Nada de esto servirá si en el menú de la SCOT > Opciones > Dominio por defecto no ponemos el nombre del dominio desde donde queremos que figure el remitente.

El servidor de correo, por otra parte, deberá estar correctamente configurado y con una adecuada política de permisos, que en ocasiones, dentro de las empresas, es muy restrictivo. De hecho, no me detengo mucho en esto porque esto es responsabilidad de Sistemas y no nuestra, meros picacódigos.

El proceso de enviar el mail en sí admite un montón de parámetros: pero, en aras de la simplicidad, he creado una función que debería funcionar en prácticamente cualquier sistema y que tiene sólo 3 parámetros: destinatario, título y contenido. Control de errores y demás están reducidos al mínimo, pero se pueden añadir a voluntad del programador.

El código

FUNCTION z_send_text_mail.
*"----------------------------------------------------------------------
*"*"Interfase local
*"  IMPORTING
*"     VALUE(EMAIL) TYPE  STRING
*"     VALUE(SUBJECT) TYPE  STRING
*"     VALUE(TEXT) TYPE  STRING
*"----------------------------------------------------------------------
  "as seen on http://cranf.com

  DATA it_packing_list TYPE TABLE OF sopcklsti1 WITH HEADER LINE.
  DATA it_receivers TYPE TABLE OF somlreci1 WITH HEADER LINE.
  DATA it_contents_txt TYPE TABLE OF solisti1 WITH HEADER LINE.
  DATA document_data TYPE sodocchgi1.
  DATA sent_to_all.

  "pasamos el string a tabla
  PERFORM string2table TABLES it_contents_txt USING text.

  "atributos del mensaje
  document_data-obj_langu = sy-langu.
  document_data-obj_name = 'SAPRPT'.
  document_data-obj_descr = subject.
  document_data-sensitivty = 'S'.
  document_data-no_change = space.

  " descripción del body
  CLEAR it_packing_list.
  REFRESH it_packing_list.
  it_packing_list-transf_bin = space.
  it_packing_list-head_start = 1.
  it_packing_list-head_num = 0.
  it_packing_list-body_start = 1.
  DESCRIBE TABLE it_contents_txt LINES it_packing_list-body_num.
  it_packing_list-doc_type = 'TXT'.
  APPEND it_packing_list.

  " destinatario
  CLEAR it_receivers.
  REFRESH it_receivers.
  it_receivers-receiver = email.
  it_receivers-rec_type = 'U'.
  it_receivers-com_type = 'INT'.
  APPEND it_receivers.

  CALL FUNCTION 'SO_NEW_DOCUMENT_ATT_SEND_API1'
    EXPORTING
      document_data              = document_data
      put_in_outbox              = 'X'
      commit_work                = 'X'
    IMPORTING
      sent_to_all                = sent_to_all
    TABLES
      packing_list               = it_packing_list
      contents_txt               = it_contents_txt
      receivers                  = it_receivers
    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.

ENDFUNCTION.

*     _        _             ____  _        _     _
* ___| |_ _ __(_)_ __   __ _|___ \| |_ __ _| |__ | | ___
*/ __| __| '__| | '_ \ / _` | __) | __| _` | '_ \| |/ _ \
*\__ \ |_| |  | | | | | (_| |/ __/| |_ (_| | |_) | |  __/
*|___/\__|_|  |_|_| |_|\__, |_____|\__|__,_|_.__/|_|\___|
*       ASCII Art made |___/ at http://ascii.cranf.net
FORM string2table TABLES ptable USING pstring TYPE string.
  DATA lstring TYPE string.
  DATA loffset TYPE i.
  DATA lofflen TYPE i.
  DATA llimlen TYPE i.
  DATA lchunks TYPE i.
  DATA ltablength TYPE i.
  DATA lstrlength TYPE i.

  lstring = pstring.
  lstrlength = STRLEN( lstring ).

  DESCRIBE FIELD ptable LENGTH ltablength IN CHARACTER MODE.
  lofflen = ltablength.

  lchunks = lstrlength / ltablength.

  WHILE loffset < lstrlength.
    llimlen = ltablength + loffset.
    IF llimlen > lstrlength.
      lofflen = lstrlength - loffset.
    ENDIF.
    ptable = lstring+loffset(lofflen).
    APPEND ptable.
    loffset = loffset + ltablength.
  ENDWHILE.
  CLEAR ptable.

ENDFORM.                    "string2table

Observaciones

El texto puede incluir saltos de línea siempre que se haga uso de saltos de línea adecuados.

Es importante tener en cuenta que la función por sí sola no manda el mail. Debemos invocar un report estándar que se encarga de liberar la cola de correo. En principio esto está, o debería estar configurado, como job periódico. Pero podemos dar un empujoncito creando la siguiente función, que no tiene parámetros, para que los mails se hagan efectivos.

FUNCTION z_mail_launch.

  SUBMIT rsconn01 WITH mode = 'INT' WITH output = '' AND RETURN.

ENDFUNCTION.
Publicado en: SAP Sin comentarios ▼

Porcentaje de IVA a partir del indicador

Introducción

Los que estamos curtidos sabemos que, a veces, los caminos de SAP son inescrutables; pero más por retorcidos que porque no se puedan deducir. Es el caso de los porcentajes que corresponden a los tipos de IVA recogidos en campos MWSKZ. En vez de ser almacenados en una tabla al efecto, pues no. Se marea al programador.

La siguiente rutina deduce el porcentaje correspondiente a un indicador de IVA simplemente conociendo este y el país. Si sy-subrc no vale 0, es que no lo ha encontrado; esto se deberá controlar.

Una advertencia: los valores son devueltos como porcentajes literales, de 0 a 100. Cualquier operación que se realice con ellos deberá ser dividida a su vez por 100 para que el resultado sea correcto.

El código

*     _          _                   _  __   _                
*  __| | ___  __| |_   _  ___ ___   (_)/ /  (_)_   ____ _     
* / _` |/ _ \/ _` | | | |/ __| _ \    / /   | | \ / / _` |    
*| (_| |  __/ (_| | |_| | (__  __/   / /_   | |\ V / (_| |    
* \__,_|\___|\__,_|\__,_|\___|___|  /_/(_)  |_| \_/ \__,_|    
* as seen on http://cranf.com
* ASCII art made at http://ascii.cranf.net
*
FORM deduce_porcentaje_iva USING pland1 pmwskz CHANGING pkbetr LIKE konp-kbetr.

  DATA lvakey LIKE konh-vakey.
  DATA lknumh LIKE konh-knumh.
  CLEAR pkbetr.

  CONCATENATE pland1 pmwskz INTO lvakey SEPARATED BY space.

  SELECT SINGLE knumh
    INTO lknumh
    FROM konh
   WHERE vakey = lvakey.

  IF sy-subrc = 0.
    SELECT SINGLE kbetr INTO pkbetr
      FROM konp
     WHERE knumh = lknumh.
    IF sy-subrc = 0.
      pkbetr = pkbetr / 10.
    ELSE.
      sy-subrc = 2.
    ENDIF.
  ELSE.
    sy-subrc = 1.
  ENDIF.
ENDFORM.
Publicado en: SAP Sin comentarios ▼

Macros para mensajes de batch-input y BAPI

Introducción

La gestión de mensajes en Batch-Input y BAPI es bastante horrorosa, teniendo en cuenta además que utilizan dos estructuras muy similares pero con nombres de campos muy parecidos, lo que suele llevar a confusiones frustrantes cuando intentamos analizar el resultado.

Estas macros permiten gestionar los mensajes de ambos tipo de llamadas unificando criterios y simplificando al máximo el código a utilizar.

Las macros

  • vc_messtab2bapiret messtab bapiret2: mueve una estructura bdcmsgcoll a bapiret2.
  • vc_bapiret2messtab bapiret2 messtab: mueve una estructura bapiret2 a bdcmsgcoll.
  • vc_messtab2mensaje messtab cadenadetexto: construye un mensaje como texto a partir de una estructura bdcmsgcoll.
  • vc_bapiret2mensaje bapiret2 cadenadetexto: construye un mensaje como texto a partir de una estructura bapiret2.

El código

* _     _    ___                 _
*| |__ (_)  / / |__   __ _ _ __ (_)   _ __ ___   ___ ___ ___  __ _  __ _  ___ ___
*| '_ \| | / /| '_ \ / _` | '_ \| |  | '_ ` _ \ / _ \ __| __|/ _` |/ _` |/ _ \ __|
*| |_) | |/ / | |_) | (_| | |_) | |  | | | | | |  __/__ \__ \ (_| | (_| |  __/__ \
*|_.__/|_|_/  |_.__/ \__,_| .__/|_|  |_| |_| |_|\___|___/___/\__,_|\__, |\___|___/
*                         |_|                                      |___/
* as seen in http://glob.cranf.net
* ASCII art made using http://ascii.cranf.net
*
***********************************************************************
DEFINE vc_messtab2bapiret."convierte estructura messtab de BI a bapiret2
  "vc_messtab2bapiret messtab bapiret2.
  "lo hace de línea en línea, no usando tablas
  perform vc_messtab2bapiret using &1 changing &2.
END-OF-DEFINITION.
*
FORM vc_messtab2bapiret USING pbi TYPE bdcmsgcoll
                      CHANGING pbapi TYPE bapiret2.
  pbapi-type = pbi-msgtyp.
  pbapi-id = pbi-msgid.
  pbapi-number = pbi-msgnr.
  pbapi-message_v1 = pbi-msgv1.
  pbapi-message_v2 = pbi-msgv2.
  pbapi-message_v3 = pbi-msgv3.
  pbapi-message_v4 = pbi-msgv4.
ENDFORM.                    "vc_messtab2bapiret
***********************************************************************
DEFINE vc_bapiret2messtab. "convierte estructura bapiret2 a messtab de BI
  "vc_bapiret2messtab bapiret2 messtab.
  "lo hace de línea en línea, no usando tablas
  perform vc_bapiret2messtab using &1 changing &2.
END-OF-DEFINITION.
*
FORM vc_bapiret2messtab USING pbapi TYPE bapiret2
                     CHANGING pbi TYPE bdcmsgcoll.
  pbi-msgtyp = pbapi-type.
  pbi-msgid = pbapi-id.
  pbi-msgnr = pbapi-number.
  pbi-msgv1 = pbapi-message_v1.
  pbi-msgv2 = pbapi-message_v2.
  pbi-msgv3 = pbapi-message_v3.
  pbi-msgv4 = pbapi-message_v4.
ENDFORM.                    "vc_bapiret2messtab
***********************************************************************
DEFINE vc_messtab2mensaje. "convierte estructura messtab en mensaje verbal
  "vc_messtab2mensaje messtab cadenadetexto
  perform vc_messtab2mensaje using &1 changing &2.
END-OF-DEFINITION.
*
FORM vc_messtab2mensaje USING pbi TYPE bdcmsgcoll
                     CHANGING pmensaje.

  DATA lmsgid LIKE sy-msgid.
  DATA lmsgnr LIKE sy-msgno.
  DATA lmensaje LIKE sy-lisel.
  DATA lmsgv1 TYPE symsgv.
  DATA lmsgv2 TYPE symsgv.
  DATA lmsgv3 TYPE symsgv.
  DATA lmsgv4 TYPE symsgv.

  lmsgid = pbi-msgid.
  lmsgnr = pbi-msgnr.
  lmsgv1 = pbi-msgv1.
  lmsgv2 = pbi-msgv2.
  lmsgv3 = pbi-msgv3.
  lmsgv4 = pbi-msgv4.

  CALL FUNCTION 'RPY_MESSAGE_COMPOSE'
    EXPORTING
      language          = sy-langu
      message_id        = lmsgid
      message_number    = lmsgnr
      message_var1      = lmsgv1
      message_var2      = lmsgv2
      message_var3      = lmsgv3
      message_var4      = lmsgv4
    IMPORTING
      message_text      = lmensaje
    EXCEPTIONS
      message_not_found = 1
      OTHERS            = 2.
  IF sy-subrc <> 0.
    CLEAR lmensaje.
  ENDIF.
  pmensaje = lmensaje.
ENDFORM.                    "vc_messtab2mensaje
***********************************************************************
DEFINE vc_bapiret2mensaje."convierte estructura bapiret2 en mensaje verbal
  perform vc_bapiret2mensaje using &1 changing &2.
END-OF-DEFINITION.
*
FORM vc_bapiret2mensaje USING pbapi TYPE bapiret2
                     CHANGING pmensaje.
  DATA lbi TYPE bdcmsgcoll.
  vc_bapiret2messtab pbapi lbi.
  vc_messtab2mensaje lbi pmensaje.
ENDFORM.                    "vc_bapiret2mensaje
***********************************************************************

Shameless self-promotion

Tengo unas estupendas macros para hacer Batch-Input en mi compactador de código BI. Échales un vistazo.

Publicado en: SAP Sin comentarios ▼
[c] Alberto Viñuela Miranda / Cranfcom 2013-2014

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.