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 }],
|
||||
batm3: [
|
||||
{ denomination: 20, count: 500 },
|
||||
{ denomination: 50, count: 500 },
|
||||
{ denomination: 20, count: 400 },
|
||||
{ denomination: 1, count: 400 },
|
||||
],
|
||||
}
|
||||
seedCassettes = presets[model] || []
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import fs from 'node:fs'
|
|||
|
||||
let db: Database.Database | null = null
|
||||
|
||||
const SCHEMA_VERSION = '5'
|
||||
const SCHEMA_VERSION = '6'
|
||||
|
||||
function getDbPath(): string {
|
||||
const prodDir = '/var/lib/lamassu-atm'
|
||||
|
|
@ -53,7 +53,8 @@ export function initDatabase(dbPath?: string): void {
|
|||
|
||||
CREATE TABLE IF NOT EXISTS cassettes (
|
||||
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 (
|
||||
|
|
@ -198,6 +199,22 @@ export function initDatabase(dbPath?: string): void {
|
|||
console.log(
|
||||
'[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()
|
||||
|
|
@ -215,30 +232,36 @@ export function initDatabase(dbPath?: string): void {
|
|||
export interface CassetteRow {
|
||||
denomination: number
|
||||
count: number
|
||||
position: number
|
||||
}
|
||||
|
||||
export function loadCassettes(): CassetteRow[] {
|
||||
if (!db) throw new Error('Database not initialized')
|
||||
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[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 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')
|
||||
|
||||
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[]) => {
|
||||
for (const row of rows) {
|
||||
upsert.run(row.denomination, row.count)
|
||||
const run = db.transaction(
|
||||
(rows: { denomination: number; count: number; position?: number }[]) => {
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const row = rows[i]!
|
||||
upsert.run(row.denomination, row.count, row.position ?? i + 1)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
run(cassettes)
|
||||
console.log('[StateStore] Cassettes updated:', cassettes)
|
||||
|
|
|
|||
|
|
@ -145,8 +145,8 @@ export const MACHINE_PRESETS: Record<MachineModel, Omit<DeviceConfig, 'fiatCode'
|
|||
type: 'f56',
|
||||
device: '/dev/ttyUSB0',
|
||||
cassettes: [
|
||||
{ denomination: 20, count: 500 },
|
||||
{ denomination: 50, count: 500 },
|
||||
{ denomination: 20, count: 400 },
|
||||
{ denomination: 1, count: 400 },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue