task_receipts/server/src/printer/serial-printer.ts

131 lines
3.5 KiB
TypeScript
Raw Normal View History

2025-06-14 22:27:33 +00:00
import { Printer } from "@node-escpos/core";
import USB from "@node-escpos/usb-adapter";
import { Task, Step, Printer as PrinterInterface } from '@shared/index';
import { steps } from '../db';
import { Knex } from 'knex';
import logger from '../logger';
export class SerialPrinter implements PrinterInterface {
private device: USB | null = null;
private printer: Printer<[]> | null = null;
constructor() {
this.initializePrinter();
}
private async initializePrinter() {
try {
this.device = new USB();
await new Promise<void>((resolve, reject) => {
this.device?.open((err) => {
if (err) {
logger.error('Failed to open printer:', err);
reject(err);
return;
}
resolve();
});
});
const options = { encoding: "CP437" };
this.printer = new Printer(this.device, options);
logger.info('Printer initialized successfully');
} catch (error) {
logger.error('Failed to initialize printer:', error);
}
}
async getTaskSteps(db: Knex, task: Task): Promise<Step[]> {
return await steps(db).where('task_id', task.id).orderBy('order').select('*');
}
async printTask(task: Task, db: Knex): Promise<void> {
if (!this.printer || !this.device) {
throw new Error('Printer not initialized');
}
const taskSteps = await this.getTaskSteps(db, task);
try {
// Print header with task ID as barcode
await this.printer
.font('a')
.align('ct')
.style('b')
.size(1, 1) // Normal size (0.08 x 2.13 mm)
.text(`Task: ${task.name}`)
.text('='.repeat(32))
.text('')
.align('lt');
// Print task ID as barcode
await this.printer
.barcode(task.id.toString(), 'CODE128', { width: 2, height: 50 })
.text('')
.text('');
// Print steps
for (let i = 0; i < taskSteps.length; i++) {
const step = taskSteps[i];
await this.printer
.size(1, 1) // Normal size for step header
.text(`Step ${i + 1}: ${step.name}`)
.text('-'.repeat(32))
.size(0, 0) // Smaller size for instructions (0.08 x 2.13 mm)
.text(step.instructions)
.text('');
// Print step ID as barcode
await this.printer
.barcode(step.id.toString(), 'CODE128', { width: 2, height: 50 })
.text('');
}
await this.printer
.text('')
.text('')
.cut()
.close();
logger.info(`Printed task ${task.id}`);
} catch (error) {
logger.error('Failed to print task:', error);
throw error;
}
}
async printStep(step: Step, db: Knex): Promise<void> {
if (!this.printer || !this.device) {
throw new Error('Printer not initialized');
}
try {
await this.printer
.font('a')
.align('ct')
.style('b')
.size(1, 1) // Normal size (0.08 x 2.13 mm)
.text(`Step: ${step.name}`)
.text('='.repeat(32))
.text('')
.align('lt')
.size(0, 0) // Smaller size for instructions
.text(step.instructions)
.text('')
.text('');
// Print step ID as barcode
await this.printer
.barcode(step.id.toString(), 'CODE128', { width: 2, height: 50 })
.text('')
.text('')
.cut()
.close();
logger.info(`Printed step ${step.id}`);
} catch (error) {
logger.error('Failed to print step:', error);
throw error;
}
}
}