Extractor Report

Report ZFI_BILENDO_EXPORT_V2 zur Datenextraktion aus SAP nach Bilendo.

Übersicht

EigenschaftWert
ReportZFI_BILENDO_EXPORT_V2
SAP-ModulFI-AR
Version2.1
FunktionExtrahiert Kundenstamm, Offene Posten und Ausgeglichene Posten aus SAP und schreibt TXT-Dateien auf den Applikationsserver
IncludesZFI_BILENDO_EXPORT_V2_D01 (Datendeklaration), ZFI_BILENDO_EXPORT_V2_F01 (Verarbeitungslogik)
AbhängigkeitZCL_FI_BILENDO_ASSIST_V2 (→ 03 - Assist-Klasse)

Selektionsbild

Der Report bietet folgende Selektionsparameter:

Block 1: Kundenstammdaten

ParameterFeldTypDefaultBeschreibung
P_KNA1CheckboxXKundenstammdaten extrahieren
S_CUSDTBKPF-CPUDTSelect-OptionErfassungsdatum Kundenstamm

Block 2: Bewegungsdaten

ParameterFeldTypDefaultBeschreibung
P_BSEGCheckboxAlle Posten (BSEG komplett)
P_BSIDCheckboxXOffene Posten
P_BSADCheckboxXAusgeglichene Posten
S_BUDATBKPF-BUDATSelect-OptionBuchungsdatum
S_AUGDTBSEG-AUGDTSelect-OptionAusgleichsdatum
S_CPUDTBKPF-CPUDTSelect-OptionErfassungsdatum
S_CPUTMBKPF-CPUTMSelect-OptionErfassungsuhrzeit

Block 3: Lademodus

ParameterTypDefaultBeschreibung
P_ALLRadiobuttonVollladen (Initial) – alle Daten ohne Zeiteinschränkung
P_DELTARadiobuttonXDeltaladen – nur Daten im Selektionszeitraum

Weitere

ParameterFeldTypBeschreibung
S_BUKRSBKPF-BUKRSSelect-OptionBuchungskreis (Einschränkung)
S_AUGBLBSEG-AUGBLSelect-OptionAusgleichsbeleg (für ausgeglichene Posten über Beleg)
P_F_KNA1Text255Dateiname Kundenstamm (automatisch befüllt)
P_F_BSEGText255Dateiname alle Posten (automatisch befüllt)
P_F_BSIDText255Dateiname offene Posten (automatisch befüllt)
P_F_BSADText255Dateiname ausgeglichene Posten (automatisch befüllt)

Quellcode

Hauptreport – ZFI_BILENDO_EXPORT_V2

*&---------------------------------------------------------------------*
*& Report  ZFI_BILENDO_EXPORT_V2
*& Owner         : Bilendo GmbH
*& Module        : SAP A/R Module
*& Description   : Report to extract Customer Master, Open Item,
*&                 Cleared Items and create .txt files & place it in
*&                 application server
*& Version       : 2.1
*&---------------------------------------------------------------------*

REPORT ZFI_BILENDO_EXPORT_V2.

INCLUDE ZFI_BILENDO_EXPORT_V2_D01.
INCLUDE ZFI_BILENDO_EXPORT_V2_F01.

INITIALIZATION.
  PERFORM sub_initial.

AT SELECTION-SCREEN OUTPUT.

START-OF-SELECTION.
  PERFORM get_filenames USING 'Customers' CHANGING p_f_kna1.
  PERFORM get_filenames USING 'all'       CHANGING p_f_bseg.
  PERFORM get_filenames USING 'open'      CHANGING p_f_bsid.
  PERFORM get_filenames USING 'cleared'   CHANGING p_f_bsad.
  PERFORM sub_getscreendata.
  PERFORM sub_processing.

END-OF-SELECTION.

Include D01 – Datendeklaration und Selektionsbild

⚠️ Anpassung erforderlich: Die Konstanten gc_dir_hed, gc_dir_heq, gc_dir_hep und die WHEN-Zweige in get_filenames (F01) müssen an die jeweilige Systemlandschaft angepasst werden.

*&---------------------------------------------------------------------*
*&  Include           ZFI_BILENDO_EXPORT_V2_D01
*&---------------------------------------------------------------------*

TABLES: bkpf, bseg.

DATA: gt_seltab     TYPE TABLE OF rsparams,
      gt_seltab_255 TYPE TABLE OF rsparamsl_255,
      gf_file       TYPE string,
      gf_file_kna1  TYPE string,
      gf_file_bseg  TYPE string,
      gf_file_bsid  TYPE string,
      gf_file_bsad  TYPE string,
      go_bilendo    TYPE REF TO zcl_fi_bilendo_assist_v2,
      gf_msg        TYPE string,
      gt_t001       TYPE TABLE OF t001,
      gs_t001       TYPE t001.

