u
This commit is contained in:
112
scripts/migrate-manifest-created-at.js
Normal file
112
scripts/migrate-manifest-created-at.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import 'dotenv/config';
|
||||
import Database from 'better-sqlite3';
|
||||
import { MssqlProvider } from '../src/providers/mssql/index.js';
|
||||
|
||||
async function migrateSqlite(sqlitePath) {
|
||||
console.log(`Migrating SQLite database at: ${sqlitePath}`);
|
||||
const db = new Database(sqlitePath);
|
||||
|
||||
const columns = db.pragma('table_info("manifest")');
|
||||
const hasCreatedAt = columns.some((c) => c.name === 'created_at');
|
||||
if (hasCreatedAt) {
|
||||
console.log('SQLite manifest already has created_at column.');
|
||||
db.close();
|
||||
return;
|
||||
}
|
||||
|
||||
db.pragma('foreign_keys = OFF');
|
||||
db.exec(`
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE manifest_new (
|
||||
id INTEGER PRIMARY KEY,
|
||||
company_id INTEGER NOT NULL,
|
||||
"number" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
entity_id INTEGER,
|
||||
external_number TEXT,
|
||||
"date" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
||||
FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE NO ACTION,
|
||||
FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE SET NULL
|
||||
);
|
||||
INSERT INTO manifest_new (id, company_id, "number", "type", entity_id, external_number, "date", created_at)
|
||||
SELECT id, company_id, "number", "type", entity_id, external_number, "date", "date"
|
||||
FROM manifest;
|
||||
DROP TABLE manifest;
|
||||
ALTER TABLE manifest_new RENAME TO manifest;
|
||||
COMMIT;
|
||||
`);
|
||||
db.pragma('foreign_keys = ON');
|
||||
|
||||
const fkErrors = db.pragma('foreign_key_check');
|
||||
if (fkErrors.length > 0) {
|
||||
console.error('Foreign key check failed after SQLite migration:', fkErrors);
|
||||
} else {
|
||||
console.log('SQLite migration completed successfully.');
|
||||
}
|
||||
|
||||
console.log('Updated SQLite manifest columns:', db.pragma('table_info("manifest")'));
|
||||
console.log('Updated SQLite manifest sample row:', db.prepare('SELECT * FROM manifest LIMIT 1').get());
|
||||
db.close();
|
||||
}
|
||||
|
||||
async function migrateMssql() {
|
||||
console.log('Migrating MSSQL database...');
|
||||
const config = {
|
||||
server: process.env.MSSQL_SERVER,
|
||||
database: process.env.MSSQL_DATABASE,
|
||||
user: process.env.MSSQL_USER,
|
||||
password: process.env.MSSQL_PASSWORD,
|
||||
options: {
|
||||
encrypt: false,
|
||||
trustServerCertificate: true,
|
||||
},
|
||||
};
|
||||
|
||||
const provider = new MssqlProvider(config);
|
||||
try {
|
||||
const pool = await provider.ensurePool();
|
||||
const checkRes = await pool.request().query(`
|
||||
SELECT * FROM sys.columns
|
||||
WHERE object_id = OBJECT_ID(N'manifest') AND name = 'created_at'
|
||||
`);
|
||||
|
||||
if (checkRes.recordset.length > 0) {
|
||||
console.log('MSSQL manifest already has created_at column.');
|
||||
} else {
|
||||
await pool.request().query(`
|
||||
ALTER TABLE manifest ADD created_at DATETIME2 NOT NULL CONSTRAINT DF_manifest_created_at DEFAULT SYSUTCDATETIME();
|
||||
`);
|
||||
await pool.request().query(`
|
||||
UPDATE manifest SET created_at = [date];
|
||||
`);
|
||||
console.log('MSSQL migration completed successfully.');
|
||||
}
|
||||
|
||||
const colsRes = await pool.request().query(`
|
||||
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_NAME = 'manifest'
|
||||
`);
|
||||
console.log('Updated MSSQL manifest columns:', colsRes.recordset);
|
||||
const sampleRes = await pool.request().query(`
|
||||
SELECT TOP 1 * FROM manifest
|
||||
`);
|
||||
console.log('Updated MSSQL manifest sample row:', sampleRes.recordset[0]);
|
||||
await provider.close();
|
||||
} catch (err) {
|
||||
console.error('MSSQL migration failed:', err);
|
||||
await provider.close();
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function run() {
|
||||
await migrateSqlite('/home/seb/src/dashback/data/dash.db');
|
||||
await migrateMssql();
|
||||
}
|
||||
|
||||
run().catch((err) => {
|
||||
console.error('Migration failed:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -55,6 +55,7 @@ async function run() {
|
||||
|
||||
// Create a delivery manifest with lines
|
||||
const delivery = await store.delivery.create(googleAuthId, {
|
||||
supplierId: supplier.id,
|
||||
externalNumber: 'DEL-1',
|
||||
date: new Date().toISOString(),
|
||||
lines: [
|
||||
@@ -217,9 +218,15 @@ async function run() {
|
||||
const history = await store.article.getHistoryBySku(googleAuthId, article.sku);
|
||||
const historyTexts = history.map((h) => h.text);
|
||||
console.log('Article history texts:', historyTexts);
|
||||
assert(historyTexts.includes('Initial delivery movement'), 'History should include initial delivery movement');
|
||||
assert(historyTexts.includes('Damaged item written off'), 'History should include damaged item written off');
|
||||
assert(historyTexts.includes('Second line goods receipt'), 'History should include second line goods receipt');
|
||||
assert(
|
||||
historyTexts.some((t) => t.includes('Initial delivery movement') && t.includes('Lieferant: "Supplier X"') && t.includes('EK brutto: 11.90') && t.includes('Menge: 5')),
|
||||
'History should include initial delivery movement with supplier, EK brutto, and amount',
|
||||
);
|
||||
assert(historyTexts.includes('Damaged item written off'), 'History should include undamaged adjustment memo as is');
|
||||
assert(
|
||||
historyTexts.some((t) => t.includes('Second line goods receipt') && t.includes('Lieferant: "Supplier X"') && t.includes('EK brutto: 23.80') && t.includes('Menge: 10')),
|
||||
'History should include second line goods receipt with details',
|
||||
);
|
||||
|
||||
console.log('✓ All ledger tests passed successfully!');
|
||||
} finally {
|
||||
|
||||
147
scripts/test-manifest-two-dates.js
Normal file
147
scripts/test-manifest-two-dates.js
Normal file
@@ -0,0 +1,147 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import 'dotenv/config';
|
||||
import LibDashStore from '../src/index.js';
|
||||
import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js';
|
||||
import { MssqlProvider } from '../src/providers/mssql/index.js';
|
||||
|
||||
async function testProvider(name, provider) {
|
||||
console.log(`\n=== Testing ${name} ===`);
|
||||
await provider.initialize();
|
||||
const store = await new LibDashStore(provider);
|
||||
|
||||
// 1. Setup company and user
|
||||
const email = `test-manifest-${Date.now()}@example.com`;
|
||||
const googleAuthId = await store.google_auth.add(email);
|
||||
const company = await store.company.create({
|
||||
name: `Test Manifest Corp ${Date.now()}`,
|
||||
iso639: 'de',
|
||||
taxrate: 19,
|
||||
reducedtaxrate: 7,
|
||||
googleAuthId,
|
||||
});
|
||||
await store.google_auth.setSelectedCompany(googleAuthId, company.id);
|
||||
|
||||
// 2. Test delivery with both dates
|
||||
console.log('Testing delivery creation with date and createdAt...');
|
||||
const deliveryDate = '2026-10-15T12:00:00.000Z';
|
||||
const customCreatedAt = '2026-09-01T08:30:00.000Z';
|
||||
|
||||
const createdDelivery = await store.delivery.create(googleAuthId, {
|
||||
externalNumber: 'DEL-2DATES-1',
|
||||
date: deliveryDate,
|
||||
createdAt: customCreatedAt,
|
||||
lines: [
|
||||
{ name: 'Article 1', amount: 2, net: 50, taxrate: 19 },
|
||||
],
|
||||
});
|
||||
|
||||
assert(createdDelivery.id, 'Delivery should have an id');
|
||||
assert(createdDelivery.date, 'Delivery should have a delivery date');
|
||||
assert(createdDelivery.createdAt, 'Delivery should have createdAt');
|
||||
console.log('Delivery created:', {
|
||||
id: createdDelivery.id,
|
||||
date: createdDelivery.date,
|
||||
createdAt: createdDelivery.createdAt,
|
||||
});
|
||||
|
||||
// Verify delivery getById
|
||||
const fetchedDelivery = await store.delivery.getById(googleAuthId, createdDelivery.id);
|
||||
assert.equal(new Date(fetchedDelivery.date).toISOString().slice(0, 10), '2026-10-15');
|
||||
assert.equal(new Date(fetchedDelivery.createdAt).toISOString().slice(0, 10), '2026-09-01');
|
||||
|
||||
// Verify delivery update
|
||||
const updatedDeliveryDate = '2026-11-20T12:00:00.000Z';
|
||||
const updatedDelivery = await store.delivery.update(googleAuthId, createdDelivery.id, {
|
||||
date: updatedDeliveryDate,
|
||||
});
|
||||
assert.equal(new Date(updatedDelivery.date).toISOString().slice(0, 10), '2026-11-20');
|
||||
assert.equal(new Date(updatedDelivery.createdAt).toISOString().slice(0, 10), '2026-09-01');
|
||||
|
||||
// Verify delivery.list ledger info before booking
|
||||
let listBefore = await store.delivery.list(googleAuthId);
|
||||
const foundBefore = listBefore.find((d) => d.id === createdDelivery.id);
|
||||
assert(foundBefore, 'Delivery should be in delivery.list');
|
||||
assert.equal(foundBefore.ledger.totalPositions, 1, 'Delivery ledger should have 1 totalPosition');
|
||||
assert.equal(foundBefore.ledger.completelyOnLedgerPositions, 0, 'Delivery ledger should have 0 completelyOnLedgerPositions initially');
|
||||
assert.equal(foundBefore.totalPositions, undefined, 'totalPositions should not be at top level');
|
||||
assert.equal(foundBefore.completelyOnLedgerPositions, undefined, 'completelyOnLedgerPositions should not be at top level');
|
||||
|
||||
// Book line to ledger
|
||||
await store.ledger.add(googleAuthId, {
|
||||
manifestarticle_id: createdDelivery.lines[0].id,
|
||||
transaction_type: 'DELIVERY',
|
||||
amount: 2,
|
||||
transaction_text: `Lieferung ${createdDelivery.id}`,
|
||||
});
|
||||
|
||||
// Verify delivery.list ledger info after booking
|
||||
let listAfter = await store.delivery.list(googleAuthId);
|
||||
const foundAfter = listAfter.find((d) => d.id === createdDelivery.id);
|
||||
assert(foundAfter, 'Delivery should be in delivery.list after booking');
|
||||
assert.equal(foundAfter.ledger.totalPositions, 1, 'Delivery ledger should have 1 totalPosition');
|
||||
assert.equal(foundAfter.ledger.completelyOnLedgerPositions, 1, 'Delivery ledger should have 1 completelyOnLedgerPosition after booking');
|
||||
console.log('✓ Verified delivery.list ledger info (unbooked -> booked):', foundAfter.ledger);
|
||||
|
||||
// 3. Test quote with both dates
|
||||
console.log('Testing quote creation...');
|
||||
const quote = await store.quote.create(googleAuthId, {
|
||||
number: `Q-${Date.now()}`,
|
||||
date: '2026-12-01T00:00:00.000Z',
|
||||
createdAt: '2026-09-10T00:00:00.000Z',
|
||||
lines: [{ name: 'Quote item', amount: 1, net: 100, taxrate: 19 }],
|
||||
});
|
||||
assert(quote.createdAt, 'Quote should have createdAt');
|
||||
assert(quote.date, 'Quote should have date');
|
||||
|
||||
// 4. Test order with default createdAt
|
||||
console.log('Testing order creation with default createdAt...');
|
||||
const order = await store.order.create(googleAuthId, {
|
||||
number: `ORD-${Date.now()}`,
|
||||
date: '2026-12-15T00:00:00.000Z',
|
||||
lines: [{ name: 'Order item', amount: 3, net: 25, taxrate: 19 }],
|
||||
});
|
||||
assert(order.createdAt, 'Order should have default createdAt populated');
|
||||
assert(order.date, 'Order should have date');
|
||||
console.log('Order created with auto createdAt:', {
|
||||
id: order.id,
|
||||
date: order.date,
|
||||
createdAt: order.createdAt,
|
||||
});
|
||||
|
||||
console.log(`✓ All tests passed for ${name}!`);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
// Test SQLite provider with existing dashback database
|
||||
const sqliteProvider = new BetterSqlite3Provider({
|
||||
filename: '/home/seb/src/dashback/data/dash.db',
|
||||
});
|
||||
try {
|
||||
await testProvider('SQLite (dash.db)', sqliteProvider);
|
||||
} finally {
|
||||
sqliteProvider.close();
|
||||
}
|
||||
|
||||
// Test MSSQL provider
|
||||
const mssqlConfig = {
|
||||
server: process.env.MSSQL_SERVER,
|
||||
database: process.env.MSSQL_DATABASE,
|
||||
user: process.env.MSSQL_USER,
|
||||
password: process.env.MSSQL_PASSWORD,
|
||||
options: {
|
||||
encrypt: false,
|
||||
trustServerCertificate: true,
|
||||
},
|
||||
};
|
||||
const mssqlProvider = new MssqlProvider(mssqlConfig);
|
||||
try {
|
||||
await testProvider('MSSQL (dashback)', mssqlProvider);
|
||||
} finally {
|
||||
await mssqlProvider.close();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Test failed:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user