docs: add Agrarmonitor polling design plans
Build and Push Multi-Platform Images / build-and-push (push) Successful in 57s
Build and Push Multi-Platform Images / build-and-push (push) Successful in 57s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,135 @@
|
||||
# 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:
|
||||
```typescript
|
||||
@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 `Eingangsdatum` → `client.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
|
||||
```typescript
|
||||
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)
|
||||
Reference in New Issue
Block a user