This commit is contained in:
seb
2026-10-30 16:56:28 +01:00
parent 211acd651d
commit 60cf5873cd
11 changed files with 70 additions and 38 deletions

6
API.md
View File

@@ -405,10 +405,10 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
- `listByManifestId(googleAuthId: number, manifestId: number, tx?: object): Promise<Array<{id: number, accountId: number, manifestId: number, type: string, amount: number}>>`
- [printeragent](API.printeragent.md)
- `create(googleAuthId: number, input: {name: string, pairingpin: string}, tx?: object): Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>`
- `create(googleAuthId: number, input: {name: string, pairingpin: string, sort?: number}, tx?: object): Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string, sort: number}>`
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
- `list(googleAuthId: number, tx?: object): Promise<Array<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>>`
- `update(googleAuthId: number, input: {id: number, name: string}, tx?: object): Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>`
- `list(googleAuthId: number, tx?: object): Promise<Array<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string, sort: number}>>`
- `update(googleAuthId: number, input: {id: number, name?: string, sort?: number}, tx?: object): Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string, sort: number}>`
- [retoure](API.retoure.md)
- `create(googleAuthId: number, body: {number?: string, date: string, entityId?: number, externalNumber?: string, lines?: Array<object>}, tx?: object): Promise<object>`
- `createShipment(googleAuthId: number, retoureId: number, input: object, tx?: object): Promise<object>`

View File

@@ -16,15 +16,16 @@ Creates an unpaired printer agent for the user's selected company. The agent reg
| `input` | `object` | The printer agent input. |
| `input.name` | `string` | The display name. |
| `input.pairingpin` | `string` | The pairing pin the agent uses to register. |
| `[input.sort]` | `number` | Display order (integer, ascending). Default 0. |
| `[tx]` | `object` | Optional transaction to run within. |
**Returns**
`Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>` — The created printer agent.
`Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string, sort: number}>` — The created printer agent.
**Throws**
`Error` — 'Invalid printeragent' if name or pairingpin is missing/blank.
`Error` — 'Invalid printeragent' if name or pairingpin is missing/blank or sort is not an integer.
**Example**
@@ -75,20 +76,20 @@ Lists the printer agents of the user's selected company.
**Returns**
`Promise<Array<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>>` — The printer agents.
`Promise<Array<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string, sort: number}>>` — The printer agents.
**Example**
```js
const agents = await store.printeragent.list(42);
// => [{ id, companyId, name, token, pairingpin, pairedAt, clientserial, clientmodel, clientstate, agentversion, lastseenAt, updatedAt }]
// => [{ id, companyId, name, token, pairingpin, pairedAt, clientserial, clientmodel, clientstate, agentversion, lastseenAt, updatedAt, sort }]
```
## `printeragent.update`
*Source: `src/store/printeragent/update.js`*
Renames a printer agent of the user's selected company.
Updates name and/or sort of a printer agent of the user's selected company.
**Parameters**
@@ -97,19 +98,20 @@ Renames a printer agent of the user's selected company.
| `googleAuthId` | `number` | The id of the Google auth user. |
| `input` | `object` | The update input. |
| `input.id` | `number` | The printer agent id. |
| `input.name` | `string` | The new display name. |
| `[input.name]` | `string` | The new display name. |
| `[input.sort]` | `number` | The new display order (integer). |
| `[tx]` | `object` | Optional transaction to run within. |
**Returns**
`Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>` — The updated printer agent.
`Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string, sort: number}>` — The updated printer agent.
**Throws**
`Error` — 'Invalid printeragent' if name is blank; 'Printeragent not found' if id is unknown in the company.
`Error` — 'Invalid printeragent' if name is blank, sort is not an integer, or neither is given; 'Printeragent not found' if id is unknown in the company.
**Example**
```js
const agent = await store.printeragent.update(42, { id: 5, name: 'Kitchen printer' });
const agent = await store.printeragent.update(42, { id: 5, name: 'Kitchen printer', sort: 1 });
```

View File

