This commit is contained in:
seb
2026-09-26 23:06:05 +02:00
parent e491ecfa47
commit e7f92ebef8
41 changed files with 3632 additions and 1751 deletions

View File

@@ -159,6 +159,18 @@ export class MssqlProvider {
await pool.request().query(script);
}
}
try {
await pool.request().query(`
IF OBJECT_ID(N'dbo.ledger', N'U') IS NOT NULL AND COL_LENGTH('ledger', 'warehouse_id') IS NULL
BEGIN
ALTER TABLE ledger ADD warehouse_id INT NULL;
ALTER TABLE ledger ADD CONSTRAINT FK_ledger_warehouse FOREIGN KEY (warehouse_id) REFERENCES warehouse(id) ON DELETE NO ACTION;
END
`);
} catch {
// ignore
}
}
async purge() {

View File

@@ -7,8 +7,10 @@ export const TABLES = [
'companysetting',
'posterminalcategory',
'posterminal',
'printer',
'numbers',
'ledger',
'warehouse',
'articlesupplier',
'manifestarticle',
'manifest',

View File

@@ -446,7 +446,29 @@ SELECT
WHERE asup.article_id = a.id
ORDER BY asup.sort ASC, asup.id ASC
FOR JSON PATH
) AS suppliersJson
) AS suppliersJson,
(
SELECT
w.id,
w.name,
COALESCE(stock_calc.stock, 0) AS stock
FROM warehouse w
LEFT JOIN (
SELECT l.warehouse_id, SUM(l.amount) AS stock
FROM ledger l
INNER JOIN manifestarticle ma ON ma.id = l.manifestarticle_id
INNER JOIN manifest m ON m.id = ma.manifest_id
WHERE m.company_id = a.company_id
AND (
ma.sku = a.sku
OR ma.sku IN (SELECT asup.sku FROM articlesupplier asup WHERE asup.article_id = a.id)
)
GROUP BY l.warehouse_id
) stock_calc ON stock_calc.warehouse_id = w.id
WHERE w.company_id = a.company_id
ORDER BY w.name ASC
FOR JSON PATH
) AS warehousesJson
FROM article a
LEFT JOIN articletext at
ON at.article_id = a.id AND at.language_id = auth.languageId

View File

