feat: make server own tabs
CI / build-and-test (push) Canceled after 0s

This commit is contained in:
2026-10-20 16:18:36 +02:00
parent 1e4438ec5a
commit 0ca9f4d16a
31 changed files with 2101 additions and 892 deletions
+34 -1
View File
@@ -33,6 +33,39 @@ describe('parseTabEvents', () => {
expect(rejected).toEqual([]);
});
it('accepts tab and stock events, and a stock count of zero', () => {
const base = { occurredAt: '2026-10-24T21:00:00.000Z' };
const { accepted, rejected } = parseTabEvents([
{ ...base, id: '1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e', type: 'tab_opened', tabId: 't1', customerName: 'Jan', openedAt: base.occurredAt },
{ ...base, id: '2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f', type: 'tab_renamed', tabId: 't1', customerName: 'Jan P.' },
{ ...base, id: '3d4e5f6a-7b8c-4d9e-8f1a-2b3c4d5e6f7a', type: 'stock_set', productId: '12', quantity: 0 },
{ ...base, id: '4e5f6a7b-8c9d-4e0f-9a2b-3c4d5e6f7a8b', type: 'stock_set', productId: '12', quantity: null },
]);
expect(rejected).toEqual([]);
expect(accepted.map((e) => e.type)).toEqual(['tab_opened', 'tab_renamed', 'stock_set', 'stock_set']);
});
it('rejects a stock count without a product or below zero, and a tab event without a tab', () => {
const base = { occurredAt: '2026-10-24T21:00:00.000Z' };
const { accepted, rejected } = parseTabEvents([
{ ...base, id: '5f6a7b8c-9d0e-4f1a-8b3c-4d5e6f7a8b9c', type: 'stock_set', quantity: 3 },
{ ...base, id: '6a7b8c9d-0e1f-4a2b-9c4d-5e6f7a8b9c0d', type: 'stock_set', productId: '12', quantity: -1 },
{ ...base, id: '7b8c9d0e-1f2a-4b3c-8d5e-6f7a8b9c0d1e', type: 'tab_opened', customerName: 'Jan' },
]);
expect(accepted).toEqual([]);
expect(rejected).toHaveLength(3);
});
it('stores a stock count without a tab', () => {
const [event] = parseTabEvents([
{ id: '8c9d0e1f-2a3b-4c4d-9e6f-7a8b9c0d1e2f', type: 'stock_set', productId: '12', quantity: 30, occurredAt: '2026-10-24T21:00:00.000Z' },
]).accepted;
expect(tabEventRow(event, 'v1', 'd1', now)).toMatchObject({ type: 'stock_set', tabId: null, productId: '12', stockSetTo: 30 });
});
it('rejects invalid events one by one, keeping their id', () => {
const { accepted, rejected } = parseTabEvents([
lineAdded,
@@ -87,7 +120,7 @@ describe('tabEventRow', () => {
const row = tabEventRow(event, 'v1', 'd1', now);
expect(row).toMatchObject({ type: 'settled', amountInCents: 500, paymentMethod: 'payconiq', commandId: null });
expect(row.items).toEqual(settled.items);
expect(row.items).toEqual([{ productId: null, productName: 'Cola', quantity: 2, unitPriceInCents: 250 }]);
expect(row.quantityDelta).toBeUndefined();
});