Business Workflow : récupérer les workitems en cours

Si vous souhaitez récupérer tous les workitems d’une instance workflow en cours, vous pouvez alors utiliser le module fonction « SAP_WAPI_WORKITEMS_TO_OBJECT ».

Publicités

Business Workflow : terminer une instance workflow

Si vous souhaitez mettre un terme à une instance workflow en cours, vous avez la possibilité de l’annuler à l’aide du module fonction « SWW_WI_ADMIN_CANCEL ».

CALL FUNCTION ‘SWW_WI_ADMIN_CANCEL’
EXPORTING
wi_id = iv_wiid
EXCEPTIONS
update_failed = 1
no_authorization = 2
infeasible_state_transition = 3
OTHERS = 4.

IF sy-subrc EQ 0.
COMMIT WORK.
ENDIF.

Business Workflow : mettre un workflow en attente et le redémarrer via un événement spécifique

Lorsque vous développez un workflow, vous pouvez être amené à vouloir mettre en attente votre workflow pour le redémarrer ultérieurement lors d’un événement particulier (cela est par exemple le cas si vous souhaitez initier un workflow et le mettre immédiatement en attente à la création d’un document pour le redémarrer plus tard (à la validation du document, suivant une action manuelle utilisateur, etc.)).

Entrez en modification sur votre Business Object et créez l’événement permettant le redémarrage du workflow :

Renseignez les informations générales de l’événement :

Procédez à l’implémentation de l’événement :

L’événement est implémenté :

Entrez en modification sur votre workflow et créez votre étape d’attente :

Spécifiez l’élément de conteneur (correspondant généralement à l’objet BOR principal de votre workflow) ainsi que l’événement permettant le redémarrage du workflow) :

L’étape d’attente est ajoutée :

Une fois le workflow démarré, on peut voir que celui-ci est immédiatement en attente :

Nous pouvons vérifier cela via le protocole du workflow :

On récupère la clé du Business Object pour pouvoir le redémarrer :

Relance du workflow (via bapi SWE_EVENT_CREATE) :

Le workflow est relancé :

On peut vérifier cela via le protocole du workflow :

Exemple d’utilisation de la bapi « SWE_EVENT_CREATE »

REPORT  ylaunch_wkf.

PARAMETERS:
p_pernr     TYPE pernr_d,
p_tripno    TYPE reinr.

TYPES:
* Déclaration des types locaux :
BEGIN OF lty_objkey,
pernr     TYPE pernr_d, « Matricule
tripno    TYPE reinr,   « N° déplacement
END OF lty_objkey.

DATA:
* Déclaration des structures locales :
stl_objkey  TYPE lty_objkey,
* Déclaration des variables locales :
lv_objkey   LIKE sweinstcou-objkey.

stl_objkey-pernr = p_pernr.
stl_objkey-tripno = p_tripno.

lv_objkey = stl_objkey.

CALL FUNCTION ‘SWE_EVENT_CREATE’
EXPORTING
objtype = ‘BUS2089’
objkey = lv_objkey
event = ‘TRIPREQUESTED’
* CREATOR = ‘ ‘
* TAKE_WORKITEM_REQUESTER = ‘ ‘
* START_WITH_DELAY = ‘ ‘
* START_RECFB_SYNCHRON = ‘ ‘
* NO_COMMIT_FOR_QUEUE = ‘ ‘
* DEBUG_FLAG = ‘ ‘
* NO_LOGGING = ‘ ‘
* IDENT =
* IMPORTING
* EVENT_ID =
* TABLES
* EVENT_CONTAINER =
EXCEPTIONS
objtype_not_found = 1
OTHERS = 2
.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ELSE.
WRITE ‘Event Triggered’.
ENDIF.
COMMIT WORK.

 

Abap OO : collection – utilisation des Maps

En tant qu’abapeurs avisés vous connaissez très probablement les collections avec la classe CL_OBJECT_COLLECTION mais connaissez-vous les maps ? Il s’agit en fait d’un type particulier de collection qui contrairement à la classe CL_OBJECT_COLLECTION vous permettra d’accéder à un élément particulier via sa clé au sein de la map. Vous pourrez ainsi créer vos propres classes collections reprenant le principe de la map en héritant de la classe CL_OBJECT_MAP.