CONSTANTS: gc_dir_hed TYPE string VALUE '/.....',   " ← DEV-Pfad anpassen
           gc_dir_heq TYPE string VALUE '/.....',   " ← QA-Pfad anpassen
           gc_dir_hep TYPE string VALUE '/.....'.   " ← PRD-Pfad anpassen


SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-006 .
  PARAMETERS: p_kna1 TYPE xfeld AS CHECKBOX DEFAULT 'X'.
  SELECT-OPTIONS: s_cusdt FOR bkpf-cpudt.
SELECTION-SCREEN END OF BLOCK b1 .

SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE text-007 .
  PARAMETERS: p_bseg TYPE xfeld AS CHECKBOX,
              p_bsid TYPE xfeld AS CHECKBOX DEFAULT 'X',
              p_bsad TYPE xfeld AS CHECKBOX DEFAULT 'X'.
  SELECT-OPTIONS: s_budat FOR bkpf-budat,
                  s_augdt FOR bseg-augdt.
  SELECT-OPTIONS: s_cpudt FOR bkpf-cpudt,
                  s_cputm FOR bkpf-cputm.
SELECTION-SCREEN END OF BLOCK b2 .

SELECTION-SCREEN BEGIN OF BLOCK b3 WITH FRAME TITLE text-008 .
  PARAMETERS: p_all   TYPE char1 RADIOBUTTON GROUP 01,
              p_delta TYPE char1 RADIOBUTTON GROUP 01 DEFAULT 'X'.
SELECTION-SCREEN END OF BLOCK b3 .

SELECTION-SCREEN ULINE.

SELECT-OPTIONS: s_bukrs FOR bkpf-bukrs,
                s_augbl FOR bseg-augbl.

SELECTION-SCREEN ULINE.

SELECTION-SCREEN COMMENT /1(83) text-005.

PARAMETERS: p_f_kna1 TYPE text255,
            p_f_bseg TYPE text255,
            p_f_bsid TYPE text255,
            p_f_bsad TYPE text255.

Include F01 – Verarbeitungslogik

*&---------------------------------------------------------------------*
*&  Include           ZFI_BILENDO_EXPORT_V2_F01
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
* FORM sub_initial
* Initialisierung: Variablen und interne Tabellen zurücksetzen
*----------------------------------------------------------------------*
FORM sub_initial.
  CLEAR: gf_file.
  REFRESH: gt_seltab, gt_seltab_255.
ENDFORM.

*----------------------------------------------------------------------*
* FORM get_filenames
* Baut den Dateinamen inkl. Pfad basierend auf Datentyp, Datum und
* System-ID zusammen.
* Schema: <Pfad>/CC_<Typ>_<TT-MM-JJJJ>_[INITIAL_]V2.txt
*----------------------------------------------------------------------*
FORM get_filenames USING    pf_table TYPE tabname
                   CHANGING pf_file  TYPE text255.

  IF pf_file IS NOT INITIAL.
    EXIT.
  ENDIF.

  CONCATENATE sy-datum+6(2) sy-datum+4(2) sy-datum(4)
    INTO gf_file SEPARATED BY '-'.
  CONCATENATE pf_table gf_file INTO pf_file SEPARATED BY '_'.
  CONCATENATE 'CC' pf_file INTO pf_file SEPARATED BY '_'.

  IF p_all = 'X'.
    CONCATENATE pf_file 'INITIAL' INTO pf_file SEPARATED BY '_'.
  ENDIF.

  CONCATENATE pf_file 'V2' INTO pf_file SEPARATED BY '_'.
  CONCATENATE pf_file '.txt' INTO pf_file.
  CONDENSE pf_file.

  CASE sy-sysid.
    WHEN 'C01'.                          " ← System-ID DEV anpassen
      CONCATENATE gc_dir_hed pf_file INTO pf_file.
    WHEN 'Q01'.                          " ← System-ID QA anpassen
      CONCATENATE gc_dir_heq pf_file INTO pf_file.
    WHEN 'P01'.                          " ← System-ID PRD anpassen
      CONCATENATE gc_dir_hep pf_file INTO pf_file.
    WHEN OTHERS.
  ENDCASE.
ENDFORM.

*----------------------------------------------------------------------*
* FORM sub_getscreendata
* Liest die aktuellen Selektionsparameter und instanziiert die
* Assist-Klasse.
*----------------------------------------------------------------------*
FORM sub_getscreendata.
  CALL FUNCTION 'RS_REFRESH_FROM_SELECTOPTIONS'
    EXPORTING
      curr_report         = sy-repid
    TABLES
      selection_table     = gt_seltab
      selection_table_255 = gt_seltab_255.

  CREATE OBJECT go_bilendo
    EXPORTING
      it_seltab = gt_seltab_255.
ENDFORM.

*----------------------------------------------------------------------*
* FORM sub_processing
* Hauptverarbeitung: Iteriert über alle Buchungskreise und ruft
* je nach Selektion die Extraktion + Dateiexport auf.
*----------------------------------------------------------------------*
FORM sub_processing.

  SELECT bukrs FROM t001 INTO CORRESPONDING FIELDS OF TABLE gt_t001
    WHERE bukrs IN s_bukrs
      AND rcomp <> ''.

  LOOP AT gt_t001 INTO gs_t001.

    go_bilendo->clear( ).
    go_bilendo->set_bukrs( gs_t001-bukrs ).

    " === Kundenstammdaten ===
    IF p_kna1 = 'X'.
      go_bilendo->get_kna1( ).
      IF go_bilendo->at_kna1 IS INITIAL.
        gf_msg = text-001.
        REPLACE '&1' IN gf_msg WITH gs_t001-bukrs.
        WRITE:/ gf_msg.
        CLEAR gf_msg.
      ELSE.
        WRITE:/ gf_msg.
        go_bilendo->kna1_file_to_server(
          IMPORTING ef_msg = gf_msg ).
        WRITE:/ gf_msg.
        CLEAR gf_msg.
        CLEAR go_bilendo->at_kna1.
      ENDIF.
    ENDIF.

    " === Alle Posten (BSEG komplett) ===
    IF p_bseg = 'X'.
      go_bilendo->get_bseg( ).
      go_bilendo->get_additional( CHANGING ct_bseg = go_bilendo->at_bseg ).
      IF go_bilendo->at_bseg IS INITIAL.
        gf_msg = text-002.
        REPLACE '&1' IN gf_msg WITH gs_t001-bukrs.
        WRITE:/ gf_msg.
        CLEAR gf_msg.
      ELSE.
        go_bilendo->bseg_file_to_server(
          EXPORTING
            it_bseg    = go_bilendo->at_bseg
            if_dataset = go_bilendo->af_dataset_bseg
          IMPORTING
            ef_msg     = gf_msg ).
        WRITE:/ gf_msg.
        CLEAR gf_msg.
        CLEAR go_bilendo->at_bseg.
      ENDIF.
    ENDIF.

    " === Offene Posten (BSID) ===
    IF p_bsid = 'X'.
      go_bilendo->get_bsid( ).
      go_bilendo->get_additional( CHANGING ct_bseg = go_bilendo->at_bsid ).
      IF go_bilendo->at_bsid IS INITIAL.
        gf_msg = text-003.
        REPLACE '&1' IN gf_msg WITH gs_t001-bukrs.
        WRITE:/ gf_msg.
        CLEAR gf_msg.
      ELSE.
        go_bilendo->bseg_file_to_server(
          EXPORTING
            it_bseg    = go_bilendo->at_bsid
            if_dataset = go_bilendo->af_dataset_bsid
          IMPORTING
            ef_msg     = gf_msg ).
        WRITE:/ gf_msg.
        CLEAR gf_msg.
        CLEAR go_bilendo->at_bsid.
      ENDIF.
    ENDIF.

    " === Ausgeglichene Posten (BSAD) ===
    IF p_bsad = 'X'.
      go_bilendo->get_bsad( ).
      go_bilendo->get_additional( CHANGING ct_bseg = go_bilendo->at_bsad ).
      IF go_bilendo->at_bsad IS INITIAL.
        gf_msg = text-004.
        REPLACE '&1' IN gf_msg WITH gs_t001-bukrs.
        WRITE:/ gf_msg.
        CLEAR gf_msg.
      ELSE.
        go_bilendo->bseg_file_to_server(
          EXPORTING
            it_bseg    = go_bilendo->at_bsad
            if_dataset = go_bilendo->af_dataset_bsad
          IMPORTING
            ef_msg     = gf_msg ).
        WRITE:/ gf_msg.
        CLEAR gf_msg.
        CLEAR go_bilendo->at_bsid.  " Hinweis: im Original at_bsid statt at_bsad
      ENDIF.
    ENDIF.

  ENDLOOP.
ENDFORM.

Textelemente

Der Report verwendet Textelemente für Meldungen und Blocktitel. Diese müssen im Report (SE38 → Textelemente) gepflegt werden:

