import assert from 'node:assert/strict'; import { mkdtempSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import LibDashStore from '../src/index.js'; import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js'; async function run() { console.log('--- Testing deposit via mandated optionslist ---'); const tempDir = mkdtempSync(join(tmpdir(), 'test-deposit-')); const dbFile = join(tempDir, 'test.db'); const storageDir = join(tempDir, 'storage'); const provider = new BetterSqlite3Provider({ filename: dbFile, storageDir, }); await provider.initialize(); const store = await new LibDashStore(provider); try { const googleAuthId = await store.google_auth.add('tester@example.com'); const company = await store.company.create({ name: 'Deposit Corp', iso639: 'de', taxrate: 19, reducedtaxrate: 7, googleAuthId, }); await store.google_auth.setSelectedCompany(googleAuthId, company.id); // 1. Create a category const cat = await store.category.createUnderParent({ googleAuthId, parentId: company.rootCategoryId, name: 'Getränke', }); // 2. Create terminal and enable category const terminal = await store.posterminal.upsert(googleAuthId, { name: 'POS 1', pairingpin: '1234', }); await store.posterminal.pair(terminal.id, { token: 'pos-token-xyz', clientserial: 'SN-001', pairedAt: new Date().toISOString(), }); await store.posterminal.setOn(googleAuthId, terminal.id, cat.id); // 3. Create beverage article const clubMate = await store.article.createUnderParent({ googleAuthId, parentId: cat.id, name: 'Club Mate 0.5l', sku: 'MATE-05', }); await store.article.setPricesBySku(googleAuthId, clubMate.sku, [ { net: 1.5, tax: 19 }, ]); // 4. Create deposit article const pfandArt = await store.article.createUnderParent({ googleAuthId, parentId: cat.id, name: 'Mehrwegpfand 0,08 €', sku: 'PFAND-0.08', track_stock: 0, }); await store.article.setPricesBySku(googleAuthId, pfandArt.sku, [ { gross: 0.08, tax: 19 }, ]); // 5. Query products BEFORE linking mandated option let prods = await store.posterminal.getProductList({ posterminalId: terminal.id }); let mateProd = prods.find((p) => p.sku === 'MATE-05'); let pfandProd = prods.find((p) => p.sku === 'PFAND-0.08'); assert.ok(mateProd, 'Club Mate should be listed'); assert.equal(mateProd.deposit, '0'); assert.equal(mateProd.d_price, '0.0'); assert.equal(mateProd.deposit_name, ''); assert.ok(pfandProd, 'Pfand article should be listed'); assert.equal(pfandProd.deposit, '0'); // 6. Link Mehrwegpfand as mandated option to Club Mate console.log('Linking Mehrwegpfand as mandated option...'); await store.optionslist.setOptionsByArticleSku(googleAuthId, clubMate.sku, [ { articleId: pfandArt.id, sku: pfandArt.sku, count: 1, sort: 0, mandated: true, }, ]); // 7. Query products AFTER linking mandated option prods = await store.posterminal.getProductList({ posterminalId: terminal.id }); mateProd = prods.find((p) => p.sku === 'MATE-05'); console.log('Club Mate with deposit option:', { sku: mateProd.sku, deposit: mateProd.deposit, d_price: mateProd.d_price, deposit_name: mateProd.deposit_name, }); assert.equal(mateProd.deposit, '1'); assert.equal(mateProd.d_price, '0.08'); assert.equal(mateProd.deposit_name, 'Mehrwegpfand 0,08 €'); // 8. Test option name change touching parent article console.log('Testing option name change touching parent article...'); const mateBeforeRename = (await provider.query('SELECT updated_at FROM article WHERE id = @id', { id: clubMate.id })).rows[0].updated_at; await new Promise((r) => setTimeout(r, 1100)); // wait >1s for timestamp delta await store.article.updateBySku(googleAuthId, pfandArt.sku, { name: 'Glas-Mehrwegpfand 0,08 €', }); const mateAfterRename = (await provider.query('SELECT updated_at FROM article WHERE id = @id', { id: clubMate.id })).rows[0].updated_at; assert.notEqual( mateBeforeRename, mateAfterRename, 'Club Mate updated_at must be bumped when its option article is renamed' ); prods = await store.posterminal.getProductList({ posterminalId: terminal.id }); mateProd = prods.find((p) => p.sku === 'MATE-05'); assert.equal(mateProd.deposit_name, 'Glas-Mehrwegpfand 0,08 €'); console.log('Renamed deposit reflected on parent product:', mateProd.deposit_name); // 9. Test option price change touching parent article console.log('Testing option price change touching parent article...'); const mateBeforePrice = mateAfterRename; await new Promise((r) => setTimeout(r, 1100)); await store.article.setPricesBySku(googleAuthId, pfandArt.sku, [ { gross: 0.15, tax: 19 }, ]); const mateAfterPrice = (await provider.query('SELECT updated_at FROM article WHERE id = @id', { id: clubMate.id })).rows[0].updated_at; assert.notEqual( mateBeforePrice, mateAfterPrice, 'Club Mate updated_at must be bumped when its option article price changes' ); prods = await store.posterminal.getProductList({ posterminalId: terminal.id }); mateProd = prods.find((p) => p.sku === 'MATE-05'); assert.equal(mateProd.d_price, '0.15'); console.log('New deposit price reflected on parent product:', mateProd.d_price); // 10. Test clearing options console.log('Clearing options...'); await store.optionslist.setOptionsByArticleSku(googleAuthId, clubMate.sku, []); prods = await store.posterminal.getProductList({ posterminalId: terminal.id }); mateProd = prods.find((p) => p.sku === 'MATE-05'); assert.equal(mateProd.deposit, '0'); assert.equal(mateProd.d_price, '0.0'); assert.equal(mateProd.deposit_name, ''); console.log('✅ ALL DEPOSIT OPTIONS TESTS PASSED'); } finally { try { rmSync(tempDir, { recursive: true, force: true }); } catch {} } } run().catch((err) => { console.error('Test failed:', err); process.exit(1); });