This commit is contained in:
seb
2026-09-22 07:25:16 +02:00
parent 4ed6260e91
commit cca131d83a
148 changed files with 5343 additions and 3466 deletions

View File

@@ -1,6 +1,7 @@
import { createHash } from 'node:crypto';
import { LIST_BY_MANIFEST } from '../../providers/mssql/queries/manifestattachment.js';
import request from '../request.js';
import * as mssqlManifestAttachmentQueries from '../../providers/mssql/queries/manifestattachment.js';
import * as sqliteManifestAttachmentQueries from '../../providers/sqlite3/queries/manifestattachment.js';
import makeRunner from '../runner.js';
import generateDocumentThumb from '../../util/generateDocumentThumb.js';
import { parseMeta } from '../manifestattachment/listByManifestId.js';
@@ -33,12 +34,25 @@ export function shapeAttachmentMeta(row) {
/**
* Loads attachment metadata (without binary content) for a manifest.
*/
export async function loadAttachments(pool, tx, manifestId) {
const result = await request(pool, tx)
.input('manifestId', manifestId)
.query(LIST_BY_MANIFEST);
export async function loadAttachments(provider, tx, manifestId) {
const runner = makeRunner(provider, tx);
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteManifestAttachmentQueries : mssqlManifestAttachmentQueries;
return result.recordset.map(shapeAttachmentMeta);
const result = await runner(queries.LIST_BY_MANIFEST, { manifestId });
const rows = await Promise.all(
result.rows.map(async (row) => {
let thumbavif = row.thumbavif;
if (isSqlite) {
thumbavif = await (runner.readThumbAvif ? runner.readThumbAvif(row.hash) : provider?.readThumbAvif?.(row.hash));
}
return shapeAttachmentMeta({
...row,
thumbavif,
});
}),
);
return rows;
}
function normalizeAttachment(raw, index) {
@@ -57,25 +71,26 @@ function normalizeAttachment(raw, index) {
throw new Error('Invalid file');
}
if (raw.content == null) {
if (rawContent(raw) == null) {
throw new Error('Invalid file');
}
let content;
if (Buffer.isBuffer(raw.content)) {
content = raw.content;
} else if (typeof raw.content === 'string') {
const trimmed = raw.content.trim();
const rawData = rawContent(raw);
if (Buffer.isBuffer(rawData)) {
content = rawData;
} else if (typeof rawData === 'string') {
const trimmed = rawData.trim();
if (mimetype === 'application/pdf' || trimmed.startsWith('JVBER') || /^[A-Za-z0-9+/=]+$/.test(trimmed.slice(0, 100))) {
try {
content = Buffer.from(trimmed, 'base64');
} catch {
content = Buffer.from(raw.content, 'utf8');
content = Buffer.from(rawData, 'utf8');
}
} else {
content = Buffer.from(raw.content, 'utf8');
content = Buffer.from(rawData, 'utf8');
}
} else {
content = Buffer.from(raw.content);
content = Buffer.from(rawData);
}
const size = Number.isFinite(raw.size) && raw.size >= 0
@@ -126,54 +141,80 @@ function normalizeAttachment(raw, index) {
};
}
function rawContent(raw) {
return raw.content;
}
/**
* Inserts pdf/txt attachments for a delivery (manifest) inside an existing
* transaction. Sort orders continue after the current maximum.
*
* @param {object} pool
* @param {object} provider
* @param {object} tx - Active transaction.
* @param {object} sql - SQL statements from delivery.js.
* @param {number} manifestId
* @param {Array<{mimetype: string, name: string, content: Buffer, sort?: number, size?: number, created?: Date|string, modified?: Date|string, hash?: string}>} [files]
* @returns {Promise<Array<object>>} Attachment metadata rows.
*/
export async function insertAttachments(pool, tx, sql, manifestId, files) {
export async function insertAttachments(provider, tx, sql, manifestId, files) {
const runner = makeRunner(provider, tx);
const attachments = (files ?? []).map(normalizeAttachment);
const sortRes = await request(pool, tx)
.input('manifestId', manifestId)
.query(sql.GET_NEXT_ATTACHMENT_SORT);
let nextSort = sortRes.recordset[0].sort;
const sortRes = await runner(sql.GET_NEXT_ATTACHMENT_SORT, { manifestId });
let nextSort = sortRes.rows[0].sort;
const results = [];
for (const a of attachments) {
const sort = a.sort ?? nextSort;
nextSort = Math.max(nextSort, sort) + 1;
// Generate thumbnail server-side (e.g. pdftocairo + sharp for PDF)
const { thumbavif, thumbx, thumby } = await generateDocumentThumb(a.content, a.mimetype, { filename: a.name });
// Use client-provided thumbavif if present, otherwise generate server-side
let thumbavif = a.thumbavif
? (Buffer.isBuffer(a.thumbavif)
? a.thumbavif
: Buffer.from(a.thumbavif, typeof a.thumbavif === 'string' ? 'base64' : undefined))
: null;
let thumbx = Number.isFinite(a.thumbx) ? Number(a.thumbx) : null;
let thumby = Number.isFinite(a.thumby) ? Number(a.thumby) : null;
if (!thumbavif) {
const generated = await generateDocumentThumb(a.content, a.mimetype, { filename: a.name });
thumbavif = generated.thumbavif;
thumbx = generated.thumbx;
thumby = generated.thumby;
}
if (provider?.dialect === 'sqlite3') {
if (runner.writeFileContent) {
await runner.writeFileContent(a.hash, a.content, a.mimetype);
if (thumbavif) await runner.writeThumbAvif(a.hash, thumbavif);
} else if (provider?.writeFileContent) {
await provider.writeFileContent(a.hash, a.content, a.mimetype);
if (thumbavif) await provider.writeThumbAvif(a.hash, thumbavif);
}
}
const fileRes = await request(pool, tx)
.input('hash', a.hash)
.input('mimetype', a.mimetype)
.input('name', a.name)
.input('size', a.size)
.input('created', a.created)
.input('modified', a.modified)
.input('content', a.content)
.input('thumbavif', thumbavif)
.input('thumbx', thumbx)
.input('thumby', thumby)
.input('meta', a.meta === null ? null : JSON.stringify(a.meta))
.query(sql.CREATE_FILE);
const fileRes = await runner(sql.CREATE_FILE, {
hash: a.hash,
mimetype: a.mimetype,
name: a.name,
size: a.size,
created: a.created,
modified: a.modified,
content: a.content,
thumbavif,
thumbx,
thumby,
meta: a.meta === null ? null : JSON.stringify(a.meta),
});
const fileId = fileRes.recordset[0].id;
const fileId = fileRes.rows[0]?.id ?? fileRes.insertId;
await request(pool, tx)
.input('manifestId', manifestId)
.input('fileId', fileId)
.input('sort', sort)
.query(sql.CREATE_ATTACHMENT);
await runner(sql.CREATE_ATTACHMENT, {
manifestId,
fileId,
sort,
});
results.push({
manifestId,

View File

@@ -1,11 +1,5 @@
import {
CREATE_MANIFEST,
CREATE_FILE,
CREATE_ATTACHMENT,
GET_NEXT_ATTACHMENT_SORT,
DELIVERY_TYPE,
} from '../../providers/mssql/queries/delivery.js';
import request from '../request.js';
import * as mssqlQueries from '../../providers/mssql/queries/delivery.js';
import * as sqliteQueries from '../../providers/sqlite3/queries/delivery.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import nextNumber from '../numbers/nextNumber.js';
import taxEnsure from '../tax/ensure.js';
@@ -13,30 +7,15 @@ import { insertLines, normalizeLines, parseDate } from '../manifestLines.js';
import { loadDelivery } from './helpers.js';
import { insertAttachments } from './attachments.js';
import { assertSupplier } from './writeLines.js';
import makeRunner from '../runner.js';
export default function create(pool) {
const access = resolveSelectedCompanyAccess(pool);
const ensureTax = taxEnsure(pool);
const allocateNumber = nextNumber(pool);
export default function create(provider) {
const access = resolveSelectedCompanyAccess(provider);
const ensureTax = taxEnsure(provider);
const allocateNumber = nextNumber(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
/**
* Creates a new delivery for the user's selected company with its lines.
* The delivery number is allocated internally via `getnextnumberwithprefixandpadding`
* (`type` `delivery`); supply `externalNumber` for an external (supplier) reference.
*
* @param {number} googleAuthId - The id of the Google auth user.
* @param {object} body - The delivery input.
* @param {string} body.date - The delivery date.
* @param {number} body.supplierId - The id of the supplier.
* @param {string} [body.externalNumber] - An external (supplier) reference number.
* @param {Array<{sku?: string, name?: string, pu?: number, amount: number, net: number, rebate?: number, taxrate: number, comment?: string|null}>} [body.lines] - The delivery lines.
* @returns {Promise<{id: number, number: string, type: string, entityId: number, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>} The created delivery.
* @throws {Error} If the delivery is invalid.
*
* @example
* const delivery = await store.delivery.create(42, { date: '2026-01-01', supplierId: 5, lines: [...] });
* // => { id, number, type, entityId, externalNumber, date, lines: [...] }
*/
return async (googleAuthId, body = {}) => {
const date = parseDate(body.date);
if (!date) {
@@ -50,58 +29,51 @@ export default function create(pool) {
const { companyId } = await access(googleAuthId);
const tx = pool.transaction();
await tx.begin();
try {
const run = async (runner, tx) => {
const supplierId = await assertSupplier(
pool,
provider,
tx,
companyId,
body.supplierId ?? null,
);
const number = await allocateNumber(companyId, DELIVERY_TYPE, tx);
const number = await allocateNumber(companyId, queries.DELIVERY_TYPE, tx);
const created = await request(pool, tx)
.input('companyId', companyId)
.input('number', number)
.input('type', DELIVERY_TYPE)
.input('entityId', supplierId)
.input('externalNumber', externalNumber)
.input('date', date)
.query(CREATE_MANIFEST);
const created = await runner(queries.CREATE_MANIFEST, {
companyId,
number,
type: queries.DELIVERY_TYPE,
entityId: supplierId,
externalNumber,
date,
});
const manifestId = created.recordset[0].id;
const manifestId = created.rows[0]?.id ?? created.insertId;
await insertLines(pool, tx, {
await insertLines(provider, tx, {
manifestId,
lines,
ensureTax,
});
await insertAttachments(
pool,
provider,
tx,
{
GET_NEXT_ATTACHMENT_SORT,
CREATE_FILE,
CREATE_ATTACHMENT,
GET_NEXT_ATTACHMENT_SORT: queries.GET_NEXT_ATTACHMENT_SORT,
CREATE_FILE: queries.CREATE_FILE,
CREATE_ATTACHMENT: queries.CREATE_ATTACHMENT,
},
manifestId,
body.files,
);
const delivery = await loadDelivery(pool, tx, companyId, manifestId);
await tx.commit();
return delivery;
} catch (err) {
try {
await tx.rollback();
} catch {
// ignore
}
throw err;
return loadDelivery(provider, tx, companyId, manifestId);
};
if (typeof provider?.transaction === 'function') {
return provider.transaction((runner, tx) => run(runner, tx));
}
return run(makeRunner(provider));
};
}

View File

@@ -1,35 +1,29 @@
import { DELETE_MANIFEST, DELIVERY_TYPE } from '../../providers/mssql/queries/delivery.js';
import * as mssqlQueries from '../../providers/mssql/queries/delivery.js';
import * as sqliteQueries from '../../providers/sqlite3/queries/delivery.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import makeRunner from '../runner.js';
export default function del(pool) {
const access = resolveSelectedCompanyAccess(pool);
export default function del(provider) {
const access = resolveSelectedCompanyAccess(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
/**
* Deletes a delivery by its id within the user's selected company.
*
* @param {number} googleAuthId - The id of the Google auth user.
* @param {number} id - The id of the delivery to delete.
* @returns {Promise<void>}
* @throws {Error} If the delivery is not found.
*
* @example
* await store.delivery.delete(42, 5);
*/
return async (googleAuthId, id) => {
if (!Number.isFinite(id)) {
throw new Error('Delivery not found');
}
const { companyId } = await access(googleAuthId);
const runner = makeRunner(provider);
const result = await pool
.request()
.input('id', id)
.input('companyId', companyId)
.input('type', DELIVERY_TYPE)
.query(DELETE_MANIFEST);
const result = await runner(queries.DELETE_MANIFEST, {
id,
companyId,
type: queries.DELIVERY_TYPE,
});
if (!result.rowsAffected[0]) {
const rowsAffected = result.rowsAffected?.[0] ?? (typeof result.rowsAffected === 'number' ? result.rowsAffected : 0);
if (!rowsAffected) {
throw new Error('Delivery not found');
}
};

View File

@@ -1,21 +1,9 @@
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import { loadDelivery } from './helpers.js';
export default function getById(pool) {
const access = resolveSelectedCompanyAccess(pool);
export default function getById(provider) {
const access = resolveSelectedCompanyAccess(provider);
/**
* Returns a single delivery by its id within the user's selected company.
*
* @param {number} googleAuthId - The id of the Google auth user.
* @param {number} id - The id of the delivery.
* @returns {Promise<{id: number, number: string, type: string, entityId: number, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>} The delivery.
* @throws {Error} If the delivery is not found.
*
* @example
* const delivery = await store.delivery.getById(42, 5);
* // => { id, number, type, entityId, externalNumber, date, lines: [...] }
*/
return async (googleAuthId, id) => {
if (!Number.isFinite(id)) {
throw new Error('Delivery not found');
@@ -23,7 +11,7 @@ export default function getById(pool) {
const { companyId } = await access(googleAuthId);
const delivery = await loadDelivery(pool, null, companyId, id);
const delivery = await loadDelivery(provider, null, companyId, id);
if (!delivery) {
throw new Error('Delivery not found');
}

View File

@@ -1,12 +1,11 @@
import {
DELIVERY_TYPE,
GET_DELIVERY_HEADER,
GET_DELIVERY_LINES,
} from '../../providers/mssql/queries/delivery.js';
import request from '../request.js';
import * as mssqlQueries from '../../providers/mssql/queries/delivery.js';
import * as sqliteQueries from '../../providers/sqlite3/queries/delivery.js';
import makeRunner from '../runner.js';
import { shapeLine } from '../manifestLines.js';
import { loadAttachments } from './attachments.js';
export const DELIVERY_TYPE = mssqlQueries.DELIVERY_TYPE;
export function shapeSummary(row) {
return {
id: row.id,
@@ -18,27 +17,31 @@ export function shapeSummary(row) {
};
}
export async function loadDelivery(pool, tx, companyId, id) {
const header = await request(pool, tx)
.input('id', id)
.input('companyId', companyId)
.input('type', DELIVERY_TYPE)
.query(GET_DELIVERY_HEADER);
export async function loadDelivery(provider, tx, companyId, id) {
const runner = makeRunner(provider, tx);
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
const row = header.recordset[0];
const header = await runner(queries.GET_DELIVERY_HEADER, {
id,
companyId,
type: DELIVERY_TYPE,
});
const row = header.rows[0];
if (!row) {
return null;
}
const lines = await request(pool, tx)
.input('manifestId', id)
.query(GET_DELIVERY_LINES);
const lines = await runner(queries.GET_DELIVERY_LINES, {
manifestId: id,
});
const files = await loadAttachments(pool, tx, id);
const files = await loadAttachments(provider, tx, id);
return {
...shapeSummary(row),
lines: lines.recordset.map(shapeLine),
lines: lines.rows.map(shapeLine),
files,
};
}

View File

@@ -1,45 +1,37 @@
import { DELIVERY_TYPE, LIST_DELIVERIES, LIST_DELIVERY_FILES } from '../../providers/mssql/queries/delivery.js';
import request from '../request.js';
import * as mssqlQueries from '../../providers/mssql/queries/delivery.js';
import * as sqliteQueries from '../../providers/sqlite3/queries/delivery.js';
import makeRunner from '../runner.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import { shapeSummary } from './helpers.js';
import { shapeAttachmentMeta } from './attachments.js';
export default function list(pool) {
const access = resolveSelectedCompanyAccess(pool);
export default function list(provider) {
const access = resolveSelectedCompanyAccess(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
/**
* Lists the deliveries of the user's selected company.
*
* @param {number} googleAuthId - The id of the Google auth user.
* @returns {Promise<Array<{id: number, number: string, type: string, entityId: number, externalNumber: string|null, date: string}>>} The deliveries.
*
* @example
* const deliveries = await store.delivery.list(42);
* // => [{ id, number, type, entityId, externalNumber, date }]
*/
return async (googleAuthId) => {
const { companyId } = await access(googleAuthId);
const runner = makeRunner(provider);
const result = await pool
.request()
.input('companyId', companyId)
.input('type', DELIVERY_TYPE)
.query(LIST_DELIVERIES);
const result = await runner(queries.LIST_DELIVERIES, {
companyId,
type: queries.DELIVERY_TYPE,
});
const filesResult = await pool
.request()
.input('companyId', companyId)
.input('type', DELIVERY_TYPE)
.query(LIST_DELIVERY_FILES);
const filesResult = await runner(queries.LIST_DELIVERY_FILES, {
companyId,
type: queries.DELIVERY_TYPE,
});
const filesByManifest = new Map();
for (const row of filesResult.recordset) {
for (const row of filesResult.rows) {
const list = filesByManifest.get(row.manifestId) ?? [];
list.push(shapeAttachmentMeta(row));
filesByManifest.set(row.manifestId, list);
}
return result.recordset.map((row) => ({
return result.rows.map((row) => ({
...shapeSummary(row),
files: filesByManifest.get(row.id) ?? [],
}));

View File

@@ -1,42 +1,19 @@
import {
DELETE_LINES_BY_MANIFEST,
DELIVERY_TYPE,
GET_DELIVERY_HEADER,
GET_NEXT_ATTACHMENT_SORT,
CREATE_FILE,
CREATE_ATTACHMENT,
UPDATE_MANIFEST,
} from '../../providers/mssql/queries/delivery.js';
import request from '../request.js';
import * as mssqlQueries from '../../providers/mssql/queries/delivery.js';
import * as sqliteQueries from '../../providers/sqlite3/queries/delivery.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import taxEnsure from '../tax/ensure.js';
import { insertLines, normalizeLines, parseDate } from '../manifestLines.js';
import { loadDelivery, shapeSummary } from './helpers.js';
import { insertAttachments } from './attachments.js';
import { assertSupplier } from './writeLines.js';
import makeRunner from '../runner.js';
export default function update(pool) {
const access = resolveSelectedCompanyAccess(pool);
const ensureTax = taxEnsure(pool);
export default function update(provider) {
const access = resolveSelectedCompanyAccess(provider);
const ensureTax = taxEnsure(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
/**
* Updates a delivery's header and/or lines.
*
* @param {number} googleAuthId - The id of the Google auth user.
* @param {number} id - The id of the delivery to update.
* @param {object} patch - The update patch.
* @param {string} [patch.number] - The new delivery number.
* @param {string} [patch.date] - The new delivery date.
* @param {number} [patch.supplierId] - The new supplier id.
* @param {string} [patch.externalNumber] - The new external (supplier) reference number.
* @param {Array<{sku?: string, name?: string, pu?: number, amount: number, net: number, rebate?: number, taxrate: number, comment?: string|null}>} [patch.lines] - The new delivery lines.
* @returns {Promise<{id: number, number: string, type: string, entityId: number, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>} The updated delivery.
* @throws {Error} If the delivery is not found.
*
* @example
* const delivery = await store.delivery.update(42, 5, { number: 'D-2', lines: [...] });
* // => { id, number, type, entityId, date, lines: [...] }
*/
return async (googleAuthId, id, patch = {}) => {
if (!Number.isFinite(id)) {
throw new Error('Delivery not found');
@@ -63,17 +40,14 @@ export default function update(pool) {
const { companyId } = await access(googleAuthId);
const tx = pool.transaction();
await tx.begin();
const run = async (runner, tx) => {
const existing = await runner(queries.GET_DELIVERY_HEADER, {
id,
companyId,
type: queries.DELIVERY_TYPE,
});
try {
const existing = await request(pool, tx)
.input('id', id)
.input('companyId', companyId)
.input('type', DELIVERY_TYPE)
.query(GET_DELIVERY_HEADER);
const current = existing.recordset[0];
const current = existing.rows[0];
if (!current) {
throw new Error('Delivery not found');
}
@@ -99,7 +73,7 @@ export default function update(pool) {
let supplierId = summary.supplierId;
if (hasSupplierId) {
supplierId = await assertSupplier(
pool,
provider,
tx,
companyId,
patch.supplierId ?? null,
@@ -113,22 +87,22 @@ export default function update(pool) {
: null;
}
await request(pool, tx)
.input('id', id)
.input('companyId', companyId)
.input('type', DELIVERY_TYPE)
.input('number', number)
.input('entityId', supplierId)
.input('externalNumber', externalNumber)
.input('date', date)
.query(UPDATE_MANIFEST);
await runner(queries.UPDATE_MANIFEST, {
id,
companyId,
type: queries.DELIVERY_TYPE,
number,
entityId: supplierId,
externalNumber,
date,
});
if (hasLines) {
await request(pool, tx)
.input('manifestId', id)
.query(DELETE_LINES_BY_MANIFEST);
await runner(queries.DELETE_LINES_BY_MANIFEST, {
manifestId: id,
});
await insertLines(pool, tx, {
await insertLines(provider, tx, {
manifestId: id,
lines: normalizedLines,
ensureTax,
@@ -137,28 +111,24 @@ export default function update(pool) {
if (hasFiles) {
await insertAttachments(
pool,
provider,
tx,
{
GET_NEXT_ATTACHMENT_SORT,
CREATE_FILE,
CREATE_ATTACHMENT,
GET_NEXT_ATTACHMENT_SORT: queries.GET_NEXT_ATTACHMENT_SORT,
CREATE_FILE: queries.CREATE_FILE,
CREATE_ATTACHMENT: queries.CREATE_ATTACHMENT,
},
id,
patch.files,
);
}
const delivery = await loadDelivery(pool, tx, companyId, id);
await tx.commit();
return delivery;
} catch (err) {
try {
await tx.rollback();
} catch {
// ignore
}
throw err;
return loadDelivery(provider, tx, companyId, id);
};
if (typeof provider?.transaction === 'function') {
return provider.transaction((runner, tx) => run(runner, tx));
}
return run(makeRunner(provider));
};
}

View File

@@ -1,7 +1,8 @@
import { GET_SUPPLIER_BY_ID, SUPPLIER_GROUP_NAME } from '../../providers/mssql/queries/entity.js';
import request from '../request.js';
import * as mssqlQueries from '../../providers/mssql/queries/entity.js';
import * as sqliteQueries from '../../providers/sqlite3/queries/entity.js';
import makeRunner from '../runner.js';
export async function assertSupplier(pool, tx, companyId, supplierId) {
export async function assertSupplier(provider, tx, companyId, supplierId) {
if (supplierId == null) {
return null;
}
@@ -9,13 +10,17 @@ export async function assertSupplier(pool, tx, companyId, supplierId) {
throw new Error('Supplier not found');
}
const result = await request(pool, tx)
.input('id', supplierId)
.input('companyId', companyId)
.input('groupName', SUPPLIER_GROUP_NAME)
.query(GET_SUPPLIER_BY_ID);
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
const runner = makeRunner(provider, tx);
if (!result.recordset[0]) {
const result = await runner(queries.GET_SUPPLIER_BY_ID, {
id: supplierId,
companyId,
groupName: queries.SUPPLIER_GROUP_NAME,
});
if (!result.rows[0]) {
throw new Error('Supplier not found');
}
return supplierId;