Si vous souhaitez en savoir un peu plus, c’est par là que ça se passe : http://scn.sap.com/community/abap/application-development/objects/blog/2012/01/04/abap-objects-rumble-in-the-jungle–internal-table-against-collection

Business Workflow : délégation

Lorsque l’on créé un workflow se basant sur un Business Object, on peut avoir besoin de customiser ce dernier. Pour ce faire, nous allons créer un nouveau Business Object en tant que sous-type du Business Objet d’origine et pour lequel on appliquera une délégation afin que ce nouveau Business Object (customisable à souhait) soit automatiquement utilisé en lieu et place de l’original.

Tout d’abord, dirigez-vous en SWO1, renseigner le nom de votre Business Object d’origine et cliquez sur le bouton « Sous-type » :

Renseignez les informations concernant le Business Object à créer :

Passez le statut de libération du type d’objet à « Implémenté » :

Le Business Object étant désormais créer, il nous faut maintenant l’assigner en tant que délégué du Business Object d’origine. Pour ce faire, dirigez-vous dans le menu « Options » et sélectionnez « Délégation » :

Passez en mode modification :

Cliquez sur « Nouvelles entrées » :

Assignez enfin votre Business Object fraîchement créé en tant que type de délégation du Business Object d’origine :

C’est tout ! Ainsi, dès lors que le Business Object d’origine sera sollicité, on passera désormais automatiquement par votre Business Object custom et non plus par celui d’origine 😉

Business Workflow : récupération d’un Workitem ID

Une fois un workflow lancé, il est parfois nécessaire de pouvoir avoir accès à son conteneur afin de le lire ou de le modifier. Pour ce faire, nous avons besoin de récupérer le workitem ID.

Le workitem ID peut être récupéré à l’aide de la bapi SAP_WAPI_WORKITEMS_TO_OBJECT via les paramètres suivants :

  • Type d’objet (OBJTYPE)
  • Clé d’objet (OBJKEY)

Les workitems ID correspondant sont retournés dans la table WORKLIST :

Business Workflow : tracer les événements exécutés durant une transaction

Dans un très grand nombre de transactions standards, SAP lance différents évènements d’objets BOR.

C’est par exemple le cas :

  • A la création/modification d’une commande de vente
  • A la création/modification d’un article
  • Etc.

Une fois ces évènements identifiés, libre à vous de les lier à un workflow (standard ou spécifique) afin que ce dernier puisse être démarré dès lors que l’évènement en question aura été lancé.

Identification des évènements lancés durant une transaction

Pour pouvoir identifier de façon certaine le ou les évènements lancés durant l’exécution d’une transaction, il vous faut procéder à une trace d’évènements.

Pour ce faire, lancer la transaction SWELS (Event Trace) et cliquez sur « Activer » :

La popup suivante devrait alors apparaître, validez :

Exécutez ensuite votre transaction pour laquelle vous souhaitez identifier les événements lancés, revenez en SWELS (Event Trace) et désactivez votre trace :

La trace étant maintenant enregistrée, il nous faut l’afficher. Pour ce faire, lancez la transaction SWEL (Afficher trace des évènements) :

On distingue alors les évènements lancés avec leurs objets BOR :

Adobe Interactive Forms : validation via e-mails

Les formulaires interactifs Adobe peuvent être utilisés de deux façons différentes :

  • Online : intégré par exemple dans une application Web Dynpro
  • Offline : renvoyé par exemple au serveur SAP par le biais d’un mail ou d’un Web Service

Nous verrons ici comment renvoyer au serveur SAP les données renseignées au sein du pdf via l’utilisation d’un e-mail.

Soit par exemple la table spécifique YTADOBE_FROM_WS qui contiendra un ensemble de noms/prénoms et qui sera alimentée par un pdf interactif :

La première étape consiste en la création d’une bapi permettant la mise à jour de cette table :

On retrouve en entrée le nom et le prénom à enregistrer :

On retourne le code retour de l’opération :

Mise à jour de la table :

La bapi étant maintenant créée et opérationnelle, la seconde étape consiste en création de la classe d’extraction des données du PDF. Pour ce faire, nous pouvons nous baser sur la classe standard CL_FP_INBOUND_HANDLER qui pourra vous donner un bon exemple de ce qu’il est possible de faire.

