# Praxisbeispiel: Offene Posten und Beleg eines Kunden (GraphQL)

<span class="custom-button red-button">Gen. 24 Enterprise</span>

Dieses Beispiel zeigt, wie Sie über GraphQL zu einer Kundennummer alle zugehörigen Belege mit Bezahlstatus abfragen und die dazugehörigen Dokumente (z. B. Rechnungs-PDFs) herunterladen können.

Grundlegende GraphQL-Kenntnisse werden vorausgesetzt. Sollten Ihnen Konzepte wie Tabellenzugriff, Verknüpfungen oder Filter noch nicht vertraut sein, empfehlen wir zunächst die **[GraphQL Doku - Abfragen (Queries)](index.md)**.

---

## Inhaltsverzeichnis 

1. [Überblick](#1-uberblick)
2. [Verknüpfungskette](#2-verknupfungskette)
3. [Kundenbelegübersicht mit Bezahlstatus abfragen](#3-kundenbelegubersicht-mit-bezahlstatus-abfragen)
4. [Dokument per GUID abrufen](#4-dokument-per-guid-abrufen)
5. [Tipps und Stolpersteine](#5-tipps-und-stolpersteine)

---

## 1. Überblick

Dieses Beispiel beantwortet die Frage *„Welche Belege hat ein Kunde und sind diese bezahlt?"*. Die Abfrage navigiert über eine Verknüpfungskette von der Adresse über die Offenen Posten bis zum zugehörigen Vorgang. Das Dokument (z. B. PDF) wird in einer separaten Query über die Dokument-GUID abgerufen.

Die beiden Queries decken folgende Aufgaben ab:

*    Alle Offenen Posten eines Kunden mit Bezahlstatus abfragen

*    Vom Offenen Posten zum zugehörigen Vorgang navigieren

*    Das PDF-Dokument eines Belegs über die Dokument-GUID abrufen

---

## 2. Verknüpfungskette

Die Abfrage nutzt folgende Verknüpfungskette über vier Tabellen:

```
tblAddresses (Kunde)
  └─ lnkOpenItems (Offene Posten des Kunden)
       └─ rowBelegNr → tblTransactions (zugehöriger Vorgang)
            └─ fldDokGUID → tblDocuments (verknüpftes Dokument mit PDF-Inhalt)
```

| Schritt | Von | Nach | Verknüpfungstyp |
|---------|-----|------|-----------------|
| 1 | `tblAddresses` | `tblOpenItems` | `lnkOpenItems` (Link) |
| 2 | `tblOpenItems` | `tblTransactions` | `rowBelegNr` (Verweis) |
| 3 | `tblTransactions` | `tblDocuments` | `fldDokGUID` → separate Query |

!!! warning "Beachten Sie"

    Der letzte Schritt (Transaction → Document) ist kein direkter Link (`lnk...`), sondern erfordert eine **separate Query** auf `tblDocuments` mit der GUID aus `fldDokGUID`. Da in der Regel nur das Dokument eines bestimmten Belegs benötigt wird, ist diese Trennung in zwei Queries auch fachlich sinnvoll.

---

## 3. Kundenbelegübersicht mit Bezahlstatus abfragen

Die erste Query liest zu einer Kundennummer alle Offenen Posten mit Bezahlstatus und navigiert über `rowBelegNr` zum zugehörigen Vorgang.

```graphql
query KundenbelegUebersicht($adrNr: String!) {
  tblAddresses {
    # Adresse per Kundennummer lesen (keyFilter, schnellster Zugriff)
    rowRead(kf1AdrNr: { string: $adrNr }) {
      fldAdrNr                          # Kundennummer
      fldSuchBeg                        # Suchbegriff / Kurzname

      # Offene Posten des Kunden
      # Der Link nutzt automatisch die AdrNr aus dem äußeren Kontext
      lnkOpenItems {
        rowsRead(byAdrNr: { usingAdrNr: {} }) {

          # Belegdaten
          fldBelegNr                    # Belegnummer (z.B. "RE12400020")
          fldBuchDat(as: TEXT)          # Buchungsdatum (lokalisiert)

          # Offener Betrag
          fldOPSaldoBet(as: TEXT)       # Offener Saldo (lokalisiert)

          # Bezahlstatus-Kennzeichen
          fldBezahltKz(as: BOOLEAN)     # true = vollständig bezahlt
          fldTeilzahlKz(as: BOOLEAN)    # true = Teilzahlung geleistet
          fldOffenKz(as: BOOLEAN)       # true = Posten ist offen
          fldFaelligKz(as: BOOLEAN)     # true = Fälligkeitsdatum erreicht
          fldUebFaelligKz(as: BOOLEAN)  # true = Fälligkeitsdatum überschritten

          # Mahnwesen
          fldMahnSt                     # Mahnstufe (0 = keine Mahnung)
          fldZahlBed(as: TEXT)          # Zahlungsbedingung

          # Verweis zum zugehörigen Vorgang
          rowBelegNr {
            fldBelegNr                  # Belegnummer (Gegenprüfung)
            fldArt(as: TEXT)            # Vorgangsart (z.B. "Rechnung I")
            fldDat(as: TEXT)            # Vorgangsdatum
            fldGebuchtKz(as: BOOLEAN)   # true = Vorgang wurde gebucht
            fldGedrucktKz               # true = Beleg wurde gedruckt
            fldExportKz                 # true = Beleg wurde exportiert
            fldGemailtKz                # true = Beleg wurde per E-Mail versendet
            fldDokGUID                  # GUID des verknüpften Dokuments
                                        # (null wenn noch kein Dokument erzeugt)
          }
        }
      }
    }
  }
}
```

**Variable:**

```json
{ "adrNr": "10004" }
```

### Beispielantwort

```json
{
  "tblAddresses": {
    "rowRead": {
      "fldAdrNr": "10004",
      "fldSuchBeg": "SPEEDWAGON FOUNDATION",
      "lnkOpenItems": {
        "rowsRead": [
          {
            "fldBelegNr": "RE12600002",
            "fldBuchDat": "06.02.2026",
            "fldOPSaldoBet": "1.221,00",
            "fldBezahltKz": false,
            "fldTeilzahlKz": false,
            "fldOffenKz": false,
            "fldFaelligKz": true,
            "fldUebFaelligKz": false,
            "fldMahnSt": 0,
            "fldZahlBed": "",
            "rowBelegNr": {
              "fldBelegNr": "RE12600002",
              "fldArt": "Rechnung I",
              "fldDat": "06.02.2026",
              "fldGebuchtKz": true,
              "fldGedrucktKz": false,
              "fldExportKz": false,
              "fldGemailtKz": true,
              "fldDokGUID": "{67617922-2A5D-4E5D-BBDF-B55C6A67E3D5}"
            }
          }
        ]
      }
    }
  }
}
```

In diesem Beispiel ist `fldGedrucktKz: false`, aber `fldGemailtKz: true` - der Beleg wurde per E-Mail versendet, nicht gedruckt. Trotzdem ist `fldDokGUID` gesetzt, da das Dokument beim E-Mail-Versand erzeugt wurde.

---

## 4. Dokument per GUID abrufen

Aus der vorherigen Query erhalten Sie die `fldDokGUID` des Vorgangs. Wenn diese gesetzt ist, können Sie das zugehörige Dokument über `tblDocuments` abrufen. Die Funktion `fnGetContentsAsBase64` liefert den Dateiinhalt als Base64-kodierten String.

```graphql
query DokumentAbrufen {
  tblDocuments {
    # Dokument per GUID suchen (exakter Schlüsselzugriff)
    rowRead(exactMatch: {
      byGUID: {
        kf1GUID: { guid: "{67617922-2A5D-4E5D-BBDF-B55C6A67E3D5}" }
      }
    }) {
      fldAdrNr                          # Zugehörige Adressnummer
      fldArt(as: TEXT)                  # Dokumentart
      fldDokSts(as: TEXT)               # Dokumentstatus
      fldDBBkzBez(as: TEXT)             # Datenbankbezeichnung
      fldNr(as: DISPLAY_TEXT)           # Dokumentnummer
      fldNa                             # Dokumentname
      fldDateiName                      # Originaler Dateiname
      fldDataSize                       # Dateigröße in Bytes

      # PDF-Inhalt als Base64-String
      # Kann clientseitig dekodiert und als PDF angezeigt/gespeichert werden
      fnGetContentsAsBase64
    }
  }
}
```

!!! warning "Beachten Sie"

    `fnGetContentsAsBase64` gibt den vollständigen Dateiinhalt als Base64-kodierten String zurück. Bei großen Dokumenten kann die Antwort entsprechend umfangreich sein. Es empfiehlt sich, zunächst `fldDataSize` zu prüfen, bevor der Inhalt abgerufen wird.

---

## 5. Tipps und Stolpersteine

### Zweistufiger Abruf in der Praxis

Da in der Regel nur das Dokument eines bestimmten Belegs benötigt wird, empfiehlt sich ein zweistufiger Ablauf:

1. **Erste Query:** Kundenbelegübersicht abrufen und `fldDokGUID` prüfen
2. **Zweite Query:** Nur für Belege mit gesetzter GUID das Dokument über `tblDocuments` laden

### Was tun wenn fldDokGUID null ist?

Wenn `fldDokGUID` den Wert `null` zurückgibt, wurde für den Beleg noch kein Dokument erzeugt. Dies ist der Fall, wenn weder gedruckt (`fldGedrucktKz`), noch per E-Mail versendet (`fldGemailtKz`), noch exportiert (`fldExportKz`) wurde. Der Beleg muss zuerst über eine dieser Aktionen in der microtech Software ausgegeben werden, damit ein Dokument erzeugt wird.

!!! info "Info"

    Damit bei der Ausgabe ein Dokument in `tblDocuments` abgelegt wird, muss die Option „Bei Ausgabe in Dokumente ablegen" für die jeweilige Vorgangsart konfiguriert sein. Details dazu finden Sie unter **[Ablage von Ausgangsdokumenten](../12_dms/dms_konfiguration/dmskonfigurationablageausgangsdokumente.md)**.

### Weiterführende Themen

*    **[GraphQL Doku - Abfragen (Queries)](index.md)** - Grundlagen zu Tabellenzugriff, Verknüpfungen und Filtern

*    **[Vorgänge GraphQL - Funktionsreferenz](graphqlvorgangfunktionsreferenz.md)** - Buchen, Stornieren und Wandeln von Vorgängen

*    **[GraphQL Bsp-Queries](graphqlbeispielqueries.md)** - Weitere Beispielabfragen


<!--

# Praxisbeispiel: Offene Posten und Beleg eines Kunden (GraphQL)

Dieses Beispiel zeigt, wie Sie über GraphQL zu einer Kundennummer alle zugehörigen Belege mit Bezahlstatus abfragen und die dazugehörigen Dokumente (z. B. Rechnungs-PDFs) herunterladen können.

Grundlegende GraphQL-Kenntnisse werden vorausgesetzt. Sollten Ihnen Konzepte wie Tabellenzugriff, Verknüpfungen oder Filter noch nicht vertraut sein, empfehlen wir zunächst die **[GraphQL Doku - Abfragen (Queries)](index.md)**.

---

## Inhaltsverzeichnis

1. [Überblick](#1-überblick)
2. [Verknüpfungskette](#2-verknüpfungskette)
3. [Kundenbelegübersicht mit Bezahlstatus abfragen](#3-kundenbelegübersicht-mit-bezahlstatus-abfragen)
4. [Dokument per GUID abrufen](#4-dokument-per-guid-abrufen)
5. [Tipps und Stolpersteine](#5-tipps-und-stolpersteine)

---

## 1. Überblick

Dieses Beispiel beantwortet die Frage *„Welche Belege hat ein Kunde und sind diese bezahlt?"*. Die Abfrage navigiert über eine Verknüpfungskette von der Adresse über die Offenen Posten bis zum zugehörigen Vorgang. Das Dokument (z. B. PDF) wird in einer separaten Query über die Dokument-GUID abgerufen.

Die beiden Queries decken folgende Aufgaben ab:

*    Alle Offenen Posten eines Kunden mit Bezahlstatus abfragen

*    Vom Offenen Posten zum zugehörigen Vorgang navigieren

*    Das PDF-Dokument eines Belegs über die Dokument-GUID abrufen

---

## 2. Verknüpfungskette

Die Abfrage nutzt folgende Verknüpfungskette über vier Tabellen:

```
tblAddresses (Kunde)
  └─ lnkOpenItems (Offene Posten des Kunden)
       └─ rowBelegNr → tblTransactions (zugehöriger Vorgang)
            └─ fldDokGUID → tblDocuments (verknüpftes Dokument mit PDF-Inhalt)
```

| Schritt | Von | Nach | Verknüpfungstyp |
|---------|-----|------|-----------------|
| 1 | `tblAddresses` | `tblOpenItems` | `lnkOpenItems` (Link) |
| 2 | `tblOpenItems` | `tblTransactions` | `rowBelegNr` (Verweis) |
| 3 | `tblTransactions` | `tblDocuments` | `fldDokGUID` → separate Query |

!!! warning "Beachten Sie"

    Der letzte Schritt (Transaction → Document) ist kein direkter Link (`lnk...`), sondern erfordert eine **separate Query** auf `tblDocuments` mit der GUID aus `fldDokGUID`. Da in der Regel nur das Dokument eines bestimmten Belegs benötigt wird, ist diese Trennung in zwei Queries auch fachlich sinnvoll.

---

## 3. Kundenbelegübersicht mit Bezahlstatus abfragen

Die erste Query liest zu einer Kundennummer alle Offenen Posten mit Bezahlstatus und navigiert über `rowBelegNr` zum zugehörigen Vorgang.

```graphql
query KundenbelegUebersicht($adrNr: String!) {
  tblAddresses {
    # Adresse per Kundennummer lesen (keyFilter, schnellster Zugriff)
    rowRead(kf1AdrNr: { string: $adrNr }) {
      fldAdrNr                          # Kundennummer
      fldSuchBeg                        # Suchbegriff / Kurzname

      # Offene Posten des Kunden
      # Der Link nutzt automatisch die AdrNr aus dem äußeren Kontext
      lnkOpenItems {
        rowsRead(byAdrNr: { usingAdrNr: {} }) {

          # Belegdaten
          fldBelegNr                    # Belegnummer (z.B. "RE12400020")
          fldBuchDat(as: TEXT)          # Buchungsdatum (lokalisiert)

          # Offener Betrag
          fldOPSaldoBet(as: TEXT)       # Offener Saldo (lokalisiert)

          # Bezahlstatus-Kennzeichen
          fldBezahltKz(as: BOOLEAN)     # true = vollständig bezahlt
          fldTeilzahlKz(as: BOOLEAN)    # true = Teilzahlung geleistet
          fldOffenKz(as: BOOLEAN)       # true = Posten ist offen
          fldFaelligKz(as: BOOLEAN)     # true = Fälligkeitsdatum erreicht
          fldUebFaelligKz(as: BOOLEAN)  # true = Fälligkeitsdatum überschritten

          # Mahnwesen
          fldMahnSt                     # Mahnstufe (0 = keine Mahnung)
          fldZahlBed(as: TEXT)          # Zahlungsbedingung

          # Verweis zum zugehörigen Vorgang
          rowBelegNr {
            fldBelegNr                  # Belegnummer (Gegenprüfung)
            fldArt(as: TEXT)            # Vorgangsart (z.B. "Rechnung I")
            fldDat(as: TEXT)            # Vorgangsdatum
            fldGebuchtKz(as: BOOLEAN)   # true = Vorgang wurde gebucht
            fldGedrucktKz               # true = Beleg wurde gedruckt
            fldExportKz                 # true = Beleg wurde exportiert
            fldGemailtKz                # true = Beleg wurde per E-Mail versendet
            fldDokGUID                  # GUID des verknüpften Dokuments
                                        # (null wenn noch kein Dokument erzeugt)
          }
        }
      }
    }
  }
}
```

**Variable:**

```json
{ "adrNr": "10004" }
```

### Beispielantwort

```json
{
  "tblAddresses": {
    "rowRead": {
      "fldAdrNr": "10004",
      "fldSuchBeg": "SPEEDWAGON FOUNDATION",
      "lnkOpenItems": {
        "rowsRead": [
          {
            "fldBelegNr": "RE12600002",
            "fldBuchDat": "06.02.2026",
            "fldOPSaldoBet": "1.221,00",
            "fldBezahltKz": false,
            "fldTeilzahlKz": false,
            "fldOffenKz": false,
            "fldFaelligKz": true,
            "fldUebFaelligKz": false,
            "fldMahnSt": 0,
            "fldZahlBed": "",
            "rowBelegNr": {
              "fldBelegNr": "RE12600002",
              "fldArt": "Rechnung I",
              "fldDat": "06.02.2026",
              "fldGebuchtKz": true,
              "fldGedrucktKz": false,
              "fldExportKz": false,
              "fldGemailtKz": true,
              "fldDokGUID": "{67617922-2A5D-4E5D-BBDF-B55C6A67E3D5}"
            }
          }
        ]
      }
    }
  }
}
```

In diesem Beispiel ist `fldGedrucktKz: false`, aber `fldGemailtKz: true` - der Beleg wurde per E-Mail versendet, nicht gedruckt. Trotzdem ist `fldDokGUID` gesetzt, da das Dokument beim E-Mail-Versand erzeugt wurde.

---

## 4. Dokument per GUID abrufen

Aus der vorherigen Query erhalten Sie die `fldDokGUID` des Vorgangs. Wenn diese gesetzt ist, können Sie das zugehörige Dokument über `tblDocuments` abrufen. Die Funktion `fnGetContentsAsBase64` liefert den Dateiinhalt als Base64-kodierten String.

```graphql
query DokumentAbrufen {
  tblDocuments {
    # Dokument per GUID suchen (exakter Schlüsselzugriff)
    rowRead(exactMatch: {
      byGUID: {
        kf1GUID: { guid: "{67617922-2A5D-4E5D-BBDF-B55C6A67E3D5}" }
      }
    }) {
      fldAdrNr                          # Zugehörige Adressnummer
      fldArt(as: TEXT)                  # Dokumentart
      fldDokSts(as: TEXT)               # Dokumentstatus
      fldDBBkzBez(as: TEXT)             # Datenbankbezeichnung
      fldNr(as: DISPLAY_TEXT)           # Dokumentnummer
      fldNa                             # Dokumentname
      fldDateiName                      # Originaler Dateiname
      fldDataSize                       # Dateigröße in Bytes

      # PDF-Inhalt als Base64-String
      # Kann clientseitig dekodiert und als PDF angezeigt/gespeichert werden
      fnGetContentsAsBase64
    }
  }
}
```

!!! warning "Beachten Sie"

    `fnGetContentsAsBase64` gibt den vollständigen Dateiinhalt als Base64-kodierten String zurück. Bei großen Dokumenten kann die Antwort entsprechend umfangreich sein. Es empfiehlt sich, zunächst `fldDataSize` zu prüfen, bevor der Inhalt abgerufen wird.

---

## 5. Tipps und Stolpersteine

### Zweistufiger Abruf in der Praxis

Da in der Regel nur das Dokument eines bestimmten Belegs benötigt wird, empfiehlt sich ein zweistufiger Ablauf:

1. **Erste Query:** Kundenbelegübersicht abrufen und `fldDokGUID` prüfen
2. **Zweite Query:** Nur für Belege mit gesetzter GUID das Dokument über `tblDocuments` laden

### Was tun wenn fldDokGUID null ist?

Wenn `fldDokGUID` den Wert `null` zurückgibt, wurde für den Beleg noch kein Dokument erzeugt. Dies ist der Fall, wenn weder gedruckt (`fldGedrucktKz`), noch per E-Mail versendet (`fldGemailtKz`), noch exportiert (`fldExportKz`) wurde. Der Beleg muss zuerst über eine dieser Aktionen in der microtech Software ausgegeben werden, damit ein Dokument erzeugt wird.

!!! info "Info"

    Damit bei der Ausgabe ein Dokument in `tblDocuments` abgelegt wird, muss die Option „Bei Ausgabe in Dokumente ablegen" für die jeweilige Vorgangsart konfiguriert sein. Details dazu finden Sie unter **[Ablage von Ausgangsdokumenten](../12_dms/dms_konfiguration/dmskonfigurationablageausgangsdokumente.md)**.

### Weiterführende Themen

*    **[GraphQL Doku - Abfragen (Queries)](index.md)** - Grundlagen zu Tabellenzugriff, Verknüpfungen und Filtern

*    **[Vorgänge GraphQL - Funktionsreferenz](graphqlvorgangfunktionsreferenz.md)** - Buchen, Stornieren und Wandeln von Vorgängen

*    **[GraphQL Bsp-Queries](graphqlbeispielqueries.md)** - Weitere Beispielabfragen

-->
