This commit is contained in:
seb
2026-10-16 22:09:12 +02:00
parent 796f6a3272
commit 7635821dad
38 changed files with 6191 additions and 3350 deletions

View File

@@ -0,0 +1,231 @@
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 Delivery Summary, Ledger Sync & Filtering in dashdbschema ---');
const tempDir = mkdtempSync(join(tmpdir(), 'test-delivery-summary-'));
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('delivery-summary-test@example.com');
const company = await store.company.create({
name: 'Delivery Summary Corp',
iso639: 'de',
taxrate: 19,
reducedtaxrate: 7,
googleAuthId,
});
await store.google_auth.setSelectedCompany(googleAuthId, company.id);
const warehouse = await store.warehouse.create(googleAuthId, { name: 'Hauptlager' });
await store.unit.upsert(googleAuthId, {
si: 'stk',
basesi: 'stk',
basesifactor: 1,
symbol: 'Stk',
name: 'Stück',
});
const supplierAlpha = await store.supplier.create(googleAuthId, {
name: 'Alpha Supplier GmbH',
});
const supplierBeta = await store.supplier.create(googleAuthId, {
name: 'Beta Logistics Inc',
});
// 1. Create articles:
// Art1: track_stock = 1 (Stock item)
const artStock1 = await store.article.createUnderParent({
googleAuthId,
parentId: company.rootCategoryId,
name: 'Stock Item 1',
track_stock: 1,
});
// Art2: track_stock = 1 (Stock item)
const artStock2 = await store.article.createUnderParent({
googleAuthId,
parentId: company.rootCategoryId,
name: 'Stock Item 2',
track_stock: 1,
});
// Art3: track_stock = 0 (Service / Non-stock item)
const artService = await store.article.createUnderParent({
googleAuthId,
parentId: company.rootCategoryId,
name: 'Shipping Freight Fee',
track_stock: 0,
});
// 2. Create Delivery 1:
// Has 2 lines: artStock1 (qty 10), artService (qty 1)
const delivery1 = await store.delivery.create(googleAuthId, {
date: '2026-08-01T10:00:00Z',
externalNumber: 'DEL-ALPHA-1001',
supplierId: supplierAlpha.id,
lines: [
{ sku: artStock1.sku, name: 'Stock Item 1', amount: 10, net: 50, taxrate: 19 },
{ sku: artService.sku, name: 'Shipping Freight Fee', amount: 1, net: 10, taxrate: 19 },
],
});
console.log('Delivery 1 created with id:', delivery1.id);
// Verify deliverysummary row for delivery 1:
// positions = 2, total_quantity = 11, stock_positions = 1, booked_positions = 0, unbooked_positions = 1, is_booked = 0
let sum1 = provider.db.prepare('SELECT * FROM deliverysummary WHERE manifest_id = ?').get(delivery1.id);
assert(sum1, 'deliverysummary row for delivery 1 must exist');
assert.equal(sum1.positions, 2, 'Total positions should be 2');
assert.equal(sum1.stock_positions, 1, 'Stock positions should be 1');
assert.equal(sum1.booked_positions, 0, 'Booked positions should initially be 0');
assert.equal(sum1.unbooked_positions, 1, 'Unbooked positions should initially be 1');
assert.equal(sum1.stock_quantity, 10, 'Stock quantity should be 10');
assert.equal(sum1.booked_quantity, 0, 'Booked quantity should initially be 0');
assert.equal(sum1.unbooked_quantity, 10, 'Unbooked quantity should initially be 10');
assert.equal(sum1.is_booked, 0, 'is_booked should be 0');
assert.equal(sum1.supplier_name, 'Alpha Supplier GmbH');
// 3. Create Delivery 2:
// Has 1 line: artStock2 (qty 5), Supplier: Beta
const delivery2 = await store.delivery.create(googleAuthId, {
date: '2026-10-01T10:00:00Z',
externalNumber: 'DEL-BETA-2002',
supplierId: supplierBeta.id,
lines: [
{ sku: artStock2.sku, name: 'Stock Item 2', amount: 5, net: 20, taxrate: 19 },
],
});
let sum2 = provider.db.prepare('SELECT * FROM deliverysummary WHERE manifest_id = ?').get(delivery2.id);
assert(sum2, 'deliverysummary row for delivery 2 must exist');
assert.equal(sum2.stock_positions, 1);
assert.equal(sum2.unbooked_positions, 1);
assert.equal(sum2.is_booked, 0);
// 4. Book Delivery 1 partially:
// Book 4 units of artStock1 in warehouse
const lineStock1 = delivery1.lines.find((l) => l.sku === artStock1.sku);
assert(lineStock1, 'lineStock1 must exist');
await store.ledger.add(googleAuthId, {
manifestarticle_id: lineStock1.id,
warehouse_id: warehouse.id,
transaction_type: 'DELIVERY',
amount: 4,
transaction_text: 'Partial goods receipt',
});
sum1 = provider.db.prepare('SELECT * FROM deliverysummary WHERE manifest_id = ?').get(delivery1.id);
assert.equal(sum1.booked_positions, 0, 'Booked positions should still be 0 since 4 < 10');
assert.equal(sum1.unbooked_positions, 1);
assert.equal(sum1.booked_quantity, 4);
assert.equal(sum1.unbooked_quantity, 6);
assert.equal(sum1.is_booked, 0);
console.log('✓ Partial booking properly updated deliverysummary');
// 5. Book remaining 6 units of artStock1
await store.ledger.add(googleAuthId, {
manifestarticle_id: lineStock1.id,
warehouse_id: warehouse.id,
transaction_type: 'DELIVERY',
amount: 6,
transaction_text: 'Final goods receipt',
});
sum1 = provider.db.prepare('SELECT * FROM deliverysummary WHERE manifest_id = ?').get(delivery1.id);
assert.equal(sum1.booked_positions, 1, 'Booked positions should now be 1');
assert.equal(sum1.unbooked_positions, 0, 'Unbooked positions should now be 0');
assert.equal(sum1.booked_quantity, 10);
assert.equal(sum1.unbooked_quantity, 0);
assert.equal(sum1.is_booked, 1, 'Delivery 1 should now be fully booked (is_booked = 1)');
console.log('✓ Full booking properly updated deliverysummary (is_booked = 1)');
// 6. Test windowed / paged list:
// Both deliveries present
const pagedAll = await store.delivery.list(googleAuthId, { offset: 0, limit: 10 });
assert.equal(pagedAll.total, 2);
assert.equal(pagedAll.unfilteredTotal, 2);
assert.equal(pagedAll.deliveries.length, 2);
assert.equal(pagedAll.offset, 0);
assert.equal(pagedAll.limit, 10);
// Filter onlyUnbooked (Delivery 1 is fully booked, Delivery 2 is unbooked)
const pagedUnbooked = await store.delivery.list(googleAuthId, { onlyUnbooked: true });
assert.equal(pagedUnbooked.total, 1, 'Only 1 delivery is unbooked');
assert.equal(pagedUnbooked.unfilteredTotal, 2, 'Unfiltered total remains 2');
assert.equal(pagedUnbooked.deliveries[0].id, delivery2.id);
console.log('✓ onlyUnbooked filter returned only unbooked deliveries');
// Search filter: 'Beta'
const searchBeta = await store.delivery.list(googleAuthId, { search: 'Beta' });
assert.equal(searchBeta.total, 1);
assert.equal(searchBeta.unfilteredTotal, 2);
assert.equal(searchBeta.deliveries[0].id, delivery2.id);
// Search filter: 'ALPHA-1001'
const searchNum = await store.delivery.list(googleAuthId, { search: 'ALPHA-1001' });
assert.equal(searchNum.total, 1);
assert.equal(searchNum.deliveries[0].id, delivery1.id);
// Test unpaged backwards compatibility
const unpaged = await store.delivery.list(googleAuthId);
assert(Array.isArray(unpaged), 'Unpaged list should return Array');
assert.equal(unpaged.length, 2);
const d1 = unpaged.find((d) => d.id === delivery1.id);
assert(d1.ledger, 'd1 should contain ledger summary object');
assert.equal(d1.ledger.totalPositions, 1);
assert.equal(d1.ledger.bookedPositions, 1);
assert.equal(d1.ledger.unbookedPositions, 0);
assert.equal(d1.ledger.isBooked, true);
const d2 = unpaged.find((d) => d.id === delivery2.id);
assert.equal(d2.ledger.unbookedPositions, 1);
assert.equal(d2.ledger.isBooked, false);
console.log('✓ Unpaged list returns enriched deliveries with ledger summary');
// 7. Test rebuildSummaries
provider.db.prepare('DELETE FROM deliverysummary').run();
const countEmpty = provider.db.prepare('SELECT COUNT(*) AS cnt FROM deliverysummary').get().cnt;
assert.equal(countEmpty, 0);
await store.delivery.rebuildSummaries(googleAuthId);
const countRebuilt = provider.db.prepare('SELECT COUNT(*) AS cnt FROM deliverysummary').get().cnt;
assert.equal(countRebuilt, 2, 'Rebuilt deliverysummary should have 2 rows');
const rebuiltD1 = provider.db.prepare('SELECT * FROM deliverysummary WHERE manifest_id = ?').get(delivery1.id);
assert.equal(rebuiltD1.is_booked, 1);
assert.equal(rebuiltD1.booked_quantity, 10);
assert.equal(rebuiltD1.unbooked_quantity, 0);
const rebuiltD2 = provider.db.prepare('SELECT * FROM deliverysummary WHERE manifest_id = ?').get(delivery2.id);
assert.equal(rebuiltD2.is_booked, 0);
assert.equal(rebuiltD2.unbooked_positions, 1);
console.log('✓ rebuildSummaries restored all deliverysummary rows accurately');
console.log('--- ALL DELIVERY SUMMARY & FILTER TESTS PASSED ---');
} finally {
try {
rmSync(tempDir, { recursive: true, force: true });
} catch {}
}
}
run().catch((err) => {
console.error(err);
process.exit(1);
});