La classe doit implémenter l’interface IF_INBOUND_EXIT_BCS :

Ajouter une instance statique à votre propre classe parmi les attributs :

Implémentez la méthode IF_INBOUND_EXIT_BCS~CREATE_INSTANCE comme suit :

Enfin, implémentez la méthode IF_INBOUND_EXIT_BCS~PROCESS_INBOUND afin d’y coder votre logique d’extraction des données du PDF :

METHOD if_inbound_exit_bcs~process_inbound.

TYPE-POOLS:
*   Pull in the iXML type group :
ixml.

DATA:
*   Déclaration des objets locaux :
lo_document       TYPE REF TO if_document_bcs,
lo_fp             TYPE REF TO if_fp,
lo_pdfobj         TYPE REF TO if_fp_pdf_object,
lo_converter      TYPE REF TO cl_abap_conv_in_ce,
lo_ixml           TYPE REF TO if_ixml,
lo_streamfactory  TYPE REF TO if_ixml_stream_factory,
lo_istream        TYPE REF TO if_ixml_istream,
lo_xml_document   TYPE REF TO if_ixml_document,
lo_parser         TYPE REF TO if_ixml_parser,
lo_node           TYPE REF TO if_ixml_node,
*   Déclaration des structures locales :
ls_pdf_table      TYPE bcss_dbpc,
ls_pdf_line       TYPE solix,
*   Déclaration des variables locales :
lv_pdf_xstring    TYPE xstring,
lv_pdf_form_data  TYPE xstring,
lv_formxml        TYPE string,
lv_strchecked     TYPE string,
lv_nom            TYPE text50,
lv_prenom         TYPE text50.

* Get the email document that was sent :
lo_document = io_sreq->get_document( ).

* Get the interactive form attachment.
ls_pdf_table = lo_document->get_body_part_content( 2 ).

CLEAR lv_pdf_xstring.
* Convert the pdf table into an xstring.
LOOP AT ls_pdf_table-cont_hex INTO ls_pdf_line.
CONCATENATE lv_pdf_xstring ls_pdf_line-line INTO lv_pdf_xstring IN BYTE MODE.
ENDLOOP.

* Get a reference to the form processing class :
lo_fp = cl_fp=>get_reference( ).

* Get a reference to the PDF Object class :
lo_pdfobj = lo_fp->create_pdf_object( ).
* Set the pdf in the PDF Object :
lo_pdfobj->set_document( pdfdata = lv_pdf_xstring ).
* Set the PDF Object to extract data the Form data :
lo_pdfobj->set_extractdata( ).
* Execute call to ADS :
lo_pdfobj->execute( ).

* Get the PDF Form data.
lo_pdfobj->get_data( IMPORTING formdata = lv_pdf_form_data ).
* Convert the xstring form data to string so it can be processed using the iXML classes :
lo_converter = cl_abap_conv_in_ce=>create( input = lv_pdf_form_data ).
lo_converter->read( IMPORTING data = lv_formxml ).

* Get a reference to iXML object :
lo_ixml = cl_ixml=>create( ).

* Get iStream object from StreamFactory :
lo_streamfactory = lo_ixml->create_stream_factory( ).
lo_istream = lo_streamfactory->create_istream_string( lv_formxml ).

* Create an XML Document class that will be used to process the XML :
lo_xml_document = lo_ixml->create_document( ).

* Create the Parser class :
lo_parser = lo_ixml->create_parser( stream_factory = lo_streamfactory
istream = lo_istream
document = lo_xml_document ).

* Parse the XML
lo_parser->parse( ).

* Recherche de la balise « NOM » dans la structure du PDF :
lo_node = lo_xml_document->find_from_name( name = ‘NOM’ ).
* Récupération de la valeur :
lv_nom = lo_node->get_value( ).
* Recherche de la balise « PRENOM » dans la structure du PDF :
lo_node = lo_xml_document->find_from_name( name = ‘PRENOM’ ).
* Récupération de la valeur :
lv_prenom = lo_node->get_value( ).

* Mise à jour des données :
CALL FUNCTION ‘YCALLBACK_ADOBE_FORM’
EXPORTING
i_nom    = lv_nom
i_prenom = lv_prenom.

ENDMETHOD.

