fix(erp-export): strict seit format, DB clock for settle window, movement index, one scope per key

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-10-13 23:24:05 +02:00
1 parent 53fab102f2
commit 25d95b0473
19 files changed
+426 -57

No files matched your search

+31 -5
View File
@@ -474,10 +474,13 @@ describe('ERP-Inventar-Export (e2e)', () => {
});
describe('Bewegungen', () => {
async function myMovements(): Promise<{ items: Item[]; cursor: string }> {
async function myMovements(
seit = at(0).toISOString(),
limit = 2,
): Promise<{ items: Item[]; cursor: string }> {
const mine = new Set(Object.values(movementIds));
const found: Item[] = [];
let query = `bewegungen?limit=2&seit=${at(0).toISOString()}`;
let query = `bewegungen?limit=${limit}&seit=${encodeURIComponent(seit)}`;
for (let page = 0; page < 40; page++) {
const body = (await get(query, erpKey).expect(200))
.body as PageBody<Item>;
@@ -489,7 +492,7 @@ describe('ERP-Inventar-Export (e2e)', () => {
if (!body.hasMore || passedMine) {
return { items: found, cursor: body.nextCursor! };
}
query = `bewegungen?limit=2&nach=${body.nextCursor}`;
query = `bewegungen?limit=${limit}&nach=${body.nextCursor}`;
}
throw new Error('zu viele Seiten');
}
@@ -545,6 +548,22 @@ describe('ERP-Inventar-Export (e2e)', () => {
expect(raw).not.toContain('userId');
});
it('nimmt seit als Kalendertag (Mitternacht UTC) und mit Zone an', async () => {
const expected = (await myMovements()).items.map((m) => m.id);
expect(expected.length).toBeGreaterThan(0);
const day = at(0).toISOString().slice(0, 10);
const fromDay = await myMovements(day, 500);
expect(fromDay.items.map((m) => m.id)).toEqual(expected);
// Derselbe Zeitpunkt wie at(0), mit +01:00 geschrieben.
const local = new Date(at(0).getTime() + 60 * 60 * 1000)
.toISOString()
.slice(0, 23);
const fromOffset = await myMovements(`${local}+01:00`);
expect(fromOffset.items.map((m) => m.id)).toEqual(expected);
});
it('meldet, bis wann die Liste vollständig ist', async () => {
const before = Date.now();
const body = (await get('bewegungen?limit=1', erpKey).expect(200))
@@ -574,6 +593,13 @@ describe('ERP-Inventar-Export (e2e)', () => {
['produkte?seite=2'],
['chargen?nach=bm90LWpzb24'],
['bewegungen?seit=gestern'],
// Andere ISO-8601-Formen: früher 500 (Woche, Kurzform) oder falsch gelesen.
['bewegungen?seit=2026-W01'],
['bewegungen?seit=20260101'],
['bewegungen?seit=-2026-01-01'],
['bewegungen?seit=2026-001'],
['bewegungen?seit=2026-01-01T24:00'],
['bewegungen?seit=9999-12-31T00:00:00Z'],
['ernten?jahr=1800'],
['ernten?jahr=dieses'],
])('lehnt %s ab (400)', async (path) => {
@@ -594,9 +620,9 @@ describe('ERP-Inventar-Export (e2e)', () => {
await get(`bewegungen?nach=${cursor}`, erpKey).expect(400);
});
it('verträgt ein fernes seit (leere Seite statt Fehler)', async () => {
it('verträgt ein fernes seit innerhalb der Jahresgrenzen (leere Seite statt Fehler)', async () => {
const body = (
await get('bewegungen?seit=9999-12-31T00:00:00Z', erpKey).expect(200)
await get('bewegungen?seit=2100-12-31T00:00:00Z', erpKey).expect(200)
).body as PageBody<Item>;
expect(body.items).toEqual([]);
});