1d11d8a3bd
Build and Push Multi-Platform Images / build-and-push (push) Successful in 57s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
136 lines
4.8 KiB
Markdown
136 lines
4.8 KiB
Markdown
# 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)
|