Votre classe d’extraction du pdf est prête, il ne reste plus qu’à effectuer le paramétrage permettant de préciser au système que lorsqu’un mail entrant arrive et que celui-ci est assigné à un certain destinataire (nous voulons par exemple extraire et intégrer les pdf qui sont seulement envoyé à « process_pdf@mycompany.com »), il faut alors passer dans notre classe de traitement.

Pour cela, dirigez-vous en transaction SO50 et précisez-y le nom de votre classe de traitement associé à l’adresse e-mail du destinataire concerné :

Cette adresse e-mail doit être associée à un utilisateur SAP de type « SERVICE » et ayant le profil « S_A.SCON » :

Les mails destinés à notre adresse de traitement (par exemple « process_pdf@mycompany.com) devant arriver dans SAP, il ne vous reste plus qu’à créer une règle de routage au niveau de votre serveur SMTP pour rediriger ces e-mails du serveur SMTP vers SAP 😉

Parce que rien ne vaut un exemple concret pour illustrer tout cela, une petite démo s’impose !

Soit la table YTADOBE_FROM_WS :

Nous voulons créer « Monsieur Test 6 », pour ce faire renseignez le formulaire avec les données concernant ce monsieur et cliquez sur l’enveloppe afin d’envoyer le formulaire par e-mail :

Cliquez sur « Joindre » :

Un nouveau message Outlook est préchargé à l’écran avec le formulaire en pièce jointe, l’utilisateur peut ainsi y préciser l’adresse e-mail du destinataire (en fait l’adresse que vous aurez paramétré au niveau de votre serveur SMTP via votre règle de routage SMTP vers SAP), un sujet ainsi qu’un corps :

Après envoie, on peut voir que le mail apparait bien dans la file d’attente des mails entrants via la transaction SOIN :

En double cliquant sur la pièce jointe le formulaire apparaît :

A la réception du mail entrant, on passe alors dans notre classe paramétrée en SO50 et l’entrée est créée :

Ci-dessous la classe CL_FP_INBOUND_HANDLER qui pourra également sans doute vous être utile :

Méthode CREATE_INSTANCE :

METHOD if_inbound_exit_bcs~create_instance.

IF cl_fp_inbound_handler=>instance IS INITIAL.
CREATE OBJECT cl_fp_inbound_handler=>instance.
ENDIF.
ro_ref = cl_fp_inbound_handler=>instance.

ENDMETHOD.

Méthode PROCESS_INBOUND :

METHOD if_inbound_exit_bcs~process_inbound.

DATA: lo_document             TYPE REF TO if_document_bcs,
lo_sender               TYPE REF TO if_sender_bcs,
ls_body_part_attributes TYPE        bcss_dbpa,
ls_body_part_content    TYPE        bcss_dbpc,
lv_ad_smtpadr           TYPE        ad_smtpadr,
lv_hex                  TYPE        solix,
lv_pdf                  TYPE        fpcontent,
lv_log_handle           TYPE        balloghndl,
ls_bal_msg              TYPE        bal_s_msg,
lv_counter              TYPE        i,
lv_ctr_pdf              TYPE        i,
lv_doc_type(3)          TYPE        c,
lv_log_entry(255)       TYPE        c,
lv_value                TYPE        string,
lx_document_bcs         TYPE REF TO cx_document_bcs,
lx_fp_offline           TYPE REF TO cx_fp_offline.

* get email
lo_document = io_sreq->get_document( ).
* initialize application log
lv_log_handle  = int_create_log( ).
lv_log_entry   = ‘Email-Eingangsverarbeitung gestartet …'(001).
ls_bal_msg-msgty    = ‘I’.
ls_bal_msg-detlevel = 1.
int_add_log( iv_log_handle = lv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry  ).
CLEAR lv_log_entry.
* log general information about the email
* sender
lo_sender = io_sreq->get_sender( ).
lv_log_entry = ‘Absender: &'(002).
lv_value = lo_sender->address_string( ).
REPLACE ‘&’ WITH lv_value INTO lv_log_entry.
ls_bal_msg-detlevel = 2.
int_add_log( iv_log_handle = lv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry  ).
* recipients
LOOP AT it_recipients INTO lv_ad_smtpadr.
lv_log_entry = ‘Empfänger: &'(003).
REPLACE ‘&’ WITH lv_ad_smtpadr INTO lv_log_entry.
int_add_log( iv_log_handle = lv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry  ).
ENDLOOP.
* subject
lv_value     = lo_document->get_subject( ).
lv_log_entry = ‘Titel: &'(004).
REPLACE ‘&’ WITH lv_value INTO lv_log_entry.
ls_bal_msg-detlevel = 2.
int_add_log( iv_log_handle = lv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry  ).
CLEAR ls_body_part_content.
CLEAR ls_bal_msg.

