1 25 package org.ofbiz.pos.device.impl; 26 27 import java.io.BufferedReader ; 28 import java.io.IOException ; 29 import java.io.InputStream ; 30 import java.io.InputStreamReader ; 31 import java.net.URL ; 32 import java.text.SimpleDateFormat ; 33 import java.util.Date ; 34 import java.util.HashMap ; 35 import java.util.Map ; 36 37 import jpos.JposException; 38 import jpos.POSPrinter; 39 import jpos.POSPrinterConst; 40 41 import org.ofbiz.base.util.Debug; 42 import org.ofbiz.base.util.UtilFormatOut; 43 import org.ofbiz.base.util.UtilURL; 44 import org.ofbiz.base.util.UtilValidate; 45 import org.ofbiz.base.util.string.FlexibleStringExpander; 46 import org.ofbiz.pos.PosTransaction; 47 import org.ofbiz.pos.device.GenericDevice; 48 import org.ofbiz.pos.screen.DialogCallback; 49 import org.ofbiz.pos.screen.PosDialog; 50 import org.ofbiz.pos.screen.PosScreen; 51 52 import org.apache.commons.collections.map.LinkedMap; 53 54 60 public class Receipt extends GenericDevice implements DialogCallback { 61 62 public static final String module = Receipt.class.getName(); 63 64 protected static final String ESC = ((char) 0x1b) + ""; 65 protected static final String LF = ((char) 0x0a) + ""; 66 67 protected static final String ALIGN_CENTER = ESC + "|cA"; 68 protected static final String ALIGN_RIGHT = ESC + "|rA"; 69 70 protected static final String TEXT_DOUBLE_HEIGHT = ESC + "|4C"; 71 protected static final String TEXT_UNDERLINE = ESC + "|uC"; 72 protected static final String TEXT_BOLD = ESC + "|bC"; 73 74 protected static final String PAPER_CUT = ESC + "|100fP"; 75 76 protected SimpleDateFormat [] dateFormat = null; 77 protected String [] storeReceiptTmpl = null; 78 protected String [] custReceiptTmpl = null; 79 protected LinkedMap reportTmpl = new LinkedMap(); 80 81 protected String [] dateFmtStr = { "EEE, d MMM yyyy HH:mm:ss z", "EEE, d MMM yyyy HH:mm:ss z", "EEE, d MMM yyyy HH:mm:ss z" }; 82 protected int[] priceLength = { 7, 7, 7 }; 83 protected int[] qtyLength = { 5, 5, 5 }; 84 protected int[] descLength = { 25, 25, 0 }; 85 protected int[] pridLength = { 25, 25, 0 }; 86 protected int[] infoLength = { 34, 34, 0 }; 87 88 protected PosTransaction lastTransaction = null; 89 90 public Receipt(String deviceName, int timeout) { 91 super(deviceName, timeout); 92 this.control = new jpos.POSPrinter(); 93 } 94 95 protected void initialize() throws JposException { 96 Debug.logInfo("Receipt [" + control.getPhysicalDeviceName() + "] Claimed : " + control.getClaimed(), module); 97 ((jpos.POSPrinter) control).setMapMode(POSPrinterConst.PTR_MM_METRIC); 100 } 101 102 public void println() { 103 this.println(""); 104 } 105 106 public void println(String p) { 107 try { 108 ((POSPrinter) control).printNormal(POSPrinterConst.PTR_S_RECEIPT, p + LF); 109 } catch (jpos.JposException e) { 110 Debug.logError(e, module); 111 } 112 } 113 114 public void printBarcode(String barcode) { 115 try { 117 ((POSPrinter) control).printBarCode(POSPrinterConst.PTR_S_RECEIPT, barcode, POSPrinterConst.PTR_BCS_Code39, 118 10 * 100, 60 * 100, POSPrinterConst.PTR_BC_CENTER, POSPrinterConst.PTR_BC_TEXT_NONE); 119 } catch (JposException e) { 120 Debug.logError(e, module); 121 } 122 } 123 124 public void printReport(PosTransaction trans, String resource, Map context) { 125 Debug.log("Print Report Requested", module); 126 String [] report = this.readReportTemplate(resource); 127 128 if (report != null) { 129 for (int i = 0; i < report.length; i++) { 130 if (report[i] != null) { 131 this.printInfo(report[i], context, trans, 2); 132 } 133 } 134 135 this.println(); 136 this.println(); 137 this.println(PAPER_CUT); 138 } 139 } 140 141 public void reprintReceipt() { 142 this.reprintReceipt(false); 143 } 144 145 public void reprintReceipt(boolean reprintStoreCopy) { 146 if (lastTransaction != null) { 147 this.printReceipt(lastTransaction, reprintStoreCopy); 148 } 149 } 150 151 public void printReceipt(PosTransaction trans, boolean printStoreCopy) { 152 Debug.log("Print Receipt Requested : " + trans.getTransactionId(), module); 153 POSPrinter printer = (POSPrinter) control; 154 this.lastTransaction = trans; 155 156 try { 157 if (!checkState(printer)) { 158 return; 159 } 160 } catch (JposException e) { 161 Debug.logError(e, module); 162 } 163 164 if (printStoreCopy) { 165 String [] storeReceipt = this.readStoreTemplate(); 166 int payments = trans.getNumberOfPayments(); 167 for (int i = 0; i < payments; i++) { 168 Map info = trans.getPaymentInfo(i); 169 if (info.containsKey("cardNumber")) { 170 this.printReceipt(trans, storeReceipt, 1, info); 171 } 172 try { 173 Thread.sleep(3000); 174 } catch (Exception e) { 175 } 176 } 177 } 178 179 String [] custReceipt = this.readCustomerTemplate(); 181 this.printReceipt(trans, custReceipt, 0, null); 182 } 183 184 private void printReceipt(PosTransaction trans, String [] template, int type, Map payInfo) { 185 if (template != null) { 186 for (int i = 0; i < template.length; i++) { 187 if (template[i] != null) { 188 if ("[ORDER_BARCODE]".equals(template[i])) { 189 this.printBarcode(trans.getOrderId()); 190 } else if (template[i].startsWith("[DLOOP]")) { 191 this.printDetail(template[i], trans, type); 192 } else if (template[i].startsWith("[PLOOP]")) { 193 this.printPayInfo(template[i], trans, type); 194 } else if (payInfo != null) { 195 this.printPayInfo(template[i], trans, type, payInfo); 196 } else { 197 this.printInfo(template[i], trans, type); 198 } 199 } 200 } 201 202 this.println(); 203 this.println(); 204 this.println(PAPER_CUT); 205 } 206 } 207 208 private synchronized String [] readStoreTemplate() { 209 if (this.storeReceiptTmpl == null) { 210 this.storeReceiptTmpl = new String [7]; 211 this.readTemplate(storeReceiptTmpl, "storereceipt.txt", 1); 212 } 213 214 return this.storeReceiptTmpl; 215 } 216 217 private synchronized String [] readCustomerTemplate() { 218 if (this.custReceiptTmpl == null) { 219 this.custReceiptTmpl = new String [7]; 220 this.readTemplate(custReceiptTmpl, "custreceipt.txt", 0); 221 } 222 223 return this.custReceiptTmpl; 224 } 225 226 private synchronized String [] readReportTemplate(String resource) { 227 String [] template = (String []) reportTmpl.get(resource); 228 if (template == null) { 229 template = new String [7]; 230 this.readTemplate(template, resource, 2); 231 reportTmpl.put(resource, template); 232 } 233 234 return template; 235 } 236 237 private String [] readTemplate(String [] template, String resource, int type) { 238 int currentPart = 0; 239 240 URL fileUrl = UtilURL.fromResource(resource); 241 StringBuffer buf = new StringBuffer (); 242 243 try { 244 InputStream in = fileUrl.openStream(); 245 BufferedReader dis = new BufferedReader (new InputStreamReader (in)); 246 247 String line; 248 while ((line = dis.readLine()) != null) { 249 if (line.trim().startsWith("#")) { 250 String [] code = line.trim().split("\\="); 251 if ("#description.length".equals(code[0])) { 252 try { 253 this.descLength[type] = Integer.parseInt(code[1]); 254 } catch (NumberFormatException e) { 255 Debug.logWarning(e, module); 256 } 257 } else if ("#productId.length".equals(code[0])) { 258 try { 259 this.pridLength[type] = Integer.parseInt(code[1]); 260 } catch (NumberFormatException e) { 261 Debug.logWarning(e, module); 262 } 263 } else if ("#price.length".equals(code[0])) { 264 try { 265 this.priceLength[type] = Integer.parseInt(code[1]); 266 } catch (NumberFormatException e) { 267 Debug.logWarning(e, module); 268 } 269 } else if ("#quantity.length".equals(code[0])) { 270 try { 271 this.qtyLength[type] = Integer.parseInt(code[1]); 272 } catch (NumberFormatException e) { 273 Debug.logWarning(e, module); 274 } 275 } else if ("#infoString.length".equals(code[0])) { 276 try { 277 this.infoLength[type] = Integer.parseInt(code[1]); 278 } catch (NumberFormatException e) { 279 Debug.logWarning(e, module); 280 } 281 } else if ("#dateFormat".equals(code[0])) { 282 this.dateFmtStr[type] = code[1]; 283 } 284 } else if (line.trim().startsWith("[BEGIN ITEM LOOP]")) { 285 template[currentPart++] = buf.toString(); 286 buf = new StringBuffer (); 287 buf.append("[DLOOP]"); 288 } else if (line.trim().startsWith("[END ITEM LOOP]")) { 289 template[currentPart++] = buf.toString(); 290 buf = new StringBuffer (); 291 } else if (line.trim().startsWith("[BEGIN PAY LOOP]")) { 292 template[currentPart++] = buf.toString(); 293 buf = new StringBuffer (); 294 buf.append("[PLOOP]"); 295 } else if (line.trim().startsWith("[END PAY LOOP]")) { 296 template[currentPart++] = buf.toString(); 297 buf = new StringBuffer (); 298 } else if (line.trim().startsWith("[ORDER BARCODE]")) { 299 template[currentPart++] = buf.toString(); 300 template[currentPart++] = "[ORDER_BARCODE]"; 301 buf = new StringBuffer (); 302 } else { 303 if (UtilValidate.isEmpty(line)) { 304 line = " "; 305 } 306 buf.append(line + "\n"); 307 } 308 } 309 in.close(); 310 } catch (IOException e) { 311 Debug.logError(e, "Unable to open receipt template", module); 312 } 313 314 template[currentPart] = buf.toString(); 315 return template; 316 } 317 318 private synchronized SimpleDateFormat getDateFormat(int type) { 319 if (dateFormat == null) { 320 dateFormat = new SimpleDateFormat [3]; 321 } 322 if (dateFormat[type] == null) { 323 dateFormat[type] = new SimpleDateFormat (this.dateFmtStr[type]); 324 } 325 return dateFormat[type]; 326 } 327 328 private void printInfo(String template, Map context, PosTransaction trans, int type) { 329 Map expandMap = this.makeCodeExpandMap(trans, type); 330 if (context != null) { 331 expandMap.putAll(context); } 333 this.printInfo(template, expandMap); 334 } 335 336 private void printInfo(String template, PosTransaction trans, int type) { 337 this.printInfo(template, null, trans, type); 338 } 339 340 private void printInfo(String template, Map context) { 341 String toPrint = FlexibleStringExpander.expandString(template, context); 342 if (toPrint.indexOf("\n") > -1) { 343 String [] lines = toPrint.split("\\n"); 344 for (int i = 0; i < lines.length; i++) { 345 this.println(lines[i]); 346 } 347 } else { 348 this.println(toPrint); 349 } 350 } 351 352 private void printDetail(String loop, PosTransaction trans, int type) { 353 String loopStr = loop.substring(7); 354 int size = trans.size(); 355 for (int i = 0; i < size; i++) { 356 Map expandMap = this.makeCodeExpandMap(trans, type); 357 expandMap.putAll(trans.getItemInfo(i)); 358 expandMap.put("description", UtilFormatOut.padString((String ) expandMap.get("description"), descLength[type], true, ' ')); 360 expandMap.put("productId", UtilFormatOut.padString((String ) expandMap.get("productId"), pridLength[type], true, ' ')); 361 expandMap.put("basePrice", UtilFormatOut.padString((String ) expandMap.get("basePrice"), priceLength[type], false, ' ')); 362 expandMap.put("subtotal", UtilFormatOut.padString((String ) expandMap.get("subtotal"), priceLength[type], false, ' ')); 363 expandMap.put("quantity", UtilFormatOut.padString((String ) expandMap.get("quantity"), qtyLength[type], false, ' ')); 364 expandMap.put("adjustments", UtilFormatOut.padString((String ) expandMap.get("adjustments"), priceLength[type], false, ' ')); 365 String toPrint = FlexibleStringExpander.expandString(loopStr, expandMap); 366 if (toPrint.indexOf("\n") > -1) { 367 String [] lines = toPrint.split("\\n"); 368 for (int x = 0; x < lines.length; x++) { 369 this.println(lines[x]); 370 } 371 } else { 372 this.println(toPrint); 373 } 374 } 375 } 376 377 private void printPayInfo(String loop, PosTransaction trans, int type) { 378 String loopStr = loop.substring(7); 379 int size = trans.getNumberOfPayments(); 380 for (int i = 0; i < size; i++) { 381 Map payInfoMap = trans.getPaymentInfo(i); 382 this.printPayInfo(loopStr, trans, type, payInfoMap); 383 } 384 } 385 386 private void printPayInfo(String template, PosTransaction trans, int type, Map payInfo) { 387 Map expandMap = this.makeCodeExpandMap(trans, type); 388 expandMap.putAll(payInfo); 389 expandMap.put("authInfoString", UtilFormatOut.padString((String ) expandMap.get("authInfoString"), infoLength[type], false, ' ')); 391 expandMap.put("nameOnCard", UtilFormatOut.padString((String ) expandMap.get("nameOnCard"), infoLength[type], false, ' ')); 392 expandMap.put("payInfo", UtilFormatOut.padString((String ) expandMap.get("payInfo"), infoLength[type], false, ' ')); 393 expandMap.put("amount", UtilFormatOut.padString((String ) expandMap.get("amount"), priceLength[type], false, ' ')); 394 String toPrint = FlexibleStringExpander.expandString(template, expandMap); 395 if (toPrint.indexOf("\n") > -1) { 396 String [] lines = toPrint.split("\\n"); 397 for (int x = 0; x < lines.length; x++) { 398 this.println(lines[x]); 399 } 400 } else { 401 this.println(toPrint); 402 } 403 } 404 405 private Map makeCodeExpandMap(PosTransaction trans, int type) { 406 Map expandMap = new HashMap (); 407 SimpleDateFormat fmt = this.getDateFormat(type); 408 String dateString = fmt.format(new Date ()); 409 410 expandMap.put("DOUBLE_HEIGHT", TEXT_DOUBLE_HEIGHT); 411 expandMap.put("CENTER", ALIGN_CENTER); 412 expandMap.put("BOLD", TEXT_BOLD); 413 expandMap.put("LF", LF); 414 expandMap.put("transactionId", trans.getTransactionId()); 415 expandMap.put("terminalId", trans.getTerminalId()); 416 expandMap.put("userId", trans.getUserId()); 417 expandMap.put("orderId", trans.getOrderId()); 418 expandMap.put("dateStamp", dateString); 419 expandMap.put("drawerNo", new Integer (trans.getDrawerNumber()).toString()); 420 expandMap.put("taxTotal", UtilFormatOut.padString(UtilFormatOut.formatPrice(trans.getTaxTotal()), priceLength[type], false, ' ')); 421 expandMap.put("grandTotal", UtilFormatOut.padString(UtilFormatOut.formatPrice(trans.getGrandTotal()), priceLength[type], false, ' ')); 422 expandMap.put("totalPayments", UtilFormatOut.padString(UtilFormatOut.formatPrice(trans.getPaymentTotal()), priceLength[type], false, ' ')); 423 expandMap.put("change", UtilFormatOut.padString((trans.getTotalDue() < 0 ? 424 UtilFormatOut.formatPrice(trans.getTotalDue() * -1) : "0.00"), priceLength[type], false, ' ')); 425 426 return expandMap; 427 } 428 429 private boolean checkState(POSPrinter printer) throws JposException { 430 if (printer.getCoverOpen() == true) { 431 PosScreen.currentScreen.showDialog("main/dialog/error/printernotready", this); 433 return false; 434 } 435 436 return true; 437 } 438 439 public void receiveDialogCb(PosDialog dialog) { 440 PosScreen.currentScreen.refresh(); 441 this.reprintReceipt(); 442 } 443 } 444 | Popular Tags |