@danielrebolledo/cafe-ipdh-lib 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -97,11 +97,50 @@ interface PrinterDriver<TCmd = unknown> {
97
97
  buildReceiptCommands(options: BuildReceiptOptions): TCmd[];
98
98
  }
99
99
 
100
+ /**
101
+ * Socket mínimo requerido por DtpClient.
102
+ * Compatible con Node net.Socket y react-native-tcp-socket.
103
+ */
104
+ interface DtpSocketLike {
105
+ on(event: "data", cb: (chunk: Buffer | Uint8Array) => void): void;
106
+ on(event: "error", cb: (err: Error) => void): void;
107
+ on(event: "close", cb: () => void): void;
108
+ once(event: "connect", cb: () => void): void;
109
+ once(event: "error", cb: (err: Error) => void): void;
110
+ write(data: Buffer | Uint8Array): void;
111
+ end(): void;
112
+ }
113
+ /**
114
+ * Factory para crear una conexión TCP al dispositivo DTP.
115
+ * Debe retornar una Promise que resuelve cuando el socket está conectado.
116
+ *
117
+ * En Node.js, usar createNodeDtpConnection (desde /node).
118
+ * En React Native, usar react-native-tcp-socket:
119
+ *
120
+ * ```ts
121
+ * import TcpSocket from "react-native-tcp-socket";
122
+ *
123
+ * const createConnection: CreateDtpConnection = (opts) =>
124
+ * new Promise((resolve, reject) => {
125
+ * const socket = TcpSocket.createConnection(opts, () => resolve(socket));
126
+ * socket.once("error", reject);
127
+ * });
128
+ *
129
+ * const client = new DtpClient({ host, port, createConnection });
130
+ * ```
131
+ */
132
+ type CreateDtpConnection = (opts: {
133
+ host: string;
134
+ port: number;
135
+ }) => Promise<DtpSocketLike>;
136
+
100
137
  type DtpOptions = {
101
138
  host: string;
102
139
  port: number;
103
140
  connectTimeoutMs?: number;
104
141
  commandTimeoutMs?: number;
142
+ /** Factory para crear la conexión TCP. Requerido. En Node usa createNodeDtpConnection; en RN usa react-native-tcp-socket. */
143
+ createConnection: CreateDtpConnection;
105
144
  };