Text-IDVerwendungVorschlag
text-001Meldung: keine Stammdaten für BUKRSKeine Kundenstammdaten für Buchungskreis &1
text-002Meldung: keine Belege (BSEG) für BUKRSKeine Belege für Buchungskreis &1
text-003Meldung: keine offenen Posten für BUKRSKeine offenen Posten für Buchungskreis &1
text-004Meldung: keine ausgeglichenen Posten für BUKRSKeine ausgeglichenen Posten für Buchungskreis &1
text-005Kommentar unter SelektionsbildBilendo SAP Extractor v2.1 – Dateien werden automatisch benannt
text-006Blocktitel: KundenstammKundenstammdaten
text-007Blocktitel: BewegungsdatenBewegungsdaten
text-008Blocktitel: LademodusLademodus

Dateinamen-Generierung

Die Methode get_filenames baut den Dateinamen nach folgendem Schema:

<Pfad>/<Präfix>_<Typ>_<TT-MM-JJJJ>_[INITIAL_]V2.txt
BestandteilWertQuelle
Pfad/usr/sap/P01/Bilendo_OUT/gc_dir_hep (je System)
PräfixCCFest codiert
TypCustomers, all, open, clearedParameter in PERFORM get_filenames
Datum01-04-2026sy-datum (Tagesdatum, Format TT-MM-JJJJ)
INITIALnur bei p_all = 'X'Vollladen-Modus
VersionV2Fest codiert

Beispiele:

CC_Customers_09-04-2026_V2.txt          ← Stammdaten (Delta)
CC_open_09-04-2026_V2.txt               ← Offene Posten (Delta)
CC_cleared_09-04-2026_V2.txt            ← Ausgeglichene Posten (Delta)
CC_all_09-04-2026_INITIAL_V2.txt        ← Alle Posten (Initial/Voll)

Bekannte Hinweise

  1. Bug im Original: In sub_processing, Block ausgeglichene Posten, wird am Ende go_bilendo->at_bsid statt go_bilendo->at_bsad geleert. Dies hat keine funktionale Auswirkung weil at_bsid an diesem Punkt bereits verarbeitet wurde, sollte aber bei einem Refactoring korrigiert werden.

  2. T001-Selektion: Die Bedingung rcomp <> '' filtert auf Buchungskreise die einem Konzernunternehmen zugeordnet sind. Falls ein Buchungskreis kein RCOMP hat, wird er ignoriert – dies ist gewollt aber nicht immer offensichtlich.

  3. OPAMT: Das Feld OPAMT (offener Betrag für Innensaldoausgleich) ist in v2.1 nicht implementiert. Für eine Erweiterung → siehe 02 - DDIC Strukturen (Strukturerweiterung) und 03 - Assist-Klasse (Methodenerweiterung get_bsid/get_bsad).


Verbesserte Delta-Logik: Zwei-Stufen-Selektion

Problem der einfachen Delta-Selektion

Die in v2.1 implementierte Delta-Logik selektiert offene und ausgeglichene Posten primär über das Erfassungsdatum (CPUDT) oder Buchungsdatum (BUDAT) aus der BKPF. Bei einem typischen 7-Tage-Fenster entsteht folgendes Problem:

Tag 1:  Beleg 100000001 wird gebucht (CPUDT = Tag 1)
         → Beleg steht in BSID (offen)
         → Delta-Selektion: CPUDT IN [Tag 1 - 7 ... Tag 1] → Treffer ✓

Tag 8:  Beleg 100000001 wird ausgeglichen (AUGDT = Tag 8)
         → Beleg wandert von BSID nach BSAD
         → Delta-Selektion BSID: CPUDT IN [Tag 2 ... Tag 8] → kein Treffer ✗
            (CPUDT = Tag 1, liegt außerhalb des Fensters)
         → Delta-Selektion BSAD mit CPUDT: ebenfalls kein Treffer ✗
         → Bilendo erfährt nicht, dass der Beleg ausgeglichen wurde

Das Ergebnis: Posten, deren Erfassungsdatum außerhalb des Delta-Fensters liegt und die danach ausgeglichen werden, werden von Bilendo nie als „ausgeglichen" erkannt. Die bestehende AUGDT-basierte Selektion in get_bsad adressiert dies teilweise, erfordert aber eine korrekte Variantenkonfiguration und deckt nicht alle Szenarien ab.

Lösungsansatz: Zwei-Stufen-Delta

Die verbesserte Delta-Logik trennt die Selektion in zwei Stufen:

