u
This commit is contained in:
223
scripts/test-order-shipping-ledger.js
Normal file
223
scripts/test-order-shipping-ledger.js
Normal file
@@ -0,0 +1,223 @@
|
||||
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 order shipping ledger & stock adjustment ---');
|
||||
|
||||
const tempDir = mkdtempSync(join(tmpdir(), 'test-order-shipping-'));
|
||||
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 company and user
|
||||
const googleAuthId = await store.google_auth.add('shipping-test@example.com');
|
||||
const company = await store.company.create({
|
||||
name: 'Shipping Test Corp',
|
||||
iso639: 'de',
|
||||
taxrate: 19,
|
||||
reducedtaxrate: 7,
|
||||
googleAuthId,
|
||||
});
|
||||
await store.google_auth.setSelectedCompany(googleAuthId, company.id);
|
||||
|
||||
// Setup warehouse
|
||||
const warehouse = await store.warehouse.create(googleAuthId, {
|
||||
name: 'Hauptlager',
|
||||
});
|
||||
assert(warehouse.id, 'Warehouse should have id');
|
||||
|
||||
// Setup units
|
||||
await store.unit.upsert(googleAuthId, {
|
||||
si: 'stk',
|
||||
basesi: 'stk',
|
||||
basesifactor: 1,
|
||||
symbol: 'Stk',
|
||||
name: 'Stück',
|
||||
});
|
||||
|
||||
// Setup customer group & customer entity
|
||||
const groups = await store.customergroup.list(googleAuthId);
|
||||
const customer = await store.entity.create(googleAuthId, {
|
||||
customergroupId: groups[0].id,
|
||||
name: 'Max Mustermann',
|
||||
});
|
||||
|
||||
// 2. Setup tracked article and untracked article
|
||||
const trackedArt = await store.article.createUnderParent({
|
||||
googleAuthId,
|
||||
parentId: company.rootCategoryId,
|
||||
name: 'Tracked Article',
|
||||
track_stock: 1,
|
||||
});
|
||||
const untrackedArt = await store.article.createUnderParent({
|
||||
googleAuthId,
|
||||
parentId: company.rootCategoryId,
|
||||
name: 'Untracked Service Item',
|
||||
track_stock: 0,
|
||||
});
|
||||
|
||||
// Initial stock for tracked article: +10
|
||||
await store.stock.adjust(googleAuthId, {
|
||||
sku: trackedArt.sku,
|
||||
warehouseId: warehouse.id,
|
||||
amount: 10,
|
||||
text: 'Initial stock intake',
|
||||
});
|
||||
|
||||
const artBefore = await store.article.getBySku(googleAuthId, trackedArt.sku);
|
||||
const stockBefore = artBefore.article.warehouses.reduce((sum, w) => sum + w.stock, 0);
|
||||
assert.equal(stockBefore, 10, 'Initial stock should be 10');
|
||||
|
||||
// 3. Create sales order with tracked and untracked items
|
||||
const order = await store.order.create(googleAuthId, {
|
||||
number: 'O-2026-001',
|
||||
date: new Date().toISOString(),
|
||||
entityId: customer.id,
|
||||
lines: [
|
||||
{
|
||||
sku: trackedArt.sku,
|
||||
name: 'Tracked Article',
|
||||
pu: 1,
|
||||
amount: 3,
|
||||
net: 50,
|
||||
taxrate: 19,
|
||||
},
|
||||
{
|
||||
sku: untrackedArt.sku,
|
||||
name: 'Untracked Service Item',
|
||||
pu: 1,
|
||||
amount: 2,
|
||||
net: 20,
|
||||
taxrate: 19,
|
||||
},
|
||||
],
|
||||
});
|
||||
assert.equal(order.lines.length, 2);
|
||||
|
||||
// 4. Create shipping with state 'open' (not shipped yet)
|
||||
console.log('4. Creating shipping with state "open"...');
|
||||
const shippingOpen = await store.shipping.create(googleAuthId, {
|
||||
manifestId: order.id,
|
||||
type: 'parcel',
|
||||
state: 'open',
|
||||
});
|
||||
assert.equal(shippingOpen.state, 'open');
|
||||
|
||||
// Assert stock is still 10
|
||||
const artStill10 = await store.article.getBySku(googleAuthId, trackedArt.sku);
|
||||
assert.equal(artStill10.article.warehouses.reduce((sum, w) => sum + w.stock, 0), 10, 'Stock should still be 10 when shipping is open');
|
||||
|
||||
// 5. Update shipping to state 'shipped'
|
||||
console.log('5. Updating shipping to state "shipped"...');
|
||||
const shippingShipped = await store.shipping.update(googleAuthId, shippingOpen.id, {
|
||||
state: 'shipped',
|
||||
warehouseId: warehouse.id,
|
||||
});
|
||||
assert.equal(shippingShipped.state, 'shipped');
|
||||
|
||||
// Assert stock is now 7 (10 - 3)
|
||||
const artAfter = await store.article.getBySku(googleAuthId, trackedArt.sku);
|
||||
assert.equal(artAfter.article.warehouses.reduce((sum, w) => sum + w.stock, 0), 7, 'Stock should be reduced to 7');
|
||||
|
||||
// Assert ledger entries
|
||||
const ledgerRows = await store.ledger.listBySku(googleAuthId, trackedArt.sku);
|
||||
assert.equal(ledgerRows.length, 2, 'Should have 2 ledger entries for tracked article (adjust + shipping)');
|
||||
const shippingLedger = ledgerRows.find((l) => l.transaction_type === 'SHIPPING');
|
||||
assert(shippingLedger, 'Shipping ledger entry should exist');
|
||||
assert.equal(shippingLedger.amount, -3, 'Shipping ledger entry should be -3');
|
||||
|
||||
// Assert untracked article has 0 warehouse ledger entries
|
||||
const untrackedLedger = await store.ledger.listBySku(googleAuthId, untrackedArt.sku);
|
||||
assert.equal(untrackedLedger.length, 0, 'Untracked article should not have warehouse ledger entries');
|
||||
|
||||
// Assert article history
|
||||
const history = await store.article.getHistoryBySku(googleAuthId, trackedArt.sku);
|
||||
console.log('Tracked article history:', history.map((h) => h.text));
|
||||
const shippingHistory = history.find((h) => h.text.includes('Versand Auftrag O-2026-001'));
|
||||
assert(shippingHistory, 'Article history should contain shipping entry');
|
||||
assert(shippingHistory.text.includes('Max Mustermann'), 'Article history should mention customer');
|
||||
assert(shippingHistory.text.includes('Hauptlager'), 'Article history should mention warehouse');
|
||||
|
||||
// 6. Test immutability: once shipped, cannot be deleted
|
||||
console.log('6. Testing cannot delete shipped shipping...');
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await store.shipping.delete(googleAuthId, shippingShipped.id);
|
||||
},
|
||||
{ message: 'Shipped shipping cannot be deleted' },
|
||||
);
|
||||
|
||||
// 7. Test immutability: once shipped, cannot be undone
|
||||
console.log('7. Testing cannot undo shipped shipping...');
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await store.shipping.update(googleAuthId, shippingShipped.id, { state: 'open' });
|
||||
},
|
||||
{ message: 'Shipped shipping cannot be undone' },
|
||||
);
|
||||
|
||||
// 8. Test order cannot be shipped again
|
||||
console.log('8. Testing order cannot be shipped twice...');
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await store.shipping.create(googleAuthId, {
|
||||
manifestId: order.id,
|
||||
type: 'express',
|
||||
state: 'shipped',
|
||||
});
|
||||
},
|
||||
{ message: 'Order already shipped' },
|
||||
);
|
||||
|
||||
// 9. Test direct creation with state 'shipped'
|
||||
console.log('9. Testing direct creation with state "shipped"...');
|
||||
const order2 = await store.order.create(googleAuthId, {
|
||||
number: 'O-2026-002',
|
||||
date: new Date().toISOString(),
|
||||
entityId: customer.id,
|
||||
lines: [
|
||||
{
|
||||
sku: trackedArt.sku,
|
||||
name: 'Tracked Article',
|
||||
pu: 1,
|
||||
amount: 2,
|
||||
net: 50,
|
||||
taxrate: 19,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const directShipped = await store.shipping.create(googleAuthId, {
|
||||
manifestId: order2.id,
|
||||
type: 'parcel',
|
||||
state: 'shipped',
|
||||
});
|
||||
assert.equal(directShipped.state, 'shipped');
|
||||
|
||||
const artFinal = await store.article.getBySku(googleAuthId, trackedArt.sku);
|
||||
assert.equal(artFinal.article.warehouses.reduce((sum, w) => sum + w.stock, 0), 5, 'Stock should now be 5 (7 - 2)');
|
||||
|
||||
console.log('✓ All order shipping ledger tests passed successfully!');
|
||||
} finally {
|
||||
try {
|
||||
rmSync(tempDir, { recursive: true, force: true });
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
run().catch((err) => {
|
||||
console.error('Test failed:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user