This commit is contained in:
seb
2026-10-31 21:02:50 +01:00
parent f612c87b6e
commit 76ea6642f4
18 changed files with 666 additions and 0 deletions

6
API.md
View File

@@ -421,6 +421,12 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
- `touchLastseen(id: number, agentversion?: string|null, tx?: object): Promise<{id: number}>` - `touchLastseen(id: number, agentversion?: string|null, tx?: object): Promise<{id: 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}>` - `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}>`
- `updateState(id: number, clientstate: string|null, 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}>` - `updateState(id: number, clientstate: string|null, 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}>`
- [printerjob](API.printerjob.md)
- `create(googleAuthId: number, input: {agentprinterId: number, data: string, type?: string, state?: string}, tx?: object): Promise<object>`
- `delete(googleAuthId: number, id: number, tx?: object): Promise<object>`
- `getById(auth: number|{agentId: number}, id: number, tx?: object): Promise<object|null>`
- `list(auth: number|{agentId: number}, filters?: {agentprinterId?: number, state?: string}, tx?: object): Promise<Array<object>>`
- `updateState(auth: number|{agentId: number}, id: number, state: string, tx?: object): Promise<object>`
- [retoure](API.retoure.md) - [retoure](API.retoure.md)
- `create(googleAuthId: number, body: {number?: string, date: string, entityId?: number, externalNumber?: string, lines?: Array<object>}, tx?: object): Promise<object>` - `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>` - `createShipment(googleAuthId: number, retoureId: number, input: object, tx?: object): Promise<object>`

100
API.printerjob.md Normal file
View File