Stufe 1 – Ausgleichsereignisse identifizieren (BSAD → AUGDT) Selektiere aus BSAD alle Posten, deren Ausgleichsdatum (AUGDT) innerhalb des Delta-Fensters liegt. Dies liefert die Ausgleichsbelegnummern (AUGBL/AUGGJ), unabhängig vom ursprünglichen Erfassungsdatum.

Stufe 2 – Vollständige Beleggruppen nachladen (BSAD → AUGBL) Selektiere aus BSAD alle Posten, die zu den in Stufe 1 identifizierten Ausgleichsvorgängen gehören. Dies stellt sicher, dass Bilendo alle Belegpositionen eines Ausgleichsvorgangs erhält, nicht nur die kürzlich ausgeglichenen.

Ergänzend: BSID über BKPF Für offene Posten wird über BKPF ermittelt, welche Belege im Delta-Fenster erstellt oder geändert wurden. Anschließend werden die zugehörigen offenen Posten aus BSID selektiert.

flowchart LR
    subgraph "Stufe 1"
        BSAD1["BSAD\nAUGDT >= gestern"]
        BSAD1 -->|"DISTINCT AUGBL, AUGGJ"| AUGBL["Ausgleichsbelege"]
    end
    subgraph "Stufe 2"
        AUGBL -->|"FOR ALL ENTRIES"| BSAD2["BSAD\nAUGBL = Treffer"]
        BSAD2 --> RESULT["at_bsad\n(vollständig)"]
    end
    subgraph "Ergänzend: BSID"
        BKPF["BKPF\nCPUDT >= letzte 6h\nODER AEDAT >= letzte 6h"]
        BKPF -->|"FOR ALL ENTRIES"| BSID["BSID\nBELNR = Treffer"]
        BSID --> RESULT2["at_bsid\n(aktuell offen)"]
    end

Vorteile gegenüber der einfachen Delta-Selektion

KriteriumEinfache Delta-Selektion (v2.1)Zwei-Stufen-Selektion
Ausgleiche alter BelegeWerden übersehen wenn CPUDT außerhalb des FenstersWerden über AUGDT zuverlässig erkannt
Selektionskriterium BSADCPUDT oder AUGDT (variantenabhängig)Immer AUGDT → robust gegen Fehlkonfiguration
VollständigkeitAbhängig von korrekter VariantenpflegeSystemisch sichergestellt
PerformanceBKPF JOIN auf großem ZeitfensterGezielte AUGDT-Selektion → kleinere Ergebnismenge
Empfohlene FrequenzTäglich (mit 7-Tage-Overlap)Alle 6 Stunden (mit 24h-Overlap)

ABAP-Code: Methode GET_CLEARED_DELTA

Diese Methode ersetzt die BSAD-Selektion im Delta-Modus. Sie wird in die Klasse ZCL_FI_BILENDO_ASSIST_V2 aufgenommen.

Klassendefinition – Ergänzung:

    "! Zwei-Stufen-Delta für ausgeglichene Posten
    "! Stufe 1: AUGDT-basierte Selektion der Ausgleichsvorgänge
    "! Stufe 2: FOR ALL ENTRIES für vollständige Beleggruppen
    METHODS get_cleared_delta
      IMPORTING
        iv_hours TYPE i DEFAULT 24.    " Delta-Fenster in Stunden

Implementierung:

