diff --git a/local_backend/main.py b/local_backend/main.py index 6cea8d3..97c04d0 100644 --- a/local_backend/main.py +++ b/local_backend/main.py @@ -406,6 +406,8 @@ def _run_migrations(): created_at DATETIME DEFAULT CURRENT_TIMESTAMP, priority VARCHAR NOT NULL DEFAULT 'normal' )""", + # Printer duplicate copies (0 = print once, 1 = print twice, etc.) + "ALTER TABLE printers ADD COLUMN duplicates INTEGER NOT NULL DEFAULT 0", ] for sql in migrations: try: diff --git a/local_backend/models/printer.py b/local_backend/models/printer.py index 6fcb3dc..b25ec6e 100644 --- a/local_backend/models/printer.py +++ b/local_backend/models/printer.py @@ -13,6 +13,7 @@ class Printer(Base): is_active = Column(Boolean, default=True, nullable=False) protocol = Column(String, default="escpos_tcp", nullable=False) line_width = Column(Integer, default=48, nullable=False) + duplicates = Column(Integer, default=0, nullable=False) products = relationship("Product", back_populates="printer_zone") print_logs = relationship("PrintLog", back_populates="printer") diff --git a/local_backend/schemas/printer.py b/local_backend/schemas/printer.py index b7f2135..4f064d0 100644 --- a/local_backend/schemas/printer.py +++ b/local_backend/schemas/printer.py @@ -12,6 +12,7 @@ class PrinterBase(BaseModel): is_active: bool = True protocol: str = "escpos_tcp" line_width: int = 48 + duplicates: int = 0 class PrinterCreate(PrinterBase): @@ -25,6 +26,7 @@ class PrinterUpdate(BaseModel): is_active: Optional[bool] = None protocol: Optional[str] = None line_width: Optional[int] = None + duplicates: Optional[int] = None class PrinterOut(PrinterBase): diff --git a/local_backend/services/printer_service.py b/local_backend/services/printer_service.py index cfbc5e8..44ca7f8 100644 --- a/local_backend/services/printer_service.py +++ b/local_backend/services/printer_service.py @@ -1256,10 +1256,12 @@ def _do_route_and_print(order_id: int, item_ids: List[int], db: Session) -> List success = False error_msg = None + copies = 1 + max(0, printer.duplicates or 0) try: - p = _get_printer(printer.ip_address, printer.port) - _print_kitchen_ticket(p, order, zone_items, db, printer.line_width) - p.close() + for _ in range(copies): + p = _get_printer(printer.ip_address, printer.port) + _print_kitchen_ticket(p, order, zone_items, db, printer.line_width) + p.close() success = True for item in zone_items: item.printed = True diff --git a/manager_dashboard/src/pages/Settings/tabs/PrintFontsTab.jsx b/manager_dashboard/src/pages/Settings/tabs/PrintFontsTab.jsx index 8865a12..a87ca6a 100644 --- a/manager_dashboard/src/pages/Settings/tabs/PrintFontsTab.jsx +++ b/manager_dashboard/src/pages/Settings/tabs/PrintFontsTab.jsx @@ -637,7 +637,7 @@ function BeepSection({ beepEnabled, beepPattern, onChange, isPending, printers } // ── Printers section ─────────────────────────────────────────────────────── const PROTOCOLS = [{ value: 'escpos_tcp', label: 'ESC/POS TCP (standard)' }] -const EMPTY_FORM = { name: '', ip_address: '', port: 9100, protocol: 'escpos_tcp', line_width: 48, is_active: true } +const EMPTY_FORM = { name: '', ip_address: '', port: 9100, protocol: 'escpos_tcp', line_width: 48, is_active: true, duplicates: 0 } function PrinterForm({ initial, onSave, onCancel, isPending }) { const [form, setForm] = useState(initial ?? EMPTY_FORM) @@ -674,6 +674,11 @@ function PrinterForm({ initial, onSave, onCancel, isPending }) { set('line_width', parseInt(e.target.value) || 48)} type="number" min={20} max={80} style={inputStyle} /> +