221 lines
7.2 KiB
JavaScript
221 lines
7.2 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { mkdtempSync, rmSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { createHash } from 'node:crypto';
|
|
import LibDashStore from '../src/index.js';
|
|
import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js';
|
|
import { INIT_HASH, computePrevHash } from '../src/store/ledger/add.js';
|
|
|
|
async function run() {
|
|
console.log('--- Testing store.ledger (add, created_at, list queries) ---');
|
|
|
|
const tempDir = mkdtempSync(join(tmpdir(), 'test-ledger-'));
|
|
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 {
|
|
// 1. Setup user and company
|
|
const googleAuthId = await store.google_auth.add('ledger-test@example.com');
|
|
const company = await store.company.create({
|
|
name: 'Ledger Test Corp',
|
|
iso639: 'de',
|
|
taxrate: 19,
|
|
reducedtaxrate: 7,
|
|
googleAuthId,
|
|
});
|
|
await store.google_auth.setSelectedCompany(googleAuthId, company.id);
|
|
|
|
// Create a delivery manifest with lines
|
|
const delivery = await store.delivery.create(googleAuthId, {
|
|
externalNumber: 'DEL-1',
|
|
date: new Date().toISOString(),
|
|
lines: [
|
|
{
|
|
sku: 'SKU-ABC',
|
|
name: 'Ledger Item 1',
|
|
pu: 1,
|
|
amount: 5,
|
|
net: 10,
|
|
rebate: 0,
|
|
taxrate: 19,
|
|
},
|
|
{
|
|
sku: 'SKU-ABC',
|
|
name: 'Ledger Item 1 Batch 2',
|
|
pu: 1,
|
|
amount: 10,
|
|
net: 20,
|
|
rebate: 0,
|
|
taxrate: 19,
|
|
},
|
|
],
|
|
});
|
|
|
|
const manifestarticleId1 = delivery.lines[0].id;
|
|
const manifestarticleId2 = delivery.lines[1].id;
|
|
assert(manifestarticleId1, 'manifestarticle line 1 should have an id');
|
|
assert(manifestarticleId2, 'manifestarticle line 2 should have an id');
|
|
|
|
// 2. Test first row (genesis row)
|
|
console.log('1. Inserting genesis ledger row...');
|
|
const row1 = await store.ledger.add(googleAuthId, {
|
|
manifestarticle_id: manifestarticleId1,
|
|
transaction_type: 'GOODS_RECEIPT',
|
|
amount: 5,
|
|
transaction_text: 'Initial delivery movement',
|
|
});
|
|
|
|
assert.equal(row1.id, 1);
|
|
assert.equal(row1.manifestarticle_id, manifestarticleId1);
|
|
assert.equal(row1.transaction_type, 'GOODS_RECEIPT');
|
|
assert.equal(row1.amount, 5);
|
|
assert.equal(row1.transaction_text, 'Initial delivery movement');
|
|
assert.equal(row1.hash_version, 1);
|
|
assert.equal(row1.prev_hash, INIT_HASH);
|
|
assert(row1.created_at, 'created_at should exist');
|
|
assert(!Number.isNaN(new Date(row1.created_at).getTime()), 'created_at should be valid date string');
|
|
console.log('✓ Row 1 created_at:', row1.created_at);
|
|
|
|
// Verify manual hash computation of row 1 (including created_at)
|
|
const expectedHash2 = computePrevHash(row1);
|
|
const manualHash2 = createHash('sha512')
|
|
.update(
|
|
JSON.stringify({
|
|
id: 1,
|
|
manifestarticle_id: manifestarticleId1,
|
|
transaction_type: 'GOODS_RECEIPT',
|
|
amount: 5,
|
|
transaction_text: 'Initial delivery movement',
|
|
hash_version: 1,
|
|
prev_hash: INIT_HASH,
|
|
created_at: new Date(row1.created_at).toISOString(),
|
|
}),
|
|
'utf8',
|
|
)
|
|
.digest('hex');
|
|
assert.equal(expectedHash2, manualHash2);
|
|
assert.equal(manualHash2.length, 128);
|
|
|
|
// 3. Test second row (line 1, different transaction type)
|
|
console.log('2. Inserting second ledger row...');
|
|
const row2 = await store.ledger.add(googleAuthId, {
|
|
manifestarticleId: manifestarticleId1,
|
|
transactionType: 'INVENTORY_ADJUST',
|
|
amount: -1,
|
|
transactionText: 'Damaged item written off',
|
|
});
|
|
|
|
assert.equal(row2.id, 2);
|
|
assert.equal(row2.hash_version, 1);
|
|
assert.equal(row2.prev_hash, expectedHash2);
|
|
assert(row2.created_at, 'row 2 created_at should exist');
|
|
console.log('✓ Row 2 prev_hash matches SHA-512 of Row 1 with created_at');
|
|
|
|
// 4. Test third row (line 2, same SKU SKU-ABC)
|
|
console.log('3. Inserting third ledger row on line 2...');
|
|
const expectedHash3 = computePrevHash(row2);
|
|
const row3 = await store.ledger.add(googleAuthId, {
|
|
manifestarticle_id: manifestarticleId2,
|
|
transaction_type: 'GOODS_RECEIPT',
|
|
amount: 10,
|
|
transaction_text: 'Second line goods receipt',
|
|
});
|
|
|
|
assert.equal(row3.id, 3);
|
|
assert.equal(row3.hash_version, 1);
|
|
assert.equal(row3.prev_hash, expectedHash3);
|
|
|
|
// 5. Test query by manifestarticle_id
|
|
console.log('4. Testing listByManifestarticleId...');
|
|
const listLine1All = await store.ledger.listByManifestarticleId(googleAuthId, manifestarticleId1);
|
|
assert.equal(listLine1All.length, 2);
|
|
assert.equal(listLine1All[0].id, 1);
|
|
assert.equal(listLine1All[1].id, 2);
|
|
assert.equal(listLine1All[0].sku, 'SKU-ABC');
|
|
|
|
const listLine1GoodsReceipt = await store.ledger.listByManifestarticleId(
|
|
googleAuthId,
|
|
manifestarticleId1,
|
|
'GOODS_RECEIPT',
|
|
);
|
|
assert.equal(listLine1GoodsReceipt.length, 1);
|
|
assert.equal(listLine1GoodsReceipt[0].id, 1);
|
|
|
|
const listLine1Adjust = await store.ledger.listByManifestarticleId(
|
|
googleAuthId,
|
|
manifestarticleId1,
|
|
{ transaction_type: 'INVENTORY_ADJUST' },
|
|
);
|
|
assert.equal(listLine1Adjust.length, 1);
|
|
assert.equal(listLine1Adjust[0].id, 2);
|
|
|
|
const listLine1None = await store.ledger.listByManifestarticleId(
|
|
googleAuthId,
|
|
manifestarticleId1,
|
|
'NON_EXISTENT',
|
|
);
|
|
assert.equal(listLine1None.length, 0);
|
|
|
|
// 6. Test query by SKU
|
|
console.log('5. Testing listBySku...');
|
|
const listSkuAll = await store.ledger.listBySku(googleAuthId, 'SKU-ABC');
|
|
assert.equal(listSkuAll.length, 3);
|
|
assert.equal(listSkuAll[0].id, 1);
|
|
assert.equal(listSkuAll[1].id, 2);
|
|
assert.equal(listSkuAll[2].id, 3);
|
|
|
|
const listSkuGoodsReceipt = await store.ledger.listBySku(
|
|
googleAuthId,
|
|
'SKU-ABC',
|
|
'GOODS_RECEIPT',
|
|
);
|
|
assert.equal(listSkuGoodsReceipt.length, 2);
|
|
assert.equal(listSkuGoodsReceipt[0].id, 1);
|
|
assert.equal(listSkuGoodsReceipt[1].id, 3);
|
|
|
|
const listSkuAdjust = await store.ledger.listBySku(
|
|
googleAuthId,
|
|
'SKU-ABC',
|
|
'INVENTORY_ADJUST',
|
|
);
|
|
assert.equal(listSkuAdjust.length, 1);
|
|
assert.equal(listSkuAdjust[0].id, 2);
|
|
|
|
const listUnknownSku = await store.ledger.listBySku(googleAuthId, 'UNKNOWN-SKU');
|
|
assert.equal(listUnknownSku.length, 0);
|
|
|
|
// 7. Test validation & company authorization
|
|
console.log('6. Testing authorization & validation errors...');
|
|
await assert.rejects(
|
|
() => store.ledger.listByManifestarticleId(googleAuthId, 999999),
|
|
/Manifest article not found/,
|
|
);
|
|
await assert.rejects(
|
|
() => store.ledger.listBySku(googleAuthId, ''),
|
|
/Invalid SKU/,
|
|
);
|
|
|
|
console.log('✓ All ledger tests passed successfully!');
|
|
} finally {
|
|
try {
|
|
rmSync(tempDir, { recursive: true, force: true });
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}
|
|
}
|
|
|
|
run().catch((err) => {
|
|
console.error('Test failed:', err);
|
|
process.exit(1);
|
|
});
|