Month: September 2019
[Fiori] Transactions and Reports
SE38:
- /UI2/START_URL
- /UI2/START_TCODE
- /UI2/FLP_ADMIN_UI
SICF:
- Frontend-Services:
/sap/bc/ui5_ui5/sap/
- Backend-Services:
/sap/opu/odata/sap/
und/sap/bc/bsp/sap/
Tcodes:
sicf | Pflege des HTTP-Service-Baums (SAP Internet Communication Framework) | |
segw | SAP Gateway Service Builder | |
/n/iwbep/view_log | SAP Gateway Protokoll-Viewer | |
/n/iwfnd/gw_client | SAP Gateway Client | |
/n/iwfnd/apps_log | SAP Gateway Anwendungsprotokoll-Viewer | |
/n/iwfnd/error_log | SAP Gateway Fehlerprotokoll | |
/n/iwfnd/maint_service | Services aktivieren und verwalten | |
/n/iwfnd/cache_cleanup | Bereinigung des Gateway-Modellcache (Frontend) | |
/n/ui2/cust | Customizing für UI-Technologien | |
/n/ui2/flp | SAP Fiori Launchpad | |
/n/ui2/flc | SAP Fiori Launchpad – Prüfungen | |
/n/ui2/flia | Fiori Launchpad: Absichtsanalyse | |
/n/ui2/flpd_cust | Fiori Launchpad: Designer (mandantenüber.) | /n/ui2/flpcm_cust (3170196) |
/n/ui2/flpd_conf | Fiori Launchpad: Designer (mandantenabh.) | /n/ui2/flpcm_conf (3170196) |
/n/ui2/flpcm/cust | FLP-Content-Manager | |
/n/ui2/flpcm/conf | FLP-Content-Manager | |
/n/ui2/semobj | Semantisches Objekt definieren – Kunde | |
/n/ui2/semobj_sap | Semantisches Objekt definieren – SAP | |
/n/ui2/theme_designer | UI Theme Designer | |
swfvisu | Workflow Visualisierungs-Metadaten | |
swfvmd1 | Workflow Visualisierungs-Metadaten |
[ABAP] Find employee subtitutes
cl_swl_substitution=>get_pers_substitutes( EXPORTING i_substituted_person = ls_substituted_person
i_start_date = sy-datum
i_end_date = sy-datum
IMPORTING et_substitutes = DATA(lt_substitutes)
EXCEPTIONS user_not_found = 1 " Benutzer existiert nicht
plan_variant_not_found = 2 " Planvariante ist nicht gepflegt
time_period_not_valid = 3 " Zeitraum ungültig
no_personal_substitution = 4 " Es handelt sich um keine persönliche Vertretung
OTHERS = 5 ).
[ABAP] Leave Request Approval Workflow with Escalation
During the leave request approval process the standard workflow WS12300111 does not include any deadlines. To archieve this you can simply copy the workflow and add a deadline at the approval task (Step 38). There are two possible ways to forward the approval step to the next processor:
1. When deadline is reached, forward the current workitem to the next approver.
2. When deadlines is reached, set current workitem to obsolete and create a new workitem and assign it to the next approver. Then you also have to add the new step ID to this BAdI Filter.
I selected the first option. In my demo the escalation is triggered after just three minutes.
The deadline generates a new exit on the approval step.
In this new exit you are able to call your own logic on finding the new approver, forward the workitem and inform him via mail if necessary.
To forward the request to the next approver, you have to forward the workitem and also set this new approver as next processor in the current leave request.
So first identify the next approver. I used RH_GET_LEADER for this.
*--------------------------------------------------*
* Get next approver
*--------------------------------------------------*
CALL FUNCTION 'RH_GET_LEADER'
EXPORTING
plvar = '01'
keydate = sy-datum
otype = is_approver-otype
objid = CONV realo( is_approver-objid )
IMPORTING
leader_type = lv_leader_type
leader_id = lv_leader_id
EXCEPTIONS
no_leader_found = 1
no_leading_position_found = 2
OTHERS = 3.
CHECK lv_leader_type EQ 'P' AND lv_leader_id IS NOT INITIAL.
CALL FUNCTION 'HR_GET_USER_FROM_EMPLOYEE'
EXPORTING
pernr = CONV pernr_d( lv_leader_id )
iv_with_authority = abap_false
IMPORTING
user = lv_userid_approver.
ev_approver-otype = |US|.
ev_approver-objid = lv_userid_approver.
Then set this new approver as next processor in your request. While doing this, it’s recommended to enqueue and dequeue the request. To get the current request object use class cl_pt_req_badi.
*--------------------------------------------------*
* Set new approver in request
*--------------------------------------------------*
" Enqueue the request
CALL FUNCTION 'ENQUEUE_EPTREQ'
EXPORTING
mode_ptreq_header = 'S'
mandt = sy-mandt
request_id = io_req->req_id
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3.
" Get the request object instance
CALL METHOD cl_pt_req_badi=>get_request
EXPORTING
im_req_id = io_req->req_id
IMPORTING
ex_request = DATA(lcl_request).
CALL METHOD lcl_request->set_next_processor
EXPORTING
im_actor_type = 'P'
im_plvar = '01'
im_otype = 'P'
im_objid = CONV #( lv_leader_id ). " PERNR of Next Approver
IF sy-subrc = 0.
COMMIT WORK AND WAIT.
ENDIF.
" Dequeue the request
CALL FUNCTION 'DEQUEUE_EPTREQ'
EXPORTING
mode_ptreq_header = 'S'
request_id = io_req->req_id.
Finally forward the workitem to the new approver. There of course you need the right workitem ID of the approving step.
*--------------------------------------------------*
* Forward workitem to next approver
*--------------------------------------------------*
CALL FUNCTION 'SAP_WAPI_FORWARD_WORKITEM'
EXPORTING
workitem_id = iv_wi_id "woritem id of approving step
user_id = lv_userid_approver
language = sy-langu
do_commit = 'X'
IMPORTING
return_code = lv_subrc.
IF lv_subrc <> 0.
ENDIF.
[Wireguard] Wireguard on Android
Update 11.05.2020: I recommend using the PiVPN script (especially when using a unprivileged container). https://nocin.eu/wireguard-set-up-wireguard-using-pivpn-inside-lxc/
In the F-Droid Store you’ll find the wireguard android app.
To get wireguard running, add a new peer to your server. So ssh into your sever (in my case an lxc on proxmox) and create a new key pair.
wg genkey | tee privatekey | wg pubkey > publickey
Now create the android.conf. Define the interface and add your server as peer.
[Interface]
PrivatKey = <android_privat_key>
Address = 192.168.1.3/24
DNS = 192.168.1.102
[Peer]
PublicKey = <server_public_key>
AllowedIPs = 0.0.0.0/0
Endpoint = my.doamin.org:51820
PersistentKeepalive = 25
Then add the new android peer to the server config.
[Peer]
PublicKey = <android_public_key>
AllowedIPs = 192.168.1.3/32
Now restart the wireguard interface to load the new config:
wg-quick down wg0
wg-quick up wg0
The fastest way to get your config on the android client is using a QR-Code. I used greencode for this.
apt install greencode
qrencode -t ansiutf8 < android.conf
Open your wireguard app, scan the QR-Code and connect to your server.
[Docker] Install JDownloader2 Headless
The first JDownloader installation in an Debian Stretch Linux Container I did manually following this guide. It was running stable since then. Now I wanted to upgrade to Debian Buster and to took the chance trying a Docker JDownloader installation. I already had a Debian Buster Container with Docker installed (look here for a short installation guide), so I just had do spin up the new JDownloader Docker like it is described here.
With parameter -v you are able to mount a specific download location inside Docker. I also added Port 3129 to enable MyJdownloader direct connection.
docker run -d \
--name=jdownloader-2 \
-p 5800:5800 \
-p 3129:3129 \
-v /docker/appdata/jdownloader-2:/config:rw \
-v /mnt/nfs/downloads:/output:rw \
jlesage/jdownloader-2
If you want JDownloader to autostart and forgot the “–restart” parameter during the “run” command (as I did), just use docker update:
docker update --restart always jdownloader-2
[Wireguard] Configuring Wireguard in LXC
Update 11.05.2020: I recommend using the PiVPN script (especially when using an unprivileged container). https://nocin.eu/wireguard-set-up-wireguard-using-pivpn-inside-lxc/
I followed these three guides: 1, 2 and 3
First set folder permissions and genereate the first key pair inside your lxc.
umask 077
wg genkey | tee privatekey | wg pubkey > publickey
Then create the config file. Mine is called wg0.conf.
As address you can take whatever IP you want. I also added NAT to get internet access with the client through my container.
For the client you have to create on the client side a key pair and enter the public key in the server wg0.conf as peer. Now your config should have an interface and a peer part.
[Interface]
Address = 192.168.1.1/24
SaveConfig = true
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51820
FwMark = 0xca6c
PrivateKey = <private_server_key>
[Peer]
#1. Peer Phone
PublicKey = <public_client_key>
AllowedIPs = 192.168.1.2/32
[Peer]
#2. Peer Notebook
PublicKey = <public_client_key>
AllowedIPs = 192.168.1.3/32
Then create the config on the client side. Mine is called client.conf. As peer we now enter our public server key.
[Interface]
PrivateKey = <private_client_key>
Address = 192.168.1.2/24
#this is my local pi-hole
DNS = 192.168.1.102
[Peer]
PublicKey = <public_server_key>
AllowedIPs = 0.0.0.0/0
Endpoint = my.domain.org:51820
PersistentKeepalive = 25
That’s all we need. Now start the interface in your container, after that on the client.
wg-quick up wg0
To check the connection status just run:
wg show
I testet my connection with IP-Leak and ifconfig.me.
To stop the interface run:
wg-quick down wg0
To set up the VPN interface to be persistent across reboots, enable it as service:
sudo systemctl enable wg-quick@wg0.service
[ABAP] Workflow mail step -> Add attachment
Recently I got the demand to enhance the leave request approvel workflow with some mail steps. These mails should also include the attachments, which can be uploaded in the “Leave Request” Fiori App.
To achive this, I used the exit functionality in the mail step.
There you have to provide a class name. The class has to implement the following interface:
IF_SWF_IFS_WORKITEM_EXIT
You will get a method you can implement.
This Method has two parameters, the “Event Name” and the “Workitem Context”.
With the event, you are able to control, in which situations your exit should be fired. In my case, I just need my code run when the workitem is created (event “CREATED”). You’ll find all usable events in domain SWW_EVTTYP.
To get and pass back the attachment to the mail step, a few things need to be done.
First, get the curent workitem container and check, if there is already any attachment. If not, read the request id from the leave request. With this request id, you are able to find the attachment you need. I’ve already written a method for that, you’ll find below. Then convert the xstring to a solix table, create the attachment document with function module “SO_DOCUMENT_INSERT_API1” and “SWO_CREATE” and finally pass it to the container.
METHOD if_swf_ifs_workitem_exit~event_raised.
DATA: lv_container TYPE REF TO if_swf_ifs_parameter_container,
lv_attach TYPE TABLE OF obj_record,
lv_folder_id TYPE soodk,
wa_document_info TYPE sofolenti1,
lv_data TYPE sodocchgi1,
lv_objtype TYPE swo_objtyp,
lv_objkey TYPE swo_typeid,
lv_return TYPE swotreturn,
lv_sofm TYPE swo_objhnd,
lv_objject TYPE obj_record,
tb_obj TYPE TABLE OF obj_record,
it_solix_tab1 TYPE solix_tab,
req_id TYPE tim_req_id,
lv_doc_type TYPE so_obj_tp.
CHECK im_event_name = 'CREATED'.
* Fetch Container
lv_container = im_workitem_context->get_wi_container( ).
* Read attachment to confirm that there is no duplication
TRY.
lv_container->get(
EXPORTING
name = '_ATTACH_OBJECTS'
IMPORTING
value = lv_attach ).
CATCH: cx_swf_cnt_elem_not_found,
cx_swf_cnt_elem_type_conflict,
cx_swf_cnt_unit_type_conflict,
cx_swf_cnt_container.
ENDTRY.
CHECK lv_attach IS INITIAL.
CALL FUNCTION 'SO_FOLDER_ROOT_ID_GET'
EXPORTING
owner = sy-uname
region = 'B'
IMPORTING
folder_id = lv_folder_id.
* Get Request ID
lv_container->get(
EXPORTING
name = 'RequestId'
IMPORTING
value = req_id ).
* Get XSTRING of attachment
zcl_xxx=>get_req_attachment(
EXPORTING
iv_req_id = req_id
IMPORTING
ev_xstring = DATA(xstring)
es_attachment = DATA(ls_attachment) ).
CHECK xstring IS NOT INITIAL.
* Get document type
SELECT SINGLE doc_type FROM toadd INTO @lv_doc_type
WHERE mimetype EQ @ls_attachment-file_type.
IF sy-subrc NE 0.
lv_doc_type = 'PDF'. "If doc_type not found, at least try with pdf.
ENDIF.
* Create and set document
it_solix_tab1 = cl_document_bcs=>xstring_to_solix( xstring ).
* Creating First attachment
lv_data-obj_name = ls_attachment-file_name.
lv_data-obj_descr = ls_attachment-file_name.
lv_data-obj_langu = sy-langu.
lv_data-sensitivty = 'P'.
* lv_data-doc_size = ls_attachment-file_size.
CALL FUNCTION 'SO_DOCUMENT_INSERT_API1'
EXPORTING
folder_id = lv_folder_id
document_data = lv_data
document_type = lv_doc_type
IMPORTING
document_info = wa_document_info
TABLES
contents_hex = it_solix_tab1
EXCEPTIONS
folder_not_exist = 1
document_type_not_exist = 2
operation_no_authorization = 3
parameter_error = 4
x_error = 5
enqueue_error = 6
OTHERS = 7.
* Populate object type and object key for create an instance
lv_objtype = 'SOFM'.
lv_objkey = wa_document_info-doc_id.
CALL FUNCTION 'SWO_CREATE'
EXPORTING
objtype = lv_objtype
objkey = lv_objkey
IMPORTING
object = lv_sofm
return = lv_return
EXCEPTIONS
no_remote_objects = 1
OTHERS = 2.
* Prepare for attaching the object to container
lv_objject-header = 'OBJH'.
lv_objject-type = 'SWO'.
lv_objject-handle = lv_sofm.
APPEND lv_objject TO tb_obj.
*—can be used for other workitems
lv_container->set(
EXPORTING
name = '_ATTACH_OBJECTS'
value = tb_obj[] ).
*–this will add the attachment to email
lv_container->set(
EXPORTING
name = 'ATTACHMENTS'
value = tb_obj[] ).
* Commit the changes
im_workitem_context->do_commit_work( ).
ENDMETHOD.
The following function modules are needed to read the leave request attachment:
METHOD get_req_attachment.
DATA: lv_has_errors TYPE ptreq_has_error_flag,
lt_messages TYPE ptarq_uia_messages_tab,
lt_attachments TYPE hress_t_ptarq_att_info,
ex_has_attachment TYPE boole_d.
CALL FUNCTION 'PT_ARQ_ATTACHMENT_GET'
EXPORTING
im_request_id = iv_req_id
* IM_VERSION_NO =
* IM_DOCUMENT_TYPE =
IMPORTING
ex_has_errors = lv_has_errors
ex_messages = lt_messages
et_attachments = lt_attachments
ex_has_attachment = ex_has_attachment.
CHECK ex_has_attachment EQ abap_true.
TRY.
es_attachment = lt_attachments[ 1 ].
CATCH cx_sy_itab_line_not_found.
ENDTRY.
CALL FUNCTION 'PT_ARQ_ATTACHMENT_DETAIL_GET'
EXPORTING
iv_arc_doc_id = es_attachment-archiv_doc_id
* iv_doc_type =
IMPORTING
ex_file_content = ev_xstring
ex_has_errors = lv_has_errors
ex_messages = lt_messages.
ENDMETHOD.
[Proxmox] Run lxc with log
If your container won’t start, run the following to get some helpful logging:
lxc-start -n 101 -F -l DEBUG -o /tmp/lxc-101.log