* get all email parts
lv_counter = lo_document->get_body_part_count( ).

* find all PDF attachments and process them
DO lv_counter TIMES.
CLEAR ls_body_part_content.
CLEAR ls_body_part_content.
TRY.
ls_body_part_attributes = lo_document->get_body_part_attributes( im_part = sy-index  ).
lv_doc_type = ls_body_part_attributes-doc_type.
TRANSLATE lv_doc_type TO UPPER CASE.
IF lv_doc_type = ‘PDF’.
ADD 1 TO lv_ctr_pdf.
lv_log_entry = ‘>Dateiname: &'(005).
REPLACE ‘&’ WITH ls_body_part_attributes-filename INTO lv_log_entry.
ls_bal_msg-msgty    = ‘I’.
ls_bal_msg-detlevel = 2.
int_add_log( iv_log_handle = lv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry ).
ls_body_part_content = lo_document->get_body_part_content( sy-index ).
ENDIF.

CATCH cx_document_bcs INTO lx_document_bcs.
lv_log_entry = lx_document_bcs->get_text( ).
ls_bal_msg-msgty    = ‘E’.
ls_bal_msg-detlevel = 3.
int_add_log( iv_log_handle = lv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry  ).
*       set bcs status & T100 message
es_t100msg-msgid = ‘FPUICHK’.
es_t100msg-msgno = 100.
es_t100msg-msgty = ‘E’.
int_split_message( EXPORTING iv_message_text = lv_log_entry
IMPORTING ev_msgv1        = es_t100msg-msgv1
ev_msgv2        = es_t100msg-msgv2
ev_msgv3        = es_t100msg-msgv3
ev_msgv4        = es_t100msg-msgv4 ).
CLEAR ls_bal_msg.
ENDTRY.

IF ls_body_part_content IS NOT INITIAL.
CLEAR lv_pdf.
*     convert body part to xstring
LOOP AT ls_body_part_content-cont_hex INTO lv_hex.
CONCATENATE lv_pdf lv_hex-line INTO lv_pdf IN BYTE MODE.
ENDLOOP.
TRY.
*         process PDF form
me->int_process_pdf( iv_pdf        = lv_pdf
iv_log_handle = lv_log_handle ).
CATCH cx_fp_offline INTO lx_fp_offline.
IF NOT lx_fp_offline->previous IS INITIAL.
lv_log_entry = lx_fp_offline->previous->get_text( ).
ELSE.
lv_log_entry = lx_fp_offline->get_text( ).
ENDIF.
ls_bal_msg-msgty    = ‘E’.
ls_bal_msg-detlevel = 3.
int_add_log( iv_log_handle = lv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry  ).
CLEAR ls_bal_msg.
*         set bcs status & T100 message
es_t100msg-msgid = ‘FPUICHK’.
es_t100msg-msgno = 100.
es_t100msg-msgty = ‘E’.
int_split_message( EXPORTING iv_message_text = lv_log_entry
IMPORTING ev_msgv1        = es_t100msg-msgv1
ev_msgv2        = es_t100msg-msgv2
ev_msgv3        = es_t100msg-msgv3
ev_msgv4        = es_t100msg-msgv4 ).
CLEAR ls_bal_msg.
ENDTRY.
ENDIF.
ENDDO.
IF  lv_ctr_pdf IS INITIAL.
ls_bal_msg-msgty    = ‘I’.
ls_bal_msg-detlevel = 2.
lv_log_entry        = ‘Kein PDF im Anhang gefunden'(006).
int_add_log( iv_log_handle = lv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry  ).
ENDIF.

