recibo.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. /**
  3. * Archivo para imprimir recibos de venta
  4. * Este archivo debe copiarse al servidor de impresión (printserver)
  5. * Imprime en la impresora de caja (normalmente POS-80C)
  6. * Usa librería: mike42/escpos-php
  7. */
  8. if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
  9. header("Access-Control-Allow-Origin: *");
  10. header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
  11. header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
  12. http_response_code(204);
  13. exit;
  14. }
  15. header("Access-Control-Allow-Origin: *");
  16. header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE");
  17. header("Access-Control-Allow-Headers: Content-Type, Authorization");
  18. header('Content-Type: application/json; charset=utf-8');
  19. error_reporting(E_ALL);
  20. ini_set('display_errors', 0);
  21. ini_set('log_errors', 1);
  22. ini_set('error_log', __DIR__ . '/logs/error.log');
  23. require __DIR__ . '/vendor/autoload.php';
  24. use Mike42\Escpos\Printer;
  25. use Mike42\Escpos\PrintConnectors\WindowsPrintConnector;
  26. // Recibir datos
  27. $dataPrint = null;
  28. $isc = '';
  29. if(isset($_POST["dataPrint"])){
  30. // jQuery envía JSON.stringify, necesitamos decodificarlo
  31. $dataPrint = $_POST["dataPrint"];
  32. if(is_string($dataPrint)){
  33. $dataPrint = json_decode($dataPrint, true);
  34. }
  35. }
  36. if(!$dataPrint || !is_array($dataPrint)){
  37. echo json_encode([
  38. 'success' => false,
  39. 'status' => 'error',
  40. 'message' => 'No se recibieron datos para imprimir o formato incorrecto',
  41. 'received' => isset($_POST["dataPrint"]) ? substr(print_r($_POST["dataPrint"], true), 0, 200) : 'nada'
  42. ]);
  43. exit;
  44. }
  45. try {
  46. // Nombre de la impresora de caja
  47. $nombreImpresora = isset($dataPrint['printer']) ? $dataPrint['printer'] : "POS-80C";
  48. $connector = new WindowsPrintConnector($nombreImpresora);
  49. $printer = new Printer($connector);
  50. // ENCABEZADO
  51. $printer->setJustification(Printer::JUSTIFY_CENTER);
  52. $printer->setTextSize(2, 2);
  53. $nombreEmpresa = isset($dataPrint['nombre_empresa']) ? $dataPrint['nombre_empresa'] :
  54. (isset($dataPrint['empresa_nombre']) ? $dataPrint['empresa_nombre'] : 'EMPRESA');
  55. $printer->text($nombreEmpresa . "\n");
  56. $printer->setTextSize(1, 1);
  57. $direccion = isset($dataPrint['direcion_empresa']) ? $dataPrint['direcion_empresa'] :
  58. (isset($dataPrint['empresa_direccion']) ? $dataPrint['empresa_direccion'] : '');
  59. if (!empty($direccion)) {
  60. $printer->text($direccion . "\n");
  61. }
  62. $printer->text(str_repeat("=", 48) . "\n");
  63. $printer->setEmphasis(true);
  64. $printer->text("R E C I B O\n");
  65. $printer->setEmphasis(false);
  66. $printer->text(str_repeat("=", 48) . "\n");
  67. // INFORMACIÓN DEL RECIBO
  68. $printer->setJustification(Printer::JUSTIFY_LEFT);
  69. $fecha = isset($dataPrint['fecha']) ? $dataPrint['fecha'] : date('d-m-Y H:i:s');
  70. $printer->setEmphasis(true);
  71. $printer->text("Fecha: ");
  72. $printer->setEmphasis(false);
  73. $printer->text($fecha . "\n");
  74. /*
  75. if (!empty($dataPrint['referencia'])) {
  76. $printer->setEmphasis(true);
  77. $printer->text("Referencia: ");
  78. $printer->setEmphasis(false);
  79. $printer->text($dataPrint['referencia'] . "\n");
  80. }*/
  81. if (!empty($dataPrint['cliente'])) {
  82. $printer->setEmphasis(true);
  83. $printer->text("Cliente: ");
  84. $printer->setEmphasis(false);
  85. $printer->text($dataPrint['cliente'] . "\n");
  86. }
  87. /*
  88. if (!empty($dataPrint['caja'])) {
  89. $printer->setEmphasis(true);
  90. $printer->text("Caja: ");
  91. $printer->setEmphasis(false);
  92. $printer->text($dataPrint['caja'] . "\n");
  93. }*/
  94. $printer->text(str_repeat("-", 48) . "\n");
  95. // ENCABEZADO DE TABLA
  96. $printer->setEmphasis(true);
  97. $printer->text("CANT DESCRIPCION TOTAL\n");
  98. $printer->setEmphasis(false);
  99. $printer->text(str_repeat("-", 48) . "\n");
  100. // PRODUCTOS
  101. $subtotal = 0;
  102. if (isset($dataPrint['productos_normal']) && is_array($dataPrint['productos_normal'])) {
  103. foreach ($dataPrint['productos_normal'] as $producto) {
  104. // Convertir objeto a array si es necesario
  105. $productoArray = is_object($producto) ? (array)$producto : $producto;
  106. $cant = isset($productoArray['cant']) ? number_format($productoArray['cant'], 0) : '0';
  107. $desc = isset($productoArray['desc']) ? $productoArray['desc'] : '';
  108. $costo = isset($productoArray['costo']) ? floatval($productoArray['costo']) : 0;
  109. $cantNum = isset($productoArray['cant']) ? floatval($productoArray['cant']) : 0;
  110. $total = $cantNum * $costo;
  111. $subtotal += $total;
  112. // Línea del producto - cant y descripción
  113. $cantTexto = $cant . "x";
  114. $descCorto = substr($desc, 0, 25);
  115. $totalStr = "$" . number_format($total, 2);
  116. $printer->text(str_pad($cantTexto, 5) . " " . str_pad($descCorto, 36) . str_pad($totalStr, 1, " ", STR_PAD_LEFT) . "\n");
  117. }
  118. }
  119. $printer->text(str_repeat("=", 48) . "\n");
  120. // TOTALES
  121. $printer->setJustification(Printer::JUSTIFY_RIGHT);
  122. $totales = isset($dataPrint['totales']) && is_array($dataPrint['totales']) ? $dataPrint['totales'] : [];
  123. // Función helper para limpiar valores numéricos
  124. $limpiarNumero = function($valor) {
  125. if(is_numeric($valor)) return floatval($valor);
  126. if(is_string($valor)) return floatval(str_replace(',', '', $valor));
  127. return 0;
  128. };
  129. $descuento = $limpiarNumero(isset($totales['descuento']) ? $totales['descuento'] : 0);
  130. $propina = $limpiarNumero(isset($totales['propina']) ? $totales['propina'] : 0);
  131. $totalTotal = $limpiarNumero(isset($totales['totalTotal']) ? $totales['totalTotal'] : 0);
  132. $efectivo = $limpiarNumero(isset($dataPrint['efectivo']) ? $dataPrint['efectivo'] : 0);
  133. $pos = $limpiarNumero(isset($dataPrint['pos']) ? $dataPrint['pos'] : 0);
  134. $cambio = $limpiarNumero(isset($dataPrint['cambio']) ? $dataPrint['cambio'] : 0);
  135. // TOTAL (PRIMERO)
  136. $printer->setEmphasis(true);
  137. $printer->setTextSize(2, 1);
  138. $printer->text("TOTAL: $" . number_format($totalTotal, 2) . "\n");
  139. $printer->setTextSize(1, 1);
  140. $printer->setEmphasis(false);
  141. // DESCUENTO
  142. if ($descuento > 0) {
  143. $printer->text("Descuento: -$" . number_format($descuento, 2) . "\n");
  144. }
  145. // PROPINA
  146. if ($propina > 0) {
  147. $printer->text("Propina: $" . number_format($propina, 2) . "\n");
  148. }
  149. // MÉTODO DE PAGO
  150. if ($efectivo > 0) {
  151. $printer->text("Efectivo: $" . number_format($efectivo, 2) . "\n");
  152. }
  153. if ($pos > 0) {
  154. $printer->text("POS/Tarjeta: $" . number_format($pos, 2) . "\n");
  155. }
  156. // CAMBIO (SIEMPRE MOSTRAR)
  157. $printer->text("Cambio: $" . number_format($cambio, 2) . "\n");
  158. $printer->text(str_repeat("=", 48) . "\n");
  159. // MENSAJE FINAL
  160. $printer->setJustification(Printer::JUSTIFY_CENTER);
  161. if (!empty($dataPrint['mensaje_ticket'])) {
  162. $printer->text($dataPrint['mensaje_ticket'] . "\n");
  163. }
  164. $printer->text("\n¡Gracias por su compra!\n");
  165. $printer->text("Este es un recibo, NO factura\n");
  166. $printer->feed(3);
  167. $printer->cut();
  168. $printer->close();
  169. echo json_encode([
  170. 'success' => true,
  171. 'status' => 'success',
  172. 'message' => 'Recibo impreso correctamente en ' . $nombreImpresora
  173. ]);
  174. } catch (Exception $e) {
  175. echo json_encode([
  176. 'success' => false,
  177. 'status' => 'error',
  178. 'message' => 'Error al imprimir: ' . $e->getMessage()
  179. ]);
  180. }
  181. ?>