feat: add cassette position for physical cartridge ordering
Add position column to cassettes table (migration v5→v6) so cassettes are ordered by physical cartridge number instead of denomination. Update BATM3 preset to $20/$1 denominations with 400-bill capacity. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5fa2dcb992
commit
ec60d3f201
3 changed files with 36 additions and 13 deletions
|
|
@ -516,8 +516,8 @@ app.whenReady().then(() => {
|
||||||
],
|
],
|
||||||
gaia: [{ denomination: 20, count: 50 }],
|
gaia: [{ denomination: 20, count: 50 }],
|
||||||
batm3: [
|
batm3: [
|
||||||
{ denomination: 20, count: 500 },
|
{ denomination: 20, count: 400 },
|
||||||
{ denomination: 50, count: 500 },
|
{ denomination: 1, count: 400 },
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
seedCassettes = presets[model] || []
|
seedCassettes = presets[model] || []
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import fs from 'node:fs'
|
||||||
|
|
||||||
let db: Database.Database | null = null
|
let db: Database.Database | null = null
|
||||||
|
|
||||||
const SCHEMA_VERSION = '5'
|
const SCHEMA_VERSION = '6'
|
||||||
|
|
||||||
function getDbPath(): string {
|
function getDbPath(): string {
|
||||||
const prodDir = '/var/lib/lamassu-atm'
|
const prodDir = '/var/lib/lamassu-atm'
|
||||||
|
|
@ -53,7 +53,8 @@ export function initDatabase(dbPath?: string): void {
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS cassettes (
|
CREATE TABLE IF NOT EXISTS cassettes (
|
||||||
denomination INTEGER PRIMARY KEY,
|
denomination INTEGER PRIMARY KEY,
|
||||||
count INTEGER NOT NULL DEFAULT 0
|
count INTEGER NOT NULL DEFAULT 0,
|
||||||
|
position INTEGER NOT NULL DEFAULT 0
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS cashbox (
|
CREATE TABLE IF NOT EXISTS cashbox (
|
||||||
|
|
@ -198,6 +199,22 @@ export function initDatabase(dbPath?: string): void {
|
||||||
console.log(
|
console.log(
|
||||||
'[StateStore] Migrated schema v4 → v5 (added manual_dispense type, remediated_by, operator_commands)'
|
'[StateStore] Migrated schema v4 → v5 (added manual_dispense type, remediated_by, operator_commands)'
|
||||||
)
|
)
|
||||||
|
existing.value = '5'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing && existing.value === '5') {
|
||||||
|
// Migration v5 → v6: add position column to cassettes for physical cartridge ordering
|
||||||
|
db.exec(`ALTER TABLE cassettes ADD COLUMN position INTEGER NOT NULL DEFAULT 0`)
|
||||||
|
// Backfill position from existing row order (by denomination)
|
||||||
|
const rows = db.prepare('SELECT denomination FROM cassettes ORDER BY denomination').all() as {
|
||||||
|
denomination: number
|
||||||
|
}[]
|
||||||
|
const update = db.prepare('UPDATE cassettes SET position = ? WHERE denomination = ?')
|
||||||
|
for (let i = 0; i < rows.length; i++) {
|
||||||
|
update.run(i + 1, rows[i]!.denomination)
|
||||||
|
}
|
||||||
|
db.prepare('UPDATE meta SET value = ? WHERE key = ?').run('6', 'schema_version')
|
||||||
|
console.log('[StateStore] Migrated schema v5 → v6 (added cassette position)')
|
||||||
}
|
}
|
||||||
|
|
||||||
const cashboxRow = db.prepare('SELECT id FROM cashbox WHERE id = 1').get()
|
const cashboxRow = db.prepare('SELECT id FROM cashbox WHERE id = 1').get()
|
||||||
|
|
@ -215,30 +232,36 @@ export function initDatabase(dbPath?: string): void {
|
||||||
export interface CassetteRow {
|
export interface CassetteRow {
|
||||||
denomination: number
|
denomination: number
|
||||||
count: number
|
count: number
|
||||||
|
position: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadCassettes(): CassetteRow[] {
|
export function loadCassettes(): CassetteRow[] {
|
||||||
if (!db) throw new Error('Database not initialized')
|
if (!db) throw new Error('Database not initialized')
|
||||||
return db
|
return db
|
||||||
.prepare('SELECT denomination, count FROM cassettes ORDER BY denomination')
|
.prepare('SELECT denomination, count, position FROM cassettes ORDER BY position, denomination')
|
||||||
.all() as CassetteRow[]
|
.all() as CassetteRow[]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upsert cassette counts. Replaces all existing rows.
|
* Upsert cassette counts. Replaces all existing rows.
|
||||||
*/
|
*/
|
||||||
export function setCassettes(cassettes: CassetteRow[]): void {
|
export function setCassettes(
|
||||||
|
cassettes: { denomination: number; count: number; position?: number }[]
|
||||||
|
): void {
|
||||||
if (!db) throw new Error('Database not initialized')
|
if (!db) throw new Error('Database not initialized')
|
||||||
|
|
||||||
const upsert = db.prepare(
|
const upsert = db.prepare(
|
||||||
'INSERT INTO cassettes (denomination, count) VALUES (?, ?) ON CONFLICT(denomination) DO UPDATE SET count = excluded.count'
|
'INSERT INTO cassettes (denomination, count, position) VALUES (?, ?, ?) ON CONFLICT(denomination) DO UPDATE SET count = excluded.count, position = excluded.position'
|
||||||
)
|
)
|
||||||
|
|
||||||
const run = db.transaction((rows: CassetteRow[]) => {
|
const run = db.transaction(
|
||||||
for (const row of rows) {
|
(rows: { denomination: number; count: number; position?: number }[]) => {
|
||||||
upsert.run(row.denomination, row.count)
|
for (let i = 0; i < rows.length; i++) {
|
||||||
|
const row = rows[i]!
|
||||||
|
upsert.run(row.denomination, row.count, row.position ?? i + 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
|
|
||||||
run(cassettes)
|
run(cassettes)
|
||||||
console.log('[StateStore] Cassettes updated:', cassettes)
|
console.log('[StateStore] Cassettes updated:', cassettes)
|
||||||
|
|
|
||||||
|
|
@ -145,8 +145,8 @@ export const MACHINE_PRESETS: Record<MachineModel, Omit<DeviceConfig, 'fiatCode'
|
||||||
type: 'f56',
|
type: 'f56',
|
||||||
device: '/dev/ttyUSB0',
|
device: '/dev/ttyUSB0',
|
||||||
cassettes: [
|
cassettes: [
|
||||||
{ denomination: 20, count: 500 },
|
{ denomination: 20, count: 400 },
|
||||||
{ denomination: 50, count: 500 },
|
{ denomination: 1, count: 400 },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue