text($leftPadded . $rightText . "\n"); } function printSeparatorLine($printer, $char = "-", $width = 48) { $printer->text(str_repeat($char, $width) . "\n"); } function printThreeColumns($printer, $left, $center, $right, $width = 48) { $colWidth = intval($width / 3); $leftPadded = str_pad($left, $colWidth, " ", STR_PAD_RIGHT); $centerPadded = str_pad($center, $colWidth, " ", STR_PAD_BOTH); $rightPadded = str_pad($right, $colWidth, " ", STR_PAD_LEFT); $printer->text($leftPadded . $centerPadded . $rightPadded . "\n"); } // Get data from POST request $dataPrint = null; if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST["dataPrint"])) { $dataPrint = json_decode($_POST["dataPrint"]); } if ($dataPrint) { // Extract printer name $PRINTER_NAME = $dataPrint->printer ?? 'POS-80C'; // Constants for formatting $maxDescripcion = 23; // Maximum characters per line for product description try { $connector = new WindowsPrintConnector($PRINTER_NAME); $printer = new Printer($connector); // COMPANY HEADER $printer->setJustification(Printer::JUSTIFY_CENTER); $printer->setTextSize(2, 2); $printer->text(cutString(strtoupper($dataPrint->nombre_empresa), 24) . "\n"); $printer->setTextSize(1, 1); $printer->text(cutString(strtoupper($dataPrint->giro_empresa), 48) . "\n"); $printer->text(cutString(strtoupper($dataPrint->direcion_empresa), 48) . "\n"); $printer->text(cutString(strtoupper($dataPrint->rsocial_empresa), 48) . "\n"); $printer->text("NRC: " . $dataPrint->nrc_empresa . " - NIT: " . $dataPrint->nit_empresa . "\n"); printSeparatorLine($printer); // DATE, CASHIER AND TICKET INFO $printer->setJustification(Printer::JUSTIFY_LEFT); printAlignedText($printer, "Fecha: " . $dataPrint->fecha, "Caja: " . $dataPrint->caja); printAlignedText($printer, "Vendedor: " . $dataPrint->vendedor, "Cajero: " . $dataPrint->cajero); $printer->text("Serie: " . $dataPrint->doc_serie . " Del " . $dataPrint->doc_desde . " Al " . $dataPrint->doc_hasta . "\n"); $printer->text("No Resolucion: " . $dataPrint->doc_resolucion . "\n"); $printer->setJustification(Printer::JUSTIFY_CENTER); $printer->setEmphasis(true); $printer->text("Ticket: " . $dataPrint->doc_numero . "\n"); $printer->setEmphasis(false); printSeparatorLine($printer); // PRODUCT TABLE HEADER $printer->setJustification(Printer::JUSTIFY_LEFT); $printer->setEmphasis(true); $printer->text("CANT DESCRIPCION PRECIO TOTAL\n"); printSeparatorLine($printer); $printer->setEmphasis(false); // PRODUCTS foreach ($dataPrint->productos_normal as $producto) { $cantidad = str_pad(number_format($producto->cant, 2), 5, " ", STR_PAD_RIGHT); $precio = str_pad(number_format($producto->costo, 2), 7, " ", STR_PAD_LEFT); $total = str_pad(number_format($producto->costo * $producto->cant, 2), 7, " ", STR_PAD_LEFT); // Handle product description with word wrapping $descripcion_completa = ($producto->ref ? $producto->ref . ' - ' : '') . $producto->desc; $descripcion = wordwrap(strtoupper($descripcion_completa), $maxDescripcion, "\n", true); $lineasDescripcion = explode("\n", $descripcion); // Print first line with all data $printer->text("$cantidad " . str_pad($lineasDescripcion[0], $maxDescripcion, " ") . " $precio $total"); // Add tax type indicator if (isset($producto->tipoventa)) { $printer->text(" " . strtoupper($producto->tipoventa)); } $printer->text("\n"); // Print additional description lines if any for ($i = 1; $i < count($lineasDescripcion); $i++) { $printer->text(" " . $lineasDescripcion[$i] . "\n"); } } printSeparatorLine($printer); // TAX TOTALS SECTION $printer->setJustification(Printer::JUSTIFY_LEFT); $printer->text("G = Gravado. " . str_pad("TOTAL GRAVADO", 17) . "$" . number_format($dataPrint->totales->totalTotal, 2) . "\n"); $printer->text("E = Exento. " . str_pad("TOTAL EXENTO", 17) . "$" . number_format($dataPrint->totales->totalExento, 2) . "\n"); $printer->text("NS = No Sujeto. " . str_pad("TOTAL NO SUJETO", 17) . "$" . number_format($dataPrint->totales->totalNS, 2) . "\n"); // PAYMENT SECTION $printer->setJustification(Printer::JUSTIFY_RIGHT); $printer->setEmphasis(true); $printer->setTextSize(1, 2); $printer->text("TOTAL $" . number_format($dataPrint->totales->totalTotal, 2) . "\n"); $printer->setTextSize(1, 1); $printer->setEmphasis(false); $printer->text("EFECTIVO $" . number_format($dataPrint->efectivo, 2) . "\n"); $printer->setJustification(Printer::JUSTIFY_LEFT); printAlignedText($printer, "REF.: " . $dataPrint->referencia, "CAMBIO $" . number_format(($dataPrint->efectivo - $dataPrint->totales->totalTotal), 2)); // CUSTOMER INFORMATION if (isset($dataPrint->cliente) && $dataPrint->cliente != "") { $printer->text("Cliente: " . $dataPrint->cliente . "\n"); } if (isset($dataPrint->direccion_cliente) && $dataPrint->direccion_cliente != "") { $printer->text("Direccion: " . $dataPrint->direccion_cliente . "\n"); } printSeparatorLine($printer); // FINAL MESSAGE $printer->setJustification(Printer::JUSTIFY_CENTER); $printer->text("\n"); // Word wrap the message if it exists if (isset($dataPrint->mensaje_ticket) && $dataPrint->mensaje_ticket != "") { $mensajeLines = wordwrap($dataPrint->mensaje_ticket, 48, "\n", true); foreach (explode("\n", $mensajeLines) as $linea) { $printer->text($linea . "\n"); } } // FINISH PRINTING $printer->feed(2); $printer->cut(); $printer->close(); echo json_encode([ "status" => "success", "message" => "Ticket impreso correctamente." ]); } catch (Exception $e) { echo json_encode([ "status" => "error", "message" => "Error al imprimir: " . $e->getMessage() ]); } } ?>