feat: Campo model en impresoras y guías de formato MCP
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 36s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 36s
- Agregar campo model a interface Printer - Nuevas tools: get_printing_guide, list_models - Guías de formato para TM-U220 (matricial) y TM-T88 (térmica) - list_printers ahora incluye el modelo
This commit is contained in:
@@ -7,6 +7,106 @@ import { getAllPrinters, getSelectedPrinter, getPrinterById } from './printers'
|
||||
import { buildFromOperations } from './eposBuilder'
|
||||
import { buildSoapEnvelope, sendToPrinter, parsePrinterResponse } from './printer'
|
||||
|
||||
// Guías de impresión por modelo
|
||||
export const PRINTING_GUIDES: Record<string, {
|
||||
model: string
|
||||
type: string
|
||||
columns: number
|
||||
columnsDoubleWidth: number
|
||||
supportedChars: string
|
||||
rules: string[]
|
||||
operations: string[]
|
||||
example: string
|
||||
}> = {
|
||||
'TM-U220': {
|
||||
model: 'Epson TM-U220',
|
||||
type: 'Matricial (impact)',
|
||||
columns: 40,
|
||||
columnsDoubleWidth: 20,
|
||||
supportedChars: 'ASCII básico (A-Z, a-z, 0-9, símbolos comunes). Evitar Unicode especial.',
|
||||
rules: [
|
||||
'Máximo 40 caracteres por línea (20 con width:2)',
|
||||
'Usar solo caracteres ASCII básicos',
|
||||
'Evitar caracteres Unicode: ╔═║╚╝ y similares',
|
||||
'Usar = - _ * para separadores',
|
||||
'Siempre usar feed entre elementos para legibilidad',
|
||||
'feed:1 entre items, feed:2 entre secciones',
|
||||
'feed:4 antes del cut final',
|
||||
'Los headers con width:2 deben ser cortos (max 20 chars)'
|
||||
],
|
||||
operations: [
|
||||
'{ op: "text", value: "texto" } - Imprime texto',
|
||||
'{ op: "feed", lines: N } - Avanza N líneas',
|
||||
'{ op: "cut" } - Corta el papel',
|
||||
'{ op: "align", align: "left|center|right" } - Alineación',
|
||||
'{ op: "style", bold: true, underline: true, width: 1-2, height: 1-2 } - Estilos'
|
||||
],
|
||||
example: `[
|
||||
{ "op": "align", "align": "center" },
|
||||
{ "op": "style", "bold": true, "width": 2, "height": 2 },
|
||||
{ "op": "text", "value": "TITULO" },
|
||||
{ "op": "style", "bold": false, "width": 1, "height": 1 },
|
||||
{ "op": "feed", "lines": 2 },
|
||||
{ "op": "text", "value": "================================" },
|
||||
{ "op": "feed", "lines": 1 },
|
||||
{ "op": "align", "align": "left" },
|
||||
{ "op": "text", "value": "Contenido aquí" },
|
||||
{ "op": "feed", "lines": 4 },
|
||||
{ "op": "cut" }
|
||||
]`
|
||||
},
|
||||
'TM-T88': {
|
||||
model: 'Epson TM-T88 (series)',
|
||||
type: 'Térmica',
|
||||
columns: 48,
|
||||
columnsDoubleWidth: 24,
|
||||
supportedChars: 'ASCII extendido, algunos caracteres Unicode soportados',
|
||||
rules: [
|
||||
'Máximo 48 caracteres por línea (24 con width:2)',
|
||||
'Soporta más caracteres que matriciales',
|
||||
'Impresión más rápida y silenciosa',
|
||||
'Usar feed para espaciado',
|
||||
'Soporta imágenes y códigos QR'
|
||||
],
|
||||
operations: [
|
||||
'{ op: "text", value: "texto" } - Imprime texto',
|
||||
'{ op: "feed", lines: N } - Avanza N líneas',
|
||||
'{ op: "cut" } - Corta el papel',
|
||||
'{ op: "align", align: "left|center|right" } - Alineación',
|
||||
'{ op: "style", bold: true, underline: true, width: 1-2, height: 1-2 } - Estilos',
|
||||
'{ op: "qrcode", data: "texto", size: 4 } - Código QR',
|
||||
'{ op: "barcode", data: "123456", type: "ean13" } - Código de barras'
|
||||
],
|
||||
example: `[
|
||||
{ "op": "align", "align": "center" },
|
||||
{ "op": "style", "bold": true, "width": 2, "height": 2 },
|
||||
{ "op": "text", "value": "RECIBO" },
|
||||
{ "op": "style", "bold": false, "width": 1, "height": 1 },
|
||||
{ "op": "feed", "lines": 1 },
|
||||
{ "op": "qrcode", "data": "https://example.com", "size": 4 },
|
||||
{ "op": "feed", "lines": 2 },
|
||||
{ "op": "cut" }
|
||||
]`
|
||||
}
|
||||
}
|
||||
|
||||
// Obtener guía por modelo (búsqueda flexible)
|
||||
export function getPrintingGuide(model: string): typeof PRINTING_GUIDES[string] | null {
|
||||
// Búsqueda exacta
|
||||
if (PRINTING_GUIDES[model]) return PRINTING_GUIDES[model]
|
||||
|
||||
// Búsqueda parcial (case-insensitive)
|
||||
const modelLower = model.toLowerCase()
|
||||
for (const [key, guide] of Object.entries(PRINTING_GUIDES)) {
|
||||
if (key.toLowerCase().includes(modelLower) || modelLower.includes(key.toLowerCase())) {
|
||||
return guide
|
||||
}
|
||||
}
|
||||
|
||||
// Default a TM-U220 si no se encuentra
|
||||
return PRINTING_GUIDES['TM-U220']
|
||||
}
|
||||
|
||||
// Definición de las tools MCP
|
||||
export const MCP_TOOLS = [
|
||||
{
|
||||
@@ -147,6 +247,29 @@ REGLAS IMPORTANTES:
|
||||
},
|
||||
required: ['templateId']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'printercentral_get_printing_guide',
|
||||
description: 'Obtiene la guía de formato para un modelo de impresora específico. Incluye límites de caracteres, reglas de formato, operaciones disponibles y ejemplos.',
|
||||
inputSchema: {
|
||||
type: 'object' as const,
|
||||
properties: {
|
||||
model: {
|
||||
type: 'string',
|
||||
description: 'Modelo de impresora (ej: "TM-U220", "TM-T88"). Si no se especifica, retorna todas las guías disponibles.'
|
||||
}
|
||||
},
|
||||
required: [] as string[]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'printercentral_list_models',
|
||||
description: 'Lista todos los modelos de impresora soportados con sus características básicas.',
|
||||
inputSchema: {
|
||||
type: 'object' as const,
|
||||
properties: {},
|
||||
required: [] as string[]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -179,6 +302,7 @@ export async function handleToolCall(toolName: string, args: Record<string, any>
|
||||
name: p.name,
|
||||
host: p.host,
|
||||
deviceId: p.deviceId,
|
||||
model: p.model || 'No especificado',
|
||||
isDefault: p.isDefault,
|
||||
isSelected: selected?.id === p.id
|
||||
}))
|
||||
@@ -403,6 +527,44 @@ export async function handleToolCall(toolName: string, args: Record<string, any>
|
||||
}
|
||||
}
|
||||
|
||||
case 'printercentral_get_printing_guide': {
|
||||
const { model } = args
|
||||
|
||||
if (model) {
|
||||
const guide = getPrintingGuide(model)
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify(guide, null, 2)
|
||||
}]
|
||||
}
|
||||
} else {
|
||||
// Retornar todas las guías
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify(PRINTING_GUIDES, null, 2)
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case 'printercentral_list_models': {
|
||||
const models = Object.entries(PRINTING_GUIDES).map(([key, guide]) => ({
|
||||
id: key,
|
||||
model: guide.model,
|
||||
type: guide.type,
|
||||
columns: guide.columns,
|
||||
columnsDoubleWidth: guide.columnsDoubleWidth
|
||||
}))
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify(models, null, 2)
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return {
|
||||
content: [{
|
||||
|
||||
Reference in New Issue
Block a user