@@ -17,6 +17,12 @@ LEFT JOIN entity e ON e.id = m.entity_id
WHERE ma.id = @manifestarticleId AND m.company_id = @companyId;
`;
export const CHECK_WAREHOUSE_ACCESS = `
SELECT id, name
FROM warehouse
WHERE id = @warehouseId AND company_id = @companyId;
`;
export const FIND_ARTICLES_FOR_HISTORY = `
SELECT DISTINCT asup.article_id AS articleId
FROM articlesupplier asup
@@ -35,6 +41,7 @@ export const GET_LATEST_ROW = `
SELECT TOP 1
id,
manifestarticle_id,
warehouse_id,
transaction_type,
amount,
transaction_text,
@@ -48,6 +55,7 @@ ORDER BY id DESC;
export const INSERT_ROW = `
INSERT INTO ledger (
manifestarticle_id,
warehouse_id,
transaction_type,
amount,
transaction_text,
@@ -57,6 +65,7 @@ INSERT INTO ledger (
OUTPUT
INSERTED.id,
INSERTED.manifestarticle_id,
INSERTED.warehouse_id,
INSERTED.transaction_type,
INSERTED.amount,
INSERTED.transaction_text,
@@ -65,6 +74,7 @@ OUTPUT
INSERTED.created_at
VALUES (
@manifestarticleId,
@warehouseId,
@transactionType,
@amount,
@transactionText,
@@ -77,6 +87,7 @@ export const LIST_BY_MANIFESTARTICLE = `
SELECT
l.id,
l.manifestarticle_id,
l.warehouse_id,
ma.sku,
l.transaction_type,
l.amount,
@@ -90,6 +101,7 @@ INNER JOIN manifest m ON ma.manifest_id = m.id
WHERE l.manifestarticle_id = @manifestarticleId
AND m.company_id = @companyId
AND (@transactionType IS NULL OR l.transaction_type = @transactionType)
AND (@warehouseId IS NULL OR l.warehouse_id = @warehouseId)
ORDER BY l.id ASC;
`;
@@ -97,6 +109,7 @@ export const LIST_BY_SKU = `
SELECT
l.id,
l.manifestarticle_id,
l.warehouse_id,
ma.sku,
l.transaction_type,
l.amount,
@@ -110,5 +123,6 @@ INNER JOIN manifest m ON ma.manifest_id = m.id
WHERE ma.sku = @sku
AND m.company_id = @companyId
AND (@transactionType IS NULL OR l.transaction_type = @transactionType)
AND (@warehouseId IS NULL OR l.warehouse_id = @warehouseId)
ORDER BY l.id ASC;
`;

View File

@@ -0,0 +1,99 @@
export const PRINTER_COLUMNS = `
id,
company_id,
address,
type,
model,
serial,
sort,
[desc]
`;
export const LIST_BY_COMPANY = `
SELECT
${PRINTER_COLUMNS}
FROM printer
WHERE company_id = @companyId
ORDER BY sort ASC, id ASC
`;
export const GET_BY_COMPANY_AND_ID = `
SELECT
${PRINTER_COLUMNS}
FROM printer
WHERE id = @id AND company_id = @companyId
`;
export const GET_NEXT_SORT = `
SELECT ISNULL(MAX(sort), -1) + 1 AS sort
FROM printer
WHERE company_id = @companyId
`;
export const LIST_IDS_BY_COMPANY = `
SELECT id
FROM printer
WHERE company_id = @companyId
`;
export const CREATE = `
INSERT INTO printer (
company_id,
address,
type,
model,
serial,
sort,
[desc]
)
OUTPUT
INSERTED.id,
INSERTED.company_id,
INSERTED.address,
INSERTED.type,
INSERTED.model,
INSERTED.serial,
INSERTED.sort,
INSERTED.[desc]
VALUES (
@companyId,
@address,
@type,
@model,
@serial,
@sort,
@desc
)
`;
export const UPDATE = `
UPDATE printer
SET
address = @address,
type = @type,
model = @model,
serial = @serial,
sort = @sort,
[desc] = @desc
OUTPUT
INSERTED.id,
INSERTED.company_id,
INSERTED.address,
INSERTED.type,
INSERTED.model,
INSERTED.serial,
INSERTED.sort,
INSERTED.[desc]
WHERE id = @id AND company_id = @companyId
`;
export const UPDATE_SORT = `
UPDATE printer
SET sort = @sort
WHERE id = @id AND company_id = @companyId
`;
export const DELETE_BY_COMPANY_AND_ID = `
DELETE FROM printer
WHERE id = @id AND company_id = @companyId
`;

View File

@@ -0,0 +1,48 @@
export const LIST_BY_COMPANY = `
SELECT
id,
company_id,
name
FROM warehouse
WHERE company_id = @companyId
ORDER BY name ASC;
`;
export const GET_BY_COMPANY_AND_ID = `
SELECT
id,
company_id,
name
FROM warehouse
WHERE id = @id AND company_id = @companyId;
`;
export const GET_BY_COMPANY_AND_NAME = `
SELECT
id,
company_id,
name
FROM warehouse
WHERE company_id = @companyId AND name = @name;
`;
export const CREATE = `
INSERT INTO warehouse (company_id, name)
OUTPUT INSERTED.id, INSERTED.company_id, INSERTED.name
VALUES (@companyId, @name);
`;
export const UPDATE_BY_ID = `
UPDATE warehouse
SET name = @name
WHERE id = @id AND company_id = @companyId;
`;
export const DELETE_BY_COMPANY_AND_ID = `
DELETE FROM warehouse
WHERE id = @id AND company_id = @companyId;
`;
export const CHECK_LEDGER_USAGE = `
SELECT TOP 1 id FROM ledger WHERE warehouse_id = @warehouseId;
`;

View File

@@ -592,19 +592,34 @@ END
`;
export const INIT_WAREHOUSE = `
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'warehouse')
BEGIN
CREATE TABLE warehouse (
id INT IDENTITY(1,1) PRIMARY KEY,
company_id INT NOT NULL,
name NVARCHAR(255) NOT NULL,
CONSTRAINT FK_warehouse_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE,
CONSTRAINT UQ_warehouse_company_name UNIQUE (company_id, name)
);
END
`;
export const INIT_LEDGER = `
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'ledger')
BEGIN
CREATE TABLE ledger (
id INT IDENTITY(1,1) PRIMARY KEY,
manifestarticle_id INT NOT NULL,
warehouse_id INT NULL,
transaction_type NVARCHAR(100) NOT NULL,
amount FLOAT NOT NULL,
transaction_text NVARCHAR(MAX) NOT NULL,
hash_version INT NOT NULL,
prev_hash NVARCHAR(128) NULL,
created_at DATETIME2 NOT NULL CONSTRAINT DF_ledger_created_at DEFAULT SYSUTCDATETIME(),
CONSTRAINT FK_ledger_manifestarticle FOREIGN KEY (manifestarticle_id) REFERENCES manifestarticle(id) ON DELETE NO ACTION
CONSTRAINT FK_ledger_manifestarticle FOREIGN KEY (manifestarticle_id) REFERENCES manifestarticle(id) ON DELETE NO ACTION,
CONSTRAINT FK_ledger_warehouse FOREIGN KEY (warehouse_id) REFERENCES warehouse(id) ON DELETE NO ACTION
) WITH (LEDGER = ON (APPEND_ONLY = ON));
END
`;
@@ -772,6 +787,25 @@ BEGIN
END
`;
export const INIT_PRINTER = `
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'printer')
BEGIN
CREATE TABLE printer (
id INT IDENTITY(1,1) PRIMARY KEY,
company_id INT NOT NULL,
address NVARCHAR(255) NOT NULL,
type NVARCHAR(50) NOT NULL,
model NVARCHAR(255) NULL,
serial NVARCHAR(255) NULL,
sort INT NOT NULL CONSTRAINT DF_printer_sort DEFAULT 0,
[desc] NVARCHAR(MAX) NULL,
CONSTRAINT FK_printer_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE,
CONSTRAINT CK_printer_type CHECK (type IN ('esc/pos', 'zpl'))
);
END
`;
export const INIT_FILE = `
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'file')
BEGIN
@@ -862,6 +896,7 @@ export const SCHEMA_SCRIPTS = [
INIT_ARTICLE_SUPPLIER,
INIT_MANIFEST,
INIT_MANIFESTARTICLE,
INIT_WAREHOUSE,
INIT_LEDGER,
INIT_NUMBERS,
INIT_GET_NEXT_NUMBER_WITH_PREFIX_AND_PADDING,
@@ -873,6 +908,7 @@ export const SCHEMA_SCRIPTS = [
INIT_COMPANYSETTING,
INIT_POSTERMINAL,
INIT_POSTERMINALCATEGORY,
INIT_PRINTER,
INIT_FILE,
INIT_MANIFESTATTACHMENT,
INIT_MANIFESTATTACHMENT_TRIGGER,

View File

@@ -386,7 +386,7 @@ export class BetterSqlite3Provider extends BetterSqlite3Executor {
}
}
// Ensure created_at exists on ledger table if created previously
// Ensure created_at and warehouse_id exist on ledger table if created previously
try {
const ledgerCols = this.db.pragma('table_info("ledger")').map((c) => c.name);
if (ledgerCols.length > 0 && !ledgerCols.includes('created_at')) {
@@ -394,6 +394,11 @@ export class BetterSqlite3Provider extends BetterSqlite3Executor {
`ALTER TABLE ledger ADD COLUMN created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))`,
);
}
if (ledgerCols.length > 0 && !ledgerCols.includes('warehouse_id')) {
this.db.exec(
`ALTER TABLE ledger ADD COLUMN warehouse_id INTEGER REFERENCES warehouse(id) ON DELETE NO ACTION`,
);
}
} catch {
// ignore
}

View File

@@ -160,7 +160,24 @@ SELECT auth.*,
LEFT JOIN price pr ON pr.id = s.price_id
LEFT JOIN tax t ON t.id = pr.tax_id
WHERE s.article_id = a.id ORDER BY s.sort, s.id
)))
))),
'warehousesJson', json((SELECT COALESCE(json_group_array(json_object(
'id', w.id, 'name', w.name, 'stock', COALESCE(stock_calc.stock, 0)
)), '[]') FROM warehouse w
LEFT JOIN (
SELECT l.warehouse_id, SUM(l.amount) AS stock
FROM ledger l
INNER JOIN manifestarticle ma ON ma.id = l.manifestarticle_id
INNER JOIN manifest m ON m.id = ma.manifest_id
WHERE m.company_id = a.company_id
AND (
ma.sku = a.sku
OR ma.sku IN (SELECT asup.sku FROM articlesupplier asup WHERE asup.article_id = a.id)
)
GROUP BY l.warehouse_id
) stock_calc ON stock_calc.warehouse_id = w.id
WHERE w.company_id = a.company_id
ORDER BY w.name ASC))
) AS articleJson
FROM auth
INNER JOIN article a ON a.id = auth.articleId

View File

@@ -17,6 +17,12 @@ LEFT JOIN entity e ON e.id = m.entity_id
WHERE ma.id = @manifestarticleId AND m.company_id = @companyId;
`;
export const CHECK_WAREHOUSE_ACCESS = `
SELECT id, name
FROM warehouse
WHERE id = @warehouseId AND company_id = @companyId;
`;
export const FIND_ARTICLES_FOR_HISTORY = `
SELECT DISTINCT asup.article_id AS articleId
FROM articlesupplier asup
@@ -35,6 +41,7 @@ export const GET_LATEST_ROW = `
SELECT
id,
manifestarticle_id,
warehouse_id,
transaction_type,
amount,
transaction_text,
@@ -49,6 +56,7 @@ LIMIT 1;
export const INSERT_ROW = `
INSERT INTO ledger (
manifestarticle_id,
warehouse_id,
transaction_type,
amount,
transaction_text,
@@ -57,6 +65,7 @@ INSERT INTO ledger (
)
VALUES (
@manifestarticleId,
@warehouseId,
@transactionType,
@amount,
@transactionText,
@@ -66,6 +75,7 @@ VALUES (
RETURNING
id,
manifestarticle_id,
warehouse_id,
transaction_type,
amount,
transaction_text,
@@ -78,6 +88,7 @@ export const LIST_BY_MANIFESTARTICLE = `
SELECT
l.id,
l.manifestarticle_id,
l.warehouse_id,
ma.sku,
l.transaction_type,
l.amount,
@@ -91,6 +102,7 @@ INNER JOIN manifest m ON ma.manifest_id = m.id
WHERE l.manifestarticle_id = @manifestarticleId
AND m.company_id = @companyId
AND (@transactionType IS NULL OR l.transaction_type = @transactionType)
AND (@warehouseId IS NULL OR l.warehouse_id = @warehouseId)
ORDER BY l.id ASC;
`;
@@ -98,6 +110,7 @@ export const LIST_BY_SKU = `
SELECT
l.id,
l.manifestarticle_id,
l.warehouse_id,
ma.sku,
l.transaction_type,
l.amount,
@@ -111,5 +124,6 @@ INNER JOIN manifest m ON ma.manifest_id = m.id
WHERE ma.sku = @sku
AND m.company_id = @companyId
AND (@transactionType IS NULL OR l.transaction_type = @transactionType)
AND (@warehouseId IS NULL OR l.warehouse_id = @warehouseId)
ORDER BY l.id ASC;
`;

View File

@@ -0,0 +1,15 @@
import * as source from '../../mssql/queries/printer.js';
import { translateQueries } from './translate.js';
const queries = translateQueries(source, 'printer');
export const {
CREATE,
DELETE_BY_COMPANY_AND_ID,
GET_BY_COMPANY_AND_ID,
GET_NEXT_SORT,
LIST_BY_COMPANY,
LIST_IDS_BY_COMPANY,
PRINTER_COLUMNS,
UPDATE,
UPDATE_SORT,
} = queries;

View File

@@ -0,0 +1,48 @@
export const LIST_BY_COMPANY = `
SELECT
id,
company_id,
name
FROM warehouse
WHERE company_id = @companyId
ORDER BY name ASC;
`;
export const GET_BY_COMPANY_AND_ID = `
SELECT
id,
company_id,
name
FROM warehouse
WHERE id = @id AND company_id = @companyId;
`;
export const GET_BY_COMPANY_AND_NAME = `
SELECT
id,
company_id,
name
FROM warehouse
WHERE company_id = @companyId AND name = @name;
`;
export const CREATE = `
INSERT INTO warehouse (company_id, name)
VALUES (@companyId, @name)
RETURNING id, company_id, name;
`;
export const UPDATE_BY_ID = `
UPDATE warehouse
SET name = @name
WHERE id = @id AND company_id = @companyId;
`;
export const DELETE_BY_COMPANY_AND_ID = `
DELETE FROM warehouse
WHERE id = @id AND company_id = @companyId;
`;
export const CHECK_LEDGER_USAGE = `
SELECT id FROM ledger WHERE warehouse_id = @warehouseId LIMIT 1;
`;

View File

@@ -426,18 +426,30 @@ CREATE TABLE IF NOT EXISTS manifestarticle (
);
`;
export const INIT_WAREHOUSE = `
CREATE TABLE IF NOT EXISTS warehouse (
id INTEGER PRIMARY KEY,
company_id INTEGER NOT NULL,
name TEXT NOT NULL COLLATE NOCASE,
UNIQUE (company_id, name),
FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE
);
`;
/* SQLite has no SQL Server ledger tables; constraints preserve the base shape. */
export const INIT_LEDGER = `
CREATE TABLE IF NOT EXISTS ledger (
id INTEGER PRIMARY KEY,
manifestarticle_id INTEGER NOT NULL,
warehouse_id INTEGER,
transaction_type TEXT NOT NULL,
amount REAL NOT NULL,
transaction_text TEXT NOT NULL,
hash_version INTEGER NOT NULL,
prev_hash TEXT,
created_at TEXT NOT NULL DEFAULT (${UTC_NOW}),
FOREIGN KEY (manifestarticle_id) REFERENCES manifestarticle(id) ON DELETE NO ACTION
FOREIGN KEY (manifestarticle_id) REFERENCES manifestarticle(id) ON DELETE NO ACTION,
FOREIGN KEY (warehouse_id) REFERENCES warehouse(id) ON DELETE NO ACTION
);
`;
@@ -536,6 +548,21 @@ CREATE TABLE IF NOT EXISTS posterminalcategory (
);
`;
export const INIT_PRINTER = `
CREATE TABLE IF NOT EXISTS printer (
id INTEGER PRIMARY KEY,
company_id INTEGER NOT NULL,
address TEXT NOT NULL,
type TEXT NOT NULL CHECK (type IN ('esc/pos', 'zpl')),
model TEXT,
serial TEXT,
sort INTEGER NOT NULL DEFAULT 0,
"desc" TEXT,
FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE
);
`;
export const INIT_FILE = `
CREATE TABLE IF NOT EXISTS "file" (
id INTEGER PRIMARY KEY,
@@ -608,6 +635,7 @@ export const SCHEMA_SCRIPTS = [
INIT_ARTICLE_SUPPLIER,
INIT_MANIFEST,
INIT_MANIFESTARTICLE,
INIT_WAREHOUSE,
INIT_LEDGER,
INIT_NUMBERS,
INIT_COMPANYUSER,
@@ -617,6 +645,7 @@ export const SCHEMA_SCRIPTS = [
INIT_COMPANYSETTING,
INIT_POSTERMINAL,
INIT_POSTERMINALCATEGORY,
INIT_PRINTER,
INIT_FILE,
INIT_MANIFESTATTACHMENT,
INIT_MANIFESTATTACHMENT_TRIGGER,