CLEAR ls_bal_msg.
lv_log_entry        = ‘… Email-Eingangsverarbeitung beendet'(007).
ls_bal_msg-msgty    = ‘I’.
ls_bal_msg-detlevel = 2.
int_add_log( iv_log_handle = lv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry  ).
* save the application log entries
int_save_log( iv_log_handle = lv_log_handle ).
ENDMETHOD.

Méthode INT_PROCESS_PDF :

METHOD int_process_pdf.

DATA: lo_fp             TYPE REF TO if_fp,
lo_pdf_object     TYPE REF TO if_fp_pdf_object,
lo_handler        TYPE REF TO if_fp_offline,
lv_xml_data       TYPE        fpcontent,
lv_form_name      TYPE        fpname,
lv_handler_name   TYPE        seoclsname,
ls_bal_msg        TYPE        bal_s_msg,
lx_fp_runtime     TYPE REF TO cx_fp_runtime,
lx_sxml           TYPE REF TO cx_sxml_parse_error,
lx_fp_api         TYPE REF TO cx_fp_api,
lx_xslt           TYPE REF TO cx_transformation_error,
lx_dyn_call       TYPE REF TO cx_sy_dyn_call_error,
lv_log_entry(255) TYPE c,
lv_value          TYPE string.

TRY.
*     get forms processing reference
lo_fp = cl_fp=>get_reference( ).

*     create PDF object
lo_pdf_object = lo_fp->create_pdf_object( ).

*     set document, i.e. PDF form
lo_pdf_object->set_document( pdfdata = iv_pdf ).

*     set task ‘extract data’
lo_pdf_object->set_task_extractdata( ).

*     execute, i.e. call ADS
lo_pdf_object->execute( ).

*     get XML data
lo_pdf_object->get_data( IMPORTING formdata = lv_xml_data ).

*     read form name from XML data
lv_form_name        = me->int_find_formname( iv_xmldata = lv_xml_data ).
ls_bal_msg-detlevel = 3.
ls_bal_msg-msgty    = ‘I’.
IF lv_form_name IS INITIAL.
ls_bal_msg-msgty  = ‘E’.
lv_log_entry      = ‘Formularname im Datenstrom nicht gefunden'(008).
int_add_log( iv_log_handle = iv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry ).
EXIT.
ENDIF.
lv_log_entry        = ‘Formularname: &'(009).
REPLACE ‘&’ WITH lv_form_name INTO lv_log_entry.
int_add_log( iv_log_handle = iv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry ).

*     get offline handler
lv_handler_name = cl_fp_wb_helper=>form_get_offline_handler( iv_name = lv_form_name ).
lv_log_entry = ‘Eingangsverarbeitung: &'(010).
REPLACE ‘&’ WITH lv_handler_name INTO lv_log_entry.
int_add_log( iv_log_handle = iv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry ).

*     get handler instance
CALL METHOD (lv_handler_name)=>if_fp_offline~get_instance
RECEIVING
ro_instance = lo_handler.

*     remove form name from XML data
CALL TRANSFORMATION fp_remove_formname
SOURCE XML lv_xml_data
RESULT XML lv_xml_data.

*     invoke offline handler with PDF form and XML data
lv_log_entry = ‘Verarbeitungsanfang…'(011).
int_add_log( iv_log_handle = iv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry ).
lo_handler->handle_pdf( iv_form_name = lv_form_name
iv_pdf       = iv_pdf
iv_xml       = lv_xml_data ).
lv_log_entry = ‘…Verarbeitungsende'(012).
int_add_log( iv_log_handle = iv_log_handle
is_bal_msg    = ls_bal_msg
iv_freetext   = lv_log_entry ).

CATCH cx_fp_runtime INTO lx_fp_runtime.
RAISE EXCEPTION TYPE cx_fp_offline
EXPORTING
textid   = cx_fp_offline=>cx_fp_offline
previous = lx_fp_runtime.
CATCH cx_sxml_parse_error INTO lx_sxml.
RAISE EXCEPTION TYPE cx_fp_offline
EXPORTING
textid   = cx_fp_offline=>cx_fp_offline
previous = lx_sxml.
CATCH cx_fp_api INTO lx_fp_api.
RAISE EXCEPTION TYPE cx_fp_offline
EXPORTING
textid   = cx_fp_offline=>cx_fp_offline
previous = lx_fp_api.
CATCH cx_transformation_error INTO lx_xslt.
RAISE EXCEPTION TYPE cx_fp_offline
EXPORTING
textid   = cx_fp_offline=>cx_fp_offline
previous = lx_xslt.
CATCH cx_sy_dyn_call_error INTO lx_dyn_call.
RAISE EXCEPTION TYPE cx_fp_offline
EXPORTING
textid   = cx_fp_offline=>cx_fp_offline
previous = lx_dyn_call.
ENDTRY.

