feat: add AgrarmonitorWebService with livesearch and date setters
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
// paperless-backend/src/agrarmonitor/agrarmonitor-web.service.ts
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { parse } from 'node-html-parser';
|
||||
import { AgrarmonitorService } from './agrarmonitor.service';
|
||||
|
||||
export interface EingangsrechnungEntry {
|
||||
eingangId: number;
|
||||
belegNummer: string;
|
||||
interneBelegNummer: string;
|
||||
kundenId: number;
|
||||
betriebId: number;
|
||||
buchungsDatum: Date | null;
|
||||
eingangsDatum: Date | null;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class AgrarmonitorWebService {
|
||||
private readonly logger = new Logger(AgrarmonitorWebService.name);
|
||||
private readonly baseUrl: string;
|
||||
|
||||
constructor(
|
||||
private readonly agrarmonitorService: AgrarmonitorService,
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
this.baseUrl = this.configService.get<string>(
|
||||
'AGRARMONITOR_BASE_URL',
|
||||
'https://admin7.agrarmonitor.de',
|
||||
);
|
||||
}
|
||||
|
||||
async eingangsrechnungenLivesearch(suchstring: string): Promise<EingangsrechnungEntry[]> {
|
||||
const client = await this.agrarmonitorService.getClient();
|
||||
|
||||
await client.http.get('/');
|
||||
const searchUrl =
|
||||
`/module/dateien/livesearch.php?suchstring=${encodeURIComponent(suchstring)}` +
|
||||
`&stammdatum_typ=-1&mobil=-1&sensibel=-1&firma=0&itemsperpage=100000&seite=1`;
|
||||
const { data: html } = await client.http.get<string>(searchUrl, { responseType: 'text' });
|
||||
|
||||
const root = parse('<doc>' + html + '</doc>');
|
||||
const table = root.querySelector('table#dateien');
|
||||
if (!table) return [];
|
||||
|
||||
const rows = table.querySelectorAll('tbody tr');
|
||||
const results: EingangsrechnungEntry[] = [];
|
||||
|
||||
for (const row of rows) {
|
||||
const tds = row.querySelectorAll('td');
|
||||
if (tds.length < 4) continue;
|
||||
if (!tds[3].text.trim().startsWith('Eingangsrechnungen')) continue;
|
||||
|
||||
const linkEl = tds[3].querySelector('a');
|
||||
if (!linkEl) continue;
|
||||
|
||||
const href = linkEl.getAttribute('href') ?? '';
|
||||
const eingangId = parseInt(href.split('/').pop() ?? '0', 10);
|
||||
if (!eingangId) continue;
|
||||
|
||||
const belegText = linkEl.text;
|
||||
const belegParts = belegText.split(',');
|
||||
const belegNummer = belegParts[0]?.trim() ?? '';
|
||||
|
||||
const { data: editHtml } = await client.http.get<string>(
|
||||
`/module/eingangsrechnungen/api/eingangsrechnungen.php?id=edit&rechnungId=${eingangId}`,
|
||||
{ responseType: 'text' },
|
||||
);
|
||||
const editRoot = parse(editHtml);
|
||||
|
||||
const interneBelegNummer =
|
||||
editRoot.querySelector('input[name="lieferscheinnummer"]')?.getAttribute('value') ?? '';
|
||||
const kundenId = parseInt(
|
||||
editRoot
|
||||
.querySelector('select[name="rgempf"] option[selected]')
|
||||
?.getAttribute('value') ?? '0',
|
||||
10,
|
||||
);
|
||||
const betriebId = parseInt(
|
||||
editRoot
|
||||
.querySelector('select[name="firma_id"] option[selected]')
|
||||
?.getAttribute('value') ?? '0',
|
||||
10,
|
||||
);
|
||||
|
||||
const { data: detailHtml } = await client.http.get<string>(
|
||||
`/eingangsrechnungen/detail/${eingangId}`,
|
||||
{ responseType: 'text' },
|
||||
);
|
||||
const detailRoot = parse(detailHtml);
|
||||
const receivedEl = detailRoot.getElementById('receivedStatus');
|
||||
|
||||
let eingangsDatum: Date | null = null;
|
||||
let buchungsDatum: Date | null = null;
|
||||
|
||||
if (receivedEl) {
|
||||
const eingangsText = receivedEl.text.trim();
|
||||
if (eingangsText !== 'Nicht empfangen' && eingangsText.length > 13) {
|
||||
eingangsDatum = this.parseGermanDate(eingangsText.substring(13));
|
||||
}
|
||||
|
||||
const parentText = receivedEl.parentNode?.text ?? '';
|
||||
const dashIdx = parentText.lastIndexOf('-');
|
||||
const buchenText = dashIdx >= 0 ? parentText.substring(dashIdx + 1).trim() : '';
|
||||
if (buchenText !== 'Nicht gebucht' && buchenText.length > 11) {
|
||||
buchungsDatum = this.parseGermanDate(buchenText.substring(11));
|
||||
}
|
||||
}
|
||||
|
||||
results.push({ eingangId, belegNummer, interneBelegNummer, kundenId, betriebId, buchungsDatum, eingangsDatum });
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
async setEingangsdatum(eingangId: number, _belegNummer: string, datum: Date): Promise<boolean> {
|
||||
const client = await this.agrarmonitorService.getClient();
|
||||
const params = new URLSearchParams();
|
||||
params.append('datum', this.formatGermanDate(datum));
|
||||
params.append('receiptID', String(eingangId));
|
||||
try {
|
||||
const res = await client.http.post(
|
||||
'/module/eingangsrechnungen/api/updateReceived.php',
|
||||
params.toString(),
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
Referer: `${this.baseUrl}/eingangsrechnungen/detail/${eingangId}`,
|
||||
Origin: this.baseUrl,
|
||||
},
|
||||
},
|
||||
);
|
||||
return res.status < 400;
|
||||
} catch (err: any) {
|
||||
this.logger.error(`setEingangsdatum(${eingangId}) Fehler: ${err?.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async setLieferscheinNummer(eingangId: number, lieferscheinNummer: string): Promise<boolean> {
|
||||
const client = await this.agrarmonitorService.getClient();
|
||||
const { data: editHtml } = await client.http.get<string>(
|
||||
`/module/eingangsrechnungen/api/eingangsrechnungen.php?id=edit&rechnungId=${eingangId}`,
|
||||
{ responseType: 'text' },
|
||||
);
|
||||
const editRoot = parse(editHtml);
|
||||
|
||||
const rechnungsnummer =
|
||||
editRoot.querySelector('input[name="rechnungsnummer"]')?.getAttribute('value') ?? '';
|
||||
const rechnungsdatum =
|
||||
editRoot.querySelector('input[name="rechnungsdatum"]')?.getAttribute('value') ?? '';
|
||||
const rgempf =
|
||||
editRoot
|
||||
.querySelector('select[name="rgempf"] option[selected]')
|
||||
?.getAttribute('value') ?? '';
|
||||
const addressName =
|
||||
editRoot.querySelector('input[name="addressName"]')?.getAttribute('value') ?? '';
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.append('lieferscheinnummer', lieferscheinNummer);
|
||||
params.append('rechnungsnummer', rechnungsnummer);
|
||||
params.append('rechnungsdatum', rechnungsdatum);
|
||||
params.append('rgempf', rgempf);
|
||||
params.append('adresstext', addressName);
|
||||
|
||||
try {
|
||||
const res = await client.http.post(
|
||||
`/module/eingangsrechnungen/api/eingangsrechnungen.php?id=update&rechnungId=${eingangId}`,
|
||||
params.toString(),
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
Referer: `${this.baseUrl}/eingangsrechnungen/detail/${eingangId}`,
|
||||
Origin: this.baseUrl,
|
||||
},
|
||||
},
|
||||
);
|
||||
return res.status < 400;
|
||||
} catch (err: any) {
|
||||
this.logger.error(`setLieferscheinNummer(${eingangId}) Fehler: ${err?.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private parseGermanDate(str: string): Date | null {
|
||||
const parts = str.trim().split('.');
|
||||
if (parts.length !== 3) return null;
|
||||
const [dd, mm, yy] = parts;
|
||||
const year = parseInt(yy, 10) < 50 ? 2000 + parseInt(yy, 10) : 1900 + parseInt(yy, 10);
|
||||
const d = new Date(year, parseInt(mm, 10) - 1, parseInt(dd, 10));
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
|
||||
private formatGermanDate(date: Date): string {
|
||||
const dd = String(date.getDate()).padStart(2, '0');
|
||||
const mm = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const yy = String(date.getFullYear()).slice(-2);
|
||||
return `${dd}.${mm}.${yy}`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user