@@ -0,0 +1,100 @@
# printerjob
This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`.
## `printerjob.create`
*Source: `src/store/printerjob/create.js`*
Creates a new printer job for an agent printer belonging to the user's selected company.
**Parameters**
| Name | Type | Description |
| --- | --- | --- |
| `googleAuthId` | `number` | The id of the Google auth user. |
| `input` | `object` | |
| `input.agentprinterId` | `number` | Target agent printer ID. |
| `input.data` | `string` | Job payload (ZPL code, etc.). |
| `[input.type]` | `string` | Job type ("zpl", "pdf", etc., defaults to agentprinter type or "zpl"). |
| `[input.state]` | `string` | Initial state (defaults to "pending"). |
| `[tx]` | `object` | Optional transaction to run within. |
**Returns**
`Promise<object>` — Created printer job with printeragentId attached.
## `printerjob.delete`
*Source: `src/store/printerjob/delete.js`*
Deletes a printer job belonging to the user's selected company.
**Parameters**
| Name | Type | Description |
| --- | --- | --- |
| `googleAuthId` | `number` | The id of the Google auth user. |
| `id` | `number` | Printer job ID. |
| `[tx]` | `object` | Optional transaction. |
**Returns**
`Promise<object>` — The deleted job's snapshot.
## `printerjob.getById`
*Source: `src/store/printerjob/getById.js`*
Retrieves a printer job by ID. If caller is an agent ({ agentId: number }), checks that the job belongs to that printer agent. If caller is a user (googleAuthId: number), checks that the job belongs to the selected company.
**Parameters**
| Name | Type | Description |
| --- | --- | --- |
| `auth` | `number|{agentId: number}` | User's googleAuthId or { agentId }. |
| `id` | `number` | Printer job ID. |
| `[tx]` | `object` | Optional transaction. |
**Returns**
`Promise<object|null>`
## `printerjob.list`
*Source: `src/store/printerjob/list.js`*
Lists printer jobs. If caller is an agent ({ agentId: number }), lists jobs for that agent. If caller is a user (googleAuthId: number), lists jobs for the selected company.
**Parameters**
| Name | Type | Description |
| --- | --- | --- |
| `auth` | `number|{agentId: number}` | User's googleAuthId or { agentId }. |
| `[filters]` | `object` | |
| `[filters.agentprinterId]` | `number` | Filter by agentprinterId (company callers only). |
| `[filters.state]` | `string` | Filter by job state (e.g. "pending"). |
| `[tx]` | `object` | Optional transaction. |
**Returns**
`Promise<Array<object>>`
## `printerjob.updateState`
*Source: `src/store/printerjob/updateState.js`*
Updates a printer job's state ("processing", "completed", "cancelled", etc.).
**Parameters**
| Name | Type | Description |
| --- | --- | --- |
| `auth` | `number|{agentId: number}` | User's googleAuthId or { agentId }. |
| `id` | `number` | Printer job ID. |
| `state` | `string` | New state. |
| `[tx]` | `object` | Optional transaction. |
**Returns**
`Promise<object>` — Updated printer job.

View File

@@ -215,6 +215,11 @@ import agentprinterFindOrCreate from './store/agentprinter/findOrCreate.js';
import agentprinterUpdate from './store/agentprinter/update.js'; import agentprinterUpdate from './store/agentprinter/update.js';
import agentprinterOrder from './store/agentprinter/order.js'; import agentprinterOrder from './store/agentprinter/order.js';
import agentprinterDelete from './store/agentprinter/delete.js'; import agentprinterDelete from './store/agentprinter/delete.js';
import printerjobCreate from './store/printerjob/create.js';
import printerjobGetById from './store/printerjob/getById.js';
import printerjobList from './store/printerjob/list.js';
import printerjobUpdateState from './store/printerjob/updateState.js';
import printerjobDelete from './store/printerjob/delete.js';
import modelconversationCreate from './store/modelconversation/create.js'; import modelconversationCreate from './store/modelconversation/create.js';
import modelconversationGet from './store/modelconversation/get.js'; import modelconversationGet from './store/modelconversation/get.js';
import modelconversationList from './store/modelconversation/list.js'; import modelconversationList from './store/modelconversation/list.js';
@@ -673,6 +678,14 @@ export default class LibDashStore {
delete: agentprinterDelete(provider), delete: agentprinterDelete(provider),
}; };
this.printerjob = {
create: printerjobCreate(provider),
getById: printerjobGetById(provider),
list: printerjobList(provider),
updateState: printerjobUpdateState(provider),
delete: printerjobDelete(provider),
};
this.modelconversation = { this.modelconversation = {
create: modelconversationCreate(provider), create: modelconversationCreate(provider),
get: modelconversationGet(provider), get: modelconversationGet(provider),

View File

@@ -0,0 +1,13 @@
/**
* Schema 5 → 4 (MSSQL):
* - Drops printerjob table
* @param {{ query: (sql: string, params?: object) => Promise<unknown>, assertVersion: (v: number) => Promise<void>, setVersion: (v: number) => Promise<void> }} ctx
*/
export default async function downgrade({ query, assertVersion, setVersion }) {
await assertVersion(5);
await query(`DROP TABLE IF EXISTS printerjob;`);
await setVersion(4);
}

View File

@@ -28,6 +28,7 @@ export const TABLES = [
'posterminalobituary', 'posterminalobituary',
'posterminalcategory', 'posterminalcategory',
'posterminal', 'posterminal',
'printerjob',
'agentprinter', 'agentprinter',
'printeragent', 'printeragent',
'printer', 'printer',

View File

@@ -0,0 +1,115 @@
export const PRINTERJOB_COLUMNS = `
pj.id,
pj.agentprinter_id AS agentprinterId,
pj.type,
pj.state,
pj.data,
pj.created_at AS createdAt,
pj.completed_at AS completedAt
`;
export const CREATE = `
INSERT INTO printerjob (agentprinter_id, type, state, data, created_at)
OUTPUT
INSERTED.id,
INSERTED.agentprinter_id AS agentprinterId,
INSERTED.type,
INSERTED.state,
INSERTED.data,
INSERTED.created_at AS createdAt,
INSERTED.completed_at AS completedAt
VALUES (@agentprinterId, @type, @state, @data, SYSUTCDATETIME())
`;
export const GET_BY_ID_FOR_COMPANY = `
SELECT
${PRINTERJOB_COLUMNS},
ap.printeragent_id AS printeragentId
FROM printerjob pj
JOIN agentprinter ap ON ap.id = pj.agentprinter_id
JOIN printeragent pa ON pa.id = ap.printeragent_id
WHERE pj.id = @id AND pa.company_id = @companyId
`;
export const GET_BY_ID_FOR_AGENT = `
SELECT
${PRINTERJOB_COLUMNS},
ap.printeragent_id AS printeragentId
FROM printerjob pj
JOIN agentprinter ap ON ap.id = pj.agentprinter_id
WHERE pj.id = @id AND ap.printeragent_id = @agentId
`;
export const LIST_BY_COMPANY = `
SELECT
${PRINTERJOB_COLUMNS},
ap.printeragent_id AS printeragentId
FROM printerjob pj
JOIN agentprinter ap ON ap.id = pj.agentprinter_id
JOIN printeragent pa ON pa.id = ap.printeragent_id
WHERE pa.company_id = @companyId
ORDER BY pj.id DESC
`;
export const LIST_BY_COMPANY_AND_AGENTPRINTER = `
SELECT
${PRINTERJOB_COLUMNS},
ap.printeragent_id AS printeragentId
FROM printerjob pj
JOIN agentprinter ap ON ap.id = pj.agentprinter_id
JOIN printeragent pa ON pa.id = ap.printeragent_id
WHERE pa.company_id = @companyId AND pj.agentprinter_id = @agentprinterId
ORDER BY pj.id DESC
`;
export const LIST_BY_AGENT = `
SELECT
${PRINTERJOB_COLUMNS},
ap.printeragent_id AS printeragentId
FROM printerjob pj
JOIN agentprinter ap ON ap.id = pj.agentprinter_id
WHERE ap.printeragent_id = @agentId
ORDER BY pj.id ASC
`;
export const LIST_BY_AGENT_AND_STATE = `
SELECT
${PRINTERJOB_COLUMNS},
ap.printeragent_id AS printeragentId
FROM printerjob pj
JOIN agentprinter ap ON ap.id = pj.agentprinter_id
WHERE ap.printeragent_id = @agentId AND pj.state = @state
ORDER BY pj.id ASC
`;
export const UPDATE_STATE_FOR_AGENT = `
UPDATE printerjob
SET
state = @state,
completed_at = CASE WHEN @state IN ('completed', 'cancelled') THEN SYSUTCDATETIME() ELSE completed_at END
WHERE id = @id AND agentprinter_id IN (
SELECT ap.id FROM agentprinter ap WHERE ap.printeragent_id = @agentId
)
`;
export const UPDATE_STATE_FOR_COMPANY = `
UPDATE printerjob
SET
state = @state,
completed_at = CASE WHEN @state IN ('completed', 'cancelled') THEN SYSUTCDATETIME() ELSE completed_at END
WHERE id = @id AND agentprinter_id IN (
SELECT ap.id FROM agentprinter ap
JOIN printeragent pa ON pa.id = ap.printeragent_id
WHERE pa.company_id = @companyId
)
`;
export const DELETE_BY_COMPANY_AND_ID = `
DELETE FROM printerjob
WHERE id = @id AND agentprinter_id IN (
SELECT ap.id FROM agentprinter ap
JOIN printeragent pa ON pa.id = ap.printeragent_id
WHERE pa.company_id = @companyId
)
`;

View File

@@ -1050,6 +1050,24 @@ BEGIN
END END
`; `;
export const INIT_PRINTERJOB = `
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'printerjob')
BEGIN
CREATE TABLE printerjob (
id INT IDENTITY(1,1) PRIMARY KEY,
agentprinter_id INT NOT NULL,
type NVARCHAR(50) NOT NULL,
state NVARCHAR(50) NOT NULL CONSTRAINT DF_printerjob_state DEFAULT 'pending',
data NVARCHAR(MAX) NOT NULL,
created_at DATETIME2 NOT NULL CONSTRAINT DF_printerjob_created_at DEFAULT SYSUTCDATETIME(),
completed_at DATETIME2 NULL,
CONSTRAINT FK_printerjob_agentprinter FOREIGN KEY (agentprinter_id) REFERENCES agentprinter(id) ON DELETE CASCADE
);
CREATE INDEX IX_printerjob_agentprinter_id ON printerjob(agentprinter_id);
CREATE INDEX IX_printerjob_state ON printerjob(state);
END
`;
export const INIT_LABELTEMPLATE = ` export const INIT_LABELTEMPLATE = `
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'labeltemplate') IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'labeltemplate')
BEGIN BEGIN
@@ -1707,6 +1725,7 @@ export const SCHEMA_SCRIPTS = [
INIT_PRINTER, INIT_PRINTER,
INIT_PRINTERAGENT, INIT_PRINTERAGENT,
INIT_AGENTPRINTER, INIT_AGENTPRINTER,
INIT_PRINTERJOB,
INIT_LABELTEMPLATE, INIT_LABELTEMPLATE,
INIT_FILE, INIT_FILE,
INIT_MANIFESTATTACHMENT, INIT_MANIFESTATTACHMENT,

View File

@@ -0,0 +1,15 @@
import { INIT_PRINTERJOB } from '../schema.js';
/**
* Schema 4 → 5 (MSSQL):
* - Creates printerjob table
* @param {{ query: (sql: string, params?: object) => Promise<unknown>, assertVersion: (v: number) => Promise<void>, setVersion: (v: number) => Promise<void> }} ctx
*/
export default async function upgrade({ query, assertVersion, setVersion }) {
await assertVersion(4);
await query(INIT_PRINTERJOB);
await setVersion(5);
}

View File

@@ -0,0 +1,13 @@
/**
* Schema 5 → 4 (SQLite):
* - Drops printerjob table
* @param {{ exec: (sql: string) => void, assertVersion: (v: number) => Promise<void>, setVersion: (v: number) => Promise<void> }} ctx
*/
export default async function downgrade({ exec, assertVersion, setVersion }) {
await assertVersion(5);
exec(`DROP TABLE IF EXISTS printerjob;`);
await setVersion(4);
}

View File

@@ -0,0 +1,18 @@
import * as source from '../../mssql/queries/printerjob.js';
import { translateQueries } from './translate.js';
const queries = translateQueries(source, 'printerjob');
export const {
PRINTERJOB_COLUMNS,
CREATE,
GET_BY_ID_FOR_COMPANY,
GET_BY_ID_FOR_AGENT,
LIST_BY_COMPANY,
LIST_BY_COMPANY_AND_AGENTPRINTER,
LIST_BY_AGENT,
LIST_BY_AGENT_AND_STATE,
UPDATE_STATE_FOR_AGENT,
UPDATE_STATE_FOR_COMPANY,
DELETE_BY_COMPANY_AND_ID,
} = queries;

View File

@@ -728,6 +728,23 @@ CREATE INDEX IF NOT EXISTS IX_agentprinter_printeragent_id
ON agentprinter(printeragent_id); ON agentprinter(printeragent_id);
`; `;
export const INIT_PRINTERJOB = `
CREATE TABLE IF NOT EXISTS printerjob (
id INTEGER PRIMARY KEY AUTOINCREMENT,
agentprinter_id INTEGER NOT NULL,
type TEXT NOT NULL,
state TEXT NOT NULL DEFAULT 'pending',
data TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
completed_at TEXT,
FOREIGN KEY (agentprinter_id) REFERENCES agentprinter(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS IX_printerjob_agentprinter_id
ON printerjob(agentprinter_id);
CREATE INDEX IF NOT EXISTS IX_printerjob_state
ON printerjob(state);
`;
export const INIT_LABELTEMPLATE = ` export const INIT_LABELTEMPLATE = `
CREATE TABLE IF NOT EXISTS labeltemplate ( CREATE TABLE IF NOT EXISTS labeltemplate (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -1263,6 +1280,7 @@ export const SCHEMA_SCRIPTS = [
INIT_PRINTER, INIT_PRINTER,
INIT_PRINTERAGENT, INIT_PRINTERAGENT,
INIT_AGENTPRINTER, INIT_AGENTPRINTER,
INIT_PRINTERJOB,
INIT_LABELTEMPLATE, INIT_LABELTEMPLATE,
INIT_FILE, INIT_FILE,
INIT_MANIFESTATTACHMENT, INIT_MANIFESTATTACHMENT,

View File

@@ -0,0 +1,15 @@
import { INIT_PRINTERJOB } from '../schema.js';
/**
* Schema 4 → 5 (SQLite):
* - Creates printerjob table
* @param {{ exec: (sql: string) => void, assertVersion: (v: number) => Promise<void>, setVersion: (v: number) => Promise<void> }} ctx
*/
export default async function upgrade({ exec, assertVersion, setVersion }) {
await assertVersion(4);
exec(INIT_PRINTERJOB);
await setVersion(5);
}

View File

@@ -0,0 +1,14 @@
export function shape(row) {
if (!row) return null;
return {
id: row.id,
agentprinterId: row.agentprinterId,
printeragentId: row.printeragentId != null ? Number(row.printeragentId) : null,
type: row.type,
state: row.state,
data: row.data,
createdAt: row.createdAt instanceof Date ? row.createdAt.toISOString() : (row.createdAt ?? null),
completedAt: row.completedAt instanceof Date ? row.completedAt.toISOString() : (row.completedAt ?? null),
};
}

View File

@@ -0,0 +1,71 @@
import { CREATE as MSSQL_CREATE } from '../../providers/mssql/queries/printerjob.js';
import { CREATE as SQLITE_CREATE } from '../../providers/sqlite3/queries/printerjob.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import makeRunner from '../runner.js';
import { shape } from './_shared.js';
const VERIFY_AGENTPRINTER = `
SELECT ap.id, ap.printeragent_id AS printeragentId, ap.type, ap.enabled
FROM agentprinter ap
JOIN printeragent pa ON pa.id = ap.printeragent_id
WHERE ap.id = @agentprinterId AND pa.company_id = @companyId
`;
export default function create(provider) {
const access = resolveSelectedCompanyAccess(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const createSql = isSqlite ? SQLITE_CREATE : MSSQL_CREATE;
/**
* Creates a new printer job for an agent printer belonging to the user's selected company.
*
* @param {number} googleAuthId - The id of the Google auth user.
* @param {object} input
* @param {number} input.agentprinterId - Target agent printer ID.
* @param {string} input.data - Job payload (ZPL code, etc.).
* @param {string} [input.type] - Job type ("zpl", "pdf", etc., defaults to agentprinter type or "zpl").
* @param {string} [input.state] - Initial state (defaults to "pending").
* @param {object} [tx] - Optional transaction to run within.
* @returns {Promise<object>} Created printer job with printeragentId attached.
*/
return async (googleAuthId, input = {}, tx) => {
const runner = makeRunner(provider, tx);
const { companyId } = await access(googleAuthId, runner);
const apId = Number(input.agentprinterId ?? input.agentprinter_id);
if (!Number.isInteger(apId) || apId <= 0) {
throw new Error('agentprinterId is required');
}
const data = input.data != null ? String(input.data) : '';
if (!data.trim()) {
throw new Error('data is required');
}
const verified = await runner.query(VERIFY_AGENTPRINTER, { agentprinterId: apId, companyId });
if (verified.rows.length === 0) {
throw new Error('Agentprinter not found');
}
const apRow = verified.rows[0];
const printeragentId = Number(apRow.printeragentId);
const type = typeof input.type === 'string' && input.type.trim()
? input.type.trim().toLowerCase()
: (apRow.type ? String(apRow.type).toLowerCase() : 'zpl');
const state = typeof input.state === 'string' && input.state.trim()
? input.state.trim().toLowerCase()
: 'pending';
const result = await runner.query(createSql, {
agentprinterId: apId,
type,
state,
data,
});
const job = shape(result.rows[0]);
job.printeragentId = printeragentId;
return job;
};
}

View File

@@ -0,0 +1,46 @@
import {
DELETE_BY_COMPANY_AND_ID as MSSQL_DELETE,
GET_BY_ID_FOR_COMPANY as MSSQL_GET,
} from '../../providers/mssql/queries/printerjob.js';
import {
DELETE_BY_COMPANY_AND_ID as SQLITE_DELETE,
GET_BY_ID_FOR_COMPANY as SQLITE_GET,
} from '../../providers/sqlite3/queries/printerjob.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import makeRunner from '../runner.js';
import { shape } from './_shared.js';
export default function deleteJob(provider) {
const access = resolveSelectedCompanyAccess(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const deleteSql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
const getSql = isSqlite ? SQLITE_GET : MSSQL_GET;
/**
* Deletes a printer job belonging to the user's selected company.
*
* @param {number} googleAuthId - The id of the Google auth user.
* @param {number} id - Printer job ID.
* @param {object} [tx] - Optional transaction.
* @returns {Promise<object>} The deleted job's snapshot.
*/
return async (googleAuthId, id, tx) => {
const jId = Number(id);
if (!Number.isInteger(jId) || jId <= 0) {
throw new Error('Printerjob not found');
}
const runner = makeRunner(provider, tx);
const { companyId } = await access(googleAuthId, runner);
const existing = await runner.query(getSql, { id: jId, companyId });
if (existing.rows.length === 0) {
throw new Error('Printerjob not found');
}
const job = shape(existing.rows[0]);
await runner.query(deleteSql, { id: jId, companyId });
return job;
};
}

View File

@@ -0,0 +1,49 @@
import {
GET_BY_ID_FOR_COMPANY as MSSQL_GET_BY_ID_FOR_COMPANY,
GET_BY_ID_FOR_AGENT as MSSQL_GET_BY_ID_FOR_AGENT,
} from '../../providers/mssql/queries/printerjob.js';
import {
GET_BY_ID_FOR_COMPANY as SQLITE_GET_BY_ID_FOR_COMPANY,
GET_BY_ID_FOR_AGENT as SQLITE_GET_BY_ID_FOR_AGENT,
} from '../../providers/sqlite3/queries/printerjob.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import makeRunner from '../runner.js';
import { shape } from './_shared.js';
export default function getById(provider) {
const access = resolveSelectedCompanyAccess(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const getForCompanySql = isSqlite ? SQLITE_GET_BY_ID_FOR_COMPANY : MSSQL_GET_BY_ID_FOR_COMPANY;
const getForAgentSql = isSqlite ? SQLITE_GET_BY_ID_FOR_AGENT : MSSQL_GET_BY_ID_FOR_AGENT;
/**
* Retrieves a printer job by ID.
* If caller is an agent ({ agentId: number }), checks that the job belongs to that printer agent.
* If caller is a user (googleAuthId: number), checks that the job belongs to the selected company.
*
* @param {number|{agentId: number}} auth - User's googleAuthId or { agentId }.
* @param {number} id - Printer job ID.
* @param {object} [tx] - Optional transaction.
* @returns {Promise<object|null>}
*/
return async (auth, id, tx) => {
const jId = Number(id);
if (!Number.isInteger(jId) || jId <= 0) {
return null;
}
const runner = makeRunner(provider, tx);
if (typeof auth === 'object' && auth !== null && auth.agentId != null) {
const aId = Number(auth.agentId);
if (!Number.isInteger(aId) || aId <= 0) return null;
const result = await runner.query(getForAgentSql, { id: jId, agentId: aId });
return result.rows.length > 0 ? shape(result.rows[0]) : null;
}
const { companyId } = await access(auth, runner);
const result = await runner.query(getForCompanySql, { id: jId, companyId });
return result.rows.length > 0 ? shape(result.rows[0]) : null;
};
}

View File

@@ -0,0 +1,74 @@
import {
LIST_BY_COMPANY as MSSQL_LIST_BY_COMPANY,
LIST_BY_COMPANY_AND_AGENTPRINTER as MSSQL_LIST_BY_COMPANY_AND_AGENTPRINTER,
LIST_BY_AGENT as MSSQL_LIST_BY_AGENT,
LIST_BY_AGENT_AND_STATE as MSSQL_LIST_BY_AGENT_AND_STATE,
} from '../../providers/mssql/queries/printerjob.js';
import {
LIST_BY_COMPANY as SQLITE_LIST_BY_COMPANY,
LIST_BY_COMPANY_AND_AGENTPRINTER as SQLITE_LIST_BY_COMPANY_AND_AGENTPRINTER,
LIST_BY_AGENT as SQLITE_LIST_BY_AGENT,
LIST_BY_AGENT_AND_STATE as SQLITE_LIST_BY_AGENT_AND_STATE,
} from '../../providers/sqlite3/queries/printerjob.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import makeRunner from '../runner.js';
import { shape } from './_shared.js';
export default function list(provider) {
const access = resolveSelectedCompanyAccess(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const listCompanySql = isSqlite ? SQLITE_LIST_BY_COMPANY : MSSQL_LIST_BY_COMPANY;
const listCompanyApSql = isSqlite ? SQLITE_LIST_BY_COMPANY_AND_AGENTPRINTER : MSSQL_LIST_BY_COMPANY_AND_AGENTPRINTER;
const listAgentSql = isSqlite ? SQLITE_LIST_BY_AGENT : MSSQL_LIST_BY_AGENT;
const listAgentStateSql = isSqlite ? SQLITE_LIST_BY_AGENT_AND_STATE : MSSQL_LIST_BY_AGENT_AND_STATE;
/**
* Lists printer jobs.
* If caller is an agent ({ agentId: number }), lists jobs for that agent.
* If caller is a user (googleAuthId: number), lists jobs for the selected company.
*
* @param {number|{agentId: number}} auth - User's googleAuthId or { agentId }.
* @param {object} [filters]
* @param {number} [filters.agentprinterId] - Filter by agentprinterId (company callers only).
* @param {string} [filters.state] - Filter by job state (e.g. "pending").
* @param {object} [tx] - Optional transaction.
* @returns {Promise<Array<object>>}
*/
return async (auth, filters = {}, tx) => {
const runner = makeRunner(provider, tx);
if (typeof auth === 'object' && auth !== null && auth.agentId != null) {
const aId = Number(auth.agentId);
if (!Number.isInteger(aId) || aId <= 0) return [];
const state = typeof filters.state === 'string' && filters.state.trim()
? filters.state.trim().toLowerCase()
: null;
let result;
if (state) {
result = await runner.query(listAgentStateSql, { agentId: aId, state });
} else {
result = await runner.query(listAgentSql, { agentId: aId });
}
return result.rows.map(shape);
}
const { companyId } = await access(auth, runner);
const apId = filters.agentprinterId != null ? Number(filters.agentprinterId) : null;
let result;
if (apId && Number.isInteger(apId) && apId > 0) {
result = await runner.query(listCompanyApSql, { companyId, agentprinterId: apId });
} else {
result = await runner.query(listCompanySql, { companyId });
}
let rows = result.rows.map(shape);
if (filters.state) {
const targetState = String(filters.state).trim().toLowerCase();
rows = rows.filter((r) => r.state === targetState);
}
return rows;
};
}

View File

@@ -0,0 +1,66 @@
import {
UPDATE_STATE_FOR_COMPANY as MSSQL_UPDATE_COMPANY,
UPDATE_STATE_FOR_AGENT as MSSQL_UPDATE_AGENT,
GET_BY_ID_FOR_COMPANY as MSSQL_GET_COMPANY,
GET_BY_ID_FOR_AGENT as MSSQL_GET_AGENT,
} from '../../providers/mssql/queries/printerjob.js';
import {
UPDATE_STATE_FOR_COMPANY as SQLITE_UPDATE_COMPANY,
UPDATE_STATE_FOR_AGENT as SQLITE_UPDATE_AGENT,
GET_BY_ID_FOR_COMPANY as SQLITE_GET_COMPANY,
GET_BY_ID_FOR_AGENT as SQLITE_GET_AGENT,
} from '../../providers/sqlite3/queries/printerjob.js';
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
import makeRunner from '../runner.js';
import { shape } from './_shared.js';
const VALID_STATES = new Set(['pending', 'processing', 'completed', 'cancelled', 'failed']);
export default function updateState(provider) {
const access = resolveSelectedCompanyAccess(provider);
const isSqlite = provider?.dialect === 'sqlite3';
const updateCompanySql = isSqlite ? SQLITE_UPDATE_COMPANY : MSSQL_UPDATE_COMPANY;
const updateAgentSql = isSqlite ? SQLITE_UPDATE_AGENT : MSSQL_UPDATE_AGENT;
const getCompanySql = isSqlite ? SQLITE_GET_COMPANY : MSSQL_GET_COMPANY;
const getAgentSql = isSqlite ? SQLITE_GET_AGENT : MSSQL_GET_AGENT;
/**
* Updates a printer job's state ("processing", "completed", "cancelled", etc.).
*
* @param {number|{agentId: number}} auth - User's googleAuthId or { agentId }.
* @param {number} id - Printer job ID.
* @param {string} state - New state.
* @param {object} [tx] - Optional transaction.
* @returns {Promise<object>} Updated printer job.
*/
return async (auth, id, state, tx) => {
const jId = Number(id);
if (!Number.isInteger(jId) || jId <= 0) {
throw new Error('Printerjob not found');
}
const normalizedState = typeof state === 'string' ? state.trim().toLowerCase() : '';
if (!VALID_STATES.has(normalizedState)) {
throw new Error(`Invalid printerjob state: ${state}`);
}
const runner = makeRunner(provider, tx);
if (typeof auth === 'object' && auth !== null && auth.agentId != null) {
const aId = Number(auth.agentId);
if (!Number.isInteger(aId) || aId <= 0) throw new Error('Not authorized');
await runner.query(updateAgentSql, { id: jId, agentId: aId, state: normalizedState });
const fetched = await runner.query(getAgentSql, { id: jId, agentId: aId });
if (fetched.rows.length === 0) throw new Error('Printerjob not found');
return shape(fetched.rows[0]);
}
const { companyId } = await access(auth, runner);
await runner.query(updateCompanySql, { id: jId, companyId, state: normalizedState });
const fetched = await runner.query(getCompanySql, { id: jId, companyId });
if (fetched.rows.length === 0) throw new Error('Printerjob not found');
return shape(fetched.rows[0]);
};
}