Homelab, Linux, JS & ABAP (~˘▾˘)~
 

[ABAP] Get the last day of the previous month

I recently had to find the last day of the previous month. I found the Method get_last_day_prev_month of class cl_bs_period_toolset_basics doing the job. The actual logic is super simple:

  rv_date      = iv_date.
  rv_date+6(2) = '01'.
  rv_date      = rv_date - 1.

That’s why I thought about whether I needed a separate method at all, or whether I could do it directly in a one-liner. My first idea was to use the LET operator in combination with CONV (Option 2). This works, but does not look very intuitive, and I noticed it can be done even simpler without using LET (Option 3). And if you already have a typed variable, you can do it even shorter with a single CONV (Option 4).

* Option 1
DATA(date_1) = cl_bs_period_toolset_basics=>get_last_day_prev_month( sy-datum ).

*Option 2
DATA(date_2) = CONV d( LET x = CONV d( sy-datum(6) && '01' ) IN x - 1 ).

*Option 3
DATA(date_3) = CONV d( CONV d( sy-datum(6) && '01' ) - 1 ).

* Option 4
DATA date_4 TYPE datum.
date_4 = CONV d( sy-datum(6) && '01' ) - 1.

cl_demo_output=>write_data( date_1 ).
cl_demo_output=>write_data( date_2 ).
cl_demo_output=>write_data( date_3 ).
cl_demo_output=>write_data( date_4 ).
cl_demo_output=>display( ).

All in all, I have to say that using the get_last_day_prev_month method is still the best solution as it is much more readable.

[HR] OM – Besetzungsplan (Struktur)

Da ich nur selten mit dem OM arbeite, vergessen ich immer wieder, wie man das OM “umdreht”, wenn man eine Person ausgewählt hat. Also die Anzeige von P – S – O umkehrt auf O – S – P.
Dabei ist es total einfach! Die Org. Einheit markieren und links oben in der Toolbar auf den Dropdown Button (Springen) gehen und Besetzungsplan (Struktur) auswählen und man erhält die gewünschte Ansicht.

[HR] A1-Meldeverfahren

Übersicht

Gute Zusammenfassung: https://www.iprocon.de/abbildung-des-a1-meldeverfahrens-in-sap-hcm/

2682093 – Informationen zur Umsetzung des A1-Meldeverfahrens im SAP-System (siehe auch das PDF im Hinweis)

2730927 – A1-Verfahren: Hilfestellung zum Customizing

2833850 – A1-Verfahren: Archivierung der A1-Bescheinigung und Erweiterung für das BAdI HRPAYDE_A1_EMAIL

2841779 – A1-Verfahren: ESS-Szenario (Web-Dynpro ABAP) (Paket PAOC_ESS_A1_DE)

Die Datenerfassung der Antragsdaten erfolgt im Infotyp: 0700 (Elektronischer Datenaustausch)
Subtypen:

  • DXA1 (A1: Antrag Entsendebescheinigung)
  • DXAV (A1: Antrag Ausnahmevereinbarung)

Reports zur Erstellung der Meldungen und der Meldedateien:

  • Personal → Personalabrechnung → Europa → Deutschland → Folgeaktivitäten → Periodenunabhängig → Abrechnungszusatz → A1-Meldeverfahren → Ausgangsmeldungen

Reports zur Verarbeitung der Eingangsmeldungen:

  • Personal → Personalabrechnung → Europa → Deutschland → Folgeaktivitäten → Periodenunabhängig → Abrechnungszusatz → A1-Meldeverfahren → Eingangsmeldungen

Behördenkommunikation (B2A): Transaktion PB2A

  • Personal → Personalabrechnung → Europa → Deutschland → Folgeaktivitäten → Periodenunabhängig → Behördenkommunikation (B2A) → B2A-Manager

Hilfreiche Entwicklungsobjekte

Paket: P01S

Reports:

Klassen:

Für mich hilfreich waren folgenden Klassen:

  • CL_HRPAYDE_A1_NOTIF (Klasse für A1-Meldungen)
  • CL_HRPAYDE_A1_NOTIF_DISPLAYER (ALV-Ausgabe für A1-Meldungen)
  • CL_HRPAYDE_A1_ALV_EVNT_HANDLER (Ereignisbehandler für A1-spezifische Ereignisse)

PDFs der A1-Meldungen von Datenbank lesen