@@ -25,6 +25,12 @@ try {
assert.equal(a.companyId, company.id);
assert.ok(a.updatedAt);
assert.equal(a.sort, 0);
const s1 = await store.printeragent.update(googleAuthId, { id: a.id, sort: 5 });
assert.equal(s1.sort, 5);
assert.equal(s1.name, 'Bar');
await assert.rejects(store.printeragent.update(googleAuthId, { id: a.id }), /Invalid printeragent/);
await assert.rejects(store.printeragent.update(googleAuthId, { id: a.id, sort: 1.5 }), /Invalid printeragent/);
const b = await store.printeragent.update(googleAuthId, { id: a.id, name: 'Kitchen' });
assert.equal(b.name, 'Kitchen');
await assert.rejects(store.printeragent.update(googleAuthId, { id: 9999, name: 'x' }), /Printeragent not found/);

View File

@@ -10,7 +10,8 @@ export const PRINTERAGENT_COLUMNS = `
clientstate,
agentversion,
lastseen_at AS lastseenAt,
updated_at AS updatedAt
updated_at AS updatedAt,
sort
`;
export const LIST_BY_COMPANY = `
@@ -18,7 +19,7 @@ SELECT
${PRINTERAGENT_COLUMNS}
FROM printeragent
WHERE company_id = @companyId
ORDER BY name, id
ORDER BY sort, id
`;
export const GET_BY_COMPANY_AND_ID = `
@@ -29,7 +30,7 @@ WHERE id = @id AND company_id = @companyId
`;
export const CREATE = `
INSERT INTO printeragent (company_id, name, pairingpin)
INSERT INTO printeragent (company_id, name, pairingpin, sort)
OUTPUT
INSERTED.id,
INSERTED.company_id AS companyId,
@@ -42,13 +43,14 @@ OUTPUT
INSERTED.clientstate,
INSERTED.agentversion,
INSERTED.lastseen_at AS lastseenAt,
INSERTED.updated_at AS updatedAt
VALUES (@companyId, @name, @pairingpin)
INSERTED.updated_at AS updatedAt,
INSERTED.sort
VALUES (@companyId, @name, @pairingpin, @sort)
`;
export const UPDATE_NAME = `
export const UPDATE = `
UPDATE printeragent
SET name = @name, updated_at = SYSUTCDATETIME()
SET name = @name, sort = @sort, updated_at = SYSUTCDATETIME()
WHERE id = @id AND company_id = @companyId
`;

View File

@@ -1027,6 +1027,7 @@ BEGIN
agentversion NVARCHAR(255) NULL,
lastseen_at DATETIME2 NULL,
updated_at DATETIME2 NOT NULL CONSTRAINT DF_printeragent_updated_at DEFAULT SYSUTCDATETIME(),
sort INT NOT NULL CONSTRAINT DF_printeragent_sort DEFAULT 0,
CONSTRAINT FK_printeragent_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX UQ_printeragent_token ON printeragent(token) WHERE token IS NOT NULL;

View File

@@ -8,5 +8,5 @@ export const {
GET_BY_COMPANY_AND_ID,
LIST_BY_COMPANY,
PRINTERAGENT_COLUMNS,
UPDATE_NAME,
UPDATE,
} = queries;

View File

@@ -706,6 +706,7 @@ CREATE TABLE IF NOT EXISTS printeragent (
agentversion TEXT,
lastseen_at TEXT,
updated_at TEXT NOT NULL DEFAULT (${UTC_NOW}),
sort INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS UQ_printeragent_token

View File

@@ -12,8 +12,9 @@ export function shape(row) {
agentversion: row.agentversion ?? null,
lastseenAt: row.lastseenAt ?? null,
updatedAt: row.updatedAt,
sort: row.sort,
};
}
export const PRINTERAGENT_TYPEDEF =
'{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}';
'{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string, sort: number}';

View File

@@ -20,9 +20,10 @@ export default function create(provider) {
* @param {object} input - The printer agent input.
* @param {string} input.name - The display name.
* @param {string} input.pairingpin - The pairing pin the agent uses to register.
* @param {number} [input.sort] - Display order (integer, ascending). Default 0.
* @param {object} [tx] - Optional transaction to run within.
* @returns {Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>} The created printer agent.
* @throws {Error} 'Invalid printeragent' if name or pairingpin is missing/blank.
* @returns {Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string, sort: number}>} The created printer agent.
* @throws {Error} 'Invalid printeragent' if name or pairingpin is missing/blank or sort is not an integer.
*
* @example
* const agent = await store.printeragent.create(42, { name: 'Bar printer', pairingpin: '123456' });
@@ -34,10 +35,15 @@ export default function create(provider) {
throw new Error('Invalid printeragent');
}
if (input.sort !== undefined && !Number.isInteger(input.sort)) {
throw new Error('Invalid printeragent');
}
const sort = input.sort ?? 0;
const runner = makeRunner(provider, tx);
const { companyId } = await access(googleAuthId, runner);
const result = await runner.query(sql, { companyId, name, pairingpin });
const result = await runner.query(sql, { companyId, name, pairingpin, sort });
return shape(result.rows[0]);
};
}

View File

@@ -13,11 +13,11 @@ export default function list(provider) {
*
* @param {number} googleAuthId - The id of the Google auth user.
* @param {object} [tx] - Optional transaction to run within.
* @returns {Promise<Array<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>>} The printer agents.
* @returns {Promise<Array<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string, sort: number}>>} The printer agents.
*
* @example
* const agents = await store.printeragent.list(42);
* // => [{ id, companyId, name, token, pairingpin, pairedAt, clientserial, clientmodel, clientstate, agentversion, lastseenAt, updatedAt }]
* // => [{ id, companyId, name, token, pairingpin, pairedAt, clientserial, clientmodel, clientstate, agentversion, lastseenAt, updatedAt, sort }]
*/
return async (googleAuthId, tx) => {
const runner = makeRunner(provider, tx);

View File

@@ -1,10 +1,10 @@
import {
GET_BY_COMPANY_AND_ID as MSSQL_GET,
UPDATE_NAME as MSSQL_UPDATE_NAME,
UPDATE as MSSQL_UPDATE,
} from '../../providers/mssql/queries/printeragent.js';
import {
GET_BY_COMPANY_AND_ID as SQLITE_GET,
UPDATE_NAME as SQLITE_UPDATE_NAME,
UPDATE as SQLITE_UPDATE,
} from '../../providers/sqlite3/queries/printeragent.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import makeRunner from '../runner.js';
@@ -14,40 +14,53 @@ export default function update(provider) {
const access = resolveSelectedCompanyAccess(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const getSql = isSqlite ? SQLITE_GET : MSSQL_GET;
const updateNameSql = isSqlite ? SQLITE_UPDATE_NAME : MSSQL_UPDATE_NAME;
const updateSql = isSqlite ? SQLITE_UPDATE : MSSQL_UPDATE;
/**
* Renames a printer agent of the user's selected company.
* Updates name and/or sort of a printer agent of the user's selected company.
*
* @param {number} googleAuthId - The id of the Google auth user.
* @param {object} input - The update input.
* @param {number} input.id - The printer agent id.
* @param {string} input.name - The new display name.
* @param {string} [input.name] - The new display name.
* @param {number} [input.sort] - The new display order (integer).
* @param {object} [tx] - Optional transaction to run within.
* @returns {Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string}>} The updated printer agent.
* @throws {Error} 'Invalid printeragent' if name is blank; 'Printeragent not found' if id is unknown in the company.
* @returns {Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, clientmodel: string|null, clientstate: string|null, agentversion: string|null, lastseenAt: string|null, updatedAt: string, sort: number}>} The updated printer agent.
* @throws {Error} 'Invalid printeragent' if name is blank, sort is not an integer, or neither is given; 'Printeragent not found' if id is unknown in the company.
*
* @example
* const agent = await store.printeragent.update(42, { id: 5, name: 'Kitchen printer' });
* const agent = await store.printeragent.update(42, { id: 5, name: 'Kitchen printer', sort: 1 });
*/
return async (googleAuthId, input = {}, tx) => {
const id = Number(input.id);
if (!Number.isInteger(id) || id <= 0) {
throw new Error('Printeragent not found');
}
const name = typeof input.name === 'string' ? input.name.trim() : '';
if (!name) {
if (input.name === undefined && input.sort === undefined) {
throw new Error('Invalid printeragent');
}
if (input.name !== undefined && (typeof input.name !== 'string' || !input.name.trim())) {
throw new Error('Invalid printeragent');
}
if (input.sort !== undefined && !Number.isInteger(input.sort)) {
throw new Error('Invalid printeragent');
}
const runner = makeRunner(provider, tx);
const { companyId } = await access(googleAuthId, runner);
const result = await runner.query(updateNameSql, { id, companyId, name });
if (!result.rowsAffected) {
const existing = await runner.query(getSql, { id, companyId });
if (!existing.rows[0]) {
throw new Error('Printeragent not found');
}
await runner.query(updateSql, {
id,
companyId,
name: input.name !== undefined ? input.name.trim() : existing.rows[0].name,
sort: input.sort !== undefined ? input.sort : existing.rows[0].sort,
});
const row = await runner.query(getSql, { id, companyId });
return shape(row.rows[0]);
};