# Guía de Impresión para Epson TM-U220

Esta guía documenta las mejores prácticas para generar impresiones legibles en impresoras Epson TM-U220 usando el sistema printerCentral.

> **Nota:** Esta guía fue actualizada el 2025-11-26 basándose en pruebas reales con la impresora "Oficina Mami" (192.168.87.147).

## Especificaciones de la Impresora

| Característica | Font A | Font B |
|----------------|--------|--------|
| Columnas (normal) | 33 | 40 |
| Columnas (doble ancho) | 16 | 20 |
| Descripción | Normal | Condensada |

| Característica | Valor |
|----------------|-------|
| Ancho de papel | 57.5mm, 69.5mm, o 76mm |
| Tipo | Matricial de impacto |

## Caracteres por Línea (Resumen Rápido)

```
Font A normal (1x1):      33 caracteres
Font A doble ancho (2x1): 16 caracteres
Font B normal (1x1):      40 caracteres
Font B doble ancho (2x1): 20 caracteres
```

**Nota:** El doble alto (1x2) NO afecta la cantidad de caracteres horizontales.

## Caracteres Soportados

### ✅ FUNCIONAN (todos probados)

**ASCII Básico:**
```
= - , : . ; " ' [ ] { } ( ) / | \ * # @ $ % & ^ ~ ` _ + < >
A-Z a-z 0-9 espacio
```

**Box Drawing (para tablas):**
```
Líneas simples: ─ │ ┌ ┐ └ ┘
Líneas dobles:  ═ ║ ╔ ╗ ╚ ╝
```

**Bloques (para gráficos ASCII):**
```
Sólido:   █
Medios:   ▀ ▄
Sombras:  ░ ▒ ▓
```

**Símbolos:**
```
Círculos: ● ○ ◘
Flechas:  ► ◄ ▲ ▼
Cartas:   ♠ ♣ ♥ ♦
```

**Latino Extendido:**
```
Español:  ñ á é í ó ú ¿ ¡
Otros:    ° ±
```

### ❌ NO PROBADOS/EVITAR

```
Emojis: cualquiera
Caracteres asiáticos
Símbolos muy especiales: → ← ↑ ↓ ★
```

## Operaciones Soportadas

### Comandos que FUNCIONAN

| Operación | Parámetros | Ejemplo |
|-----------|------------|---------|
| `text` | `value` | `{ "op": "text", "value": "Hola" }` |
| `textAlign` | `align`: left, center, right | `{ "op": "textAlign", "align": "center" }` |
| `textFont` | `font`: font_a, font_b | `{ "op": "textFont", "font": "font_a" }` |
| `textSize` | `width`: 1-2, `height`: 1-2 | `{ "op": "textSize", "width": 2, "height": 1 }` |
| `textStyle` | `em`, `ul` (booleans) | `{ "op": "textStyle", "em": true, "ul": true }` |
| `textDouble` | `dw`, `dh` (booleans) | `{ "op": "textDouble", "dw": true }` |
| `textRotate` | `rotate`: true/false | `{ "op": "textRotate", "rotate": true }` |
| `textLineSpace` | `linespc`: número | `{ "op": "textLineSpace", "linespc": 50 }` |
| `feedLine` | `line`: número | `{ "op": "feedLine", "line": 2 }` |
| `feedUnit` | `unit`: número | `{ "op": "feedUnit", "unit": 50 }` |
| `feed` | (ninguno) | `{ "op": "feed" }` |
| `cut` | (ninguno, sin type) | `{ "op": "cut" }` |

### Comandos que NO FUNCIONAN

| Operación | Motivo |
|-----------|--------|
| `textPosition` | No soportado en TM-U220 |
| `textVPosition` | No soportado en TM-U220 |
| `textSmooth` | Sin efecto (es para térmicas) |
| `textLang` | Sin efecto |
| `textStyle.reverse` | No soportado |
| `textStyle.color` | Solo color_1 (negro) funciona |
| `textFont` font_c/d/e | No existen en TM-U220 |
| `textSize` > 2 | Se trata como 2 |
| `cut` con `type` | Genera SchemaError |
| `barcode` | No soportado (matricial) |
| `qrcode` | No soportado (matricial) |
| `imageRaw` | No soportado (matricial) |

## Estructura Recomendada de un Ticket

### Header (Centrado, Destacado)

```json
{ "op": "textAlign", "align": "center" },
{ "op": "textSize", "width": 2, "height": 2 },
{ "op": "textStyle", "em": true },
{ "op": "text", "value": "TITULO" },
{ "op": "textStyle", "em": false },
{ "op": "textSize", "width": 1, "height": 1 },
{ "op": "feedLine", "line": 2 }
```

**Importante:** Con doble ancho solo caben 16 caracteres en Font A.

### Separadores

Usar 33 caracteres `=` para Font A (o 40 para Font B):

```json
{ "op": "text", "value": "=================================" },
{ "op": "feedLine", "line": 1 }
```

### Títulos de Sección

```json
{ "op": "textStyle", "em": true, "ul": true },
{ "op": "text", "value": "NOMBRE SECCION" },
{ "op": "textStyle", "em": false, "ul": false },
{ "op": "feedLine", "line": 1 }
```

### Items de Lista

```json
{ "op": "text", "value": "[ ] Item uno" },
{ "op": "feedLine", "line": 1 },
{ "op": "text", "value": "[ ] Item dos" },
{ "op": "feedLine", "line": 1 }
```

### Footer y Corte

```json
{ "op": "textAlign", "align": "center" },
{ "op": "text", "value": "Texto de pie" },
{ "op": "feedLine", "line": 4 },
{ "op": "cut" }
```

## Ejemplo Completo

```json
{
  "operations": [
    { "op": "textAlign", "align": "center" },
    { "op": "textSize", "width": 2, "height": 2 },
    { "op": "textStyle", "em": true },
    { "op": "text", "value": "MI TITULO" },
    { "op": "textStyle", "em": false },
    { "op": "textSize", "width": 1, "height": 1 },
    { "op": "feedLine", "line": 2 },

    { "op": "text", "value": "=================================" },
    { "op": "feedLine", "line": 1 },
    { "op": "textStyle", "em": true },
    { "op": "text", "value": "SUBTITULO" },
    { "op": "textStyle", "em": false },
    { "op": "feedLine", "line": 1 },
    { "op": "text", "value": "=================================" },
    { "op": "feedLine", "line": 2 },

    { "op": "textAlign", "align": "left" },
    { "op": "textStyle", "em": true, "ul": true },
    { "op": "text", "value": "SECCION 1" },
    { "op": "textStyle", "em": false, "ul": false },
    { "op": "feedLine", "line": 1 },
    { "op": "text", "value": "[ ] Item A" },
    { "op": "feedLine", "line": 1 },
    { "op": "text", "value": "[ ] Item B" },
    { "op": "feedLine", "line": 2 },

    { "op": "textAlign", "align": "center" },
    { "op": "text", "value": "=================================" },
    { "op": "feedLine", "line": 1 },
    { "op": "text", "value": "Pie de pagina" },
    { "op": "feedLine", "line": 4 },
    { "op": "cut" }
  ]
}
```

## Ejemplo con Box Drawing (Tabla)

```json
{
  "operations": [
    { "op": "textFont", "font": "font_a" },
    { "op": "text", "value": "╔═══════════════╦═══════════════╗" },
    { "op": "feedLine", "line": 1 },
    { "op": "text", "value": "║ PRODUCTO      ║ PRECIO        ║" },
    { "op": "feedLine", "line": 1 },
    { "op": "text", "value": "╠═══════════════╬═══════════════╣" },
    { "op": "feedLine", "line": 1 },
    { "op": "text", "value": "║ Cafe          ║ $2.50         ║" },
    { "op": "feedLine", "line": 1 },
    { "op": "text", "value": "║ Pan           ║ $1.00         ║" },
    { "op": "feedLine", "line": 1 },
    { "op": "text", "value": "╚═══════════════╩═══════════════╝" },
    { "op": "feedLine", "line": 4 },
    { "op": "cut" }
  ]
}
```

## Endpoints de Impresión

### Imprimir Template Guardado

```
POST /api/print/template
{
  "templateId": "template_xxx",
  "variables": { "nombre": "Juan" },
  "printerId": "printer_xxx",  // opcional
  "dryRun": false              // true para preview
}
```

### Imprimir Operaciones Directas

```
POST /api/print/raw
{
  "operations": [...],
  "variables": { "var1": "valor1" },
  "printerId": "printer_xxx",  // opcional
  "dryRun": false
}
```

## Variables en Templates

Sintaxis: `{{nombre}}` o `{{nombre:label:default}}`

```json
{ "op": "text", "value": "Cliente: {{cliente}}" },
{ "op": "text", "value": "Fecha: {{fecha:Fecha:2025-01-01}}" }
```

## Errores Comunes

1. **Texto cortado**: Excediste 33 caracteres (Font A) o 40 (Font B)
2. **Todo pegado**: Falta `feedLine` entre elementos
3. **SchemaError en cut**: Usaste `cut` con parámetro `type` (no soportado)
4. **Header muy largo**: Con doble ancho solo caben 16 chars (Font A)
5. **Colores no funcionan**: Solo funciona color_1 (negro)
6. **Reverse no funciona**: No está soportado en TM-U220

## Checklist Pre-Impresión

- [ ] Ninguna línea excede 33 caracteres (16 si doble ancho) en Font A
- [ ] Ninguna línea excede 40 caracteres (20 si doble ancho) en Font B
- [ ] `feedLine` entre cada elemento para legibilidad
- [ ] `feedLine: 4` antes del `cut` final
- [ ] Header centrado con estilo bold
- [ ] Usando sintaxis correcta: `textAlign`, `textStyle`, `feedLine`
- [ ] `cut` sin parámetro `type`
- [ ] No usando: textPosition, textVPosition, textSmooth, textLang
