/******************************************************************* Module : /assets/js/print.js Desc. : JS Class Printer & Printer POS Created By : Siau Pheng (siaupheng@3fonia.com). Created Date : May 27th, 2007. Last Modified : November 2nd, 2026. (c) 3FONIA Software; WWW.3FONIA.COM. ******************************************************************* * * Class Printer * * Standard Web Document Printing & Report Preview Class * * @license MIT, https://www.3fonia.com * @copyright Copyright (c) 2008-2026, Siau Pheng * * @param {object} options * @param {string} options.url - Endpoint URL Print Page * @param {number} [options.zoom=90] - Zoom percentage in viewer * @param {Array} [options.params] - Request payload */ class Printer { constructor(options = {}) { this.url = typeof options === 'string' ? options : options.url || ''; this.zoom = options.zoom || 90; this.params = options.params || []; } addParam(id, val) { this.params.push(val !== undefined ? `${id}=${encodeURIComponent(val)}` : id); return this; } doPrint() { if (!this.url) { console.warn('Url Laporan dibutuhkan!'); return; } $.ajax({ type: 'POST', url: this.url, data: FoniaJS.RequestParam(this.params), success: (txt) => { let $printData = $('#dataPrint'); if (!$printData.length) { $printData = $('
', { id: 'dataPrint', class: 'd-none d-print-block print-body' }).appendTo('body'); } $printData.html(txt); window.print(); }, error: typeof this.onFailure === 'function' ? this.onFailure : null }); return this; } doPreview() { if (!this.url) { console.warn('Url Laporan dibutuhkan!'); return; } $.ajax({ type: 'POST', url: this.url, data: FoniaJS.RequestParam(this.params), success: (txt) => { if (!txt) { FoniaJS.showInfo('Tidak ada data untuk pembuatan laporan !'); return false; } const modalHtml = ` `; $('#winAPPPrint').modal('dispose').remove(); $(modalHtml) .on('shown.bs.modal', () => { $('#winAPPPrint #tombCetak').off('click').on('click', () => { let $printData = $('#dataPrint'); if (!$printData.length) { $printData = $('
', { id: 'dataPrint', class: 'd-none d-print-block print-body' }).appendTo('body'); } $printData.html($('#divPrintP').html()); FoniaJS.closeWindow($('#winAPPPrint')); window.print(); }); }) .on('hidden.bs.modal', function () { $(this).remove(); }) .modal('show'); }, error: typeof this.onFailure === 'function' ? this.onFailure : null }); return this; } } /** * Class PrinterPos * * Direct Thermal POS Printer Class (via QZ Tray API) * * @license MIT, https://www.3fonia.com * @copyright Copyright (c) 2008-2026, Siau Pheng * * @param {object} options * @param {string} options.url - Endpoint URL Print Page * @param {number} [options.printer=FoniaJS._def_printer] - Printer Name * @param {Array} [options.params] - Request payload */ class PrinterPos { constructor(options = {}) { this.url = typeof options === 'string' ? options : options.url || ''; this.printer = options.printer || (FoniaJS._def_printer ?? null); this.cut_paper = options.cut_paper || '\x1D\x56\x41'; this.open_draw = options.open_draw || '\x1B\x70\x30\x19\x19'; this.chr_norm = options.chr_norm || '\x1B\x21\x01'; this.chr_bold = options.chr_bold || '\x1B\x21\x10'; this.chr_sbold = options.chr_sbold || '\x1B\x21\x31'; this.chr_uline = options.chr_uline || '\x1B\x21\x80'; this.params = options.params || []; } _detectPrinter() { if (!qz?.websocket?.isActive?.()) { FoniaJS.showInfo('Status Printer belum Active !'); return false; } return true; } setPrinter(nprint) { if (nprint != null) this.printer = nprint; return this; } addParam(id, val) { this.params.push(val !== undefined ? `${id}=${encodeURIComponent(val)}` : id); return this; } async exec() { if (!this._detectPrinter()) return; let printerName = this.printer; if (typeof printerName === 'object' && printerName !== null) { if (printerName.name !== undefined) { printerName = printerName.name; } else if (printerName.file !== undefined) { printerName = printerName.file; } else if (printerName.host !== undefined) { printerName = `${printerName.host}:${printerName.port}`; } } printerName = printerName ?? 'None'; this.params.push(`Printer=${printerName}`); this.doPrint(this.printer, this.url, this.params); } doPrint(printerName, url, params) { const qzcfg = qz.configs.create(printerName); new Request({ url, sendParam: params, onSuccess: (ajson) => { if (typeof ajson === 'object' && ajson !== null) { const printPayload = ajson.type === 'escp' ? this.genEscp(ajson) : this.genEpl(ajson); qz.print(qzcfg, printPayload); } else { FoniaJS.showInfo('Error dalam proses Cetak.'); } } }).send(); } genEscp(adata) { const ohead = ['\x1B\x40', '\x1B\x61\x01']; if (adata.config?.logo) { ohead.push({ type: 'raw', format: 'image', flavor: 'base64', data: adata.config.logo, options: { language: 'ESCPOS', dotDensity: 'double' } }); ohead.push('\x1B\x32'); } if (parseInt(adata.config?.fontsize, 10) === 2) { this.chr_norm = '\x1B\x21\x02'; } if (Array.isArray(adata.header)) { adata.header.forEach((headerLine, index) => { if (index === 0 && !adata.config?.logo) ohead.push(this.chr_bold); ohead.push(`${headerLine}\x0A`); if (index === 0 && !adata.config?.logo) ohead.push(this.chr_norm); }); } let ocetak = []; if (Array.isArray(adata.content)) { adata.content.forEach((sheetContent) => { if (!sheetContent?.length) return; const osheet = [...ohead]; sheetContent.forEach((line) => { const formattedLine = line .replace('_SBOLD_', this.chr_sbold) .replace('_BOLD_', this.chr_bold) .replace('_NORM_', this.chr_norm) .replace('_ULINE_', this.chr_uline); osheet.push(`${formattedLine}\x0A`); }); if (adata.config?.cutpaper) { osheet.push(`${this.cut_paper}\x0A`); } ocetak = ocetak.concat(osheet); }); } let notaout = []; if (adata.config?.opendraw) { notaout.push(this.open_draw); } const times = adata.config?.times || 1; for (let i = 0; i < times; i++) { notaout = notaout.concat(ocetak); } return notaout; } genEpl(adata) { const cetak = (adata.content || []).map((line) => `${line}\r\n`); let notaout = []; const times = adata.config?.times || 1; for (let i = 0; i < times; i++) { notaout = notaout.concat(cetak); } return notaout; } }