From 137571476f1f5c69c0fafd464cb39c95b13c2136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klaus=20W=C3=B6lfel?= <klaus@nexedi.com> Date: Mon, 16 Mar 2015 11:35:19 +0000 Subject: [PATCH] erp5_printer: print with html5 canvas to support chinese characters --- .../SaleOrder_viewEpsonPrintout.xml | 2 +- .../erp5_epson_canvas_printout.js.xml | 449 ++++++++++++++++++ 2 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 bt5/erp5_printer/SkinTemplateItem/portal_skins/erp5_printer/erp5_epson_canvas_printout.js.xml diff --git a/bt5/erp5_printer/SkinTemplateItem/portal_skins/erp5_printer/SaleOrder_viewEpsonPrintout.xml b/bt5/erp5_printer/SkinTemplateItem/portal_skins/erp5_printer/SaleOrder_viewEpsonPrintout.xml index d86ffeaa80..f7f119ebf7 100644 --- a/bt5/erp5_printer/SkinTemplateItem/portal_skins/erp5_printer/SaleOrder_viewEpsonPrintout.xml +++ b/bt5/erp5_printer/SkinTemplateItem/portal_skins/erp5_printer/SaleOrder_viewEpsonPrintout.xml @@ -52,7 +52,7 @@ <title>Receipt</title>\n <script type="text/javascript" tal:attributes=\'src python:"%s/jquery/core/jquery.js" % portal_url\'></script>\n <script type="text/javascript" tal:attributes=\'src python:"%s/epos-print-4.1.0.js" % portal_url\' ></script>\n - <script type="text/javascript" tal:attributes=\'src python:"%s/erp5_epson_printout.js" % portal_url\' ></script>\n + <script type="text/javascript" tal:attributes=\'src python:"%s/erp5_epson_canvas_printout.js" % portal_url\' ></script>\n <link rel="license" href="http://www.opensource.org/licenses/mit-license/">\n </head>\n <body style="background:white">\n diff --git a/bt5/erp5_printer/SkinTemplateItem/portal_skins/erp5_printer/erp5_epson_canvas_printout.js.xml b/bt5/erp5_printer/SkinTemplateItem/portal_skins/erp5_printer/erp5_epson_canvas_printout.js.xml new file mode 100644 index 0000000000..a419f74f44 --- /dev/null +++ b/bt5/erp5_printer/SkinTemplateItem/portal_skins/erp5_printer/erp5_epson_canvas_printout.js.xml @@ -0,0 +1,449 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="DTMLMethod" module="OFS.DTMLMethod"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_Cacheable__manager_id</string> </key> + <value> <string>http_cache</string> </value> + </item> + <item> + <key> <string>__name__</string> </key> + <value> <string>erp5_epson_canvas_printout.js</string> </value> + </item> + <item> + <key> <string>_proxy_roles</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>_vars</string> </key> + <value> + <dictionary/> + </value> + </item> + <item> + <key> <string>globals</string> </key> + <value> + <dictionary/> + </value> + </item> + <item> + <key> <string>raw</string> </key> + <value> <string encoding="cdata"><![CDATA[ + +/*\n +Copyright (c) 20xx-2006 Nexedi SARL and Contributors. All Rights Reserved.\n +\n +This program is Free Software; you can redistribute it ahand/or\n +modify it under the terms of the GNU General Public License\n +as published by the Free Software Foundation; either version 2\n +of the License, or (at your option) any later version.\n +cful,\n +but WITHOUT ANY WARRANTY; without even the implied warranty of\n +MERCHANTABILITY or FITNESS FgOR A PARTICULAR PURPOSE. See the\n +GNU General Public License for more details.\n +\n +You should have received a copy of the GNU General Public License\n +along with this program; if not, write to the Free Software\n +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n +*/\n +var y;\n +\n +function draw(canvas) {\n + y = 0;\n + context = canvas.getContext(\'2d\');\n + //add logo\n + context.drawImage($(\'#company_logo\')[0], (canvas.width-330)/2, 0, 330, 75);\n + addFeed(75);\n + addFeed();\n + addFeed();\n + \n + //add company information\n + $("#company-info div").each(function(){\n + addText(context, $(this).text());\n + });\n + addFeed();\n +\n + //add invoice information\n + addText(context, $.trim($("#invoice_information_title").text()), {\n + size: 36,\n + line: 46\n + });\n + $("#invoice_information_detail div").each(function(){\n + $(this).find("span").each(function(i){\n + if(i==0){\n + addText(context, $.trim($(this).text()), {bold: true, nobreak: true});\n + }\n + else {\n + addText(context, $.trim($(this).text()), {x: 300});\n + }\n + });\n + });\n + addFeed(100);\n +\n + //add products line\n + $("#invoice_line thead tr").each(function(j){\n + var textPosition=0;\n + $(this).find("th").each(function(i){\n + addText(context, $.trim($(this).text()), {\n + x: textPosition,\n + bold: true,\n + nobreak: true\n + });\n + switch(i)\n + {\n + case 0:\n + textPosition+=285;\n + break;\n + case 1:\n + textPosition+=100; \n + break;\n + case 3:\n + textPosition+=60;\n + break;\n + }\n + });\n + });\n + addFeed();\n + $("#invoice_line tbody tr").each(function(){\n + var textPosition=0;\n + $(this).find("td").each(function(i){\n + switch(i)\n + {\n + case 0:\n + var content=$.trim($(this).text());\n + content_len=content.length;\n + if(content_len>20)\n + content=content.substr(0,12)+"..."+content.substr(content_len-4,5);\n + addText(context, content, {x:textPosition, nobreak: true});\n + textPosition+=330;\n + break;\n + case 1:\n + var content=parseFloat($.trim($(this).text())).toFixed(1);\n + var content_len=content.length;\n + if(content_len>10)\n + content=parseFloat(content).toExponential(2);\n + else if(content_len>8&&content_len<11)\n + content=parseInt(content);\n + addText(context, content, {\n + x:textPosition,\n + nobreak: true,\n + textalign: \'right\'\n + });\n + textPosition+=140;\n + break;\n + case 2:\n + priceControl(context, $.trim($(this).text()), {\n + x:textPosition,\n + textalign: \'right\'\n + });\n + textPosition+=60;\n + break;\n + case 3:\n + var content=$.trim($(this).text());\n + var content_len=content.length;\n + content=content.substr(0,5);\n + addText(context, content, {x:textPosition, nobreak: true});\n + break;\n + case 4:\n + priceControl(context, $.trim($(this).text()), {\n + x:60,\n + textalign: \'right\'\n + });\n + break;\n + }\n + });\n + });\n +\n + addText(context, "===========", {x:360});\n + addText(context, $.trim($("#total_price tr th").text()), {\n + bold: true,\n + size: 28,\n + line: 36,\n + nobreak: true\n + });\n + priceControl(context, $.trim($("#total_price tr td").text()), {\n + x:480,\n + textalign: \'right\',\n + bold: true,\n + size: 28,\n + line: 36\n + });\n + addFeed();\n +\n + if ($("#total_discount").length > 0) {\n + builder.addText(context, $.trim($("#total_discount tr th").text()), {x:130});\n + priceControl(context, $.trim($("#total_discount tr td").text()), {x:385});\n + addFeed();\n +\n + addText(context, "===========", x=360);\n + addText(context, $.trim($("#total_price_with_discount tr th").text()), {x:130});\n + priceControl(context, $.trim($("#total_price_with_discount tr td").text()), {x:385});\n + }\n +\n + addFeed();\n + // append date and time\n + var now = new Date();\n + addText(context, now.toDateString() + \' \' + now.toTimeString().slice(0, 8) + \'\\n\');\n + \n + return canvas;\n +}\n +\n +function addText(context, text, options) {\n + if (!options) options = {};\n + if (!options.x) options.x = 0;\n + if (!options.bold) options.bold = false;\n + if (!options.size) options.size = 24;\n + if (!options.line) options.line = 30;\n + if (!options.nobreak) options.nobreak = false;\n + if (!options.font) options.font = \'Courier\';\n + if (!options.textalign) options.textalign = \'left\';\n + context.font =\n + (options.bold ? \'bold \' : \'normal \') + options.size + \'px \' + options.font;\n + context.textAlign = options.textalign;\n + context.fillText(text, options.x, y);\n + // line feed\n + if (options.nobreak === false) {\n + y = y + options.line;\n + }\n + console.log(options.line);\n +}\n +\n +function addFeed(px) {\n + if (!px) px = 30;\n + y = y + px;\n +}\n +\n +// if the price number length > 13 use the Scientific notation,\n +// if the length==11,12,13 , just need to remove the number after Decimal point\n +function priceControl(context, price, options){\n + var content=parseFloat(price).toFixed(2);\n + var content_len=content.length;\n + if(content_len>13)\n + content=parseFloat(content).toExponential(4);\n + else if(content_len>10&&content_len<14)\n + content=parseInt(content);\n + addText(context, content, options);\n +}\n +\n +monitoring_enabled = 0;\n +\n +function enableEpsonMonitoring(printer_url){\n + if (monitoring_enabled == 0) {\n + monitoring_enabled = 1;\n + } else { \n + return true;\n + };\n + var monitoting_epos = new epson.ePOSPrint(printer_url);\n + monitoting_epos.interval = 5000;\n + monitoting_epos.onpoweroff = function () {\n + msg = "ERROR: Unable to connect to the printer at the URL (Unreachable or Power off): " + monitoting_epos.address\n + $("#js_error_log").append("<div>" + msg + "</div>");\n + console.log(msg);\n + }\n +\n + monitoting_epos.onoffline = function () {\n + msg = "ERROR: Printer seems offline check if you can access printer at the URL (Unreachable or Power off): " + monitoting_epos.address\n + $("#js_error_log").append("<div>" + msg + "</div>");\n + console.log(msg);\n + }\n +\n + monitoting_epos.online = function () {\n + msg = "INFO: Printer is online at" + monitoting_epos.address\n + $("#js_error_log").append("<div>" + msg + "</div>");\n + console.log(msg);\n + }\n +\n + monitoting_epos.onpaperend = function () {\n + msg = "WARNNING: Printer report that paper is finished!"\n + $("#js_error_log").append("<div>" + msg + "</div>");\n + console.log(msg);\n + };\n +\n + monitoting_epos.onpapernearend = function () {\n + msg = "WARNNING: Printer report that paper is near finished from finish!"\n + $("#js_error_log").append("<div>" + msg + "</div>");\n + console.log(msg);\n + };\n +\n + monitoting_epos.onpaperok = function () {\n + msg = "INFO: Printer report that paper is OK."\n + $("#js_error_log").append("<div>" + msg + "</div>");\n + console.log(msg);\n + };\n +\n + monitoting_epos.ondrawerclosed = function () {\n + msg = "INFO: Printer report that drawer is closed."\n + $("#js_error_log").append("<div>" + msg + "</div>");\n + console.log(msg);\n + };\n +\n + monitoting_epos.ondraweropen = function () {\n + msg = "INFO: Printer report that drawer is open."\n + $("#js_error_log").append("<div>" + msg + "</div>");\n + console.log(msg);\n + };\n +\n + monitoting_epos.oncoveropen = function () {\n + msg = "WARNNING: Printer report that cover is open! Please close it!"\n + $("#js_error_log").append("<div>" + msg + "</div>");\n + console.log(msg);\n + };\n +\n + monitoting_epos.oncoverok = function () {\n + msg = "INFO: Printer cover is closed."\n + $("#js_error_log").append("<div>" + msg + "</div>");\n + console.log(msg);\n + };\n +\n + monitoting_epos.onstatuschange = function (status) {\n + msg = "INFO: Printer changed status to :" + status;\n + $("#js_error_log").append("<div>" + msg + "</div>");\n + console.log(msg);\n + };\n +\n + monitoting_epos.open();\n +}\n + \n +function printInvoiceOnEpson(printer_url){\n + enableEpsonMonitoring(printer_url);\n + // create print object\n + var epos = new epson.CanvasPrint(printer_url);\n + // set paper cutting\n + epos.cut = true;\n + \n + // register callback function\n + epos.onreceive = function (res) {\n + // Obtain the print result and error code\n + var msg = \'Print\' + (res.success ? \'Success\' : \'Failure\') + \'\\nCode:\' + res.code;\n +\n + switch(res.code) {\n + case "EPTR_AUTOMATICAL":\n + msg += \' An automatically recoverable error occurred\\n\';\n + break;\n + case "EPTR_COVER_OPEN":\n + msg += \' A cover open error occurred\\n\';\n + break;\n + case "EPTR_CUTTER":\n + msg += \' An autocutter error occurred\\n\';\n + break;\n + case \'EPTR_MECHANICAL\':\n + msg += \' A mechanical error occurred\\n\';\n + break;\n + case \'EPTR_REC_EMPTY\':\n + msg += \' No paper in roll paper end sensor\\n\';\n + break;\n + case \'EPTR_UNRECOVERABLE\':\n + msg += \' An unrecoverable error occurred\\n\';\n + break;\n + case \'SchemaError\':\n + msg += \' The request document contains a syntax error\\n\';\n + break;\n + case \'DeviceNotFound\':\n + msg += \' The printer with the specified device ID does not exist\\n\';\n + break;\n + case \'PrintSystemError\':\n + msg += \' An error occurred on the printing system\\n\';\n + break;\n + case \'EX_BADPORT\':\n + msg += \' An error was detected on the communication port\\n\';\n + break;\n + case \'EX_TIMEOUT\':\n + msg += \' A print timeout occurred\\n\';\n + break;\n + }\n + \n + msg += \'\\nStatus:\\n\';\n + // Obtain the printer status\n + var asb = res.status;\n + if (asb & epos.ASB_NO_RESPONSE) {\n + msg += \' No printer response\\n\';\n + }\n + if (asb & epos.ASB_PRINT_SUCCESS) {\n + msg += \' Print complete\\n\';\n + }\n + if (asb & epos.ASB_DRAWER_KICK) {\n + msg += \' Status of the drawer kick number 3 connector pin = "H"\\n\';\n + }\n + if (asb & epos.ASB_OFF_LINE) {\n + msg += \' Offline status\\n\';\n + }\n + if (asb & epos.ASB_COVER_OPEN) {\n + msg += \' Cover is open\\n\';\n + }\n + if (asb & epos.ASB_PAPER_FEED) {\n + msg += \' Paper feed switch is feeding paper\\n\';\n + }\n + if (asb & epos.ASB_WAIT_ON_LINE) {\n + msg += \' Waiting for online recovery\\n\';\n + }\n + if (asb & epos.ASB_PANEL_SWITCH) {\n + msg += \' Panel switch is ON\\n\';\n + }\n + if (asb & epos.ASB_MECHANICAL_ERR) {\n + msg += \' Mechanical error generated\\n\';\n + }\n + if (asb & epos.ASB_AUTOCUTTER_ERR) {\n + msg += \' Auto cutter error generated\\n\';\n + }\n + if (asb & epos.ASB_UNRECOVER_ERR) {\n + msg += \' Unrecoverable error generated\\n\';\n + }\n + if (asb & epos.ASB_AUTORECOVER_ERR) {\n + msg += \' Auto recovery error generated\\n\';\n + }\n + if (asb & epos.ASB_RECEIPT_NEAR_END) {\n + msg += \' No paper in the roll paper near end detector\\n\';\n + }\n + if (asb & epos.ASB_RECEIPT_END) {\n + msg += \' No paper in the roll paper end detector\\n\';\n + }\n + if (asb & epos.ASB_BUZZER) {\n + msg += \' Sounding the buzzer (limited model)\\n\';\n + }\n + if (asb & epos.ASB_SPOOLER_IS_STOPPED) {\n + msg += \' Stop the spooler\\n\';\n + }\n + // Display in the dialog box\n + console.log(msg);\n + $("#js_error_log").append("<div>" + msg + "</div>");\n + }\n +\n + // register callback function\n + epos.onerror = function (err) {\n + $("#js_error_log").append("<div> Error Status: " + err.status + " Response: " + err.responseText + "</div>");\n + if (err.status == 0) {\n + $("#js_error_log").append("<div> Make sure you are able to access the printer at: " + epos.address + "</div>");\n + };\n + console.log("Error Status: " + err.status + "Response: " + err.responseText);\n + }\n +\n + // send\n + $("#js_error_log").append("<div> The print will start soon...</div>");\n + \n + // first draw on dummy canvas to get canvas height\n + // needed because setting size clears canvas\n + draw(document.createElement("canvas"));\n + console.log(y);\n + var canvas = document.createElement("canvas");\n + canvas.width = 512;\n + canvas.height = y;\n + epos.print(draw(canvas));\n +}\n + + +]]></string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> -- 2.30.9