106
145
  declare class DtpClient {
107
146
  private opts;
@@ -214,4 +253,4 @@ interface ExecuteDtpCommandsResult {
214
253
  */
215
254
  declare function executeDtpCommands(client: DtpClient, commands: DtpPrinterCommand[]): Promise<ExecuteDtpCommandsResult>;
216
255
 
217
- export { type BuildInvoiceOptions as B, type DocumentType as D, type ExecuteDtpCommandsResult as E, type FiscalClient as F, type ItemTax as I, type Order as O, type PrinterDriver as P, type BuildReceiptOptions as a, type DtpPrinterCommand as b, type OrderItem as c, type OrderPayment as d, type PrinterCommandResponse as e, dtpPrinter as f, executeDtpCommands as g, DtpClient as h, type DtpOptions as i };
256
+ export { type BuildInvoiceOptions as B, type CreateDtpConnection as C, type DocumentType as D, type ExecuteDtpCommandsResult as E, type FiscalClient as F, type ItemTax as I, type Order as O, type PrinterDriver as P, type BuildReceiptOptions as a, DtpClient as b, type DtpOptions as c, type DtpPrinterCommand as d, type DtpSocketLike as e, type OrderItem as f, type OrderPayment as g, type PrinterCommandResponse as h, dtpPrinter as i, executeDtpCommands as j };
@@ -97,11 +97,50 @@ interface PrinterDriver<TCmd = unknown> {
97
97
  buildReceiptCommands(options: BuildReceiptOptions): TCmd[];
98
98
  }
99
99
 
100
+ /**
101
+ * Socket mínimo requerido por DtpClient.
102
+ * Compatible con Node net.Socket y react-native-tcp-socket.
103
+ */
104
+ interface DtpSocketLike {
105
+ on(event: "data", cb: (chunk: Buffer | Uint8Array) => void): void;
106
+ on(event: "error", cb: (err: Error) => void): void;
107
+ on(event: "close", cb: () => void): void;
108
+ once(event: "connect", cb: () => void): void;
109
+ once(event: "error", cb: (err: Error) => void): void;
110
+ write(data: Buffer | Uint8Array): void;
111
+ end(): void;
112
+ }
113
+ /**
114
+ * Factory para crear una conexión TCP al dispositivo DTP.
115
+ * Debe retornar una Promise que resuelve cuando el socket está conectado.
116
+ *
117
+ * En Node.js, usar createNodeDtpConnection (desde /node).
118
+ * En React Native, usar react-native-tcp-socket:
119
+ *
120
+ * ```ts
121
+ * import TcpSocket from "react-native-tcp-socket";
122
+ *
123
+ * const createConnection: CreateDtpConnection = (opts) =>
124
+ * new Promise((resolve, reject) => {
125
+ * const socket = TcpSocket.createConnection(opts, () => resolve(socket));
126
+ * socket.once("error", reject);
127
+ * });
128
+ *
129
+ * const client = new DtpClient({ host, port, createConnection });
130
+ * ```
131
+ */
132
+ type CreateDtpConnection = (opts: {
133
+ host: string;
134
+ port: number;
135
+ }) => Promise<DtpSocketLike>;
136
+
100
137
  type DtpOptions = {
101
138
  host: string;
102
139
  port: number;
103
140
  connectTimeoutMs?: number;
104
141
  commandTimeoutMs?: number;
142
+ /** Factory para crear la conexión TCP. Requerido. En Node usa createNodeDtpConnection; en RN usa react-native-tcp-socket. */
143
+ createConnection: CreateDtpConnection;
105
144
  };
106
145
  declare class DtpClient {
107
146
  private opts;
@@ -214,4 +253,4 @@ interface ExecuteDtpCommandsResult {
214
253
  */
215
254
  declare function executeDtpCommands(client: DtpClient, commands: DtpPrinterCommand[]): Promise<ExecuteDtpCommandsResult>;
216
255
 
217
- export { type BuildInvoiceOptions as B, type DocumentType as D, type ExecuteDtpCommandsResult as E, type FiscalClient as F, type ItemTax as I, type Order as O, type PrinterDriver as P, type BuildReceiptOptions as a, type DtpPrinterCommand as b, type OrderItem as c, type OrderPayment as d, type PrinterCommandResponse as e, dtpPrinter as f, executeDtpCommands as g, DtpClient as h, type DtpOptions as i };
256
+ export { type BuildInvoiceOptions as B, type CreateDtpConnection as C, type DocumentType as D, type ExecuteDtpCommandsResult as E, type FiscalClient as F, type ItemTax as I, type Order as O, type PrinterDriver as P, type BuildReceiptOptions as a, DtpClient as b, type DtpOptions as c, type DtpPrinterCommand as d, type DtpSocketLike as e, type OrderItem as f, type OrderPayment as g, type PrinterCommandResponse as h, dtpPrinter as i, executeDtpCommands as j };
package/dist/index.cjs CHANGED
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ DtpClient: () => DtpClient,
23
24
  PaymentMethodId: () => PaymentMethodId,
24
25
  PrinterTaxValues: () => PrinterTaxValues,
25
26
  TaxValues: () => TaxValues,
@@ -30,6 +31,97 @@ __export(index_exports, {
30
31
  });
31
32
  module.exports = __toCommonJS(index_exports);
32
33
 
34
+ // src/printers/dtp/dtp-client.ts
35
+ var STX = 2;
36
+ var ETX = 3;
37
+ var FS = 28;
38
+ var DtpClient = class {
39
+ constructor(opts) {
40
+ this.opts = opts;
41
+ }
42
+ socket = null;
43
+ buffer = Buffer.alloc(0);
44
+ pending = null;
45
+ async connect() {
46
+ if (this.socket) return;
47
+ const timeoutMs = this.opts.connectTimeoutMs ?? 3e3;
48
+ const socket = await Promise.race([
49
+ this.opts.createConnection({
50
+ host: this.opts.host,
51
+ port: this.opts.port
52
+ }),
53
+ new Promise(
54
+ (_, reject) => setTimeout(() => reject(new Error("Connect timeout")), timeoutMs)
55
+ )
56
+ ]);
57
+ this.socket = socket;
58
+ socket.on(
59
+ "data",
60
+ (chunk) => this.onData(chunk instanceof Buffer ? chunk : Buffer.from(chunk))
61
+ );
62
+ socket.on("error", (e) => this.onError(e));
63
+ socket.on("close", () => this.onClose());
64
+ }
65
+ close() {
66
+ this.socket?.end();
67
+ this.socket = null;
68
+ this.buffer = Buffer.alloc(0);
69
+ }
70
+ async send(parts) {
71
+ if (!this.socket) throw new Error("Socket not connected");
72
+ if (this.pending) throw new Error("Another command is in-flight");
73
+ const frame = this.buildFrame(parts);
74
+ const timeoutMs = this.opts.commandTimeoutMs ?? 1e4;
75
+ return await new Promise((resolve, reject) => {
76
+ const timer = setTimeout(() => {
77
+ this.pending = null;
78
+ reject(new Error(`Command timeout: ${parts[0]}`));
79
+ }, timeoutMs);
80
+ this.pending = { resolve, reject, timer };
81
+ this.socket?.write(frame);
82
+ });
83
+ }
84
+ buildFrame(parts) {
85
+ const payload = Buffer.from(parts.join(String.fromCharCode(FS)), "utf8");
86
+ return Buffer.concat([Buffer.from([STX]), payload, Buffer.from([ETX])]);
87
+ }
88
+ tryParseOneFrame() {
89
+ const start = this.buffer.indexOf(STX);
90
+ const end = this.buffer.indexOf(ETX, start + 1);
91
+ if (start === -1 || end === -1) return null;
92
+ const body = this.buffer.subarray(start + 1, end);
93
+ this.buffer = this.buffer.subarray(end + 1);
94
+ const params = body.toString("utf8").split(String.fromCharCode(FS));
95
+ return params;
96
+ }
97
+ onData(chunk) {
98
+ this.buffer = Buffer.concat([this.buffer, chunk]);
99
+ const params = this.tryParseOneFrame();
100
+ if (!params) return;
101
+ if (!this.pending) return;
102
+ const { resolve, timer } = this.pending;
103
+ clearTimeout(timer);
104
+ this.pending = null;
105
+ resolve(params);
106
+ }
107
+ onError(e) {
108
+ if (this.pending) {
109
+ const { reject, timer } = this.pending;
110
+ clearTimeout(timer);
111
+ this.pending = null;
112
+ reject(e);
113
+ }
114
+ }
115
+ onClose() {
116
+ if (this.pending) {
117
+ const { reject, timer } = this.pending;
118
+ clearTimeout(timer);
119
+ this.pending = null;
120
+ reject(new Error("Socket closed"));
121
+ }
122
+ }
123
+ };
124
+
33
125
  // src/types/enums.ts
34
126
  var TaxValues = /* @__PURE__ */ ((TaxValues2) => {
35
127
  TaxValues2[TaxValues2["EXENTO_E"] = 0] = "EXENTO_E";
@@ -750,6 +842,7 @@ async function sendAegCommands(args, options) {
750
842
  }
751
843
  // Annotate the CommonJS export names for ESM import in node:
752
844
  0 && (module.exports = {
845
+ DtpClient,
753
846
  PaymentMethodId,
754
847
  PrinterTaxValues,
755
848
  TaxValues,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types/enums.ts","../src/printers/aeg/aeg-printer.ts","../src/printers/dtp/dtp-printer.ts","../src/printers/dtp/dtp-printer-driver.ts","../src/runner/send-printer-commands.ts"],"sourcesContent":["/**\n * cafe-ipdh-lib\n * Librería para gestionar impresoras fiscales y de recibos.\n *\n * Soporta:\n * - AEG-R1: impresora fiscal vía HTTP (comandos JSON)\n *\n * Uso:\n * ```ts\n * import { aegPrinter } from \"cafe-ipdh-lib\";\n *\n * const commands = aegPrinter.buildInvoiceCommands(order, {\n * paymentMethodId: \"pos_credit\",\n * storeName: \"Mi Tienda\"\n * });\n * // Enviar commands a la impresora vía tu API/transport\n * ```\n */\n\nexport type {\n\tBuildInvoiceOptions,\n\tBuildReceiptOptions,\n\tDocumentType,\n\tDtpPrinterCommand,\n\tExecuteDtpCommandsResult,\n\tPrinterCommandResponse,\n\tPrinterDriver,\n} from \"./printers/index.js\";\nexport {\n\taegPrinter,\n\tdtpPrinter,\n\texecuteDtpCommands,\n} from \"./printers/index.js\";\nexport type {\n\tAegModel,\n\tDtpModel,\n\tPrinterBrand,\n\tSendPrinterCommandsAeg,\n\tSendPrinterCommandsArgs,\n\tSendPrinterCommandsDtp,\n} from \"./runner/index.js\";\nexport { sendPrinterCommands } from \"./runner/index.js\";\nexport type {\n\tAegPrinterCommand,\n\tFiscalClient,\n\tItemTax,\n\tOrder,\n\tOrderItem,\n\tOrderPayment,\n} from \"./types/index.js\";\nexport {\n\tPaymentMethodId,\n\tPrinterTaxValues,\n\tTaxValues,\n} from \"./types/index.js\";\n","/**\n * Valores de impuestos (porcentajes) según legislación venezolana.\n */\nexport enum TaxValues {\n\tEXENTO_E = 0,\n\tBI_G = 16.0,\n\tIVA_G = 16.0,\n\tBI_R = 8.0,\n\tIVA_R = 8.0,\n\tBI_A = 31.0,\n\tIVA_A = 31.0,\n\tPERCIBIDO = 0,\n\tBI_IGTF = 3.0,\n\tIVA_IGTF = 3.0,\n}\n\n/**\n * Códigos de impuesto para impresora fiscal AEG-R1.\n */\nexport enum PrinterTaxValues {\n\tEXENTO_E = 1,\n\tBI_G = 2,\n\tIVA_G = 2,\n\tBI_R = 3,\n\tIVA_R = 3,\n\tBI_A = 4,\n\tIVA_A = 4,\n\tPERCIBIDO = 5,\n\tBI_IGTF = 5,\n\tIVA_IGTF = 5,\n}\n\n/**\n * IDs de método de pago para impresora fiscal AEG-R1.\n * Efectivo: 1, Débito: 2, Crédito: 3, Pago Móvil: 5,\n * Débito/Crédito int: 11, Efectivo int: 12\n */\nexport enum PaymentMethodId {\n\tCASH = 1,\n\tPOS_DEBIT = 2,\n\tPOS_CREDIT = 3,\n\tPAGO_MOVIL = 5,\n\tPOS_DEBIT_CREDIT_INT = 11,\n\tCASH_INT = 12,\n}\n","import type { AegPrinterCommand } from \"../../types/aeg-commands.js\";\nimport {\n\tPaymentMethodId,\n\tPrinterTaxValues,\n\tTaxValues,\n} from \"../../types/enums.js\";\nimport type { Order } from \"../../types/order.js\";\nimport type {\n\tBuildInvoiceOptions,\n\tBuildReceiptOptions,\n\tPrinterDriver,\n} from \"../printer.types.js\";\n\nfunction truncateString(str: string, maxLength = 64): string {\n\tif (!str) return \"\";\n\treturn str.length > maxLength ? str.substring(0, maxLength) : str;\n}\n\n// biome-ignore lint: avoid control char in literal\nconst ISO_8859_1_REGEX = new RegExp(\"[^\\\\u0000-\\\\u00FF]\", \"g\");\n\nfunction normalizeIso88591(str: string): string {\n\treturn str.replace(ISO_8859_1_REGEX, \"?\");\n}\n\nfunction formatDate(date: Date): string {\n\tconst day = date.getDate().toString().padStart(2, \"0\");\n\tconst month = (date.getMonth() + 1).toString().padStart(2, \"0\");\n\tconst year = date.getFullYear();\n\treturn `${day}/${month}/${year}`;\n}\n\nfunction formatTime(date: Date): string {\n\tconst hours = date.getHours().toString().padStart(2, \"0\");\n\tconst minutes = date.getMinutes().toString().padStart(2, \"0\");\n\treturn `${hours}:${minutes}`;\n}\n\nfunction mapTaxIdToPrinterCode(taxId: string | null | undefined): number {\n\tif (!taxId) {\n\t\treturn PrinterTaxValues.EXENTO_E;\n\t}\n\tconst taxIdUpper = taxId.toUpperCase();\n\tconst printerTaxValue =\n\t\tPrinterTaxValues[taxIdUpper as keyof typeof PrinterTaxValues];\n\tif (printerTaxValue !== undefined) {\n\t\treturn printerTaxValue;\n\t}\n\treturn PrinterTaxValues.EXENTO_E;\n}\n\nfunction mapPaymentMethod(method: string): PaymentMethodId {\n\tif (method === \"pos_debit\") return PaymentMethodId.POS_DEBIT;\n\tif (method === \"pos_credit\") return PaymentMethodId.POS_CREDIT;\n\tif (method === \"pos_debit_credit_int\")\n\t\treturn PaymentMethodId.POS_DEBIT_CREDIT_INT;\n\tif (method === \"cash_int\") return PaymentMethodId.CASH_INT;\n\tif (method === \"cash_nat\") return PaymentMethodId.CASH;\n\tthrow new Error(\n\t\t`Método de pago inválido: ${method}. Debe ser \"pos_debit\", \"pos_credit\", \"pos_debit_credit_int\", \"cash_int\" o \"cash_nat\"`,\n\t);\n}\n\n/**\n * Driver para impresora fiscal AEG-R1.\n * Construye comandos JSON según documentación oficial.\n */\nexport const aegPrinter: PrinterDriver<AegPrinterCommand> = {\n\tmodel: \"aeg-r1\",\n\n\tbuildInvoiceCommands(\n\t\torder: Order,\n\t\toptions: BuildInvoiceOptions,\n\t): AegPrinterCommand[] {\n\t\tconst commands: AegPrinterCommand[] = [];\n\n\t\tif (!order) {\n\t\t\tthrow new Error(\"Order es requerido\");\n\t\t}\n\t\tif (!order.client) {\n\t\t\tthrow new Error(\"Order debe tener un cliente asociado\");\n\t\t}\n\t\tif (!order.items || order.items.length === 0) {\n\t\t\tthrow new Error(\"Order debe tener al menos un item\");\n\t\t}\n\n\t\tconst { paymentMethodId, storeName = \"N/A\" } = options;\n\n\t\t// 1. cliF - Datos del cliente\n\t\tconst clientRifCI = order.client.id || \"\";\n\t\tconst clientName = order.client.name || \"\";\n\t\tconst clientEmail = order.client.email || \"\";\n\t\tconst clientPhone = order.client.phone || \"\";\n\t\tconst clientAddress = order.client.address || \"\";\n\t\tconst razSoc = [clientName, clientEmail, clientPhone]\n\t\t\t.filter(Boolean)\n\t\t\t.map((v) => truncateString(v, 64));\n\t\tconst storeLine = `Tienda: ${storeName}`;\n\t\tconst LineAd = [storeLine, clientAddress]\n\t\t\t.filter(Boolean)\n\t\t\t.map((v) => truncateString(v, 64));\n\n\t\tcommands.push({\n\t\t\tcmd: \"cliF\",\n\t\t\tdata: { rifCI: clientRifCI, razSoc, LineAd },\n\t\t});\n\n\t\t// 2. proF - Productos\n\t\tlet subtotalWithoutTaxes = 0;\n\n\t\tfor (const item of order.items) {\n\t\t\tif (!item.name) continue;\n\n\t\t\tconst taxId =\n\t\t\t\titem.taxes && item.taxes.length > 0 ? item.taxes[0].id : null;\n\t\t\tconst imp = mapTaxIdToPrinterCode(taxId);\n\t\t\tconst price = item.price || 0;\n\t\t\tconst pre = Math.round(Math.max(price, 0) * 100);\n\t\t\tconst quantity = item.selectedQuantity ?? item.quantity ?? 1;\n\t\t\tconst cant = Math.round(Math.max(quantity, 1) * 1000);\n\t\t\tconst des01 = truncateString(item.name, 64);\n\n\t\t\tsubtotalWithoutTaxes += price * Math.max(quantity, 1);\n\n\t\t\tcommands.push({\n\t\t\t\tcmd: \"proF\",\n\t\t\t\tdata: { imp, pre, cant, des01 },\n\t\t\t});\n\t\t}\n\n\t\t// 2.1 IGTF si pago en divisas\n\t\tconst isForeignCurrency =\n\t\t\tpaymentMethodId === \"pos_debit_credit_int\" ||\n\t\t\tpaymentMethodId === \"cash_int\";\n\n\t\tif (isForeignCurrency && subtotalWithoutTaxes > 0) {\n\t\t\tconst roundedSubtotal =\n\t\t\t\tMath.round((subtotalWithoutTaxes + Number.EPSILON) * 100) / 100;\n\t\t\tconst igtfPercentage = TaxValues.BI_IGTF / 100;\n\t\t\tconst igtfAmount =\n\t\t\t\tMath.round((roundedSubtotal * igtfPercentage + Number.EPSILON) * 100) /\n\t\t\t\t100;\n\n\t\t\tcommands.push({\n\t\t\t\tcmd: \"proF\",\n\t\t\t\tdata: {\n\t\t\t\t\timp: PrinterTaxValues.PERCIBIDO,\n\t\t\t\t\tpre: Math.round(igtfAmount * 100),\n\t\t\t\t\tcant: 1000,\n\t\t\t\t\tdes01: \"IGTF 3% pago en divisas\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// 3. subToF - Subtotal\n\t\tcommands.push({ cmd: \"subToF\", data: 1, valor: 0 });\n\n\t\t// 4. fpaF - Forma de pago\n\t\tif (!order.payments?.length) {\n\t\t\tthrow new Error(\"Order debe tener al menos un pago exitoso\");\n\t\t}\n\n\t\tfor (const payment of order.payments) {\n\t\t\tconst paymentType = mapPaymentMethod(payment.paymentMethod);\n\t\t\tconst paymentAmount = Math.round(payment.amount * 100);\n\t\t\tcommands.push({\n\t\t\t\tcmd: \"fpaF\",\n\t\t\t\tdata: {\n\t\t\t\t\ttipo: paymentType,\n\t\t\t\t\tmonto: paymentAmount,\n\t\t\t\t\ttasaConv: 0,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// 5. endFac - Cierre\n\t\tcommands.push({ cmd: \"endFac\", data: 1 });\n\n\t\treturn commands;\n\t},\n\n\tbuildReceiptCommands(options: BuildReceiptOptions): AegPrinterCommand[] {\n\t\tconst {\n\t\t\torderId,\n\t\t\tamountPaid,\n\t\t\tpaymentMethod,\n\t\t\tpaidAt,\n\t\t\tcardLast4,\n\t\t\torganizationName,\n\t\t} = options;\n\n\t\tif (!orderId) {\n\t\t\tthrow new Error(\"OrderId es requerido\");\n\t\t}\n\t\tif (!Number.isFinite(amountPaid) || amountPaid <= 0) {\n\t\t\tthrow new Error(\"Monto pagado inválido\");\n\t\t}\n\n\t\tconst paidDate = paidAt ?? new Date();\n\t\tconst amountLabel = `Bs ${amountPaid}`;\n\t\tconst paymentLabel = `Medio de pago: ${paymentMethod}`;\n\t\tconst dateLabel = `Fecha del pago: ${formatDate(paidDate)}`;\n\t\tconst timeLabel = `Hora del pago: ${formatTime(paidDate)}`;\n\t\tconst cardLabel = `Tarjeta ${cardLast4 ?? \"N/A\"}`;\n\t\tconst orgLabel = organizationName?.trim() || \"N/A\";\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tcmd: \"encDNF\",\n\t\t\t\tdata: [\n\t\t\t\t\tnormalizeIso88591(truncateString(\"RECIBO DE PAGO\")),\n\t\t\t\t\tnormalizeIso88591(truncateString(orderId)),\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"aperDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(\"Recibo de pago\")),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"efeNorJuIzDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(orgLabel)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"efeNorJuIzDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(amountLabel)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"efeNorJuIzDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(paymentLabel)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"efeNorJuIzDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(cardLabel)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"efeNorJuIzDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(timeLabel)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"efeNorJuIzDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(dateLabel)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"endDNF\",\n\t\t\t\tdata: normalizeIso88591(\"Cierre del Documento No Fiscal\"),\n\t\t\t},\n\t\t];\n\t},\n};\n","import type { DtpClient } from \"./dtp-client\";\nimport type { AbrirCfArgs, ItemCfArgs, PagoCfArgs } from \"./dtp-printer.types\";\n\nconst formatDateDDMMYYYY = (d: Date) => {\n\tconst dd = String(d.getDate()).padStart(2, \"0\");\n\tconst mm = String(d.getMonth() + 1).padStart(2, \"0\");\n\tconst yyyy = String(d.getFullYear());\n\treturn `${dd}${mm}${yyyy}`;\n};\n\nfunction parseCode(r: string[], idx = 0): number {\n\tconst v = r[idx];\n\tconst n = Number(v);\n\treturn v !== undefined && v !== null && !Number.isNaN(n) ? n : 16;\n}\n\n// C0 Get Status (used as \"real ping\")\nexport async function getStatus(client: DtpClient) {\n\tconst r = await client.send([\"C0\"]);\n\tconst code = parseCode(r);\n\treturn {\n\t\tcode,\n\t\tstate: code === 0 && r.length > 2 ? Number(r[2] ?? -1) : -1,\n\t\tblock: code === 0 && r.length > 3 ? Number(r[3] ?? -1) : -1,\n\t\tfiscalStatus: code === 0 && r.length > 4 ? String(r[4] ?? \"\") : \"\",\n\t\tlastCommandResponse:\n\t\t\tcode === 0 && r.length > 5 ? Number(r[5] ?? -1) : -1,\n\t\traw: r,\n\t};\n}\n\nexport async function openFiscalDoc(client: DtpClient, args: AbrirCfArgs) {\n\tconst r = await client.send([\n\t\t\"F0\",\n\t\tString(args.iTipo ?? 0),\n\t\targs.sNombreCliente,\n\t\targs.sRifCliente,\n\t\tString(args.iFacturaReferencia ?? 0),\n\t\tformatDateDDMMYYYY(args.fechaReferencia ?? new Date()),\n\t\targs.sSerialReferencia ?? \"\",\n\t\t(args.bLogo ?? false) ? \"1\" : \"0\",\n\t\targs.sLineaAdicional ?? \"\",\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tdocumentNumber: Number(r[1] ?? -1),\n\t\traw: r,\n\t};\n}\n\nexport async function addFiscalItem(client: DtpClient, args: ItemCfArgs) {\n\tconst r = await client.send([\n\t\t\"F1\",\n\t\tString(args.iTipo ?? 0),\n\t\targs.sDescripcion,\n\t\targs.sCodigo,\n\t\tString(args.lCantidad),\n\t\targs.sUnidad,\n\t\tString(args.lPrecio),\n\t\tString(args.iImpuesto),\n\t\tString(args.iDecPrecio),\n\t\tString(args.iDecCantidad),\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\titemCount: Number(r[1] ?? -1),\n\t\ttotalItem: Number(r[2] ?? -1),\n\t\tprintedLines: Number(r[3] ?? -1),\n\t\traw: r,\n\t};\n}\n\nexport async function subtotalFiscalDoc(\n\tclient: DtpClient,\n\tmode = 0,\n\tforeignCurrencyAmount = 0,\n) {\n\tconst r = await client.send([\n\t\t\"F2\",\n\t\tString(mode),\n\t\tString(foreignCurrencyAmount),\n\t]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function payFiscalDoc(client: DtpClient, args: PagoCfArgs) {\n\tconst r = await client.send([\n\t\t\"F4\",\n\t\tString(args.iTipoPago ?? 0),\n\t\tString(args.iFormaPago),\n\t\targs.sDescripcion,\n\t\tString(args.lMonto),\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tamountDue: Number(r[1] ?? -1),\n\t\tchangeAmount: Number(r[2] ?? -1),\n\t\tprintedLines: Number(r[3] ?? -1),\n\t\traw: r,\n\t};\n}\n\nexport async function addFiscalComment(\n\tclient: DtpClient,\n\tcomment: string,\n\tsize = 0,\n\talign = 0,\n\tstyle = 0,\n) {\n\tconst r = await client.send([\n\t\t\"F7\",\n\t\tcomment,\n\t\tString(size),\n\t\tString(align),\n\t\tString(style),\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tprintedLines: Number(r[1] ?? -1),\n\t\traw: r,\n\t};\n}\n\nexport async function closeFiscalDoc(\n\tclient: DtpClient,\n\tadditionalLine = \"\",\n) {\n\tconst r = await client.send([\"F5\", additionalLine]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tdocumentNumber: Number(r[1] ?? -1),\n\t\ttotalAmount: Number(r[2] ?? -1),\n\t\traw: r,\n\t};\n}\n\nexport async function cancelFiscalDoc(client: DtpClient) {\n\tconst r = await client.send([\"F6\"]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function getSerializationData(client: DtpClient) {\n\tconst r = await client.send([\"C2\"]);\n\tconst code = parseCode(r);\n\treturn {\n\t\tcode,\n\t\tfiscalSerial: code === 0 && r.length >= 2 ? r[1] : \"\",\n\t\tprinterSerial: code === 0 && r.length >= 3 ? r[2] : \"\",\n\t\tkitSerial: code === 0 && r.length >= 4 ? r[3] : \"\",\n\t\tmfSerial: code === 0 && r.length >= 5 ? r[4] : \"\",\n\t\tmaSerial: code === 0 && r.length >= 6 ? r[5] : \"\",\n\t\traw: r,\n\t};\n}\n\nexport async function getFiscalizationData(client: DtpClient) {\n\tconst r = await client.send([\"C3\"]);\n\tconst code = parseCode(r);\n\treturn {\n\t\tcode,\n\t\ttaxpayerName: code === 0 && r.length >= 2 ? r[1] : \"\",\n\t\tfiscalAddress: code === 0 && r.length >= 3 ? r[2] : \"\",\n\t\ttaxpayerRif: code === 0 && r.length >= 4 ? r[3] : \"\",\n\t\tcommercialName: code === 0 && r.length >= 5 ? r[4] : \"\",\n\t\tdistributorName: code === 0 && r.length >= 6 ? r[5] : \"\",\n\t\tdistributorRif: code === 0 && r.length >= 7 ? r[6] : \"\",\n\t\ttaxRate1: code === 0 && r.length >= 8 ? Number(r[7]) : 0,\n\t\ttaxRate2: code === 0 && r.length >= 9 ? Number(r[8]) : 0,\n\t\ttaxRate3: code === 0 && r.length >= 10 ? Number(r[9]) : 0,\n\t\ttaxRate4: code === 0 && r.length >= 11 ? Number(r[10]) : 0,\n\t\traw: r,\n\t};\n}\n\nexport async function getPaymentMethod(\n\tclient: DtpClient,\n\tpaymentMethodId: number,\n) {\n\tconst r = await client.send([\"C9\", String(paymentMethodId)]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tname: parseCode(r) === 0 && r.length >= 2 ? r[1] : \"\",\n\t\traw: r,\n\t};\n}\n\nexport async function setPaymentMethod(\n\tclient: DtpClient,\n\tpaymentMethodId: number,\n\tname: string,\n) {\n\tconst r = await client.send([\"C10\", String(paymentMethodId), name]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function payFiscalDocForeignCurrency(\n\tclient: DtpClient,\n\targs: {\n\t\tiFormaPago: number;\n\t\tsDescripcion: string;\n\t\tlMonto: number;\n\t\tlTasaCambio: number;\n\t\tsSimbolo: string;\n\t},\n) {\n\tconst r = await client.send([\n\t\t\"F11\",\n\t\t\"0\",\n\t\targs.sDescripcion,\n\t\tString(args.lMonto),\n\t\tString(args.lTasaCambio),\n\t\targs.sSimbolo,\n\t\tString(args.iFormaPago),\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tamountDue: Number(r[1] ?? -1),\n\t\tchangeAmount: Number(r[2] ?? -1),\n\t\tprintedLines: Number(r[3] ?? -1),\n\t\traw: r,\n\t};\n}\n\nexport async function reportX(\n\tclient: DtpClient,\n\tnoOpenDrawer = false,\n) {\n\tconst parts = [\"R0\", \"0\"];\n\tif (noOpenDrawer) parts.push(\"1\");\n\tconst r = await client.send(parts);\n\tconst code = parseCode(r);\n\treturn {\n\t\tcode,\n\t\tdocumentNumber: code === 0 && r.length >= 2 ? Number(r[1]) : -1,\n\t\traw: r,\n\t};\n}\n\nexport async function reportZ(\n\tclient: DtpClient,\n\tnoOpenDrawer = false,\n) {\n\tconst parts = [\"R0\", \"1\"];\n\tif (noOpenDrawer) parts.push(\"1\");\n\tconst r = await client.send(parts);\n\tconst code = parseCode(r);\n\treturn {\n\t\tcode,\n\t\treportNumber: code === 0 && r.length >= 2 ? Number(r[1]) : -1,\n\t\traw: r,\n\t};\n}\n\nexport async function getFiscalDayInfo(client: DtpClient) {\n\tconst r = await client.send([\"R1\"]);\n\tconst code = parseCode(r);\n\tif (code !== 0 || r.length < 84) {\n\t\treturn { code, raw: r };\n\t}\n\treturn {\n\t\tcode,\n\t\tzNumber: Number(r[1]),\n\t\tzDate: r[2],\n\t\tzTime: r[3],\n\t\tzStartDate: r[4],\n\t\tzStartTime: r[5],\n\t\tlastInvoiceNumber: Number(r[67]),\n\t\tlastInvoiceDate: r[68],\n\t\tlastInvoiceTime: r[69],\n\t\tlastCreditNoteNumber: Number(r[71]),\n\t\tlastDebitNoteNumber: Number(r[75]),\n\t\traw: r,\n\t};\n}\n\nexport async function getCounters(client: DtpClient) {\n\tconst r = await client.send([\"R9\"]);\n\tconst code = parseCode(r);\n\treturn {\n\t\tcode,\n\t\tlastInvoice: code === 0 && r.length >= 2 ? Number(r[1]) : -1,\n\t\tlastVoidedInvoice: code === 0 && r.length >= 3 ? Number(r[2]) : -1,\n\t\tlastCreditNote: code === 0 && r.length >= 4 ? Number(r[3]) : -1,\n\t\tlastDebitNote: code === 0 && r.length >= 5 ? Number(r[4]) : -1,\n\t\tlastNonFiscal: code === 0 && r.length >= 6 ? Number(r[5]) : -1,\n\t\tlastZReport: code === 0 && r.length >= 7 ? Number(r[6]) : -1,\n\t\traw: r,\n\t};\n}\n\nexport async function searchReprint(\n\tclient: DtpClient,\n\tdocumentType: number,\n\tdocumentNumber: number,\n\tprint = true,\n) {\n\tconst r = await client.send([\n\t\t\"R8\",\n\t\tprint ? \"1\" : \"0\",\n\t\tString(documentType),\n\t\tString(documentNumber),\n\t]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function startFiscalMemoryReportByDateRange(\n\tclient: DtpClient,\n\treportType: number,\n\tstartDate: Date,\n\tendDate: Date,\n) {\n\tconst r = await client.send([\n\t\t\"R2\",\n\t\t\"0\",\n\t\tString(reportType),\n\t\tformatDateDDMMYYYY(startDate),\n\t\tformatDateDDMMYYYY(endDate),\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\trecordCount: parseCode(r) === 0 && r.length >= 2 ? Number(r[1]) : -1,\n\t\traw: r,\n\t};\n}\n\nexport async function getFiscalMemoryReportData(client: DtpClient) {\n\tconst r = await client.send([\"R3\"]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function finishFiscalMemoryReport(client: DtpClient) {\n\tconst r = await client.send([\"R4\"]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function openNonFiscalDoc(client: DtpClient) {\n\tconst r = await client.send([\"N0\"]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function addNonFiscalLine(\n\tclient: DtpClient,\n\tline: string,\n\tsize = 0,\n\talign = 0,\n\tstyle = 0,\n) {\n\tconst r = await client.send([\n\t\t\"N1\",\n\t\tline,\n\t\tString(size),\n\t\tString(align),\n\t\tString(style),\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tprintedLines: parseCode(r) === 0 && r.length >= 2 ? Number(r[1]) : -1,\n\t\traw: r,\n\t};\n}\n\nexport async function closeNonFiscalDoc(client: DtpClient) {\n\tconst r = await client.send([\"N3\"]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tdocumentNumber: parseCode(r) === 0 && r.length >= 2 ? Number(r[1]) : -1,\n\t\traw: r,\n\t};\n}\n","import {\n\tPaymentMethodId,\n\tPrinterTaxValues,\n\tTaxValues,\n} from \"../../types/enums.js\";\nimport type { Order } from \"../../types/order.js\";\nimport type {\n\tBuildInvoiceOptions,\n\tBuildReceiptOptions,\n\tPrinterDriver,\n} from \"../printer.types.js\";\nimport type { DtpClient } from \"./dtp-client.js\";\nimport type { DtpPrinterCommand } from \"./dtp-commands.js\";\nimport {\n\taddFiscalItem,\n\taddNonFiscalLine,\n\tcloseFiscalDoc,\n\tcloseNonFiscalDoc,\n\topenFiscalDoc,\n\topenNonFiscalDoc,\n\tpayFiscalDoc,\n\tpayFiscalDocForeignCurrency,\n\tsubtotalFiscalDoc,\n} from \"./dtp-printer.js\";\n\nfunction truncateString(str: string, maxLength = 64): string {\n\tif (!str) return \"\";\n\treturn str.length > maxLength ? str.substring(0, maxLength) : str;\n}\n\nfunction formatDate(date: Date): string {\n\tconst day = date.getDate().toString().padStart(2, \"0\");\n\tconst month = (date.getMonth() + 1).toString().padStart(2, \"0\");\n\tconst year = date.getFullYear();\n\treturn `${day}/${month}/${year}`;\n}\n\nfunction formatTime(date: Date): string {\n\tconst hours = date.getHours().toString().padStart(2, \"0\");\n\tconst minutes = date.getMinutes().toString().padStart(2, \"0\");\n\treturn `${hours}:${minutes}`;\n}\n\n/**\n * Mapea taxId (IVA_G, EXENTO_E, etc.) a código DTP iImpuesto (0..4).\n * DTP: 0=exento, 1=16%, 2=8%, 3=31%, 4=percibido/IGTF.\n */\nfunction mapTaxIdToDtpCode(taxId: string | null | undefined): number {\n\tif (!taxId) return 0;\n\tconst taxIdUpper = taxId.toUpperCase();\n\tconst aegCode =\n\t\tPrinterTaxValues[taxIdUpper as keyof typeof PrinterTaxValues];\n\tif (aegCode === undefined) return 0;\n\tconst n = Number(aegCode);\n\t// DTP iImpuesto: 0=exento, 1=16%, 2=8%, 3=31%, 4=percibido\n\tif (n === PrinterTaxValues.EXENTO_E) return 0;\n\tif (n === PrinterTaxValues.BI_G || n === PrinterTaxValues.IVA_G)\n\t\treturn 1;\n\tif (n === PrinterTaxValues.BI_R || n === PrinterTaxValues.IVA_R)\n\t\treturn 2;\n\tif (n === PrinterTaxValues.BI_A || n === PrinterTaxValues.IVA_A)\n\t\treturn 3;\n\tif (\n\t\tn === PrinterTaxValues.PERCIBIDO ||\n\t\tn === PrinterTaxValues.BI_IGTF ||\n\t\tn === PrinterTaxValues.IVA_IGTF\n\t)\n\t\treturn 4;\n\treturn 0;\n}\n\nfunction mapPaymentMethod(method: string): PaymentMethodId {\n\tif (method === \"pos_debit\") return PaymentMethodId.POS_DEBIT;\n\tif (method === \"pos_credit\") return PaymentMethodId.POS_CREDIT;\n\tif (method === \"pos_debit_credit_int\")\n\t\treturn PaymentMethodId.POS_DEBIT_CREDIT_INT;\n\tif (method === \"cash_int\") return PaymentMethodId.CASH_INT;\n\tif (method === \"cash_nat\") return PaymentMethodId.CASH;\n\tthrow new Error(\n\t\t`Método de pago inválido: ${method}. Debe ser \"pos_debit\", \"pos_credit\", \"pos_debit_credit_int\", \"cash_int\" o \"cash_nat\"`,\n\t);\n}\n\nfunction paymentMethodLabel(id: PaymentMethodId): string {\n\tswitch (id) {\n\t\tcase PaymentMethodId.CASH:\n\t\t\treturn \"EFECTIVO\";\n\t\tcase PaymentMethodId.POS_DEBIT:\n\t\t\treturn \"TARJETA DEBITO\";\n\t\tcase PaymentMethodId.POS_CREDIT:\n\t\t\treturn \"TARJETA CREDITO\";\n\t\tcase PaymentMethodId.PAGO_MOVIL:\n\t\t\treturn \"PAGO MOVIL\";\n\t\tcase PaymentMethodId.POS_DEBIT_CREDIT_INT:\n\t\t\treturn \"TARJETA INT\";\n\t\tcase PaymentMethodId.CASH_INT:\n\t\t\treturn \"EFECTIVO USD\";\n\t\tdefault:\n\t\t\treturn \"EFECTIVO\";\n\t}\n}\n\n/**\n * Driver para impresora fiscal DTP-80i.\n * Construye comandos DTP compatibles con el protocolo TCP.\n */\nexport const dtpPrinter: PrinterDriver<DtpPrinterCommand> = {\n\tmodel: \"dtp-80i\",\n\n\tbuildInvoiceCommands(\n\t\torder: Order,\n\t\toptions: BuildInvoiceOptions,\n\t): DtpPrinterCommand[] {\n\t\tconst commands: DtpPrinterCommand[] = [];\n\n\t\tif (!order) {\n\t\t\tthrow new Error(\"Order es requerido\");\n\t\t}\n\t\tif (!order.client) {\n\t\t\tthrow new Error(\"Order debe tener un cliente asociado\");\n\t\t}\n\t\tif (!order.items || order.items.length === 0) {\n\t\t\tthrow new Error(\"Order debe tener al menos un item\");\n\t\t}\n\n\t\tconst { paymentMethodId, storeName = \"N/A\" } = options;\n\n\t\tconst clientName = order.client.name || \"\";\n\t\tconst clientRif = order.client.id || \"\";\n\t\tconst storeLine = `Tienda: ${storeName}`;\n\n\t\tcommands.push({\n\t\t\tcmd: \"F0\",\n\t\t\tdata: {\n\t\t\t\tsNombreCliente: truncateString(clientName, 64),\n\t\t\t\tsRifCliente: truncateString(clientRif, 20),\n\t\t\t\tbLogo: false,\n\t\t\t\tsLineaAdicional: truncateString(storeLine, 64),\n\t\t\t},\n\t\t});\n\n\t\tlet subtotalWithoutTaxes = 0;\n\n\t\tfor (const item of order.items) {\n\t\t\tif (!item.name) continue;\n\n\t\t\tconst taxId =\n\t\t\t\titem.taxes && item.taxes.length > 0 ? item.taxes[0].id : null;\n\t\t\tconst iImpuesto = mapTaxIdToDtpCode(taxId);\n\t\t\tconst price = item.price ?? 0;\n\t\t\tconst lPrecio = Math.round(Math.max(price, 0) * 100);\n\t\t\tconst quantity = item.selectedQuantity ?? item.quantity ?? 1;\n\t\t\tconst lCantidad = Math.round(Math.max(quantity, 1) * 1000);\n\n\t\t\tsubtotalWithoutTaxes += price * Math.max(quantity, 1);\n\n\t\t\tcommands.push({\n\t\t\t\tcmd: \"F1\",\n\t\t\t\tdata: {\n\t\t\t\t\tsDescripcion: truncateString(item.name, 64),\n\t\t\t\t\tsCodigo: truncateString(item.sku ?? \"N/A\", 20),\n\t\t\t\t\tlCantidad,\n\t\t\t\t\tsUnidad: \"UND\",\n\t\t\t\t\tlPrecio,\n\t\t\t\t\tiImpuesto,\n\t\t\t\t\tiDecPrecio: 2,\n\t\t\t\t\tiDecCantidad: 3,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tconst isForeignCurrency =\n\t\t\tpaymentMethodId === \"pos_debit_credit_int\" ||\n\t\t\tpaymentMethodId === \"cash_int\";\n\n\t\tif (isForeignCurrency && subtotalWithoutTaxes > 0) {\n\t\t\tconst roundedSubtotal =\n\t\t\t\tMath.round((subtotalWithoutTaxes + Number.EPSILON) * 100) / 100;\n\t\t\tconst igtfPercentage = TaxValues.BI_IGTF / 100;\n\t\t\tconst igtfAmount =\n\t\t\t\tMath.round((roundedSubtotal * igtfPercentage + Number.EPSILON) * 100) /\n\t\t\t\t100;\n\n\t\t\tcommands.push({\n\t\t\t\tcmd: \"F1\",\n\t\t\t\tdata: {\n\t\t\t\t\tsDescripcion: \"IGTF 3% pago en divisas\",\n\t\t\t\t\tsCodigo: \"IGTF\",\n\t\t\t\t\tlCantidad: 1000,\n\t\t\t\t\tsUnidad: \"UND\",\n\t\t\t\t\tlPrecio: Math.round(igtfAmount * 100),\n\t\t\t\t\tiImpuesto: 4,\n\t\t\t\t\tiDecPrecio: 2,\n\t\t\t\t\tiDecCantidad: 3,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tcommands.push({\n\t\t\tcmd: \"F2\",\n\t\t\tdata: { mode: 1, foreignCurrencyAmount: 0 },\n\t\t});\n\n\t\tif (!order.payments?.length) {\n\t\t\tthrow new Error(\"Order debe tener al menos un pago exitoso\");\n\t\t}\n\n\t\tfor (const payment of order.payments) {\n\t\t\tconst tipo = mapPaymentMethod(payment.paymentMethod);\n\t\t\tconst lMonto = Math.round(payment.amount * 100);\n\t\t\tconst isForeign =\n\t\t\t\tpayment.paymentMethod === \"pos_debit_credit_int\" ||\n\t\t\t\tpayment.paymentMethod === \"cash_int\";\n\n\t\t\tif (isForeign) {\n\t\t\t\tcommands.push({\n\t\t\t\t\tcmd: \"F11\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tiFormaPago: tipo,\n\t\t\t\t\t\tsDescripcion: paymentMethodLabel(tipo),\n\t\t\t\t\t\tlMonto,\n\t\t\t\t\t\tlTasaCambio: 1,\n\t\t\t\t\t\tsSimbolo: \"USD\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tcommands.push({\n\t\t\t\t\tcmd: \"F4\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tiFormaPago: tipo,\n\t\t\t\t\t\tsDescripcion: paymentMethodLabel(tipo),\n\t\t\t\t\t\tlMonto,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tcommands.push({ cmd: \"F5\", data: {} });\n\n\t\treturn commands;\n\t},\n\n\tbuildReceiptCommands(options: BuildReceiptOptions): DtpPrinterCommand[] {\n\t\tconst {\n\t\t\torderId,\n\t\t\tamountPaid,\n\t\t\tpaymentMethod,\n\t\t\tpaidAt,\n\t\t\tcardLast4,\n\t\t\torganizationName,\n\t\t} = options;\n\n\t\tif (!orderId) {\n\t\t\tthrow new Error(\"OrderId es requerido\");\n\t\t}\n\t\tif (!Number.isFinite(amountPaid) || amountPaid <= 0) {\n\t\t\tthrow new Error(\"Monto pagado inválido\");\n\t\t}\n\n\t\tconst paidDate = paidAt ?? new Date();\n\t\tconst lines = [\n\t\t\t\"RECIBO DE PAGO\",\n\t\t\torderId,\n\t\t\t\"Recibo de pago\",\n\t\t\torganizationName?.trim() || \"N/A\",\n\t\t\t`Bs ${amountPaid}`,\n\t\t\t`Medio de pago: ${paymentMethod}`,\n\t\t\t`Tarjeta ${cardLast4 ?? \"N/A\"}`,\n\t\t\t`Hora del pago: ${formatTime(paidDate)}`,\n\t\t\t`Fecha del pago: ${formatDate(paidDate)}`,\n\t\t\t\"Cierre del Documento No Fiscal\",\n\t\t];\n\n\t\tconst commands: DtpPrinterCommand[] = [{ cmd: \"N0\" }];\n\n\t\tfor (const line of lines) {\n\t\t\tcommands.push({\n\t\t\t\tcmd: \"N1\",\n\t\t\t\tdata: { line: truncateString(line, 64) },\n\t\t\t});\n\t\t}\n\n\t\tcommands.push({ cmd: \"N3\" });\n\n\t\treturn commands;\n\t},\n};\n\n/**\n * Resultado de ejecutar comandos DTP.\n * Incluye documentNumber y totalAmount cuando el último comando es F5 (cerrar factura).\n */\nexport interface ExecuteDtpCommandsResult {\n\tdocumentNumber?: number;\n\ttotalAmount?: number;\n}\n\n/**\n * Ejecuta una secuencia de comandos DTP contra un cliente conectado.\n * Lanza en el primer error.\n * Retorna documentNumber y totalAmount cuando se ejecuta F5 (cerrar factura).\n */\nexport async function executeDtpCommands(\n\tclient: DtpClient,\n\tcommands: DtpPrinterCommand[],\n): Promise<ExecuteDtpCommandsResult> {\n\tlet documentNumber: number | undefined;\n\tlet totalAmount: number | undefined;\n\tfor (const cmd of commands) {\n\t\tswitch (cmd.cmd) {\n\t\t\tcase \"F0\": {\n\t\t\t\tconst r = await openFiscalDoc(client, cmd.data);\n\t\t\t\tif (r.code !== 0) throw new Error(`F0 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"F1\": {\n\t\t\t\tconst r = await addFiscalItem(client, cmd.data);\n\t\t\t\tif (r.code !== 0) throw new Error(`F1 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"F2\": {\n\t\t\t\tconst r = await subtotalFiscalDoc(\n\t\t\t\t\tclient,\n\t\t\t\t\tcmd.data?.mode ?? 1,\n\t\t\t\t\tcmd.data?.foreignCurrencyAmount ?? 0,\n\t\t\t\t);\n\t\t\t\tif (r.code !== 0) throw new Error(`F2 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"F4\": {\n\t\t\t\tconst r = await payFiscalDoc(client, cmd.data);\n\t\t\t\tif (r.code !== 0) throw new Error(`F4 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"F5\": {\n\t\t\t\tconst r = await closeFiscalDoc(client, cmd.data?.additionalLine ?? \"\");\n\t\t\t\tif (r.code !== 0) throw new Error(`F5 falló: código ${r.code}`);\n\t\t\t\tdocumentNumber = r.documentNumber;\n\t\t\t\ttotalAmount = r.totalAmount;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"F11\": {\n\t\t\t\tconst r = await payFiscalDocForeignCurrency(client, cmd.data);\n\t\t\t\tif (r.code !== 0)\n\t\t\t\t\tthrow new Error(`F11 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"N0\": {\n\t\t\t\tconst r = await openNonFiscalDoc(client);\n\t\t\t\tif (r.code !== 0) throw new Error(`N0 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"N1\": {\n\t\t\t\tconst r = await addNonFiscalLine(\n\t\t\t\t\tclient,\n\t\t\t\t\tcmd.data.line,\n\t\t\t\t\tcmd.data.size ?? 0,\n\t\t\t\t\tcmd.data.align ?? 0,\n\t\t\t\t\tcmd.data.style ?? 0,\n\t\t\t\t);\n\t\t\t\tif (r.code !== 0) throw new Error(`N1 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"N3\": {\n\t\t\t\tconst r = await closeNonFiscalDoc(client);\n\t\t\t\tif (r.code !== 0) throw new Error(`N3 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tconst _: never = cmd;\n\t\t\t\tthrow new Error(`Comando DTP desconocido: ${String((cmd as { cmd: string }).cmd)}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn { documentNumber, totalAmount };\n}\n","import type {\n\tPrinterCommandResponse,\n\tPrinterResponse,\n\tSendPrinterCommandsAeg,\n\tSendPrinterCommandsArgs,\n} from \"./types.js\";\n\nfunction normalizeBaseUrl(address: string): string {\n\tconst trimmed = address.trim();\n\tif (!trimmed) return trimmed;\n\tconst withProtocol = /^https?:\\/\\//i.test(trimmed)\n\t\t? trimmed\n\t\t: `http://${trimmed}`;\n\treturn withProtocol.replace(/\\/+$/, \"\");\n}\n\n/**\n * Envía comandos a una impresora fiscal.\n *\n * - **AEG-R1**: POST HTTP a {ip}/cmdoJson con body = commands (JSON)\n * - **DTP-80i**: No soportado en esta librería (usa TCP vía módulo nativo).\n * El consumidor debe usar ExpoDtpFiscalPrinter directamente.\n */\nexport async function sendPrinterCommands(\n\targs: SendPrinterCommandsArgs,\n\toptions?: { timeout?: number },\n): Promise<PrinterResponse> {\n\tconst { brand, model, commands } = args;\n\n\tif (!commands || commands.length === 0) {\n\t\tthrow new Error(\"No hay comandos para enviar\");\n\t}\n\n\tswitch (brand) {\n\t\tcase \"AEG\":\n\t\t\tif (model !== \"R1\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Modelo inválido para AEG: \"${model}\". Solo se soporta \"R1\".`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn sendAegCommands(args as SendPrinterCommandsAeg, options);\n\t\tcase \"DTP\":\n\t\t\tif (model !== \"80i\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Modelo inválido para DTP: \"${model}\". Solo se soporta \"80i\".`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t\"DTP-80i requiere el módulo nativo ExpoDtpFiscalPrinter. \" +\n\t\t\t\t\t\"Use la conexión TCP directamente desde su aplicación.\",\n\t\t\t);\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = brand;\n\t\t\tthrow new Error(\n\t\t\t\t`Marca de impresora no soportada: ${String(_exhaustive)}`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nasync function sendAegCommands(\n\targs: SendPrinterCommandsAeg,\n\toptions?: { timeout?: number },\n): Promise<PrinterResponse> {\n\tconst { ip, commands } = args;\n\tconst baseUrl = normalizeBaseUrl(ip);\n\tconst url = `${baseUrl}/cmdoJson`;\n\tconst controller = new AbortController();\n\tconst timeoutId =\n\t\toptions?.timeout != null\n\t\t\t? setTimeout(() => controller.abort(), options.timeout)\n\t\t\t: undefined;\n\n\ttry {\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(commands),\n\t\t\tsignal: controller.signal,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Error HTTP ${response.status}: ${response.statusText}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as unknown;\n\n\t\tif (!Array.isArray(data)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Respuesta inválida de la impresora: se esperaba un array, se recibió ${typeof data}`,\n\t\t\t);\n\t\t}\n\n\t\tconst result = data as PrinterCommandResponse[];\n\n\t\tconst failedCommands: PrinterCommandResponse[] = [];\n\t\tfor (const commandResponse of result) {\n\t\t\tconst codeValue =\n\t\t\t\ttypeof commandResponse.code === \"string\"\n\t\t\t\t\t? Number.parseInt(commandResponse.code, 10)\n\t\t\t\t\t: commandResponse.code;\n\n\t\t\tif (Number.isNaN(codeValue) || codeValue !== 0) {\n\t\t\t\tfailedCommands.push(commandResponse);\n\t\t\t}\n\t\t}\n\n\t\tif (failedCommands.length > 0) {\n\t\t\tconst errorMessages = failedCommands\n\t\t\t\t.map(\n\t\t\t\t\t(cmd) =>\n\t\t\t\t\t\t`Comando ${cmd.cmd}: código ${cmd.code}${cmd.message ? ` - ${cmd.message}` : \"\"}`,\n\t\t\t\t)\n\t\t\t\t.join(\"; \");\n\t\t\tthrow new Error(\n\t\t\t\t`Error en la impresora: ${failedCommands.length} comando(s) fallaron. ${errorMessages}`,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t} catch (error) {\n\t\tif (error instanceof Error) {\n\t\t\tif (error.name === \"AbortError\") {\n\t\t\t\tthrow new Error(\"Timeout al enviar comandos a la impresora\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new Error(\"Error desconocido al enviar comandos a la impresora\");\n\t} finally {\n\t\tif (timeoutId) clearTimeout(timeoutId);\n\t}\n}\n"],"mappings":"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","names":["TaxValues","PrinterTaxValues","PaymentMethodId","truncateString","formatDate","formatTime","mapPaymentMethod"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/printers/dtp/dtp-client.ts","../src/types/enums.ts","../src/printers/aeg/aeg-printer.ts","../src/printers/dtp/dtp-printer.ts","../src/printers/dtp/dtp-printer-driver.ts","../src/runner/send-printer-commands.ts"],"sourcesContent":["/**\n * cafe-ipdh-lib\n * Librería para gestionar impresoras fiscales y de recibos.\n *\n * Soporta:\n * - AEG-R1: impresora fiscal vía HTTP (comandos JSON)\n *\n * Uso:\n * ```ts\n * import { aegPrinter } from \"cafe-ipdh-lib\";\n *\n * const commands = aegPrinter.buildInvoiceCommands(order, {\n * paymentMethodId: \"pos_credit\",\n * storeName: \"Mi Tienda\"\n * });\n * // Enviar commands a la impresora vía tu API/transport\n * ```\n */\n\nexport type {\n\tBuildInvoiceOptions,\n\tBuildReceiptOptions,\n\tCreateDtpConnection,\n\tDocumentType,\n\tDtpOptions,\n\tDtpPrinterCommand,\n\tDtpSocketLike,\n\tExecuteDtpCommandsResult,\n\tPrinterCommandResponse,\n\tPrinterDriver,\n} from \"./printers/index.js\";\nexport { DtpClient } from \"./printers/dtp/dtp-client.js\";\nexport {\n\taegPrinter,\n\tdtpPrinter,\n\texecuteDtpCommands,\n} from \"./printers/index.js\";\nexport type {\n\tAegModel,\n\tDtpModel,\n\tPrinterBrand,\n\tSendPrinterCommandsAeg,\n\tSendPrinterCommandsArgs,\n\tSendPrinterCommandsDtp,\n} from \"./runner/index.js\";\nexport { sendPrinterCommands } from \"./runner/index.js\";\nexport type {\n\tAegPrinterCommand,\n\tFiscalClient,\n\tItemTax,\n\tOrder,\n\tOrderItem,\n\tOrderPayment,\n} from \"./types/index.js\";\nexport {\n\tPaymentMethodId,\n\tPrinterTaxValues,\n\tTaxValues,\n} from \"./types/index.js\";\n","import type { CreateDtpConnection, DtpSocketLike } from \"./dtp-transport.types.js\";\n\nconst STX = 0x02;\nconst ETX = 0x03;\nconst FS = 0x1c;\n\nexport type DtpOptions = {\n\thost: string;\n\tport: number;\n\tconnectTimeoutMs?: number;\n\tcommandTimeoutMs?: number;\n\t/** Factory para crear la conexión TCP. Requerido. En Node usa createNodeDtpConnection; en RN usa react-native-tcp-socket. */\n\tcreateConnection: CreateDtpConnection;\n};\n\nexport class DtpClient {\n\tprivate socket: DtpSocketLike | null = null;\n\tprivate buffer = Buffer.alloc(0);\n\tprivate pending: {\n\t\tresolve: (v: string[]) => void;\n\t\treject: (e: Error) => void;\n\t\ttimer: ReturnType<typeof setTimeout>;\n\t} | null = null;\n\n\tconstructor(private opts: DtpOptions) {}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.socket) return;\n\n\t\tconst timeoutMs = this.opts.connectTimeoutMs ?? 3000;\n\n\t\tconst socket = await Promise.race([\n\t\t\tthis.opts.createConnection({\n\t\t\t\thost: this.opts.host,\n\t\t\t\tport: this.opts.port,\n\t\t\t}),\n\t\t\tnew Promise<never>((_, reject) =>\n\t\t\t\tsetTimeout(() => reject(new Error(\"Connect timeout\")), timeoutMs),\n\t\t\t),\n\t\t]);\n\n\t\tthis.socket = socket;\n\n\t\tsocket.on(\"data\", (chunk: Buffer | Uint8Array) =>\n\t\t\tthis.onData(chunk instanceof Buffer ? chunk : Buffer.from(chunk)),\n\t\t);\n\t\tsocket.on(\"error\", (e) => this.onError(e));\n\t\tsocket.on(\"close\", () => this.onClose());\n\t}\n\n\tclose(): void {\n\t\tthis.socket?.end();\n\t\tthis.socket = null;\n\t\tthis.buffer = Buffer.alloc(0);\n\t}\n\n\tasync send(parts: string[]): Promise<string[]> {\n\t\tif (!this.socket) throw new Error(\"Socket not connected\");\n\n\t\tif (this.pending) throw new Error(\"Another command is in-flight\");\n\n\t\tconst frame = this.buildFrame(parts);\n\t\tconst timeoutMs = this.opts.commandTimeoutMs ?? 10_000;\n\n\t\treturn await new Promise<string[]>((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tthis.pending = null;\n\t\t\t\treject(new Error(`Command timeout: ${parts[0]}`));\n\t\t\t}, timeoutMs);\n\n\t\t\tthis.pending = { resolve, reject, timer };\n\n\t\t\tthis.socket?.write(frame);\n\t\t});\n\t}\n\n\tprivate buildFrame(parts: string[]): Buffer {\n\t\tconst payload = Buffer.from(parts.join(String.fromCharCode(FS)), \"utf8\");\n\t\treturn Buffer.concat([Buffer.from([STX]), payload, Buffer.from([ETX])]);\n\t}\n\n\tprivate tryParseOneFrame(): string[] | null {\n\t\tconst start = this.buffer.indexOf(STX);\n\t\tconst end = this.buffer.indexOf(ETX, start + 1);\n\n\t\tif (start === -1 || end === -1) return null;\n\n\t\tconst body = this.buffer.subarray(start + 1, end);\n\n\t\tthis.buffer = this.buffer.subarray(end + 1);\n\n\t\tconst params = body.toString(\"utf8\").split(String.fromCharCode(FS));\n\t\treturn params;\n\t}\n\n\tprivate onData(chunk: Buffer) {\n\t\tthis.buffer = Buffer.concat([this.buffer, chunk]);\n\n\t\tconst params = this.tryParseOneFrame();\n\t\tif (!params) return;\n\n\t\tif (!this.pending) return;\n\n\t\tconst { resolve, timer } = this.pending;\n\t\tclearTimeout(timer);\n\t\tthis.pending = null;\n\n\t\tresolve(params);\n\t}\n\n\tprivate onError(e: Error) {\n\t\tif (this.pending) {\n\t\t\tconst { reject, timer } = this.pending;\n\t\t\tclearTimeout(timer);\n\t\t\tthis.pending = null;\n\t\t\treject(e);\n\t\t}\n\t}\n\n\tprivate onClose() {\n\t\tif (this.pending) {\n\t\t\tconst { reject, timer } = this.pending;\n\t\t\tclearTimeout(timer);\n\t\t\tthis.pending = null;\n\t\t\treject(new Error(\"Socket closed\"));\n\t\t}\n\t}\n}\n","/**\n * Valores de impuestos (porcentajes) según legislación venezolana.\n */\nexport enum TaxValues {\n\tEXENTO_E = 0,\n\tBI_G = 16.0,\n\tIVA_G = 16.0,\n\tBI_R = 8.0,\n\tIVA_R = 8.0,\n\tBI_A = 31.0,\n\tIVA_A = 31.0,\n\tPERCIBIDO = 0,\n\tBI_IGTF = 3.0,\n\tIVA_IGTF = 3.0,\n}\n\n/**\n * Códigos de impuesto para impresora fiscal AEG-R1.\n */\nexport enum PrinterTaxValues {\n\tEXENTO_E = 1,\n\tBI_G = 2,\n\tIVA_G = 2,\n\tBI_R = 3,\n\tIVA_R = 3,\n\tBI_A = 4,\n\tIVA_A = 4,\n\tPERCIBIDO = 5,\n\tBI_IGTF = 5,\n\tIVA_IGTF = 5,\n}\n\n/**\n * IDs de método de pago para impresora fiscal AEG-R1.\n * Efectivo: 1, Débito: 2, Crédito: 3, Pago Móvil: 5,\n * Débito/Crédito int: 11, Efectivo int: 12\n */\nexport enum PaymentMethodId {\n\tCASH = 1,\n\tPOS_DEBIT = 2,\n\tPOS_CREDIT = 3,\n\tPAGO_MOVIL = 5,\n\tPOS_DEBIT_CREDIT_INT = 11,\n\tCASH_INT = 12,\n}\n","import type { AegPrinterCommand } from \"../../types/aeg-commands.js\";\nimport {\n\tPaymentMethodId,\n\tPrinterTaxValues,\n\tTaxValues,\n} from \"../../types/enums.js\";\nimport type { Order } from \"../../types/order.js\";\nimport type {\n\tBuildInvoiceOptions,\n\tBuildReceiptOptions,\n\tPrinterDriver,\n} from \"../printer.types.js\";\n\nfunction truncateString(str: string, maxLength = 64): string {\n\tif (!str) return \"\";\n\treturn str.length > maxLength ? str.substring(0, maxLength) : str;\n}\n\n// biome-ignore lint: avoid control char in literal\nconst ISO_8859_1_REGEX = new RegExp(\"[^\\\\u0000-\\\\u00FF]\", \"g\");\n\nfunction normalizeIso88591(str: string): string {\n\treturn str.replace(ISO_8859_1_REGEX, \"?\");\n}\n\nfunction formatDate(date: Date): string {\n\tconst day = date.getDate().toString().padStart(2, \"0\");\n\tconst month = (date.getMonth() + 1).toString().padStart(2, \"0\");\n\tconst year = date.getFullYear();\n\treturn `${day}/${month}/${year}`;\n}\n\nfunction formatTime(date: Date): string {\n\tconst hours = date.getHours().toString().padStart(2, \"0\");\n\tconst minutes = date.getMinutes().toString().padStart(2, \"0\");\n\treturn `${hours}:${minutes}`;\n}\n\nfunction mapTaxIdToPrinterCode(taxId: string | null | undefined): number {\n\tif (!taxId) {\n\t\treturn PrinterTaxValues.EXENTO_E;\n\t}\n\tconst taxIdUpper = taxId.toUpperCase();\n\tconst printerTaxValue =\n\t\tPrinterTaxValues[taxIdUpper as keyof typeof PrinterTaxValues];\n\tif (printerTaxValue !== undefined) {\n\t\treturn printerTaxValue;\n\t}\n\treturn PrinterTaxValues.EXENTO_E;\n}\n\nfunction mapPaymentMethod(method: string): PaymentMethodId {\n\tif (method === \"pos_debit\") return PaymentMethodId.POS_DEBIT;\n\tif (method === \"pos_credit\") return PaymentMethodId.POS_CREDIT;\n\tif (method === \"pos_debit_credit_int\")\n\t\treturn PaymentMethodId.POS_DEBIT_CREDIT_INT;\n\tif (method === \"cash_int\") return PaymentMethodId.CASH_INT;\n\tif (method === \"cash_nat\") return PaymentMethodId.CASH;\n\tthrow new Error(\n\t\t`Método de pago inválido: ${method}. Debe ser \"pos_debit\", \"pos_credit\", \"pos_debit_credit_int\", \"cash_int\" o \"cash_nat\"`,\n\t);\n}\n\n/**\n * Driver para impresora fiscal AEG-R1.\n * Construye comandos JSON según documentación oficial.\n */\nexport const aegPrinter: PrinterDriver<AegPrinterCommand> = {\n\tmodel: \"aeg-r1\",\n\n\tbuildInvoiceCommands(\n\t\torder: Order,\n\t\toptions: BuildInvoiceOptions,\n\t): AegPrinterCommand[] {\n\t\tconst commands: AegPrinterCommand[] = [];\n\n\t\tif (!order) {\n\t\t\tthrow new Error(\"Order es requerido\");\n\t\t}\n\t\tif (!order.client) {\n\t\t\tthrow new Error(\"Order debe tener un cliente asociado\");\n\t\t}\n\t\tif (!order.items || order.items.length === 0) {\n\t\t\tthrow new Error(\"Order debe tener al menos un item\");\n\t\t}\n\n\t\tconst { paymentMethodId, storeName = \"N/A\" } = options;\n\n\t\t// 1. cliF - Datos del cliente\n\t\tconst clientRifCI = order.client.id || \"\";\n\t\tconst clientName = order.client.name || \"\";\n\t\tconst clientEmail = order.client.email || \"\";\n\t\tconst clientPhone = order.client.phone || \"\";\n\t\tconst clientAddress = order.client.address || \"\";\n\t\tconst razSoc = [clientName, clientEmail, clientPhone]\n\t\t\t.filter(Boolean)\n\t\t\t.map((v) => truncateString(v, 64));\n\t\tconst storeLine = `Tienda: ${storeName}`;\n\t\tconst LineAd = [storeLine, clientAddress]\n\t\t\t.filter(Boolean)\n\t\t\t.map((v) => truncateString(v, 64));\n\n\t\tcommands.push({\n\t\t\tcmd: \"cliF\",\n\t\t\tdata: { rifCI: clientRifCI, razSoc, LineAd },\n\t\t});\n\n\t\t// 2. proF - Productos\n\t\tlet subtotalWithoutTaxes = 0;\n\n\t\tfor (const item of order.items) {\n\t\t\tif (!item.name) continue;\n\n\t\t\tconst taxId =\n\t\t\t\titem.taxes && item.taxes.length > 0 ? item.taxes[0].id : null;\n\t\t\tconst imp = mapTaxIdToPrinterCode(taxId);\n\t\t\tconst price = item.price || 0;\n\t\t\tconst pre = Math.round(Math.max(price, 0) * 100);\n\t\t\tconst quantity = item.selectedQuantity ?? item.quantity ?? 1;\n\t\t\tconst cant = Math.round(Math.max(quantity, 1) * 1000);\n\t\t\tconst des01 = truncateString(item.name, 64);\n\n\t\t\tsubtotalWithoutTaxes += price * Math.max(quantity, 1);\n\n\t\t\tcommands.push({\n\t\t\t\tcmd: \"proF\",\n\t\t\t\tdata: { imp, pre, cant, des01 },\n\t\t\t});\n\t\t}\n\n\t\t// 2.1 IGTF si pago en divisas\n\t\tconst isForeignCurrency =\n\t\t\tpaymentMethodId === \"pos_debit_credit_int\" ||\n\t\t\tpaymentMethodId === \"cash_int\";\n\n\t\tif (isForeignCurrency && subtotalWithoutTaxes > 0) {\n\t\t\tconst roundedSubtotal =\n\t\t\t\tMath.round((subtotalWithoutTaxes + Number.EPSILON) * 100) / 100;\n\t\t\tconst igtfPercentage = TaxValues.BI_IGTF / 100;\n\t\t\tconst igtfAmount =\n\t\t\t\tMath.round((roundedSubtotal * igtfPercentage + Number.EPSILON) * 100) /\n\t\t\t\t100;\n\n\t\t\tcommands.push({\n\t\t\t\tcmd: \"proF\",\n\t\t\t\tdata: {\n\t\t\t\t\timp: PrinterTaxValues.PERCIBIDO,\n\t\t\t\t\tpre: Math.round(igtfAmount * 100),\n\t\t\t\t\tcant: 1000,\n\t\t\t\t\tdes01: \"IGTF 3% pago en divisas\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// 3. subToF - Subtotal\n\t\tcommands.push({ cmd: \"subToF\", data: 1, valor: 0 });\n\n\t\t// 4. fpaF - Forma de pago\n\t\tif (!order.payments?.length) {\n\t\t\tthrow new Error(\"Order debe tener al menos un pago exitoso\");\n\t\t}\n\n\t\tfor (const payment of order.payments) {\n\t\t\tconst paymentType = mapPaymentMethod(payment.paymentMethod);\n\t\t\tconst paymentAmount = Math.round(payment.amount * 100);\n\t\t\tcommands.push({\n\t\t\t\tcmd: \"fpaF\",\n\t\t\t\tdata: {\n\t\t\t\t\ttipo: paymentType,\n\t\t\t\t\tmonto: paymentAmount,\n\t\t\t\t\ttasaConv: 0,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// 5. endFac - Cierre\n\t\tcommands.push({ cmd: \"endFac\", data: 1 });\n\n\t\treturn commands;\n\t},\n\n\tbuildReceiptCommands(options: BuildReceiptOptions): AegPrinterCommand[] {\n\t\tconst {\n\t\t\torderId,\n\t\t\tamountPaid,\n\t\t\tpaymentMethod,\n\t\t\tpaidAt,\n\t\t\tcardLast4,\n\t\t\torganizationName,\n\t\t} = options;\n\n\t\tif (!orderId) {\n\t\t\tthrow new Error(\"OrderId es requerido\");\n\t\t}\n\t\tif (!Number.isFinite(amountPaid) || amountPaid <= 0) {\n\t\t\tthrow new Error(\"Monto pagado inválido\");\n\t\t}\n\n\t\tconst paidDate = paidAt ?? new Date();\n\t\tconst amountLabel = `Bs ${amountPaid}`;\n\t\tconst paymentLabel = `Medio de pago: ${paymentMethod}`;\n\t\tconst dateLabel = `Fecha del pago: ${formatDate(paidDate)}`;\n\t\tconst timeLabel = `Hora del pago: ${formatTime(paidDate)}`;\n\t\tconst cardLabel = `Tarjeta ${cardLast4 ?? \"N/A\"}`;\n\t\tconst orgLabel = organizationName?.trim() || \"N/A\";\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tcmd: \"encDNF\",\n\t\t\t\tdata: [\n\t\t\t\t\tnormalizeIso88591(truncateString(\"RECIBO DE PAGO\")),\n\t\t\t\t\tnormalizeIso88591(truncateString(orderId)),\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"aperDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(\"Recibo de pago\")),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"efeNorJuIzDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(orgLabel)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"efeNorJuIzDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(amountLabel)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"efeNorJuIzDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(paymentLabel)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"efeNorJuIzDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(cardLabel)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"efeNorJuIzDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(timeLabel)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"efeNorJuIzDNF\",\n\t\t\t\tdata: normalizeIso88591(truncateString(dateLabel)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tcmd: \"endDNF\",\n\t\t\t\tdata: normalizeIso88591(\"Cierre del Documento No Fiscal\"),\n\t\t\t},\n\t\t];\n\t},\n};\n","import type { DtpClient } from \"./dtp-client\";\nimport type { AbrirCfArgs, ItemCfArgs, PagoCfArgs } from \"./dtp-printer.types\";\n\nconst formatDateDDMMYYYY = (d: Date) => {\n\tconst dd = String(d.getDate()).padStart(2, \"0\");\n\tconst mm = String(d.getMonth() + 1).padStart(2, \"0\");\n\tconst yyyy = String(d.getFullYear());\n\treturn `${dd}${mm}${yyyy}`;\n};\n\nfunction parseCode(r: string[], idx = 0): number {\n\tconst v = r[idx];\n\tconst n = Number(v);\n\treturn v !== undefined && v !== null && !Number.isNaN(n) ? n : 16;\n}\n\n// C0 Get Status (used as \"real ping\")\nexport async function getStatus(client: DtpClient) {\n\tconst r = await client.send([\"C0\"]);\n\tconst code = parseCode(r);\n\treturn {\n\t\tcode,\n\t\tstate: code === 0 && r.length > 2 ? Number(r[2] ?? -1) : -1,\n\t\tblock: code === 0 && r.length > 3 ? Number(r[3] ?? -1) : -1,\n\t\tfiscalStatus: code === 0 && r.length > 4 ? String(r[4] ?? \"\") : \"\",\n\t\tlastCommandResponse:\n\t\t\tcode === 0 && r.length > 5 ? Number(r[5] ?? -1) : -1,\n\t\traw: r,\n\t};\n}\n\nexport async function openFiscalDoc(client: DtpClient, args: AbrirCfArgs) {\n\tconst r = await client.send([\n\t\t\"F0\",\n\t\tString(args.iTipo ?? 0),\n\t\targs.sNombreCliente,\n\t\targs.sRifCliente,\n\t\tString(args.iFacturaReferencia ?? 0),\n\t\tformatDateDDMMYYYY(args.fechaReferencia ?? new Date()),\n\t\targs.sSerialReferencia ?? \"\",\n\t\t(args.bLogo ?? false) ? \"1\" : \"0\",\n\t\targs.sLineaAdicional ?? \"\",\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tdocumentNumber: Number(r[1] ?? -1),\n\t\traw: r,\n\t};\n}\n\nexport async function addFiscalItem(client: DtpClient, args: ItemCfArgs) {\n\tconst r = await client.send([\n\t\t\"F1\",\n\t\tString(args.iTipo ?? 0),\n\t\targs.sDescripcion,\n\t\targs.sCodigo,\n\t\tString(args.lCantidad),\n\t\targs.sUnidad,\n\t\tString(args.lPrecio),\n\t\tString(args.iImpuesto),\n\t\tString(args.iDecPrecio),\n\t\tString(args.iDecCantidad),\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\titemCount: Number(r[1] ?? -1),\n\t\ttotalItem: Number(r[2] ?? -1),\n\t\tprintedLines: Number(r[3] ?? -1),\n\t\traw: r,\n\t};\n}\n\nexport async function subtotalFiscalDoc(\n\tclient: DtpClient,\n\tmode = 0,\n\tforeignCurrencyAmount = 0,\n) {\n\tconst r = await client.send([\n\t\t\"F2\",\n\t\tString(mode),\n\t\tString(foreignCurrencyAmount),\n\t]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function payFiscalDoc(client: DtpClient, args: PagoCfArgs) {\n\tconst r = await client.send([\n\t\t\"F4\",\n\t\tString(args.iTipoPago ?? 0),\n\t\tString(args.iFormaPago),\n\t\targs.sDescripcion,\n\t\tString(args.lMonto),\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tamountDue: Number(r[1] ?? -1),\n\t\tchangeAmount: Number(r[2] ?? -1),\n\t\tprintedLines: Number(r[3] ?? -1),\n\t\traw: r,\n\t};\n}\n\nexport async function addFiscalComment(\n\tclient: DtpClient,\n\tcomment: string,\n\tsize = 0,\n\talign = 0,\n\tstyle = 0,\n) {\n\tconst r = await client.send([\n\t\t\"F7\",\n\t\tcomment,\n\t\tString(size),\n\t\tString(align),\n\t\tString(style),\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tprintedLines: Number(r[1] ?? -1),\n\t\traw: r,\n\t};\n}\n\nexport async function closeFiscalDoc(\n\tclient: DtpClient,\n\tadditionalLine = \"\",\n) {\n\tconst r = await client.send([\"F5\", additionalLine]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tdocumentNumber: Number(r[1] ?? -1),\n\t\ttotalAmount: Number(r[2] ?? -1),\n\t\traw: r,\n\t};\n}\n\nexport async function cancelFiscalDoc(client: DtpClient) {\n\tconst r = await client.send([\"F6\"]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function getSerializationData(client: DtpClient) {\n\tconst r = await client.send([\"C2\"]);\n\tconst code = parseCode(r);\n\treturn {\n\t\tcode,\n\t\tfiscalSerial: code === 0 && r.length >= 2 ? r[1] : \"\",\n\t\tprinterSerial: code === 0 && r.length >= 3 ? r[2] : \"\",\n\t\tkitSerial: code === 0 && r.length >= 4 ? r[3] : \"\",\n\t\tmfSerial: code === 0 && r.length >= 5 ? r[4] : \"\",\n\t\tmaSerial: code === 0 && r.length >= 6 ? r[5] : \"\",\n\t\traw: r,\n\t};\n}\n\nexport async function getFiscalizationData(client: DtpClient) {\n\tconst r = await client.send([\"C3\"]);\n\tconst code = parseCode(r);\n\treturn {\n\t\tcode,\n\t\ttaxpayerName: code === 0 && r.length >= 2 ? r[1] : \"\",\n\t\tfiscalAddress: code === 0 && r.length >= 3 ? r[2] : \"\",\n\t\ttaxpayerRif: code === 0 && r.length >= 4 ? r[3] : \"\",\n\t\tcommercialName: code === 0 && r.length >= 5 ? r[4] : \"\",\n\t\tdistributorName: code === 0 && r.length >= 6 ? r[5] : \"\",\n\t\tdistributorRif: code === 0 && r.length >= 7 ? r[6] : \"\",\n\t\ttaxRate1: code === 0 && r.length >= 8 ? Number(r[7]) : 0,\n\t\ttaxRate2: code === 0 && r.length >= 9 ? Number(r[8]) : 0,\n\t\ttaxRate3: code === 0 && r.length >= 10 ? Number(r[9]) : 0,\n\t\ttaxRate4: code === 0 && r.length >= 11 ? Number(r[10]) : 0,\n\t\traw: r,\n\t};\n}\n\nexport async function getPaymentMethod(\n\tclient: DtpClient,\n\tpaymentMethodId: number,\n) {\n\tconst r = await client.send([\"C9\", String(paymentMethodId)]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tname: parseCode(r) === 0 && r.length >= 2 ? r[1] : \"\",\n\t\traw: r,\n\t};\n}\n\nexport async function setPaymentMethod(\n\tclient: DtpClient,\n\tpaymentMethodId: number,\n\tname: string,\n) {\n\tconst r = await client.send([\"C10\", String(paymentMethodId), name]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function payFiscalDocForeignCurrency(\n\tclient: DtpClient,\n\targs: {\n\t\tiFormaPago: number;\n\t\tsDescripcion: string;\n\t\tlMonto: number;\n\t\tlTasaCambio: number;\n\t\tsSimbolo: string;\n\t},\n) {\n\tconst r = await client.send([\n\t\t\"F11\",\n\t\t\"0\",\n\t\targs.sDescripcion,\n\t\tString(args.lMonto),\n\t\tString(args.lTasaCambio),\n\t\targs.sSimbolo,\n\t\tString(args.iFormaPago),\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tamountDue: Number(r[1] ?? -1),\n\t\tchangeAmount: Number(r[2] ?? -1),\n\t\tprintedLines: Number(r[3] ?? -1),\n\t\traw: r,\n\t};\n}\n\nexport async function reportX(\n\tclient: DtpClient,\n\tnoOpenDrawer = false,\n) {\n\tconst parts = [\"R0\", \"0\"];\n\tif (noOpenDrawer) parts.push(\"1\");\n\tconst r = await client.send(parts);\n\tconst code = parseCode(r);\n\treturn {\n\t\tcode,\n\t\tdocumentNumber: code === 0 && r.length >= 2 ? Number(r[1]) : -1,\n\t\traw: r,\n\t};\n}\n\nexport async function reportZ(\n\tclient: DtpClient,\n\tnoOpenDrawer = false,\n) {\n\tconst parts = [\"R0\", \"1\"];\n\tif (noOpenDrawer) parts.push(\"1\");\n\tconst r = await client.send(parts);\n\tconst code = parseCode(r);\n\treturn {\n\t\tcode,\n\t\treportNumber: code === 0 && r.length >= 2 ? Number(r[1]) : -1,\n\t\traw: r,\n\t};\n}\n\nexport async function getFiscalDayInfo(client: DtpClient) {\n\tconst r = await client.send([\"R1\"]);\n\tconst code = parseCode(r);\n\tif (code !== 0 || r.length < 84) {\n\t\treturn { code, raw: r };\n\t}\n\treturn {\n\t\tcode,\n\t\tzNumber: Number(r[1]),\n\t\tzDate: r[2],\n\t\tzTime: r[3],\n\t\tzStartDate: r[4],\n\t\tzStartTime: r[5],\n\t\tlastInvoiceNumber: Number(r[67]),\n\t\tlastInvoiceDate: r[68],\n\t\tlastInvoiceTime: r[69],\n\t\tlastCreditNoteNumber: Number(r[71]),\n\t\tlastDebitNoteNumber: Number(r[75]),\n\t\traw: r,\n\t};\n}\n\nexport async function getCounters(client: DtpClient) {\n\tconst r = await client.send([\"R9\"]);\n\tconst code = parseCode(r);\n\treturn {\n\t\tcode,\n\t\tlastInvoice: code === 0 && r.length >= 2 ? Number(r[1]) : -1,\n\t\tlastVoidedInvoice: code === 0 && r.length >= 3 ? Number(r[2]) : -1,\n\t\tlastCreditNote: code === 0 && r.length >= 4 ? Number(r[3]) : -1,\n\t\tlastDebitNote: code === 0 && r.length >= 5 ? Number(r[4]) : -1,\n\t\tlastNonFiscal: code === 0 && r.length >= 6 ? Number(r[5]) : -1,\n\t\tlastZReport: code === 0 && r.length >= 7 ? Number(r[6]) : -1,\n\t\traw: r,\n\t};\n}\n\nexport async function searchReprint(\n\tclient: DtpClient,\n\tdocumentType: number,\n\tdocumentNumber: number,\n\tprint = true,\n) {\n\tconst r = await client.send([\n\t\t\"R8\",\n\t\tprint ? \"1\" : \"0\",\n\t\tString(documentType),\n\t\tString(documentNumber),\n\t]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function startFiscalMemoryReportByDateRange(\n\tclient: DtpClient,\n\treportType: number,\n\tstartDate: Date,\n\tendDate: Date,\n) {\n\tconst r = await client.send([\n\t\t\"R2\",\n\t\t\"0\",\n\t\tString(reportType),\n\t\tformatDateDDMMYYYY(startDate),\n\t\tformatDateDDMMYYYY(endDate),\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\trecordCount: parseCode(r) === 0 && r.length >= 2 ? Number(r[1]) : -1,\n\t\traw: r,\n\t};\n}\n\nexport async function getFiscalMemoryReportData(client: DtpClient) {\n\tconst r = await client.send([\"R3\"]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function finishFiscalMemoryReport(client: DtpClient) {\n\tconst r = await client.send([\"R4\"]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function openNonFiscalDoc(client: DtpClient) {\n\tconst r = await client.send([\"N0\"]);\n\treturn { code: parseCode(r), raw: r };\n}\n\nexport async function addNonFiscalLine(\n\tclient: DtpClient,\n\tline: string,\n\tsize = 0,\n\talign = 0,\n\tstyle = 0,\n) {\n\tconst r = await client.send([\n\t\t\"N1\",\n\t\tline,\n\t\tString(size),\n\t\tString(align),\n\t\tString(style),\n\t]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tprintedLines: parseCode(r) === 0 && r.length >= 2 ? Number(r[1]) : -1,\n\t\traw: r,\n\t};\n}\n\nexport async function closeNonFiscalDoc(client: DtpClient) {\n\tconst r = await client.send([\"N3\"]);\n\treturn {\n\t\tcode: parseCode(r),\n\t\tdocumentNumber: parseCode(r) === 0 && r.length >= 2 ? Number(r[1]) : -1,\n\t\traw: r,\n\t};\n}\n","import {\n\tPaymentMethodId,\n\tPrinterTaxValues,\n\tTaxValues,\n} from \"../../types/enums.js\";\nimport type { Order } from \"../../types/order.js\";\nimport type {\n\tBuildInvoiceOptions,\n\tBuildReceiptOptions,\n\tPrinterDriver,\n} from \"../printer.types.js\";\nimport type { DtpClient } from \"./dtp-client.js\";\nimport type { DtpPrinterCommand } from \"./dtp-commands.js\";\nimport {\n\taddFiscalItem,\n\taddNonFiscalLine,\n\tcloseFiscalDoc,\n\tcloseNonFiscalDoc,\n\topenFiscalDoc,\n\topenNonFiscalDoc,\n\tpayFiscalDoc,\n\tpayFiscalDocForeignCurrency,\n\tsubtotalFiscalDoc,\n} from \"./dtp-printer.js\";\n\nfunction truncateString(str: string, maxLength = 64): string {\n\tif (!str) return \"\";\n\treturn str.length > maxLength ? str.substring(0, maxLength) : str;\n}\n\nfunction formatDate(date: Date): string {\n\tconst day = date.getDate().toString().padStart(2, \"0\");\n\tconst month = (date.getMonth() + 1).toString().padStart(2, \"0\");\n\tconst year = date.getFullYear();\n\treturn `${day}/${month}/${year}`;\n}\n\nfunction formatTime(date: Date): string {\n\tconst hours = date.getHours().toString().padStart(2, \"0\");\n\tconst minutes = date.getMinutes().toString().padStart(2, \"0\");\n\treturn `${hours}:${minutes}`;\n}\n\n/**\n * Mapea taxId (IVA_G, EXENTO_E, etc.) a código DTP iImpuesto (0..4).\n * DTP: 0=exento, 1=16%, 2=8%, 3=31%, 4=percibido/IGTF.\n */\nfunction mapTaxIdToDtpCode(taxId: string | null | undefined): number {\n\tif (!taxId) return 0;\n\tconst taxIdUpper = taxId.toUpperCase();\n\tconst aegCode =\n\t\tPrinterTaxValues[taxIdUpper as keyof typeof PrinterTaxValues];\n\tif (aegCode === undefined) return 0;\n\tconst n = Number(aegCode);\n\t// DTP iImpuesto: 0=exento, 1=16%, 2=8%, 3=31%, 4=percibido\n\tif (n === PrinterTaxValues.EXENTO_E) return 0;\n\tif (n === PrinterTaxValues.BI_G || n === PrinterTaxValues.IVA_G)\n\t\treturn 1;\n\tif (n === PrinterTaxValues.BI_R || n === PrinterTaxValues.IVA_R)\n\t\treturn 2;\n\tif (n === PrinterTaxValues.BI_A || n === PrinterTaxValues.IVA_A)\n\t\treturn 3;\n\tif (\n\t\tn === PrinterTaxValues.PERCIBIDO ||\n\t\tn === PrinterTaxValues.BI_IGTF ||\n\t\tn === PrinterTaxValues.IVA_IGTF\n\t)\n\t\treturn 4;\n\treturn 0;\n}\n\nfunction mapPaymentMethod(method: string): PaymentMethodId {\n\tif (method === \"pos_debit\") return PaymentMethodId.POS_DEBIT;\n\tif (method === \"pos_credit\") return PaymentMethodId.POS_CREDIT;\n\tif (method === \"pos_debit_credit_int\")\n\t\treturn PaymentMethodId.POS_DEBIT_CREDIT_INT;\n\tif (method === \"cash_int\") return PaymentMethodId.CASH_INT;\n\tif (method === \"cash_nat\") return PaymentMethodId.CASH;\n\tthrow new Error(\n\t\t`Método de pago inválido: ${method}. Debe ser \"pos_debit\", \"pos_credit\", \"pos_debit_credit_int\", \"cash_int\" o \"cash_nat\"`,\n\t);\n}\n\nfunction paymentMethodLabel(id: PaymentMethodId): string {\n\tswitch (id) {\n\t\tcase PaymentMethodId.CASH:\n\t\t\treturn \"EFECTIVO\";\n\t\tcase PaymentMethodId.POS_DEBIT:\n\t\t\treturn \"TARJETA DEBITO\";\n\t\tcase PaymentMethodId.POS_CREDIT:\n\t\t\treturn \"TARJETA CREDITO\";\n\t\tcase PaymentMethodId.PAGO_MOVIL:\n\t\t\treturn \"PAGO MOVIL\";\n\t\tcase PaymentMethodId.POS_DEBIT_CREDIT_INT:\n\t\t\treturn \"TARJETA INT\";\n\t\tcase PaymentMethodId.CASH_INT:\n\t\t\treturn \"EFECTIVO USD\";\n\t\tdefault:\n\t\t\treturn \"EFECTIVO\";\n\t}\n}\n\n/**\n * Driver para impresora fiscal DTP-80i.\n * Construye comandos DTP compatibles con el protocolo TCP.\n */\nexport const dtpPrinter: PrinterDriver<DtpPrinterCommand> = {\n\tmodel: \"dtp-80i\",\n\n\tbuildInvoiceCommands(\n\t\torder: Order,\n\t\toptions: BuildInvoiceOptions,\n\t): DtpPrinterCommand[] {\n\t\tconst commands: DtpPrinterCommand[] = [];\n\n\t\tif (!order) {\n\t\t\tthrow new Error(\"Order es requerido\");\n\t\t}\n\t\tif (!order.client) {\n\t\t\tthrow new Error(\"Order debe tener un cliente asociado\");\n\t\t}\n\t\tif (!order.items || order.items.length === 0) {\n\t\t\tthrow new Error(\"Order debe tener al menos un item\");\n\t\t}\n\n\t\tconst { paymentMethodId, storeName = \"N/A\" } = options;\n\n\t\tconst clientName = order.client.name || \"\";\n\t\tconst clientRif = order.client.id || \"\";\n\t\tconst storeLine = `Tienda: ${storeName}`;\n\n\t\tcommands.push({\n\t\t\tcmd: \"F0\",\n\t\t\tdata: {\n\t\t\t\tsNombreCliente: truncateString(clientName, 64),\n\t\t\t\tsRifCliente: truncateString(clientRif, 20),\n\t\t\t\tbLogo: false,\n\t\t\t\tsLineaAdicional: truncateString(storeLine, 64),\n\t\t\t},\n\t\t});\n\n\t\tlet subtotalWithoutTaxes = 0;\n\n\t\tfor (const item of order.items) {\n\t\t\tif (!item.name) continue;\n\n\t\t\tconst taxId =\n\t\t\t\titem.taxes && item.taxes.length > 0 ? item.taxes[0].id : null;\n\t\t\tconst iImpuesto = mapTaxIdToDtpCode(taxId);\n\t\t\tconst price = item.price ?? 0;\n\t\t\tconst lPrecio = Math.round(Math.max(price, 0) * 100);\n\t\t\tconst quantity = item.selectedQuantity ?? item.quantity ?? 1;\n\t\t\tconst lCantidad = Math.round(Math.max(quantity, 1) * 1000);\n\n\t\t\tsubtotalWithoutTaxes += price * Math.max(quantity, 1);\n\n\t\t\tcommands.push({\n\t\t\t\tcmd: \"F1\",\n\t\t\t\tdata: {\n\t\t\t\t\tsDescripcion: truncateString(item.name, 64),\n\t\t\t\t\tsCodigo: truncateString(item.sku ?? \"N/A\", 20),\n\t\t\t\t\tlCantidad,\n\t\t\t\t\tsUnidad: \"UND\",\n\t\t\t\t\tlPrecio,\n\t\t\t\t\tiImpuesto,\n\t\t\t\t\tiDecPrecio: 2,\n\t\t\t\t\tiDecCantidad: 3,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tconst isForeignCurrency =\n\t\t\tpaymentMethodId === \"pos_debit_credit_int\" ||\n\t\t\tpaymentMethodId === \"cash_int\";\n\n\t\tif (isForeignCurrency && subtotalWithoutTaxes > 0) {\n\t\t\tconst roundedSubtotal =\n\t\t\t\tMath.round((subtotalWithoutTaxes + Number.EPSILON) * 100) / 100;\n\t\t\tconst igtfPercentage = TaxValues.BI_IGTF / 100;\n\t\t\tconst igtfAmount =\n\t\t\t\tMath.round((roundedSubtotal * igtfPercentage + Number.EPSILON) * 100) /\n\t\t\t\t100;\n\n\t\t\tcommands.push({\n\t\t\t\tcmd: \"F1\",\n\t\t\t\tdata: {\n\t\t\t\t\tsDescripcion: \"IGTF 3% pago en divisas\",\n\t\t\t\t\tsCodigo: \"IGTF\",\n\t\t\t\t\tlCantidad: 1000,\n\t\t\t\t\tsUnidad: \"UND\",\n\t\t\t\t\tlPrecio: Math.round(igtfAmount * 100),\n\t\t\t\t\tiImpuesto: 4,\n\t\t\t\t\tiDecPrecio: 2,\n\t\t\t\t\tiDecCantidad: 3,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tcommands.push({\n\t\t\tcmd: \"F2\",\n\t\t\tdata: { mode: 1, foreignCurrencyAmount: 0 },\n\t\t});\n\n\t\tif (!order.payments?.length) {\n\t\t\tthrow new Error(\"Order debe tener al menos un pago exitoso\");\n\t\t}\n\n\t\tfor (const payment of order.payments) {\n\t\t\tconst tipo = mapPaymentMethod(payment.paymentMethod);\n\t\t\tconst lMonto = Math.round(payment.amount * 100);\n\t\t\tconst isForeign =\n\t\t\t\tpayment.paymentMethod === \"pos_debit_credit_int\" ||\n\t\t\t\tpayment.paymentMethod === \"cash_int\";\n\n\t\t\tif (isForeign) {\n\t\t\t\tcommands.push({\n\t\t\t\t\tcmd: \"F11\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tiFormaPago: tipo,\n\t\t\t\t\t\tsDescripcion: paymentMethodLabel(tipo),\n\t\t\t\t\t\tlMonto,\n\t\t\t\t\t\tlTasaCambio: 1,\n\t\t\t\t\t\tsSimbolo: \"USD\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tcommands.push({\n\t\t\t\t\tcmd: \"F4\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tiFormaPago: tipo,\n\t\t\t\t\t\tsDescripcion: paymentMethodLabel(tipo),\n\t\t\t\t\t\tlMonto,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tcommands.push({ cmd: \"F5\", data: {} });\n\n\t\treturn commands;\n\t},\n\n\tbuildReceiptCommands(options: BuildReceiptOptions): DtpPrinterCommand[] {\n\t\tconst {\n\t\t\torderId,\n\t\t\tamountPaid,\n\t\t\tpaymentMethod,\n\t\t\tpaidAt,\n\t\t\tcardLast4,\n\t\t\torganizationName,\n\t\t} = options;\n\n\t\tif (!orderId) {\n\t\t\tthrow new Error(\"OrderId es requerido\");\n\t\t}\n\t\tif (!Number.isFinite(amountPaid) || amountPaid <= 0) {\n\t\t\tthrow new Error(\"Monto pagado inválido\");\n\t\t}\n\n\t\tconst paidDate = paidAt ?? new Date();\n\t\tconst lines = [\n\t\t\t\"RECIBO DE PAGO\",\n\t\t\torderId,\n\t\t\t\"Recibo de pago\",\n\t\t\torganizationName?.trim() || \"N/A\",\n\t\t\t`Bs ${amountPaid}`,\n\t\t\t`Medio de pago: ${paymentMethod}`,\n\t\t\t`Tarjeta ${cardLast4 ?? \"N/A\"}`,\n\t\t\t`Hora del pago: ${formatTime(paidDate)}`,\n\t\t\t`Fecha del pago: ${formatDate(paidDate)}`,\n\t\t\t\"Cierre del Documento No Fiscal\",\n\t\t];\n\n\t\tconst commands: DtpPrinterCommand[] = [{ cmd: \"N0\" }];\n\n\t\tfor (const line of lines) {\n\t\t\tcommands.push({\n\t\t\t\tcmd: \"N1\",\n\t\t\t\tdata: { line: truncateString(line, 64) },\n\t\t\t});\n\t\t}\n\n\t\tcommands.push({ cmd: \"N3\" });\n\n\t\treturn commands;\n\t},\n};\n\n/**\n * Resultado de ejecutar comandos DTP.\n * Incluye documentNumber y totalAmount cuando el último comando es F5 (cerrar factura).\n */\nexport interface ExecuteDtpCommandsResult {\n\tdocumentNumber?: number;\n\ttotalAmount?: number;\n}\n\n/**\n * Ejecuta una secuencia de comandos DTP contra un cliente conectado.\n * Lanza en el primer error.\n * Retorna documentNumber y totalAmount cuando se ejecuta F5 (cerrar factura).\n */\nexport async function executeDtpCommands(\n\tclient: DtpClient,\n\tcommands: DtpPrinterCommand[],\n): Promise<ExecuteDtpCommandsResult> {\n\tlet documentNumber: number | undefined;\n\tlet totalAmount: number | undefined;\n\tfor (const cmd of commands) {\n\t\tswitch (cmd.cmd) {\n\t\t\tcase \"F0\": {\n\t\t\t\tconst r = await openFiscalDoc(client, cmd.data);\n\t\t\t\tif (r.code !== 0) throw new Error(`F0 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"F1\": {\n\t\t\t\tconst r = await addFiscalItem(client, cmd.data);\n\t\t\t\tif (r.code !== 0) throw new Error(`F1 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"F2\": {\n\t\t\t\tconst r = await subtotalFiscalDoc(\n\t\t\t\t\tclient,\n\t\t\t\t\tcmd.data?.mode ?? 1,\n\t\t\t\t\tcmd.data?.foreignCurrencyAmount ?? 0,\n\t\t\t\t);\n\t\t\t\tif (r.code !== 0) throw new Error(`F2 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"F4\": {\n\t\t\t\tconst r = await payFiscalDoc(client, cmd.data);\n\t\t\t\tif (r.code !== 0) throw new Error(`F4 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"F5\": {\n\t\t\t\tconst r = await closeFiscalDoc(client, cmd.data?.additionalLine ?? \"\");\n\t\t\t\tif (r.code !== 0) throw new Error(`F5 falló: código ${r.code}`);\n\t\t\t\tdocumentNumber = r.documentNumber;\n\t\t\t\ttotalAmount = r.totalAmount;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"F11\": {\n\t\t\t\tconst r = await payFiscalDocForeignCurrency(client, cmd.data);\n\t\t\t\tif (r.code !== 0)\n\t\t\t\t\tthrow new Error(`F11 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"N0\": {\n\t\t\t\tconst r = await openNonFiscalDoc(client);\n\t\t\t\tif (r.code !== 0) throw new Error(`N0 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"N1\": {\n\t\t\t\tconst r = await addNonFiscalLine(\n\t\t\t\t\tclient,\n\t\t\t\t\tcmd.data.line,\n\t\t\t\t\tcmd.data.size ?? 0,\n\t\t\t\t\tcmd.data.align ?? 0,\n\t\t\t\t\tcmd.data.style ?? 0,\n\t\t\t\t);\n\t\t\t\tif (r.code !== 0) throw new Error(`N1 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"N3\": {\n\t\t\t\tconst r = await closeNonFiscalDoc(client);\n\t\t\t\tif (r.code !== 0) throw new Error(`N3 falló: código ${r.code}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tconst _: never = cmd;\n\t\t\t\tthrow new Error(`Comando DTP desconocido: ${String((cmd as { cmd: string }).cmd)}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn { documentNumber, totalAmount };\n}\n","import type {\n\tPrinterCommandResponse,\n\tPrinterResponse,\n\tSendPrinterCommandsAeg,\n\tSendPrinterCommandsArgs,\n} from \"./types.js\";\n\nfunction normalizeBaseUrl(address: string): string {\n\tconst trimmed = address.trim();\n\tif (!trimmed) return trimmed;\n\tconst withProtocol = /^https?:\\/\\//i.test(trimmed)\n\t\t? trimmed\n\t\t: `http://${trimmed}`;\n\treturn withProtocol.replace(/\\/+$/, \"\");\n}\n\n/**\n * Envía comandos a una impresora fiscal.\n *\n * - **AEG-R1**: POST HTTP a {ip}/cmdoJson con body = commands (JSON)\n * - **DTP-80i**: No soportado en esta librería (usa TCP vía módulo nativo).\n * El consumidor debe usar ExpoDtpFiscalPrinter directamente.\n */\nexport async function sendPrinterCommands(\n\targs: SendPrinterCommandsArgs,\n\toptions?: { timeout?: number },\n): Promise<PrinterResponse> {\n\tconst { brand, model, commands } = args;\n\n\tif (!commands || commands.length === 0) {\n\t\tthrow new Error(\"No hay comandos para enviar\");\n\t}\n\n\tswitch (brand) {\n\t\tcase \"AEG\":\n\t\t\tif (model !== \"R1\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Modelo inválido para AEG: \"${model}\". Solo se soporta \"R1\".`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn sendAegCommands(args as SendPrinterCommandsAeg, options);\n\t\tcase \"DTP\":\n\t\t\tif (model !== \"80i\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Modelo inválido para DTP: \"${model}\". Solo se soporta \"80i\".`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t\"DTP-80i requiere el módulo nativo ExpoDtpFiscalPrinter. \" +\n\t\t\t\t\t\"Use la conexión TCP directamente desde su aplicación.\",\n\t\t\t);\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = brand;\n\t\t\tthrow new Error(\n\t\t\t\t`Marca de impresora no soportada: ${String(_exhaustive)}`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nasync function sendAegCommands(\n\targs: SendPrinterCommandsAeg,\n\toptions?: { timeout?: number },\n): Promise<PrinterResponse> {\n\tconst { ip, commands } = args;\n\tconst baseUrl = normalizeBaseUrl(ip);\n\tconst url = `${baseUrl}/cmdoJson`;\n\tconst controller = new AbortController();\n\tconst timeoutId =\n\t\toptions?.timeout != null\n\t\t\t? setTimeout(() => controller.abort(), options.timeout)\n\t\t\t: undefined;\n\n\ttry {\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(commands),\n\t\t\tsignal: controller.signal,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Error HTTP ${response.status}: ${response.statusText}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as unknown;\n\n\t\tif (!Array.isArray(data)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Respuesta inválida de la impresora: se esperaba un array, se recibió ${typeof data}`,\n\t\t\t);\n\t\t}\n\n\t\tconst result = data as PrinterCommandResponse[];\n\n\t\tconst failedCommands: PrinterCommandResponse[] = [];\n\t\tfor (const commandResponse of result) {\n\t\t\tconst codeValue =\n\t\t\t\ttypeof commandResponse.code === \"string\"\n\t\t\t\t\t? Number.parseInt(commandResponse.code, 10)\n\t\t\t\t\t: commandResponse.code;\n\n\t\t\tif (Number.isNaN(codeValue) || codeValue !== 0) {\n\t\t\t\tfailedCommands.push(commandResponse);\n\t\t\t}\n\t\t}\n\n\t\tif (failedCommands.length > 0) {\n\t\t\tconst errorMessages = failedCommands\n\t\t\t\t.map(\n\t\t\t\t\t(cmd) =>\n\t\t\t\t\t\t`Comando ${cmd.cmd}: código ${cmd.code}${cmd.message ? ` - ${cmd.message}` : \"\"}`,\n\t\t\t\t)\n\t\t\t\t.join(\"; \");\n\t\t\tthrow new Error(\n\t\t\t\t`Error en la impresora: ${failedCommands.length} comando(s) fallaron. ${errorMessages}`,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t} catch (error) {\n\t\tif (error instanceof Error) {\n\t\t\tif (error.name === \"AbortError\") {\n\t\t\t\tthrow new Error(\"Timeout al enviar comandos a la impresora\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new Error(\"Error desconocido al enviar comandos a la impresora\");\n\t} finally {\n\t\tif (timeoutId) clearTimeout(timeoutId);\n\t}\n}\n"],"mappings":"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","names":["TaxValues","PrinterTaxValues","PaymentMethodId","truncateString","formatDate","formatTime","mapPaymentMethod"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as PrinterDriver } from './node-DVAcYJpM.cjs';
2
- export { B as BuildInvoiceOptions, a as BuildReceiptOptions, D as DocumentType, b as DtpPrinterCommand, E as ExecuteDtpCommandsResult, F as FiscalClient, I as ItemTax, O as Order, c as OrderItem, d as OrderPayment, e as PrinterCommandResponse, f as dtpPrinter, g as executeDtpCommands } from './node-DVAcYJpM.cjs';
1
+ import { P as PrinterDriver } from './dtp-printer-driver-CwJLSh2i.cjs';
2
+ export { B as BuildInvoiceOptions, a as BuildReceiptOptions, C as CreateDtpConnection, D as DocumentType, b as DtpClient, c as DtpOptions, d as DtpPrinterCommand, e as DtpSocketLike, E as ExecuteDtpCommandsResult, F as FiscalClient, I as ItemTax, O as Order, f as OrderItem, g as OrderPayment, h as PrinterCommandResponse, i as dtpPrinter, j as executeDtpCommands } from './dtp-printer-driver-CwJLSh2i.cjs';
3
3
 
4
4
  /**
5
5
  * Comandos JSON para impresora fiscal AEG-R1.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as PrinterDriver } from './node-DVAcYJpM.js';
2
- export { B as BuildInvoiceOptions, a as BuildReceiptOptions, D as DocumentType, b as DtpPrinterCommand, E as ExecuteDtpCommandsResult, F as FiscalClient, I as ItemTax, O as Order, c as OrderItem, d as OrderPayment, e as PrinterCommandResponse, f as dtpPrinter, g as executeDtpCommands } from './node-DVAcYJpM.js';
1
+ import { P as PrinterDriver } from './dtp-printer-driver-CwJLSh2i.js';
2
+ export { B as BuildInvoiceOptions, a as BuildReceiptOptions, C as CreateDtpConnection, D as DocumentType, b as DtpClient, c as DtpOptions, d as DtpPrinterCommand, e as DtpSocketLike, E as ExecuteDtpCommandsResult, F as FiscalClient, I as ItemTax, O as Order, f as OrderItem, g as OrderPayment, h as PrinterCommandResponse, i as dtpPrinter, j as executeDtpCommands } from './dtp-printer-driver-CwJLSh2i.js';
3
3
 
4
4
  /**
5
5
  * Comandos JSON para impresora fiscal AEG-R1.
package/dist/index.js CHANGED
@@ -1,3 +1,94 @@
1
+ // src/printers/dtp/dtp-client.ts
2
+ var STX = 2;
3
+ var ETX = 3;
4
+ var FS = 28;
5
+ var DtpClient = class {
6
+ constructor(opts) {
7
+ this.opts = opts;
8
+ }
9
+ socket = null;
10
+ buffer = Buffer.alloc(0);
11
+ pending = null;
12
+ async connect() {
13
+ if (this.socket) return;
14
+ const timeoutMs = this.opts.connectTimeoutMs ?? 3e3;
15
+ const socket = await Promise.race([
16
+ this.opts.createConnection({
17
+ host: this.opts.host,
18
+ port: this.opts.port
19
+ }),
20
+ new Promise(
21
+ (_, reject) => setTimeout(() => reject(new Error("Connect timeout")), timeoutMs)
22
+ )
23
+ ]);
24
+ this.socket = socket;
25
+ socket.on(
26
+ "data",
27
+ (chunk) => this.onData(chunk instanceof Buffer ? chunk : Buffer.from(chunk))
28
+ );
29
+ socket.on("error", (e) => this.onError(e));
30
+ socket.on("close", () => this.onClose());
31
+ }
32
+ close() {
33
+ this.socket?.end();
34
+ this.socket = null;
35
+ this.buffer = Buffer.alloc(0);
36
+ }
37
+ async send(parts) {
38
+ if (!this.socket) throw new Error("Socket not connected");
39
+ if (this.pending) throw new Error("Another command is in-flight");
40
+ const frame = this.buildFrame(parts);
41
+ const timeoutMs = this.opts.commandTimeoutMs ?? 1e4;
42
+ return await new Promise((resolve, reject) => {
43
+ const timer = setTimeout(() => {
44
+ this.pending = null;
45
+ reject(new Error(`Command timeout: ${parts[0]}`));
46
+ }, timeoutMs);
47
+ this.pending = { resolve, reject, timer };
48
+ this.socket?.write(frame);
49
+ });
50
+ }
51
+ buildFrame(parts) {
52
+ const payload = Buffer.from(parts.join(String.fromCharCode(FS)), "utf8");
53
+ return Buffer.concat([Buffer.from([STX]), payload, Buffer.from([ETX])]);
54
+ }
55
+ tryParseOneFrame() {
56
+ const start = this.buffer.indexOf(STX);
57
+ const end = this.buffer.indexOf(ETX, start + 1);
58
+ if (start === -1 || end === -1) return null;
59
+ const body = this.buffer.subarray(start + 1, end);
60
+ this.buffer = this.buffer.subarray(end + 1);
61
+ const params = body.toString("utf8").split(String.fromCharCode(FS));
62
+ return params;
63
+ }
64
+ onData(chunk) {
65
+ this.buffer = Buffer.concat([this.buffer, chunk]);
66
+ const params = this.tryParseOneFrame();
67
+ if (!params) return;
68
+ if (!this.pending) return;
69
+ const { resolve, timer } = this.pending;
70
+ clearTimeout(timer);
71
+ this.pending = null;
72
+ resolve(params);
73
+ }
74
+ onError(e) {
75
+ if (this.pending) {
76
+ const { reject, timer } = this.pending;
77
+ clearTimeout(timer);
78
+ this.pending = null;
79
+ reject(e);
80
+ }
81
+ }
82
+ onClose() {
83
+ if (this.pending) {
84
+ const { reject, timer } = this.pending;
85
+ clearTimeout(timer);
86
+ this.pending = null;
87
+ reject(new Error("Socket closed"));
88
+ }
89
+ }
90
+ };
91
+
1
92
  // src/types/enums.ts
2
93
  var TaxValues = /* @__PURE__ */ ((TaxValues2) => {
3
94
  TaxValues2[TaxValues2["EXENTO_E"] = 0] = "EXENTO_E";
@@ -717,6 +808,7 @@ async function sendAegCommands(args, options) {
717
808
  }
718
809
  }
719
810
  export {
811
+ DtpClient,
720
812
  PaymentMethodId,
721
813
  PrinterTaxValues,
722
814
  TaxValues,