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 main() { console.log('--- Testing updated_at touch on all inventory movements ---'); const tempDir = mkdtempSync(join(tmpdir(), 'test-touch-')); 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: 'Inventory Corp', iso639: 'de', taxrate: 19, reducedtaxrate: 7, googleAuthId, }); await store.google_auth.setSelectedCompany(googleAuthId, company.id); // Create warehouse const wh = await store.warehouse.create(googleAuthId, { name: 'Hauptlager' }); const cat = await store.category.createUnderParent({ googleAuthId, parentId: company.rootCategoryId, name: 'Waren', }); // Create article with past updated_at const art = await store.article.createUnderParent({ googleAuthId, parentId: cat.id, sku: 'TEST-SKU', name: 'Test Article', track_stock: 1, }); const oldTime = '2020-01-01T00:00:00.000Z'; await provider.query(`UPDATE article SET updated_at = @oldTime WHERE id = @id`, { oldTime, id: art.id }); const getUpdatedAt = async (articleId) => { const res = await provider.query(`SELECT updated_at FROM article WHERE id = @articleId`, { articleId }); return res.rows[0]?.updated_at; }; const initialUpdatedAt = await getUpdatedAt(art.id); assert.equal(initialUpdatedAt, oldTime, 'Should start with old updated_at'); // 1. Test store.stock.adjust console.log('1. Testing store.stock.adjust touches article.updated_at...'); await store.stock.adjust(googleAuthId, { sku: 'TEST-SKU', warehouseId: wh.id, amount: 2, // reason omitted so it defaults to "Manual stock addition (+2)" }); const afterAdjustUpdatedAt = await getUpdatedAt(art.id); assert.notEqual(afterAdjustUpdatedAt, oldTime, 'stock.adjust should touch updated_at'); assert.ok(new Date(afterAdjustUpdatedAt).getTime() > new Date(oldTime).getTime()); // Check history was recorded with exact text const historyRes = await provider.query(`SELECT text FROM articlehistory WHERE article_id = @id`, { id: art.id }); const adjustmentEntry = historyRes.rows.find((h) => h.text.includes('Bestandskorrektur +2 (Manual stock addition (+2))')); assert.ok(adjustmentEntry, 'Should have exact article history entry'); // Reset updated_at to old time await provider.query(`UPDATE article SET updated_at = @oldTime WHERE id = @id`, { oldTime, id: art.id }); // 2. Test Stückliste component touch console.log('2. Testing Stückliste parent is touched when component has stock adjustment...'); const bundle = await store.article.createUnderParent({ googleAuthId, parentId: cat.id, sku: 'BUNDLE-1', name: 'Bundle 1', track_stock: 0, }); await store.articlelist.setItemsByArticleSku(googleAuthId, 'BUNDLE-1', [ { sku: 'TEST-SKU', count: 1 }, ]); await provider.query(`UPDATE article SET updated_at = @oldTime WHERE id = @id`, { oldTime, id: bundle.id }); await store.stock.adjust(googleAuthId, { sku: 'TEST-SKU', warehouseId: wh.id, amount: 5, text: 'Restock component', }); const bundleUpdatedAt = await getUpdatedAt(bundle.id); assert.notEqual(bundleUpdatedAt, oldTime, 'Stückliste bundle updated_at should be touched when component changes stock'); // 3. Test delivery acceptance touches article.updated_at console.log('3. Testing delivery touches article.updated_at...'); const supplier = await store.supplier.create(googleAuthId, { name: 'Supplier Inc' }); const delivery = await store.delivery.create(googleAuthId, { supplierId: supplier.id, date: new Date().toISOString(), lines: [{ sku: 'TEST-SKU', amount: 10, net: 5, taxrate: 19 }], }); await provider.query(`UPDATE article SET updated_at = @oldTime WHERE id = @id`, { oldTime, id: art.id }); await store.delivery.book(googleAuthId, { id: delivery.id, warehouseId: wh.id }); const deliveryUpdatedAt = await getUpdatedAt(art.id); assert.notEqual(deliveryUpdatedAt, oldTime, 'delivery.book should touch article.updated_at'); // 4. Test customer shipment touches article.updated_at console.log('4. Testing shipment touches article.updated_at...'); const groups = await store.customergroup.list(googleAuthId); const customer = await store.entity.create(googleAuthId, { name: 'Customer A', customergroupId: groups[0].id }); const order = await store.order.create(googleAuthId, { number: 'AUF-000001', date: new Date().toISOString(), entityId: customer.id, lines: [{ sku: 'TEST-SKU', amount: 3, net: 10, taxrate: 19 }], }); const carrier = await store.carrier.create(googleAuthId, { name: 'DHL' }); await provider.query(`UPDATE article SET updated_at = @oldTime WHERE id = @id`, { oldTime, id: art.id }); await store.shipment.create(googleAuthId, { orderId: order.id, lines: [{ sku: 'TEST-SKU', amount: 3 }], warehouseId: wh.id, shipping: { carrierId: carrier.id, type: 'standard', state: 'shipped', warehouseId: wh.id, }, }); const shipmentUpdatedAt = await getUpdatedAt(art.id); assert.notEqual(shipmentUpdatedAt, oldTime, 'shipment.create should touch article.updated_at'); console.log('✅ ALL INVENTORY TOUCH TESTS PASSED'); } finally { try { rmSync(tempDir, { recursive: true, force: true }); } catch {} } } main().catch((err) => { console.error('Test failed:', err); process.exit(1); });