feat: implement ProcessVerarbeiteteDocuments (Upload-Check)
Build and Push Multi-Platform Images / build-and-push (push) Successful in 37s
Build and Push Multi-Platform Images / build-and-push (push) Successful in 37s
Ported ProcessVerarbeiteteDocuments() from C# ProcessUploads.cs: - Checks docs tagged "hochgeladen" → eingangsrechnungVorhanden() - On match: livesearch, update title/type/created/correspondent/tags, set custom fields (externeBelegnummer, AgrarmonitorLink), addNote - Tag "hochgeladen" → "fertig" swap; owner via Client.AgrarmonitorBetriebId - 401/403 guard: clearClient() + break (same pattern as runPolling) - Cron: AGRARMONITOR_UPLOAD_CHECK_CRON (default: 0 * * * * *) - New settings: agrarmonitor_tag_hochgeladen, agrarmonitor_link_field - Endpoint: POST /api/agrarmonitor/process-uploads - Frontend: polling-config extended with tagHochgeladen + linkField select, new card "Dokumenten-Verarbeitung" with run button + result display Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -199,6 +199,8 @@ export interface AgrarmonitorStatusData {
|
||||
export interface AgrarmonitorPollingConfig {
|
||||
tagFertig: string;
|
||||
tagVerbucht: string;
|
||||
tagHochgeladen: string;
|
||||
linkField: string;
|
||||
}
|
||||
|
||||
export interface AgrarmonitorPollingResult {
|
||||
@@ -221,4 +223,6 @@ export const agrarmonitorApi = {
|
||||
api.put<AgrarmonitorPollingConfig>('/api/agrarmonitor/polling-config', config).then((r) => r.data),
|
||||
runPolling: () =>
|
||||
api.post<AgrarmonitorPollingResult>('/api/agrarmonitor/run-polling').then((r) => r.data),
|
||||
processUploads: () =>
|
||||
api.post<AgrarmonitorPollingResult>('/api/agrarmonitor/process-uploads').then((r) => r.data),
|
||||
};
|
||||
|
||||
@@ -2291,9 +2291,12 @@ function AgrarmonitorTab() {
|
||||
const [pollingConfigLoading, setPollingConfigLoading] = useState(false);
|
||||
const [pollingSaving, setPollingSaving] = useState(false);
|
||||
const [pollingRunning, setPollingRunning] = useState(false);
|
||||
const [uploadCheckRunning, setUploadCheckRunning] = useState(false);
|
||||
const [status, setStatus] = useState<AgrarmonitorStatusData | null>(null);
|
||||
const [registerResult, setRegisterResult] = useState<{ success: boolean; message: string } | null>(null);
|
||||
const [pollingResult, setPollingResult] = useState<AgrarmonitorPollingResult | null>(null);
|
||||
const [uploadCheckResult, setUploadCheckResult] = useState<AgrarmonitorPollingResult | null>(null);
|
||||
const [customFields, setCustomFields] = useState<PaperlessCustomField[]>([]);
|
||||
|
||||
const handleLoadStatus = async () => {
|
||||
setLoading(true);
|
||||
@@ -2341,7 +2344,10 @@ function AgrarmonitorTab() {
|
||||
}
|
||||
}, [pollingForm]);
|
||||
|
||||
useEffect(() => { handleLoadPollingConfig(); }, [handleLoadPollingConfig]);
|
||||
useEffect(() => {
|
||||
handleLoadPollingConfig();
|
||||
paperlessApi.getCustomFields().then(setCustomFields).catch(() => {});
|
||||
}, [handleLoadPollingConfig]);
|
||||
|
||||
const handleSavePollingConfig = async () => {
|
||||
const values = await pollingForm.validateFields() as AgrarmonitorPollingConfig;
|
||||
@@ -2369,6 +2375,19 @@ function AgrarmonitorTab() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleProcessUploads = async () => {
|
||||
setUploadCheckRunning(true);
|
||||
setUploadCheckResult(null);
|
||||
try {
|
||||
const result = await agrarmonitorApi.processUploads();
|
||||
setUploadCheckResult(result);
|
||||
} catch {
|
||||
message.error('Upload-Check fehlgeschlagen');
|
||||
} finally {
|
||||
setUploadCheckRunning(false);
|
||||
}
|
||||
};
|
||||
|
||||
const renderStatusTag = (value: boolean | null, labelTrue: string, labelFalse: string) => {
|
||||
if (value === null) return <Tag>–</Tag>;
|
||||
return value
|
||||
@@ -2462,6 +2481,16 @@ function AgrarmonitorTab() {
|
||||
>
|
||||
<Input placeholder="9" style={{ width: 120 }} />
|
||||
</Form.Item>
|
||||
<Form.Item name="tagHochgeladen" label="Tag-ID: Hochgeladen in Agrarmonitor">
|
||||
<Input placeholder="3" style={{ width: 120 }} />
|
||||
</Form.Item>
|
||||
<Form.Item name="linkField" label="Custom Field: Agrarmonitor-Link">
|
||||
<Select allowClear placeholder="Kein Feld ausgewählt" style={{ width: 280 }}>
|
||||
{customFields.map(f => (
|
||||
<Select.Option key={f.id} value={String(f.id)}>{f.id}: {f.name}</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Button type="primary" loading={pollingSaving} onClick={handleSavePollingConfig}>
|
||||
Speichern
|
||||
</Button>
|
||||
@@ -2492,6 +2521,35 @@ function AgrarmonitorTab() {
|
||||
)}
|
||||
</Space>
|
||||
</Card>
|
||||
|
||||
<Card size="small" title="Dokumenten-Verarbeitung">
|
||||
<Typography.Text type="secondary" style={{ display: 'block', marginBottom: 12 }}>
|
||||
Prüft Belege mit Tag "Hochgeladen in Agrarmonitor" und setzt den Tag auf "AMfertig",
|
||||
sobald sie im Agrarmonitor-Buchungssystem erscheinen.
|
||||
</Typography.Text>
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<Button loading={uploadCheckRunning} onClick={handleProcessUploads}>
|
||||
Jetzt prüfen
|
||||
</Button>
|
||||
{uploadCheckResult && (
|
||||
<div>
|
||||
<Tag color="blue">{uploadCheckResult.processed} geprüft</Tag>
|
||||
<Tag color="success">{uploadCheckResult.updated} aktualisiert</Tag>
|
||||
<Tag>{uploadCheckResult.skipped} übersprungen</Tag>
|
||||
{uploadCheckResult.errors.length > 0 && (
|
||||
<Tag color="error">{uploadCheckResult.errors.length} Fehler</Tag>
|
||||
)}
|
||||
{uploadCheckResult.errors.length > 0 && (
|
||||
<ul style={{ marginTop: 8, paddingLeft: 20 }}>
|
||||
{uploadCheckResult.errors.map((e, i) => (
|
||||
<li key={i} style={{ color: '#ff4d4f' }}>{e}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Space>
|
||||
</Card>
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user