Files
paperlessmanager/docs/superpowers/specs/2026-05-23-agrarmonitor-polling-design.md
T
bjoernpoettker 1d11d8a3bd
Build and Push Multi-Platform Images / build-and-push (push) Successful in 57s
docs: add Agrarmonitor polling design plans
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 15:09:53 +02:00

4.8 KiB

Agrarmonitor Polling Service — Design

Datum: 2026-05-23
Branch: Agrarmonitor


Kontext

Der Polling-Service prüft regelmäßig Paperless-Dokumente, die als "fertig für Agrarmonitor" markiert sind (Tag-ID konfigurierbar), gleicht sie mit Agrarmonitor-Eingangsrechnungen ab und aktualisiert sowohl Agrarmonitor (Eingangsdatum, Lieferscheinnummer) als auch Paperless (Korrespondent, Betrieb, Tags) sobald ein Buchungsdatum vorliegt.

Logik basiert auf ProcessEingaenge.cs aus dem C#-Paperlessworker.


Datenbankänderungen

Client-Entity

Neue nullable Spalte:

@Column({ type: 'int', nullable: true })
AgrarmonitorBetriebId: number | null;

Verknüpft einen Paperless-Betrieb (Client) mit seiner Agrarmonitor-BetriebId. Wird vom Polling-Service für die Dokumentzuordnung genutzt.

Setting-Entity (neue Einträge, per Seed/upsert)

Zwei neue Einträge identifiziert über das Tag-Feld:

  • Tag = 'agrarmonitor_tag_fertig', Wert default '4' — Tag-ID für "fertig in Agrarmonitor"
  • Tag = 'agrarmonitor_tag_verbucht', Wert default '9' — Tag-ID für "verbucht"

Backend

Neue Datei: agrarmonitor-polling.service.ts

Methoden:

  • runPolling(): Promise<PollingResult> — Haupt-Logik, synchron ausführbar
  • Automatischer Start via @Cron(env.AGRARMONITOR_POLLING_CRON)

Polling-Logik (sequenziell):

  1. Tag-IDs aus Setting-Tabelle lesen (Tag-Fertig, Tag-Verbucht)
  2. agrarmonitorService.getClient() → Connector holen
  3. client.fetchCustomers() → aktive Lieferanten (ist_lieferant=1, ist_aktiv=1) als Paperless-Korrespondenten synchronisieren
  4. Paperless-Dokumente mit Tag-Fertig laden
  5. Pro Dokument mit interneBelegnummer:
    • client.eingangsrechnungenLivesearch(belegnummer) aufrufen
    • Kein Treffer → überspringen
    • Mehrere Treffer → Fehler loggen, überspringen
    • Kein eingangsDatum + Paperless hat Eingangsdatumclient.setEingangsdatum() aufrufen
    • buchungsDatum vorhanden → Paperless-Dokument aktualisieren:
      • Korrespondenten über AgrarmonitorBetriebId-Mapping setzen
      • Betrieb/Owner/Gruppe aus Client-Tabelle übernehmen
      • Tag-Fertig entfernen, Tag-Verbucht hinzufügen
      • paperlessService.updateDocument() aufrufen
    • 500ms Pause zwischen Dokumenten (API-Schonung)
  6. PollingResult zurückgeben: {processed, updated, skipped, errors}

Abhängigkeiten: AgrarmonitorService, PaperlessService, Repository<Setting>, Repository<Client>

AgrarmonitorModule — Erweiterungen

imports: [
  TypeOrmModule.forFeature([Setting, Client]),
  PaperlessModule,
  ScheduleModule,  // bereits global registriert
]
providers: [AgrarmonitorService, AgrarmonitorPollingService]

Neue Endpoints (in AgrarmonitorController)

Method Route Beschreibung
GET /api/agrarmonitor/polling-config Tag-IDs lesen
PUT /api/agrarmonitor/polling-config Tag-IDs speichern
POST /api/agrarmonitor/run-polling Polling manuell auslösen

Alle Routen: @RequirePermissions(Permission.MANAGE_SETTINGS)

.env.example — neuer Eintrag

AGRARMONITOR_POLLING_CRON=0 */30 * * * *   # alle 30 Minuten

Frontend

Agrarmonitor-Tab (bestehend erweitern)

Neuer Abschnitt "Polling-Konfiguration":

  • Input "Tag: Fertig in Agrarmonitor" (Zahl, lädt aus /api/agrarmonitor/polling-config)
  • Input "Tag: Verbucht" (Zahl)
  • Speichern-Button → PUT /api/agrarmonitor/polling-config

Neuer Abschnitt "Polling ausführen":

  • Button "Jetzt ausführen" → POST /api/agrarmonitor/run-polling
  • Ergebnisanzeige: "X verarbeitet, X aktualisiert, X Fehler"

"Benutzer & Betriebe"-Tab (bestehend erweitern)

In der Client-Tabelle: neue Spalte "Agrarmonitor-BetriebId" (inline editierbar, Zahl oder leer).
Speichern via PUT /api/settings/clients/:id (neuer Endpoint oder bestehenden erweitern).


Datenfluss

Cron / manueller Trigger
  → AgrarmonitorPollingService.runPolling()
    → AgrarmonitorService.getClient()      (Connector)
    → PaperlessService.getDocuments()      (Tag-Fertig-Filter)
    → pro Dokument:
        → client.eingangsrechnungenLivesearch()
        → client.setEingangsdatum()         (falls nötig)
        → client.fetchCustomers() + PaperlessService.updateDocument()

Fehlerbehandlung

  • Einzelne Dokument-Fehler werden geloggt, überspringen den Eintrag, brechen den gesamten Lauf nicht ab
  • Connector-Fehler (Verbindung zu Agrarmonitor) brechen den Lauf ab, geben {error} zurück
  • Ergebnis wird immer als strukturiertes Objekt zurückgegeben (nie 500)

Nicht im Scope

  • E-Mail-Benachrichtigung bei Fehlern (kommt ggf. später via Postprocessing)
  • Rückgängig machen von Buchungen
  • Polling-Log in der Datenbank (Ergebnis nur in Backend-Logs + API-Response)