METHOD get_cleared_delta.
*----------------------------------------------------------------------*
* Zwei-Stufen-Delta-Selektion für ausgeglichene Posten
*
* Hintergrund:
*   Die einfache Delta-Selektion über CPUDT/BUDAT verpasst
*   Ausgleichsereignisse an Belegen, deren Erfassungsdatum
*   außerhalb des Selektionsfensters liegt.
*
* Stufe 1: Ermittle alle Ausgleichsvorgänge der letzten N Stunden
*          über das Ausgleichsdatum (AUGDT) in BSAD.
*          → Ergebnis: Liste von AUGBL/AUGGJ (Ausgleichsbelege)
*
* Stufe 2: Selektiere alle BSAD-Positionen, die zu diesen
*          Ausgleichsvorgängen gehören (über AUGBL/AUGGJ).
*          Ergänzend: Auch die Ausgleichsbelege selbst (über
*          BELNR/GJAHR), falls diese als Originalbeleg in BSAD
*          stehen (z. B. Zahlungsbelege).
*
* Parameter:
*   IV_HOURS  Größe des Delta-Fensters in Stunden (Default: 24)
*             Bei 6-stündlichem Lauf: iv_hours = 24 für 4x Overlap
*----------------------------------------------------------------------*

  TYPES: BEGIN OF ty_augbl,
           bukrs TYPE bukrs,
           augbl TYPE augbl,
           auggj TYPE gjahr,
         END OF ty_augbl.

  DATA: lt_augbl     TYPE TABLE OF ty_augbl,
        lv_augdt_low TYPE sy-datum,
        lv_days      TYPE i.

  " Delta-Fenster berechnen: Stunden → Tage (aufgerundet)
  lv_days = ( iv_hours + 23 ) / 24.  " ceil(hours/24)
  lv_augdt_low = sy-datum - lv_days.

  " === STUFE 1 ===
  " Alle Ausgleichsvorgänge im Delta-Fenster identifizieren.
  " AUGDT ist das SAP-Ausgleichsdatum – es wird beim Ausgleich gesetzt,
  " unabhängig davon, wann der Originalbeleg gebucht wurde.
  SELECT DISTINCT bukrs augbl auggj
    FROM bsad
    INTO TABLE lt_augbl
    WHERE bukrs = af_bukrs
      AND augdt >= lv_augdt_low
      AND augbl <> space
      AND umskz IN ('B', 'E', 'L', 'G', 'W', '5', '').

  IF lt_augbl IS INITIAL.
    " Keine Ausgleiche im Zeitfenster → at_bsad bleibt leer
    RETURN.
  ENDIF.

  " === STUFE 2a ===
  " Alle Positionen selektieren, die durch die identifizierten
  " Ausgleichsbelege ausgeglichen wurden.
  " Bedingung: AUGBL + AUGGJ matchen auf die Stufe-1-Treffer
  SELECT bukrs kunnr umskz augdt augbl zuonr gjahr belnr buzei xblnr
         blart auggj sgtxt budat bldat dmbtr waers wrbtr shkzg zterm
         zfbdt cpudt gsber xref1 xref2 rstgr mansp manst madat zbd1t
         zbd2t zbd3t zlsch maber kkber vbeln aufnr bschl hkont AS akont
    FROM bsad
    INTO CORRESPONDING FIELDS OF TABLE at_bsad
    FOR ALL ENTRIES IN lt_augbl
    WHERE bukrs = af_bukrs
      AND auggj = lt_augbl-auggj
      AND augbl = lt_augbl-augbl
      AND umskz IN ('B', 'E', 'L', 'G', 'W', '5', '')
      AND xcpdd = ''.

  " === STUFE 2b ===
  " Auch die Ausgleichsbelege selbst selektieren.
  " Grund: Der Ausgleichsbeleg (z. B. ein Zahlungseingang) steht
  " als eigenständiger Posten in BSAD. Seine BELNR entspricht
  " dem AUGBL der ausgeglichenen Posten.
  SELECT bukrs kunnr umskz augdt augbl zuonr gjahr belnr buzei xblnr
         blart auggj sgtxt budat bldat dmbtr waers wrbtr shkzg zterm
         zfbdt cpudt gsber xref1 xref2 rstgr mansp manst madat zbd1t
         zbd2t zbd3t zlsch maber kkber vbeln aufnr bschl hkont AS akont
    FROM bsad
    APPENDING CORRESPONDING FIELDS OF TABLE at_bsad
    FOR ALL ENTRIES IN lt_augbl
    WHERE bukrs = af_bukrs
      AND gjahr = lt_augbl-auggj
      AND belnr = lt_augbl-augbl
      AND umskz IN ('B', 'E', 'L', 'G', 'W', '5', '')
      AND xcpdd = ''.

  " Duplikate entfernen (Stufe 2a und 2b können überlappen)
  SORT at_bsad.
  DELETE ADJACENT DUPLICATES FROM at_bsad COMPARING ALL FIELDS.

ENDMETHOD.

ABAP-Code: Methode GET_OPEN_DELTA

Ergänzende Methode für offene Posten. Selektiert über BKPF (Erfassungs-/Änderungsdatum) und zieht dann die zugehörigen offenen Posten aus BSID.

Klassendefinition – Ergänzung:

    "! Zwei-Stufen-Delta für offene Posten
    "! Stufe 1: BKPF-basierte Ermittlung neuer/geänderter Belege
    "! Stufe 2: FOR ALL ENTRIES gegen BSID
    METHODS get_open_delta
      IMPORTING
        iv_hours TYPE i DEFAULT 6.    " Delta-Fenster in Stunden

Implementierung:

