Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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):
- Tag-IDs aus
Setting-Tabelle lesen (Tag-Fertig, Tag-Verbucht) agrarmonitorService.getClient()→ Connector holenclient.fetchCustomers()→ aktive Lieferanten (ist_lieferant=1,ist_aktiv=1) als Paperless-Korrespondenten synchronisieren- Paperless-Dokumente mit Tag-Fertig laden
- Pro Dokument mit
interneBelegnummer:client.eingangsrechnungenLivesearch(belegnummer)aufrufen- Kein Treffer → überspringen
- Mehrere Treffer → Fehler loggen, überspringen
- Kein
eingangsDatum+ Paperless hatEingangsdatum→client.setEingangsdatum()aufrufen buchungsDatumvorhanden → 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
- Korrespondenten über
- 500ms Pause zwischen Dokumenten (API-Schonung)
PollingResultzurü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)