ENDMETHOD.

Méthode INT_FIND_FORMNAME :

METHOD int_find_formname.

DATA lo_reader TYPE REF TO if_sxml_reader.

CLEAR rv_formname.

lo_reader = cl_sxml_string_reader=>create( iv_xmldata ).

WHILE lo_reader->node_type <> if_sxml_node=>co_nt_final AND rv_formname IS INITIAL.
lo_reader->read_next_node( ).

*   Search node in XML
IF lo_reader->node_type = if_sxml_node=>co_nt_value.
IF lo_reader->prefix = ‘fpoffline’ AND lo_reader->name = ‘form’. « #EC NOTEXT
MOVE lo_reader->value TO rv_formname.
ENDIF.
ENDIF.
ENDWHILE.

ENDMETHOD.

Méthode INT_CREATE_LOG :

METHOD int_create_log.

DATA: ls_log_header TYPE bal_s_log.

* initialization
ls_log_header-object      = ‘FP’.
ls_log_header-aldate_del  = sy-datum + 14.

* Create a new protocol file
CALL FUNCTION ‘BAL_LOG_CREATE’
EXPORTING
i_s_log                 = ls_log_header
IMPORTING
e_log_handle            = rv_log_handle
EXCEPTIONS
log_header_inconsistent = 1
OTHERS                  = 2.
ASSERT sy-subrc = 0.

ENDMETHOD.

Méthode INT_ADD_LOG :

METHOD int_add_log.

DATA: ls_param TYPE bal_s_mdef.

IF NOT iv_freetext IS INITIAL.
*   Vorbelegungen für Meldungen lesen
CALL FUNCTION ‘BAL_GLB_MSG_DEFAULTS_GET’
IMPORTING
e_s_msg_defaults = ls_param.
*   Detaillierungsgrad ändern
IF ls_param-detlevel <> is_bal_msg-detlevel.
ls_param-detlevel = is_bal_msg-detlevel.
*     Vorbelegungen für Meldungen setzen
CALL FUNCTION ‘BAL_GLB_MSG_DEFAULTS_SET’
EXPORTING
i_s_msg_defaults      = ls_param
EXCEPTIONS
defaults_inconsistent = 2
OTHERS                = 3.
ASSERT sy-subrc = 0.
ENDIF.

*   add a log entry as free text to a specific protocol
CALL FUNCTION ‘BAL_LOG_MSG_ADD_FREE_TEXT’
EXPORTING
i_log_handle     = iv_log_handle
i_msgty          = is_bal_msg-msgty
i_text           = iv_freetext
EXCEPTIONS
log_not_found    = 1
msg_inconsistent = 2
log_is_full      = 3
OTHERS           = 4.
ASSERT sy-subrc = 0.

ELSE.
* add a log entry to a specific protocol
CALL FUNCTION ‘BAL_LOG_MSG_ADD’
EXPORTING
i_log_handle     = iv_log_handle
i_s_msg          = is_bal_msg
EXCEPTIONS
log_not_found    = 1
msg_inconsistent = 2
log_is_full      = 3
OTHERS           = 4.
ASSERT sy-subrc = 0.
ENDIF.

ENDMETHOD.

Méthode INT_SAVE_LOG :

METHOD int_save_log.

DATA lt_handle TYPE bal_t_logh.

* Save all collected log entries.
INSERT iv_log_handle INTO TABLE lt_handle.
CALL FUNCTION ‘BAL_DB_SAVE’
EXPORTING
i_save_all       = abap_true
i_t_log_handle   = lt_handle
EXCEPTIONS
log_not_found    = 1
save_not_allowed = 2
numbering_error  = 3
OTHERS           = 4.
ASSERT sy-subrc = 0.

ENDMETHOD.

Méthode INT_SPLIT_MESSAGE :