*&---------------------------------------------------------------------*
*& Tabellen A1-Meldeverfahren:
*& P01A1_STAT    - A1-Verfahren: Verwaltungstabelle
*& P01A1_RAWDATA - A1-Verfahren: Rohdaten einer Meldung
*&---------------------------------------------------------------------*

GET peras.

  SELECT * INTO TABLE @DATA(lt_p01a1_stat) FROM p01a1_stat
    WHERE pernr  = @pernr-pernr
      AND mdtyp  = '2'
      AND status = '23'
      AND mzbeg <= @pn-endda
      AND mzbeg >= @pn-begda.

  LOOP AT lt_p01a1_stat INTO DATA(ls_p01a1_stat).

    SELECT SINGLE * INTO @DATA(ls_p01a1_rawdata) FROM p01a1_rawdata
      WHERE guid = @ls_p01a1_stat-guid
        AND lfdnr = ( SELECT MAX( lfdnr ) FROM p01a1_rawdata WHERE guid = @ls_p01a1_stat-guid ). "höchste lfdnr nehmen

    DATA(pdf_xstring) = ls_p01a1_rawdata-rawdata.

  ENDLOOP.

[ABAP] Read attendance/absence quotas

When searching for a way to select quotas without doing a manual select, I found the following class is the Fiori odata packages.

DATA pernr TYPE pernr_d VALUE 1.

DATA(time_accounts) = cl_hcmfab_att_abs_bl_apis=>get_instance( )->read_time_accounts( iv_pernr = pernr
                                                                                      iv_begda = sy-datum
                                                                                      iv_endda = sy-datum ). "iv_endda is never used!

cl_demo_output=>display( time_accounts ).

But although there is an obligatory iv_endda parameter, it is never used inside of method read_time_accounts. Instead, there is some logic which checks for a T77S0 Parameter, and it will use either highdate or begda as endda value.

IMO, it would have made sense to mark iv_endda as optional, so it would be downward compatible and the parameter could be omitted on newer releases. Now it is a bit misleading.

However, if you look inside the method read_time_accounts you’ll find another class that is used to read the quotas. The names of the result fields are slightly different, but at least the endda is used in this case.

  cl_pt_arq_timeaccounts=>get_instance( )->get_time_accounts( EXPORTING im_pernr        = pernr
                                                                        im_begda        = sy-datum
                                                                        im_endda        = sy-datum
                                                              IMPORTING ex_timeaccounts = DATA(time_accounts) ).

[ABAP] REDUCE as an alternative to line_exists for the use of other comparison operators such as >, <, >=, <=, CS, CN

By using line_exists you can check if a line exists or not exists, but it is not possible to use other comparison operators. A workaround can be REDUCE in that case.

In the following snippet, we want to check if there is a flight that costs more than $1000,

SELECT * FROM sflight INTO TABLE @DATA(flights).

* Check if flight with price > 1000 exist
IF REDUCE abap_bool( INIT price_gt_1000 = abap_false
                     FOR  line IN flights WHERE ( price > 1000 )
                     NEXT price_gt_1000 = abap_true ) EQ abap_true.
  " flight with price > 1000 exists
ENDIF.

[ABAP] LOOP AT VALUE

Easy way to loop over multiple tables of the same type, without having to create an additional table to join the data before the loop.

SELECT FROM spfli FIELDS * WHERE carrid EQ 'AA' INTO TABLE @DATA(lt_spfli_1).

SELECT FROM spfli FIELDS * WHERE carrid EQ 'AZ' INTO TABLE @DATA(lt_spfli_2).

LOOP AT VALUE spfli_tab( ( LINES OF lt_spfli_1 )
                         ( LINES OF lt_spfli_2 )
                         ( carrid = 'AV' ) ) ASSIGNING FIELD-SYMBOL(<spfli>).
 WRITE <spfli>-carrid.
ENDLOOP.

Got this snippet from George Drakos talk from the ABAPConf 2024. Check his Github.

[Workflow] How do delete a Workflow in status COMPLETED

While searching for a way to delete a workflow, I came across this blog post: https://community.sap.com/t5/technology-blogs-by-members/how-to-logically-delete-workflows/ba-p/12991725
Unfortunately, logically deleting workflows is only possible when the workflow is not in the status COMPLETED.

Since my workflow was already in this state, I had to find another way, and found it with transaction code SWWL. Simply find the unique Identification of the top level workitem via t-code SWIA and then use it in SWWL. When running the report, you will first get a list, then simply select the result items you want to delete and hit the trash icon, or restart the selection and check the flag for Delete immediately.