diff --git a/src/index.js b/src/index.js index 4b6aff2..50bd256 100644 --- a/src/index.js +++ b/src/index.js @@ -97,6 +97,8 @@ import posterminalSetOff from './store/posterminal/setOff.js'; import posterminalSetOnAll from './store/posterminal/setOnAll.js'; import posterminalSetOffAll from './store/posterminal/setOffAll.js'; import posterminalGetCategoryPosterminalIds from './store/posterminal/getCategoryPosterminalIds.js'; +import posterminalFindByPairingpin from './store/posterminal/findByPairingpin.js'; +import posterminalPair from './store/posterminal/pair.js'; import langCreate from './store/lang/create.js'; import langDelete from './store/lang/delete.js'; import langList from './store/lang/list.js'; @@ -328,6 +330,8 @@ export default class LibDashStore { setOnAll: posterminalSetOnAll(provider), setOffAll: posterminalSetOffAll(provider), getCategoryPosterminalIds: posterminalGetCategoryPosterminalIds(provider), + findByPairingpin: posterminalFindByPairingpin(provider), + pair: posterminalPair(provider), }; this.google_auth = { diff --git a/src/providers/mssql/index.js b/src/providers/mssql/index.js index 8c3d1ff..3722cde 100644 --- a/src/providers/mssql/index.js +++ b/src/providers/mssql/index.js @@ -167,6 +167,16 @@ export class MssqlProvider { ALTER TABLE ledger ADD warehouse_id INT NULL; ALTER TABLE ledger ADD CONSTRAINT FK_ledger_warehouse FOREIGN KEY (warehouse_id) REFERENCES warehouse(id) ON DELETE NO ACTION; END + + IF OBJECT_ID(N'dbo.posterminal', N'U') IS NOT NULL AND COL_LENGTH('posterminal', 'paired_at') IS NULL + BEGIN + ALTER TABLE posterminal ADD paired_at DATETIME2 NULL; + END + + IF OBJECT_ID(N'dbo.posterminal', N'U') IS NOT NULL AND COL_LENGTH('posterminal', 'clientserial') IS NULL + BEGIN + ALTER TABLE posterminal ADD clientserial NVARCHAR(255) NULL; + END `); } catch { // ignore diff --git a/src/providers/mssql/queries/posterminal.js b/src/providers/mssql/queries/posterminal.js index 3432900..49ae4b1 100644 --- a/src/providers/mssql/queries/posterminal.js +++ b/src/providers/mssql/queries/posterminal.js @@ -3,7 +3,9 @@ SELECT id, name, token, - pairingpin + pairingpin, + paired_at AS pairedAt, + clientserial AS clientserial FROM posterminal WHERE company_id = @companyId ORDER BY id @@ -15,20 +17,41 @@ SELECT company_id AS companyId, name, token, - pairingpin + pairingpin, + paired_at AS pairedAt, + clientserial AS clientserial FROM posterminal WHERE id = @id `; +export const FIND_BY_PAIRINGPIN = ` +SELECT + id, + company_id AS companyId, + name, + token, + pairingpin, + paired_at AS pairedAt, + clientserial AS clientserial +FROM posterminal +WHERE pairingpin = @pairingpin +`; + +export const PAIR = ` +UPDATE posterminal +SET token = @token, paired_at = @pairedAt, clientserial = @clientserial, pairingpin = '' +WHERE id = @id +`; + export const CREATE = ` -INSERT INTO posterminal (company_id, name, token, pairingpin) -OUTPUT INSERTED.id, INSERTED.name, INSERTED.token, INSERTED.pairingpin -VALUES (@companyId, @name, @token, @pairingpin) +INSERT INTO posterminal (company_id, name, token, pairingpin, paired_at, clientserial) +OUTPUT INSERTED.id, INSERTED.name, INSERTED.token, INSERTED.pairingpin, INSERTED.paired_at AS pairedAt, INSERTED.clientserial AS clientserial +VALUES (@companyId, @name, @token, @pairingpin, @pairedAt, @clientserial) `; export const UPDATE = ` UPDATE posterminal -SET name = @name, token = @token, pairingpin = @pairingpin +SET name = @name, token = @token, pairingpin = @pairingpin, paired_at = @pairedAt, clientserial = @clientserial WHERE id = @id AND company_id = @companyId `; diff --git a/src/providers/mssql/schema.js b/src/providers/mssql/schema.js index 34b6c6c..82a9c54 100644 --- a/src/providers/mssql/schema.js +++ b/src/providers/mssql/schema.js @@ -777,6 +777,8 @@ BEGIN name NVARCHAR(255) NOT NULL, token NVARCHAR(255) NULL, pairingpin NVARCHAR(50) NOT NULL, + paired_at DATETIME2 NULL, + clientserial NVARCHAR(255) NULL, CONSTRAINT FK_posterminal_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE ); CREATE UNIQUE INDEX UQ_posterminal_token ON posterminal(token) WHERE token IS NOT NULL; diff --git a/src/providers/sqlite3/index.js b/src/providers/sqlite3/index.js index 9921ee0..fa922c4 100644 --- a/src/providers/sqlite3/index.js +++ b/src/providers/sqlite3/index.js @@ -413,6 +413,14 @@ export class BetterSqlite3Provider extends BetterSqlite3Executor { `ALTER TABLE warehouse ADD COLUMN sort INTEGER NOT NULL DEFAULT 0`, ); } + + const posterminalCols = this.db.pragma('table_info("posterminal")').map((c) => c.name); + if (posterminalCols.length > 0 && !posterminalCols.includes('paired_at')) { + this.db.exec(`ALTER TABLE posterminal ADD COLUMN paired_at TEXT`); + } + if (posterminalCols.length > 0 && !posterminalCols.includes('clientserial')) { + this.db.exec(`ALTER TABLE posterminal ADD COLUMN clientserial TEXT`); + } } catch { // ignore } diff --git a/src/providers/sqlite3/queries/posterminal.js b/src/providers/sqlite3/queries/posterminal.js index f33a636..5e1faf0 100644 --- a/src/providers/sqlite3/queries/posterminal.js +++ b/src/providers/sqlite3/queries/posterminal.js @@ -5,6 +5,7 @@ const queries = translateQueries(source, 'posterminal'); export const { CREATE, DELETE_BY_COMPANY_AND_ID, GET_BY_ID, LIST_BY_COMPANY, LIST_CATEGORY_IDS, POSTERMINAL_IDS_BY_COMPANY, SET_OFF, SET_OFF_ALL, UPDATE, + FIND_BY_PAIRINGPIN, PAIR, } = queries; export const SET_ON = ` diff --git a/src/providers/sqlite3/schema.js b/src/providers/sqlite3/schema.js index aefc7e4..08807cf 100644 --- a/src/providers/sqlite3/schema.js +++ b/src/providers/sqlite3/schema.js @@ -533,6 +533,8 @@ CREATE TABLE IF NOT EXISTS posterminal ( name TEXT NOT NULL, token TEXT, pairingpin TEXT NOT NULL, + paired_at TEXT, + clientserial TEXT, FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE ); CREATE UNIQUE INDEX IF NOT EXISTS UQ_posterminal_token diff --git a/src/store/posterminal/findByPairingpin.js b/src/store/posterminal/findByPairingpin.js new file mode 100644 index 0000000..5cb62c6 --- /dev/null +++ b/src/store/posterminal/findByPairingpin.js @@ -0,0 +1,22 @@ +import { FIND_BY_PAIRINGPIN as MSSQL_FIND } from '../../providers/mssql/queries/posterminal.js'; +import { FIND_BY_PAIRINGPIN as SQLITE_FIND } from '../../providers/sqlite3/queries/posterminal.js'; +import makeRunner from '../runner.js'; + +export default function findByPairingpin(provider) { + const sql = provider?.dialect === 'sqlite3' ? SQLITE_FIND : MSSQL_FIND; + + /** + * Finds a posterminal by its pairingpin. + * + * @param {string} pairingpin - The pairing pin to search for. + * @param {object} [tx] - Optional transaction to run within. + * @returns {Promise} The posterminal row, or null if not found. + */ + return async (pairingpin, tx) => { + if (!pairingpin) return null; + const result = await makeRunner(provider, tx).query(sql, { + pairingpin: String(pairingpin).trim(), + }); + return result.rows[0] || null; + }; +} diff --git a/src/store/posterminal/pair.js b/src/store/posterminal/pair.js new file mode 100644 index 0000000..bdcc3a4 --- /dev/null +++ b/src/store/posterminal/pair.js @@ -0,0 +1,34 @@ +import { PAIR as MSSQL_PAIR } from '../../providers/mssql/queries/posterminal.js'; +import { PAIR as SQLITE_PAIR } from '../../providers/sqlite3/queries/posterminal.js'; +import makeRunner from '../runner.js'; + +export default function pair(provider) { + const sql = provider?.dialect === 'sqlite3' ? SQLITE_PAIR : MSSQL_PAIR; + + /** + * Completes POS device pairing for a terminal. + * + * @param {number} id - The posterminal id. + * @param {object} input + * @param {string} input.token - The auth token for the paired device. + * @param {string} [input.clientserial] - The client name or serial identifier. + * @param {string} [input.pairedAt] - Timestamp when paired. + * @param {object} [tx] - Optional transaction to run within. + * @returns {Promise<{id: number, token: string, clientserial: string|null, pairedAt: string|null}>} + */ + return async (id, { token, clientserial, pairedAt }, tx) => { + await makeRunner(provider, tx).query(sql, { + id, + token, + clientserial: clientserial ?? null, + pairedAt: pairedAt ?? null, + }); + + return { + id, + token, + clientserial: clientserial ?? null, + pairedAt: pairedAt ?? null, + }; + }; +} diff --git a/src/store/posterminal/upsert.js b/src/store/posterminal/upsert.js index f945d3e..cc11c6f 100644 --- a/src/store/posterminal/upsert.js +++ b/src/store/posterminal/upsert.js @@ -47,6 +47,8 @@ export default function upsert(provider) { } const token = input.token ?? null; const id = input.id ?? null; + const pairedAt = input.pairedAt ?? null; + const clientserial = input.clientserial ?? null; const runner = makeRunner(provider, tx); const { companyId } = await access(googleAuthId, tx); @@ -64,9 +66,11 @@ export default function upsert(provider) { name, token, pairingpin, + pairedAt, + clientserial, }); - return { id, name, token, pairingpin }; + return { id, name, token, pairingpin, pairedAt, clientserial }; } const created = await runner.query(createSql, { @@ -74,6 +78,8 @@ export default function upsert(provider) { name, token, pairingpin, + pairedAt, + clientserial, }); const row = created.rows[0] ?? { @@ -81,6 +87,8 @@ export default function upsert(provider) { name, token, pairingpin, + pairedAt, + clientserial, }; return { @@ -88,6 +96,8 @@ export default function upsert(provider) { name: row.name, token: row.token, pairingpin: row.pairingpin, + pairedAt: row.pairedAt ?? null, + clientserial: row.clientserial ?? null, }; }; }