METHOD int_split_message.

DATA: ls_str      TYPE string,
ls_buff(50) TYPE c.

ls_str  = iv_message_text.

ls_buff = ls_str .
ev_msgv1  = ls_buff.

SHIFT ls_str BY 50 PLACES LEFT.
ls_buff = ls_str.
ev_msgv2 = ls_buff.

SHIFT ls_str BY 50 PLACES LEFT.
ls_buff = ls_str.
ev_msgv3 = ls_buff.

SHIFT ls_str BY 50 PLACES LEFT.
ls_buff = ls_str.
ev_msgv4 = ls_buff.

ENDMETHOD.

Business Workflow : objets et pièces jointes, attacher un lien vers une transaction

A un workitem peut être attaché un ensemble d’objets et pièces jointes :

Nous allons voir aujourd’hui comment attacher un objet qui, lorsque l’on cliquera dessus, nous renverra vers la transaction de notre choix pour un document donné.

Prenons par exemple la transaction TRIP (création d’une demande de déplacement pour un employé) et disons que dès lors qu’une demande de déplacement est faite par l’employé, son manager doit automatiquement recevoir une demande d’autorisation par le biais d’un workitem. Ce workitem devra permettre d’accéder à la transaction TP04 (Demande de déplacement) pour la demande de déplacement concernée.

L’objet pour lequel on souhaite effectuer un CALL TRANSACTION correspond en fait à un objet BOR. En effet, globalement il suffit d’assigner un objet BOR à la liste des pièces jointes de la tâche pour que celui-ci apparaisse automatiquement à la liste des objets et pièces jointes. Lors du clic sur celui-ci, on passera alors dans la méthode DISPLAY de cet objet BOR, méthode au sein de laquelle on aura implémenté notre CALL TRANSACTION.

Création de l’objet BOR

Vous l’aurez compris, la première étape consiste en la création de notre objet BOR qui nous permettra de gérer le CALL TRANSACTION. Pour rappel nous souhaitons donc pouvoir accéder à la transaction TP04 pour la clé matricule/numéro de demande de déplacement.

Création de l’objet BOR en SWO1 :

Création des zones clés :

Lorsque l’on cliquera sur notre objet lié, la méthode DISPLAY de l’objet BOR est automatiquement exécutée, il convient donc de la surcharger en la sélectionnant puis « Traiter >>> Surdéfinir » :

Implémentez-y votre CALL TRANSACTION :

Faites ensuite un petit test :

Ça fonctionne, votre objet BOR est prêt !

Instanciation de l’objet BOR

Notre objet BOR n’est pas l’objet BOR principal de notre workflow. En effet, cet objet n’a été créé qu’afin de nous permettre de pouvoir gérer notre objet attaché et son CALL TRANSACTION. Il nous faut donc prévoir son instanciation. Nous allons gérer cela par l’intermédiaire d’une classe objet.

Création de la classe objet :

Création de la méthode statique d’instanciation de l’objet BOR :

Nous allons ensuite créer une méthode statique chapeau qui appellera notre méthode GET_GENERIC_BOR_INSTANCE et qui sera elle-même appelée dans notre workflow :

Création de la tâche

Nous allons maintenant créer la tâche permettant l’instanciation de l’objet BOR en PFTC :

Dirigez-vous sur l’onglet « Conteneur » et vérifiez que l’objet est bien de type BOR :

Cliquez sur l’icône avec les carrés verts pour effectuer le mapping :

Votre tâche est prête, allez hop on passe au workflow !

Workflow

Entrez en modification sur votre workflow et commencez par créer un nouvel élément dans votre conteneur et correspondant à votre objet BOR spécifique :

Nous allons maintenant créer une nouvelle activité nous permettant d’appeler notre tâche fraichement créée afin de pouvoir instancier notre objet :

Renseignez y votre tâche créée précédemment et cliquez sur « Flux de données (existant) afin d’effectuer le mapping :

Entrez maintenant en modification sur la décision utilisateur afin d’y ajouter l’objet BOR dans la liste des objets liés :

Accédez au flux de données :

Mappez l’objet BOR à l’élément _ATTACH_OBJECTS :

Et voilà, pour le reste ça se fait tout seul, comme on dit y a plus qu’à 😉