Build and Push Multi-Platform Images / build-and-push (push) Successful in 1m1s
Neuer Bereich „Lieferantennummern überprüfen“ in den Agrarmonitor- Einstellungen. Er vergibt allen aktiven Lieferanten ohne Lieferantennummer eine fortlaufende Nummer im Schema 1555xxxx, ab der höchsten vergebenen Nummer (Inaktive zählen mit, Altlasten werden ignoriert). - Vorschau „Lieferant → neue Nummer“, geschrieben wird erst nach Bestätigung; Einzelmodus zum Testen an einem Lieferanten - formData wird wie in der Weboberfläche aus #form_detail aufgebaut, nur die Lieferantennummer ändert sich - Dublettencheck über vorhanden.php, Erfolgskontrolle durch Neuladen des Details, Abbruch beim ersten Fehler - Lauf im Hintergrund mit Status-Abfrage (wegen Proxy-Timeouts), Listenfilter werden danach zurückgesetzt - HTML-Parsing mit cheerio, Unit-Tests für Parser und Vergabe-Ablauf Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
152 lines
4.6 KiB
TypeScript
152 lines
4.6 KiB
TypeScript
import type { AxiosInstance } from 'axios';
|
||
import type { AgrarmonitorService } from './agrarmonitor.service';
|
||
import {
|
||
LieferantennummernService,
|
||
type LieferantennummerLaufErgebnis,
|
||
} from './lieferantennummern.service';
|
||
import type { ListenLieferant } from './lieferantennummern.parser';
|
||
|
||
// Der echte Connector lädt jsdom (ESM), das Jest nicht verarbeiten kann – hier wird er nicht gebraucht.
|
||
jest.mock('agrarmonitor-connector', () => ({}));
|
||
|
||
interface UpdateBody {
|
||
kundeID: number;
|
||
formData: Record<string, unknown>;
|
||
}
|
||
|
||
function detail(nummer: string): string {
|
||
return (
|
||
'<form id="form_detail">' +
|
||
'<input type="text" name="kundennummer" id="kundennummer" value="21207">' +
|
||
`<input type="text" name="lieferantennummer" id="lieferantennummer" value="${nummer}">` +
|
||
'<input type="text" name="firma" value="Firma">' +
|
||
'<input type="checkbox" name="ist_kunde" value="1">' +
|
||
'<input type="checkbox" name="ist_lieferant" value="1" checked>' +
|
||
'</form>'
|
||
);
|
||
}
|
||
|
||
function kandidat(kundeId: number, firma: string): ListenLieferant {
|
||
return { kundeId, lieferantennummer: '', firma, name: '', aktiv: true };
|
||
}
|
||
|
||
function neuerLauf(gesamt: number): LieferantennummerLaufErgebnis {
|
||
return {
|
||
modus: 'alle',
|
||
gestartetAm: '',
|
||
beendetAm: null,
|
||
gesamt,
|
||
vergeben: 0,
|
||
uebersprungen: 0,
|
||
zuPruefen: 0,
|
||
fehler: 0,
|
||
abgebrochen: false,
|
||
eintraege: [],
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Simuliert Agrarmonitor: speichert Nummern aus updateKunde.php pro Kunde,
|
||
* vorhanden.php meldet für die Ids in `dubletten` ähnliche Kontakte.
|
||
*/
|
||
function fakeHttp(opts: {
|
||
nummern: Record<number, string>;
|
||
dubletten?: number[];
|
||
speichernIgnorieren?: number[];
|
||
}) {
|
||
const aufrufe: string[] = [];
|
||
const updates: UpdateBody[] = [];
|
||
const http = {
|
||
get: jest.fn((url: string) => {
|
||
aufrufe.push(`GET ${url}`);
|
||
const m = /\/kunden\/detail\/(\d+)/.exec(url);
|
||
if (m) {
|
||
return Promise.resolve({
|
||
data: detail(opts.nummern[Number(m[1])] ?? ''),
|
||
});
|
||
}
|
||
return Promise.resolve({ data: '' });
|
||
}),
|
||
post: jest.fn((url: string, body: string | UpdateBody) => {
|
||
aufrufe.push(`POST ${url}`);
|
||
if (typeof body === 'string') {
|
||
const id = Number(new URLSearchParams(body).get('customerID'));
|
||
return Promise.resolve({
|
||
data: opts.dubletten?.includes(id) ? '<div>Ähnlich</div>' : '',
|
||
});
|
||
}
|
||
updates.push(body);
|
||
if (!opts.speichernIgnorieren?.includes(body.kundeID)) {
|
||
opts.nummern[body.kundeID] = String(body.formData.lieferantennummer);
|
||
}
|
||
return Promise.resolve({ data: '/kunden/detail/' + body.kundeID });
|
||
}),
|
||
};
|
||
return { http: http as unknown as AxiosInstance, aufrufe, updates };
|
||
}
|
||
|
||
function service() {
|
||
const agrarmonitor = { clearClient: jest.fn() };
|
||
return new LieferantennummernService(
|
||
agrarmonitor as unknown as AgrarmonitorService,
|
||
);
|
||
}
|
||
|
||
describe('LieferantennummernService.vergeben', () => {
|
||
it('vergibt fortlaufend, überspringt Vorhandene und verbraucht bei Dubletten keine Nummer', async () => {
|
||
const { http, updates, aufrufe } = fakeHttp({
|
||
nummern: { 2: '15550010' },
|
||
dubletten: [3],
|
||
});
|
||
const lauf = neuerLauf(4);
|
||
await service().vergeben(
|
||
http,
|
||
[kandidat(1, 'A'), kandidat(2, 'B'), kandidat(3, 'C'), kandidat(4, 'D')],
|
||
15550706,
|
||
lauf,
|
||
);
|
||
|
||
expect(lauf.eintraege.map((e) => [e.kundeId, e.status, e.nummer])).toEqual([
|
||
[1, 'vergeben', '15550706'],
|
||
[2, 'uebersprungen', undefined],
|
||
[3, 'pruefen', undefined],
|
||
[4, 'vergeben', '15550707'],
|
||
]);
|
||
expect(lauf).toMatchObject({
|
||
vergeben: 2,
|
||
uebersprungen: 1,
|
||
zuPruefen: 1,
|
||
fehler: 0,
|
||
abgebrochen: false,
|
||
});
|
||
expect(updates[0].kundeID).toBe(1);
|
||
expect(updates[0].formData).toMatchObject({
|
||
kundennummer: '21207',
|
||
lieferantennummer: '15550706',
|
||
ist_kunde: '',
|
||
ist_lieferant: '1',
|
||
});
|
||
expect(aufrufe[aufrufe.length - 1]).toContain('itemsperpage=25');
|
||
expect(lauf.beendetAm).not.toBeNull();
|
||
});
|
||
|
||
it('bricht ab, wenn die Nummer nach dem Speichern nicht übernommen wurde', async () => {
|
||
const { http, updates, aufrufe } = fakeHttp({
|
||
nummern: {},
|
||
speichernIgnorieren: [1],
|
||
});
|
||
const lauf = neuerLauf(2);
|
||
await service().vergeben(
|
||
http,
|
||
[kandidat(1, 'A'), kandidat(2, 'B')],
|
||
15550706,
|
||
lauf,
|
||
);
|
||
|
||
expect(updates).toHaveLength(1);
|
||
expect(lauf).toMatchObject({ vergeben: 0, fehler: 1, abgebrochen: true });
|
||
expect(lauf.eintraege[0].hinweis).toContain('15550706');
|
||
expect(aufrufe[aufrufe.length - 1]).toContain('itemsperpage=25');
|
||
});
|
||
});
|