u
This commit is contained in:
146
API.labeltemplate.md
Normal file
146
API.labeltemplate.md
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
# labeltemplate
|
||||||
|
|
||||||
|
This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`.
|
||||||
|
|
||||||
|
## `labeltemplate.create`
|
||||||
|
|
||||||
|
*Source: `src/store/labeltemplate/create.js`*
|
||||||
|
|
||||||
|
Creates a new label template for the user's selected company.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||||
|
| `input` | `object` | Label template input. |
|
||||||
|
| `input.name` | `string` | Template name. |
|
||||||
|
| `input.width` | `number` | Canvas width in pixels. |
|
||||||
|
| `input.height` | `number` | Canvas height in pixels. |
|
||||||
|
| `input.dpi` | `number` | Printer DPI (203 or 300). |
|
||||||
|
| `input.type` | `string` | Template type (`"zpl"`). |
|
||||||
|
| `input.content` | `object` | Template content (JSON — label editor objects). |
|
||||||
|
| `[input.thumb]` | `Buffer\|null` | Optional pre-rendered 50×50 1-bit PNG thumbnail. |
|
||||||
|
| `[tx]` | `object` | Optional transaction to run within. |
|
||||||
|
|
||||||
|
**Returns**
|
||||||
|
|
||||||
|
`Promise<{id: number, company_id: number, name: string, width: number, height: number, dpi: number, type: string, content: object, thumb: Buffer|null}>`
|
||||||
|
|
||||||
|
**Throws**
|
||||||
|
|
||||||
|
`Error` — If name, content or dimensions are missing, or dpi/type is invalid.
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```js
|
||||||
|
const template = await store.labeltemplate.create(googleAuthId, {
|
||||||
|
name: 'Product Label',
|
||||||
|
width: 448,
|
||||||
|
height: 200,
|
||||||
|
dpi: 203,
|
||||||
|
type: 'zpl',
|
||||||
|
content: { objects: [] },
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## `labeltemplate.delete`
|
||||||
|
|
||||||
|
*Source: `src/store/labeltemplate/delete.js`*
|
||||||
|
|
||||||
|
Deletes a label template for the user's selected company.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||||
|
| `id` | `number` | The label template ID to delete. |
|
||||||
|
| `[tx]` | `object` | Optional transaction to run within. |
|
||||||
|
|
||||||
|
**Returns**
|
||||||
|
|
||||||
|
`Promise<void>`
|
||||||
|
|
||||||
|
**Throws**
|
||||||
|
|
||||||
|
`Error` — If template is not found.
|
||||||
|
|
||||||
|
## `labeltemplate.getById`
|
||||||
|
|
||||||
|
*Source: `src/store/labeltemplate/getById.js`*
|
||||||
|
|
||||||
|
Retrieves a label template by its ID for the user's selected company.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||||
|
| `id` | `number` | The label template ID. |
|
||||||
|
| `[tx]` | `object` | Optional transaction to run within. |
|
||||||
|
|
||||||
|
**Returns**
|
||||||
|
|
||||||
|
`Promise<{id: number, company_id: number, name: string, width: number, height: number, dpi: number, type: string, content: object, thumb: Buffer|null}|undefined>`
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```js
|
||||||
|
const template = await store.labeltemplate.getById(googleAuthId, 1);
|
||||||
|
// => { id: 1, company_id: 1, name: 'Product Label', width: 448, height: 200, dpi: 203, type: 'zpl', ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
## `labeltemplate.list`
|
||||||
|
|
||||||
|
*Source: `src/store/labeltemplate/list.js`*
|
||||||
|
|
||||||
|
Lists all label templates for the user's selected company.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||||
|
| `[tx]` | `object` | Optional transaction to run within. |
|
||||||
|
|
||||||
|
**Returns**
|
||||||
|
|
||||||
|
`Promise<Array<{id: number, company_id: number, name: string, width: number, height: number, dpi: number, type: string, content: object, thumb: Buffer|null}>>`
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```js
|
||||||
|
const templates = await store.labeltemplate.list(42);
|
||||||
|
// => [{ id: 1, company_id: 1, name: 'Product Label', ... }]
|
||||||
|
```
|
||||||
|
|
||||||
|
## `labeltemplate.update`
|
||||||
|
|
||||||
|
*Source: `src/store/labeltemplate/update.js`*
|
||||||
|
|
||||||
|
Updates a label template for the user's selected company.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||||
|
| `id` | `number` | The label template ID to update. |
|
||||||
|
| `input` | `object` | Update payload (all fields optional). |
|
||||||
|
| `[input.name]` | `string` | Template name. |
|
||||||
|
| `[input.width]` | `number` | Canvas width in pixels. |
|
||||||
|
| `[input.height]` | `number` | Canvas height in pixels. |
|
||||||
|
| `[input.dpi]` | `number` | Printer DPI (203 or 300). |
|
||||||
|
| `[input.type]` | `string` | Template type (`"zpl"`). |
|
||||||
|
| `[input.content]` | `object` | Template content (JSON). |
|
||||||
|
| `[input.thumb]` | `Buffer\|null` | 50×50 1-bit PNG thumbnail. |
|
||||||
|
| `[tx]` | `object` | Optional transaction to run within. |
|
||||||
|
|
||||||
|
**Returns**
|
||||||
|
|
||||||
|
`Promise<{id: number, company_id: number, name: string, width: number, height: number, dpi: number, type: string, content: object, thumb: Buffer|null}>`
|
||||||
|
|
||||||
|
**Throws**
|
||||||
|
|
||||||
|
`Error` — If template not found, name is empty, or dpi/type is invalid.
|
||||||
13
src/index.js
13
src/index.js
@@ -139,6 +139,11 @@ import printerList from './store/printer/list.js';
|
|||||||
import printerUpdate from './store/printer/update.js';
|
import printerUpdate from './store/printer/update.js';
|
||||||
import printerDelete from './store/printer/delete.js';
|
import printerDelete from './store/printer/delete.js';
|
||||||
import printerOrder from './store/printer/order.js';
|
import printerOrder from './store/printer/order.js';
|
||||||
|
import labeltemplateCreate from './store/labeltemplate/create.js';
|
||||||
|
import labeltemplateGetById from './store/labeltemplate/getById.js';
|
||||||
|
import labeltemplateList from './store/labeltemplate/list.js';
|
||||||
|
import labeltemplateUpdate from './store/labeltemplate/update.js';
|
||||||
|
import labeltemplateDelete from './store/labeltemplate/delete.js';
|
||||||
import stockAdjust from './store/stock/adjust.js';
|
import stockAdjust from './store/stock/adjust.js';
|
||||||
|
|
||||||
export default class LibDashStore {
|
export default class LibDashStore {
|
||||||
@@ -377,6 +382,14 @@ export default class LibDashStore {
|
|||||||
order: printerOrder(provider),
|
order: printerOrder(provider),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.labeltemplate = {
|
||||||
|
create: labeltemplateCreate(provider),
|
||||||
|
getById: labeltemplateGetById(provider),
|
||||||
|
list: labeltemplateList(provider),
|
||||||
|
update: labeltemplateUpdate(provider),
|
||||||
|
delete: labeltemplateDelete(provider),
|
||||||
|
};
|
||||||
|
|
||||||
this.stock = {
|
this.stock = {
|
||||||
adjust: stockAdjust(provider),
|
adjust: stockAdjust(provider),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/** Drop order = reverse of schema create dependency order. */
|
/** Drop order = reverse of schema create dependency order. */
|
||||||
export const TABLES = [
|
export const TABLES = [
|
||||||
'manifestattachment',
|
'manifestattachment',
|
||||||
|
'labeltemplate',
|
||||||
'file',
|
'file',
|
||||||
'companyuser',
|
'companyuser',
|
||||||
'syncpos',
|
'syncpos',
|
||||||
|
|||||||
87
src/providers/mssql/queries/labeltemplate.js
Normal file
87
src/providers/mssql/queries/labeltemplate.js
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
export const LABELTEMPLATE_COLUMNS = `
|
||||||
|
id,
|
||||||
|
company_id,
|
||||||
|
name,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
dpi,
|
||||||
|
type,
|
||||||
|
content,
|
||||||
|
thumb
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const LIST_BY_COMPANY = `
|
||||||
|
SELECT
|
||||||
|
${LABELTEMPLATE_COLUMNS}
|
||||||
|
FROM labeltemplate
|
||||||
|
WHERE company_id = @companyId
|
||||||
|
ORDER BY id ASC
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const GET_BY_COMPANY_AND_ID = `
|
||||||
|
SELECT
|
||||||
|
${LABELTEMPLATE_COLUMNS}
|
||||||
|
FROM labeltemplate
|
||||||
|
WHERE id = @id AND company_id = @companyId
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const CREATE = `
|
||||||
|
INSERT INTO labeltemplate (
|
||||||
|
company_id,
|
||||||
|
name,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
dpi,
|
||||||
|
type,
|
||||||
|
content,
|
||||||
|
thumb
|
||||||
|
)
|
||||||
|
OUTPUT
|
||||||
|
INSERTED.id,
|
||||||
|
INSERTED.company_id,
|
||||||
|
INSERTED.name,
|
||||||
|
INSERTED.width,
|
||||||
|
INSERTED.height,
|
||||||
|
INSERTED.dpi,
|
||||||
|
INSERTED.type,
|
||||||
|
INSERTED.content,
|
||||||
|
INSERTED.thumb
|
||||||
|
VALUES (
|
||||||
|
@companyId,
|
||||||
|
@name,
|
||||||
|
@width,
|
||||||
|
@height,
|
||||||
|
@dpi,
|
||||||
|
@type,
|
||||||
|
@content,
|
||||||
|
@thumb
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const UPDATE = `
|
||||||
|
UPDATE labeltemplate
|
||||||
|
SET
|
||||||
|
name = @name,
|
||||||
|
width = @width,
|
||||||
|
height = @height,
|
||||||
|
dpi = @dpi,
|
||||||
|
type = @type,
|
||||||
|
content = @content,
|
||||||
|
thumb = @thumb
|
||||||
|
OUTPUT
|
||||||
|
INSERTED.id,
|
||||||
|
INSERTED.company_id,
|
||||||
|
INSERTED.name,
|
||||||
|
INSERTED.width,
|
||||||
|
INSERTED.height,
|
||||||
|
INSERTED.dpi,
|
||||||
|
INSERTED.type,
|
||||||
|
INSERTED.content,
|
||||||
|
INSERTED.thumb
|
||||||
|
WHERE id = @id AND company_id = @companyId
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const DELETE_BY_COMPANY_AND_ID = `
|
||||||
|
DELETE FROM labeltemplate
|
||||||
|
WHERE id = @id AND company_id = @companyId
|
||||||
|
`;
|
||||||
@@ -816,6 +816,26 @@ END
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
export const INIT_LABELTEMPLATE = `
|
||||||
|
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'labeltemplate')
|
||||||
|
BEGIN
|
||||||
|
CREATE TABLE labeltemplate (
|
||||||
|
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||||
|
company_id INT NOT NULL,
|
||||||
|
name NVARCHAR(255) NOT NULL,
|
||||||
|
width INT NOT NULL,
|
||||||
|
height INT NOT NULL,
|
||||||
|
dpi INT NOT NULL,
|
||||||
|
type NVARCHAR(50) NOT NULL,
|
||||||
|
content NVARCHAR(MAX) NOT NULL,
|
||||||
|
thumb VARBINARY(MAX) NULL,
|
||||||
|
CONSTRAINT FK_labeltemplate_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT CK_labeltemplate_dpi CHECK (dpi IN (203, 300)),
|
||||||
|
CONSTRAINT CK_labeltemplate_type CHECK (type IN ('zpl'))
|
||||||
|
);
|
||||||
|
END
|
||||||
|
`;
|
||||||
|
|
||||||
export const INIT_FILE = `
|
export const INIT_FILE = `
|
||||||
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'file')
|
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'file')
|
||||||
BEGIN
|
BEGIN
|
||||||
@@ -919,6 +939,7 @@ export const SCHEMA_SCRIPTS = [
|
|||||||
INIT_POSTERMINAL,
|
INIT_POSTERMINAL,
|
||||||
INIT_POSTERMINALCATEGORY,
|
INIT_POSTERMINALCATEGORY,
|
||||||
INIT_PRINTER,
|
INIT_PRINTER,
|
||||||
|
INIT_LABELTEMPLATE,
|
||||||
INIT_FILE,
|
INIT_FILE,
|
||||||
INIT_MANIFESTATTACHMENT,
|
INIT_MANIFESTATTACHMENT,
|
||||||
INIT_MANIFESTATTACHMENT_TRIGGER,
|
INIT_MANIFESTATTACHMENT_TRIGGER,
|
||||||
|
|||||||
12
src/providers/sqlite3/queries/labeltemplate.js
Normal file
12
src/providers/sqlite3/queries/labeltemplate.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import * as source from '../../mssql/queries/labeltemplate.js';
|
||||||
|
import { translateQueries } from './translate.js';
|
||||||
|
|
||||||
|
const queries = translateQueries(source, 'labeltemplate');
|
||||||
|
export const {
|
||||||
|
CREATE,
|
||||||
|
DELETE_BY_COMPANY_AND_ID,
|
||||||
|
GET_BY_COMPANY_AND_ID,
|
||||||
|
LABELTEMPLATE_COLUMNS,
|
||||||
|
LIST_BY_COMPANY,
|
||||||
|
UPDATE,
|
||||||
|
} = queries;
|
||||||
@@ -565,6 +565,21 @@ CREATE TABLE IF NOT EXISTS printer (
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
export const INIT_LABELTEMPLATE = `
|
||||||
|
CREATE TABLE IF NOT EXISTS labeltemplate (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
company_id INTEGER NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
width INTEGER NOT NULL,
|
||||||
|
height INTEGER NOT NULL,
|
||||||
|
dpi INTEGER NOT NULL CHECK (dpi IN (203, 300)),
|
||||||
|
type TEXT NOT NULL CHECK (type IN ('zpl')),
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
thumb BLOB,
|
||||||
|
FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
`;
|
||||||
|
|
||||||
export const INIT_FILE = `
|
export const INIT_FILE = `
|
||||||
CREATE TABLE IF NOT EXISTS "file" (
|
CREATE TABLE IF NOT EXISTS "file" (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
@@ -648,6 +663,7 @@ export const SCHEMA_SCRIPTS = [
|
|||||||
INIT_POSTERMINAL,
|
INIT_POSTERMINAL,
|
||||||
INIT_POSTERMINALCATEGORY,
|
INIT_POSTERMINALCATEGORY,
|
||||||
INIT_PRINTER,
|
INIT_PRINTER,
|
||||||
|
INIT_LABELTEMPLATE,
|
||||||
INIT_FILE,
|
INIT_FILE,
|
||||||
INIT_MANIFESTATTACHMENT,
|
INIT_MANIFESTATTACHMENT,
|
||||||
INIT_MANIFESTATTACHMENT_TRIGGER,
|
INIT_MANIFESTATTACHMENT_TRIGGER,
|
||||||
|
|||||||
121
src/store/labeltemplate/create.js
Normal file
121
src/store/labeltemplate/create.js
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
import {
|
||||||
|
CREATE as MSSQL_CREATE,
|
||||||
|
} from '../../providers/mssql/queries/labeltemplate.js';
|
||||||
|
import {
|
||||||
|
CREATE as SQLITE_CREATE,
|
||||||
|
} from '../../providers/sqlite3/queries/labeltemplate.js';
|
||||||
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
|
const VALID_TYPES = new Set(['zpl']);
|
||||||
|
const VALID_DPIS = new Set([203, 300]);
|
||||||
|
|
||||||
|
function shape(row) {
|
||||||
|
return {
|
||||||
|
id: row.id,
|
||||||
|
company_id: row.company_id ?? row.companyId,
|
||||||
|
name: row.name,
|
||||||
|
width: row.width,
|
||||||
|
height: row.height,
|
||||||
|
dpi: row.dpi,
|
||||||
|
type: row.type,
|
||||||
|
content: typeof row.content === 'string' ? JSON.parse(row.content) : row.content,
|
||||||
|
thumb: row.thumb ?? null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function create(provider) {
|
||||||
|
const access = resolveSelectedCompanyAccess(provider);
|
||||||
|
const isSqlite = provider?.dialect === 'sqlite3';
|
||||||
|
const createSql = isSqlite ? SQLITE_CREATE : MSSQL_CREATE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new label template for the user's selected company.
|
||||||
|
*
|
||||||
|
* @param {number} googleAuthId - The id of the Google auth user.
|
||||||
|
* @param {object} input - Label template input.
|
||||||
|
* @param {string} input.name - Template name.
|
||||||
|
* @param {number} input.width - Canvas width in pixels.
|
||||||
|
* @param {number} input.height - Canvas height in pixels.
|
||||||
|
* @param {number} input.dpi - Printer DPI (203 or 300).
|
||||||
|
* @param {string} input.type - Template type ("zpl").
|
||||||
|
* @param {object} input.content - Template content (JSON).
|
||||||
|
* @param {Buffer|null} [input.thumb] - 50×50 1-bit PNG thumbnail buffer.
|
||||||
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
|
* @returns {Promise<{id: number, company_id: number, name: string, width: number, height: number, dpi: number, type: string, content: object, thumb: Buffer|null}>}
|
||||||
|
* @throws {Error} If required fields are missing or invalid.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const template = await store.labeltemplate.create(googleAuthId, {
|
||||||
|
* name: 'Product Label',
|
||||||
|
* width: 448,
|
||||||
|
* height: 200,
|
||||||
|
* dpi: 203,
|
||||||
|
* type: 'zpl',
|
||||||
|
* content: { objects: [] },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
return async (googleAuthId, input = {}, tx) => {
|
||||||
|
const name = typeof input.name === 'string' ? input.name.trim() : '';
|
||||||
|
if (!name) {
|
||||||
|
throw new Error('Name required');
|
||||||
|
}
|
||||||
|
|
||||||
|
const width = Number(input.width);
|
||||||
|
if (!Number.isInteger(width) || width <= 0) {
|
||||||
|
throw new Error('Invalid width');
|
||||||
|
}
|
||||||
|
|
||||||
|
const height = Number(input.height);
|
||||||
|
if (!Number.isInteger(height) || height <= 0) {
|
||||||
|
throw new Error('Invalid height');
|
||||||
|
}
|
||||||
|
|
||||||
|
const dpi = Number(input.dpi);
|
||||||
|
if (!VALID_DPIS.has(dpi)) {
|
||||||
|
throw new Error('Invalid dpi: must be 203 or 300');
|
||||||
|
}
|
||||||
|
|
||||||
|
const type = typeof input.type === 'string' ? input.type.trim() : '';
|
||||||
|
if (!type || !VALID_TYPES.has(type)) {
|
||||||
|
throw new Error('Invalid type: must be "zpl"');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.content == null) {
|
||||||
|
throw new Error('Content required');
|
||||||
|
}
|
||||||
|
const content = typeof input.content === 'string'
|
||||||
|
? input.content
|
||||||
|
: JSON.stringify(input.content);
|
||||||
|
|
||||||
|
const thumb = input.thumb instanceof Buffer ? input.thumb : null;
|
||||||
|
|
||||||
|
const runner = makeRunner(provider, tx);
|
||||||
|
const { companyId } = await access(googleAuthId, runner);
|
||||||
|
|
||||||
|
const result = await runner.query(createSql, {
|
||||||
|
companyId,
|
||||||
|
name,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
dpi,
|
||||||
|
type,
|
||||||
|
content,
|
||||||
|
thumb,
|
||||||
|
});
|
||||||
|
|
||||||
|
const row = result.rows[0] ?? {
|
||||||
|
id: result.insertId,
|
||||||
|
company_id: companyId,
|
||||||
|
name,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
dpi,
|
||||||
|
type,
|
||||||
|
content,
|
||||||
|
thumb,
|
||||||
|
};
|
||||||
|
|
||||||
|
return shape(row);
|
||||||
|
};
|
||||||
|
}
|
||||||
35
src/store/labeltemplate/delete.js
Normal file
35
src/store/labeltemplate/delete.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { DELETE_BY_COMPANY_AND_ID as MSSQL_DELETE } from '../../providers/mssql/queries/labeltemplate.js';
|
||||||
|
import { DELETE_BY_COMPANY_AND_ID as SQLITE_DELETE } from '../../providers/sqlite3/queries/labeltemplate.js';
|
||||||
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
|
export default function del(provider) {
|
||||||
|
const access = resolveSelectedCompanyAccess(provider);
|
||||||
|
const sql =
|
||||||
|
provider?.dialect === 'sqlite3' ? SQLITE_DELETE : MSSQL_DELETE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a label template for the user's selected company.
|
||||||
|
*
|
||||||
|
* @param {number} googleAuthId - The id of the Google auth user.
|
||||||
|
* @param {number} id - The label template ID to delete.
|
||||||
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
* @throws {Error} If template is not found.
|
||||||
|
*/
|
||||||
|
return async (googleAuthId, id, tx) => {
|
||||||
|
const numericId = Number(id);
|
||||||
|
if (!Number.isInteger(numericId) || numericId <= 0) {
|
||||||
|
throw new Error('Label template not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const runner = makeRunner(provider, tx);
|
||||||
|
const { companyId } = await access(googleAuthId, runner);
|
||||||
|
|
||||||
|
const result = await runner.query(sql, { id: numericId, companyId });
|
||||||
|
|
||||||
|
if (!result.rowsAffected) {
|
||||||
|
throw new Error('Label template not found');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
49
src/store/labeltemplate/getById.js
Normal file
49
src/store/labeltemplate/getById.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { GET_BY_COMPANY_AND_ID as MSSQL_GET_BY_ID } from '../../providers/mssql/queries/labeltemplate.js';
|
||||||
|
import { GET_BY_COMPANY_AND_ID as SQLITE_GET_BY_ID } from '../../providers/sqlite3/queries/labeltemplate.js';
|
||||||
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
|
function shape(row) {
|
||||||
|
return {
|
||||||
|
id: row.id,
|
||||||
|
company_id: row.company_id ?? row.companyId,
|
||||||
|
name: row.name,
|
||||||
|
width: row.width,
|
||||||
|
height: row.height,
|
||||||
|
dpi: row.dpi,
|
||||||
|
type: row.type,
|
||||||
|
content: typeof row.content === 'string' ? JSON.parse(row.content) : row.content,
|
||||||
|
thumb: row.thumb ?? null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function getById(provider) {
|
||||||
|
const access = resolveSelectedCompanyAccess(provider);
|
||||||
|
const sql =
|
||||||
|
provider?.dialect === 'sqlite3' ? SQLITE_GET_BY_ID : MSSQL_GET_BY_ID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a label template by its ID for the user's selected company.
|
||||||
|
*
|
||||||
|
* @param {number} googleAuthId - The id of the Google auth user.
|
||||||
|
* @param {number} id - The label template ID.
|
||||||
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
|
* @returns {Promise<{id: number, company_id: number, name: string, width: number, height: number, dpi: number, type: string, content: object, thumb: Buffer|null}|undefined>}
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const template = await store.labeltemplate.getById(googleAuthId, 1);
|
||||||
|
*/
|
||||||
|
return async (googleAuthId, id, tx) => {
|
||||||
|
const numericId = Number(id);
|
||||||
|
if (!Number.isInteger(numericId) || numericId <= 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const runner = makeRunner(provider, tx);
|
||||||
|
const { companyId } = await access(googleAuthId, runner);
|
||||||
|
|
||||||
|
const result = await runner.query(sql, { id: numericId, companyId });
|
||||||
|
const row = result.rows[0];
|
||||||
|
return row ? shape(row) : undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
44
src/store/labeltemplate/list.js
Normal file
44
src/store/labeltemplate/list.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { LIST_BY_COMPANY as MSSQL_LIST_BY_COMPANY } from '../../providers/mssql/queries/labeltemplate.js';
|
||||||
|
import { LIST_BY_COMPANY as SQLITE_LIST_BY_COMPANY } from '../../providers/sqlite3/queries/labeltemplate.js';
|
||||||
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
|
function shape(row) {
|
||||||
|
return {
|
||||||
|
id: row.id,
|
||||||
|
company_id: row.company_id ?? row.companyId,
|
||||||
|
name: row.name,
|
||||||
|
width: row.width,
|
||||||
|
height: row.height,
|
||||||
|
dpi: row.dpi,
|
||||||
|
type: row.type,
|
||||||
|
content: typeof row.content === 'string' ? JSON.parse(row.content) : row.content,
|
||||||
|
thumb: row.thumb ?? null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function list(provider) {
|
||||||
|
const access = resolveSelectedCompanyAccess(provider);
|
||||||
|
const sql =
|
||||||
|
provider?.dialect === 'sqlite3'
|
||||||
|
? SQLITE_LIST_BY_COMPANY
|
||||||
|
: MSSQL_LIST_BY_COMPANY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all label templates for the user's selected company.
|
||||||
|
*
|
||||||
|
* @param {number} googleAuthId - The id of the Google auth user.
|
||||||
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
|
* @returns {Promise<Array<{id: number, company_id: number, name: string, width: number, height: number, dpi: number, type: string, content: object, thumb: Buffer|null}>>}
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const templates = await store.labeltemplate.list(42);
|
||||||
|
*/
|
||||||
|
return async (googleAuthId, tx) => {
|
||||||
|
const runner = makeRunner(provider, tx);
|
||||||
|
const { companyId } = await access(googleAuthId, runner);
|
||||||
|
|
||||||
|
const result = await runner.query(sql, { companyId });
|
||||||
|
return result.rows.map(shape);
|
||||||
|
};
|
||||||
|
}
|
||||||
141
src/store/labeltemplate/update.js
Normal file
141
src/store/labeltemplate/update.js
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
import {
|
||||||
|
GET_BY_COMPANY_AND_ID as MSSQL_GET_BY_ID,
|
||||||
|
UPDATE as MSSQL_UPDATE,
|
||||||
|
} from '../../providers/mssql/queries/labeltemplate.js';
|
||||||
|
import {
|
||||||
|
GET_BY_COMPANY_AND_ID as SQLITE_GET_BY_ID,
|
||||||
|
UPDATE as SQLITE_UPDATE,
|
||||||
|
} from '../../providers/sqlite3/queries/labeltemplate.js';
|
||||||
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
|
const VALID_TYPES = new Set(['zpl']);
|
||||||
|
const VALID_DPIS = new Set([203, 300]);
|
||||||
|
|
||||||
|
function shape(row) {
|
||||||
|
return {
|
||||||
|
id: row.id,
|
||||||
|
company_id: row.company_id ?? row.companyId,
|
||||||
|
name: row.name,
|
||||||
|
width: row.width,
|
||||||
|
height: row.height,
|
||||||
|
dpi: row.dpi,
|
||||||
|
type: row.type,
|
||||||
|
content: typeof row.content === 'string' ? JSON.parse(row.content) : row.content,
|
||||||
|
thumb: row.thumb ?? null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function update(provider) {
|
||||||
|
const access = resolveSelectedCompanyAccess(provider);
|
||||||
|
const isSqlite = provider?.dialect === 'sqlite3';
|
||||||
|
const getSql = isSqlite ? SQLITE_GET_BY_ID : MSSQL_GET_BY_ID;
|
||||||
|
const updateSql = isSqlite ? SQLITE_UPDATE : MSSQL_UPDATE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a label template for the user's selected company.
|
||||||
|
*
|
||||||
|
* @param {number} googleAuthId - The id of the Google auth user.
|
||||||
|
* @param {number} id - The label template ID to update.
|
||||||
|
* @param {object} input - Update payload.
|
||||||
|
* @param {string} [input.name] - Template name.
|
||||||
|
* @param {number} [input.width] - Canvas width in pixels.
|
||||||
|
* @param {number} [input.height] - Canvas height in pixels.
|
||||||
|
* @param {number} [input.dpi] - Printer DPI (203 or 300).
|
||||||
|
* @param {string} [input.type] - Template type ("zpl").
|
||||||
|
* @param {object} [input.content] - Template content (JSON).
|
||||||
|
* @param {Buffer|null} [input.thumb] - 50×50 1-bit PNG thumbnail buffer.
|
||||||
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
|
* @returns {Promise<{id: number, company_id: number, name: string, width: number, height: number, dpi: number, type: string, content: object, thumb: Buffer|null}>}
|
||||||
|
* @throws {Error} If template not found or input invalid.
|
||||||
|
*/
|
||||||
|
return async (googleAuthId, id, input = {}, tx) => {
|
||||||
|
const numericId = Number(id);
|
||||||
|
if (!Number.isInteger(numericId) || numericId <= 0) {
|
||||||
|
throw new Error('Label template not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const runner = makeRunner(provider, tx);
|
||||||
|
const { companyId } = await access(googleAuthId, runner);
|
||||||
|
|
||||||
|
const existing = await runner.query(getSql, { id: numericId, companyId });
|
||||||
|
const current = existing.rows[0];
|
||||||
|
if (!current) {
|
||||||
|
throw new Error('Label template not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = current.name;
|
||||||
|
if (input.name !== undefined) {
|
||||||
|
const cleaned = typeof input.name === 'string' ? input.name.trim() : '';
|
||||||
|
if (!cleaned) throw new Error('Name required');
|
||||||
|
name = cleaned;
|
||||||
|
}
|
||||||
|
|
||||||
|
let width = current.width;
|
||||||
|
if (input.width !== undefined) {
|
||||||
|
const w = Number(input.width);
|
||||||
|
if (!Number.isInteger(w) || w <= 0) throw new Error('Invalid width');
|
||||||
|
width = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
let height = current.height;
|
||||||
|
if (input.height !== undefined) {
|
||||||
|
const h = Number(input.height);
|
||||||
|
if (!Number.isInteger(h) || h <= 0) throw new Error('Invalid height');
|
||||||
|
height = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dpi = current.dpi;
|
||||||
|
if (input.dpi !== undefined) {
|
||||||
|
const d = Number(input.dpi);
|
||||||
|
if (!VALID_DPIS.has(d)) throw new Error('Invalid dpi: must be 203 or 300');
|
||||||
|
dpi = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
let type = current.type;
|
||||||
|
if (input.type !== undefined) {
|
||||||
|
const cleaned = typeof input.type === 'string' ? input.type.trim() : '';
|
||||||
|
if (!cleaned || !VALID_TYPES.has(cleaned)) throw new Error('Invalid type: must be "zpl"');
|
||||||
|
type = cleaned;
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = current.content;
|
||||||
|
if (input.content !== undefined) {
|
||||||
|
if (input.content == null) throw new Error('Content required');
|
||||||
|
content = typeof input.content === 'string'
|
||||||
|
? input.content
|
||||||
|
: JSON.stringify(input.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
let thumb = current.thumb ?? null;
|
||||||
|
if (input.thumb !== undefined) {
|
||||||
|
thumb = input.thumb instanceof Buffer ? input.thumb : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await runner.query(updateSql, {
|
||||||
|
id: numericId,
|
||||||
|
companyId,
|
||||||
|
name,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
dpi,
|
||||||
|
type,
|
||||||
|
content,
|
||||||
|
thumb,
|
||||||
|
});
|
||||||
|
|
||||||
|
const row = result.rows[0] ?? {
|
||||||
|
id: numericId,
|
||||||
|
company_id: companyId,
|
||||||
|
name,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
dpi,
|
||||||
|
type,
|
||||||
|
content,
|
||||||
|
thumb,
|
||||||
|
};
|
||||||
|
|
||||||
|
return shape(row);
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user