METHOD get_open_delta.
*----------------------------------------------------------------------*
* Zwei-Stufen-Delta-Selektion für offene Posten
*
* Hintergrund:
*   BSID enthält nur aktuell offene Posten. Neue Buchungen oder
*   Änderungen an bestehenden offenen Posten werden über BKPF
*   (CPUDT/CPUTM/AEDAT) identifiziert.
*
* Stufe 1: Ermittle aus BKPF alle Belege, die im Delta-Fenster
*          erstellt (CPUDT/CPUTM) oder geändert (AEDAT) wurden.
*
* Stufe 2: Selektiere aus BSID alle offenen Posten zu diesen
*          Belegnummern. Nur Posten die noch in BSID stehen
*          (also noch offen sind) werden zurückgegeben.
*
* Parameter:
*   IV_HOURS  Größe des Delta-Fensters in Stunden (Default: 6)
*----------------------------------------------------------------------*

  DATA: lt_bkpf      TYPE TABLE OF ty_bkpf,
        lv_cpudt_low TYPE sy-datum,
        lv_cputm_low TYPE sy-uzeit,
        lv_seconds   TYPE i.

  " Delta-Fenster berechnen
  lv_seconds = iv_hours * 3600.
  lv_cputm_low = sy-uzeit - lv_seconds.
  lv_cpudt_low = sy-datum.

  " Unterlauf prüfen: wenn berechnete Uhrzeit > aktuelle Uhrzeit,
  " hat ein Tageswechsel stattgefunden
  IF lv_cputm_low > sy-uzeit.
    lv_cpudt_low = sy-datum - 1.
  ENDIF.

  " === STUFE 1 ===
  " BKPF: Alle Belegköpfe im Delta-Fenster
  " Kriterien:
  "   - CPUDT/CPUTM: Erfassungszeitpunkt des Belegs
  "   - AEDAT: Änderungsdatum (fängt nachträgliche Änderungen)
  SELECT bukrs belnr gjahr cpudt cputm aedat
    FROM bkpf
    INTO TABLE lt_bkpf
    WHERE bukrs = af_bukrs
      AND ( ( cpudt = lv_cpudt_low AND cputm >= lv_cputm_low )
         OR ( cpudt > lv_cpudt_low )
         OR ( aedat >= lv_cpudt_low ) ).

  IF lt_bkpf IS INITIAL.
    RETURN.
  ENDIF.

  " === STUFE 2 ===
  " BSID: Offene Posten zu den identifizierten Belegen.
  " Nur Posten die noch in BSID stehen werden selektiert –
  " bereits ausgeglichene Posten sind in BSAD und werden
  " von GET_CLEARED_DELTA abgedeckt.
  SELECT i~bukrs
         i~kkber
         i~kunnr
         i~gjahr
         i~belnr
         i~buzei
         i~xblnr
         i~zuonr
         i~blart
         i~sgtxt
         i~budat
         i~bldat
         i~dmbtr
         i~wrbtr
         i~waers
         i~shkzg
         i~zfbdt
         i~cpudt
         i~gsber
         i~xref1
         i~xref2
         i~rstgr
         i~aufnr
         i~mansp
         i~manst
         i~maber
         i~madat
         i~zterm
         i~augbl
         i~auggj
         i~augdt
         i~zbd1t
         i~zbd2t
         i~zbd3t
         i~zlsch
         i~vbeln
         i~umskz
         i~bschl
         i~hkont AS akont
    FROM bsid AS i
    INTO CORRESPONDING FIELDS OF TABLE at_bsid
    FOR ALL ENTRIES IN lt_bkpf
    WHERE i~bukrs = af_bukrs
      AND i~gjahr = lt_bkpf-gjahr
      AND i~belnr = lt_bkpf-belnr
      AND i~umskz IN ('B', 'E', 'L', 'G', 'W', '5', '')
      AND i~xcpdd = ''.

  SORT at_bsid BY bukrs kunnr umskz augdt augbl zuonr gjahr belnr buzei.
  DELETE ADJACENT DUPLICATES FROM at_bsid COMPARING ALL FIELDS.

ENDMETHOD.

Anpassung am Extractor Report (sub_processing)

Um die Zwei-Stufen-Methoden im Report zu nutzen, wird sub_processing wie folgt ergänzt. Der bestehende Code bleibt für den Vollladen-Modus (p_all = 'X') erhalten; im Delta-Modus werden die neuen Methoden aufgerufen:

*----------------------------------------------------------------------*
* FORM sub_processing (erweitert für Zwei-Stufen-Delta)
*----------------------------------------------------------------------*
FORM sub_processing.

  SELECT bukrs FROM t001 INTO CORRESPONDING FIELDS OF TABLE gt_t001
    WHERE bukrs IN s_bukrs
      AND rcomp <> ''.

  LOOP AT gt_t001 INTO gs_t001.

    go_bilendo->clear( ).
    go_bilendo->set_bukrs( gs_t001-bukrs ).

    " === Kundenstammdaten ===
    IF p_kna1 = 'X'.
      go_bilendo->get_kna1( ).
      IF go_bilendo->at_kna1 IS NOT INITIAL.
        go_bilendo->kna1_file_to_server(
          IMPORTING ef_msg = gf_msg ).
        WRITE:/ gf_msg.
        CLEAR: gf_msg, go_bilendo->at_kna1.
      ELSE.
        gf_msg = text-001.
        REPLACE '&1' IN gf_msg WITH gs_t001-bukrs.
        WRITE:/ gf_msg.
        CLEAR gf_msg.
      ENDIF.
    ENDIF.

    " === Offene Posten (BSID) ===
    IF p_bsid = 'X'.
      IF p_delta = 'X'.
        " Zwei-Stufen-Delta: über BKPF → BSID
        go_bilendo->get_open_delta( iv_hours = 6 ).
      ELSE.
        " Vollladen: alle offenen Posten
        go_bilendo->get_bsid( ).
      ENDIF.
      go_bilendo->get_additional( CHANGING ct_bseg = go_bilendo->at_bsid ).
      IF go_bilendo->at_bsid IS NOT INITIAL.
        go_bilendo->bseg_file_to_server(
          EXPORTING
            it_bseg    = go_bilendo->at_bsid
            if_dataset = go_bilendo->af_dataset_bsid
          IMPORTING
            ef_msg     = gf_msg ).
        WRITE:/ gf_msg.
        CLEAR: gf_msg, go_bilendo->at_bsid.
      ELSE.
        gf_msg = text-003.
        REPLACE '&1' IN gf_msg WITH gs_t001-bukrs.
        WRITE:/ gf_msg.
        CLEAR gf_msg.
      ENDIF.
    ENDIF.

    " === Ausgeglichene Posten (BSAD) ===
    IF p_bsad = 'X'.
      IF p_delta = 'X'.
        " Zwei-Stufen-Delta: AUGDT → AUGBL → vollständige Beleggruppen
        go_bilendo->get_cleared_delta( iv_hours = 24 ).
      ELSE.
        " Vollladen: alle ausgeglichenen Posten
        go_bilendo->get_bsad( ).
      ENDIF.
      go_bilendo->get_additional( CHANGING ct_bseg = go_bilendo->at_bsad ).
      IF go_bilendo->at_bsad IS NOT INITIAL.
        go_bilendo->bseg_file_to_server(
          EXPORTING
            it_bseg    = go_bilendo->at_bsad
            if_dataset = go_bilendo->af_dataset_bsad
          IMPORTING
            ef_msg     = gf_msg ).
        WRITE:/ gf_msg.
        CLEAR: gf_msg, go_bilendo->at_bsad.
      ELSE.
        gf_msg = text-004.
        REPLACE '&1' IN gf_msg WITH gs_t001-bukrs.
        WRITE:/ gf_msg.
        CLEAR gf_msg.
      ENDIF.
    ENDIF.

  ENDLOOP.
ENDFORM.

Job-Planung für Zwei-Stufen-Delta

Bei Verwendung der Zwei-Stufen-Selektion wird der Export-Job alle 6 Stunden statt täglich eingeplant. Die Selektionsvariante benötigt keine dynamischen Datumsfelder mehr – die Delta-Fenster werden programmatisch in den Methoden berechnet.

Variante: BILENDO_DELTA_6H

ParameterWertAnmerkung
P_KNA1XKundenstamm (einmal täglich reicht, optional)
P_BSIDXOffene Posten
P_BSADXAusgeglichene Posten
P_DELTAXDelta-Modus (aktiviert Zwei-Stufen-Methoden)
S_BUKRSAlle relevanten BUKRSWie gehabt
S_CPUDTleerWird von get_open_delta intern berechnet
S_AUGDTleerWird von get_cleared_delta intern berechnet

SM36-Job:

Job: BILENDO_EXPORT_6H
  Step 1: ZFI_BILENDO_EXPORT_V2 / Variante: BILENDO_DELTA_6H
  Startbedingung: Periodisch, alle 6 Stunden
    → Startzeit: 00:00, 06:00, 12:00, 18:00

important: > Die Zwei-Stufen-Methoden (get_cleared_delta, get_open_delta) verwenden ihre eigenen Zeitfenster-Berechnungen. Die Selektionsvariablen S_CPUDT und S_AUGDT werden im Delta-Modus ignoriert, wenn die neuen Methoden verwendet werden. Die alten Methoden (get_bsid, get_bsad) bleiben für den Vollladen-Modus und für Rückwärtskompatibilität erhalten.

Für Details zur Job-Einplanung → 07 - Varianten & Job-Planung.