NoteFormatter.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. package com.fuint.common.util;
  2. import org.apache.commons.lang3.StringUtils;
  3. import java.io.UnsupportedEncodingException;
  4. import java.text.DecimalFormat;
  5. /**
  6. * 小票格式化器
  7. *
  8. * Created by FSQ
  9. * CopyRight https://www.fuint.cn
  10. */
  11. public class NoteFormatter {
  12. /**
  13. * 58mm 系列打印机每行可以打印的字符数
  14. */
  15. private static final Integer ROW_MAX_CHAR_LEN = 32;
  16. private static final Integer MAX_NAME_CHAR_LEN = 20;
  17. private static final Integer LAST_ROW_MAX_NAME_CHAR_LEN = 9;
  18. private static final Integer MAX_QUANTITY_CHAR_LEN = 6;
  19. private static final Integer MAX_PRICE_CHAR_LEN = 6;
  20. /**
  21. * 80mm 系列打印机每行可以打印的字符数
  22. */
  23. private static final Integer ROW_MAX_CHAR_LEN80 = 48;
  24. private static final Integer MAX_NAME_CHAR_LEN80 = 36;
  25. private static final Integer LAST_ROW_MAX_NAME_CHAR_LEN80 = 17;
  26. private static final Integer MAX_QUANTITY_CHAR_LEN80 = 6;
  27. private static final Integer MAX_PRICE_CHAR_LEN80 = 6;
  28. private static String orderNameEmpty = StringUtils.repeat(" ", MAX_NAME_CHAR_LEN);
  29. /**
  30. * 格式化订单数据 80mm打印机使用
  31. *
  32. * @param foodName
  33. * @param quantity
  34. * @param price
  35. * @return
  36. * @throws Exception
  37. */
  38. public static String formatPrintOrderItemBy4Column(String foodName, Integer quantity, Double singlePrice, Double price) throws Exception {
  39. StringBuilder builder = new StringBuilder();
  40. byte[] itemNames = foodName.getBytes("GBK");
  41. Integer mod = itemNames.length % ROW_MAX_CHAR_LEN;
  42. String quanityStr = quantity.toString();
  43. byte[] itemQuans = quanityStr.getBytes("GBK");
  44. String priceStr = roundByTwo(price);
  45. byte[] itemPrices = (priceStr).getBytes("GBK");
  46. if (mod <= LAST_ROW_MAX_NAME_CHAR_LEN) {
  47. builder.append("<C>").append(foodName).append("</C>");
  48. // 在同一行,留4个英文字符的空格
  49. //if in the same row, fill with 4 spaces at the end of name column
  50. builder.append(StringUtils.repeat(" ", (MAX_NAME_CHAR_LEN - mod)));
  51. builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN - itemQuans.length)));
  52. builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN - itemPrices.length)));
  53. } else {
  54. // 对菜名进行猜分
  55. builder.append(foodName);
  56. // 另起新行
  57. // new line
  58. builder.append("<BR>");
  59. builder.append(orderNameEmpty);
  60. builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN - itemQuans.length)));
  61. builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN - itemPrices.length)));
  62. }
  63. builder.append("<BR>");
  64. return builder.toString();
  65. }
  66. /**
  67. * 格式化菜名名称,菜名名称打满一行自动换行
  68. *
  69. * @param foodName
  70. * @param quantity
  71. * @param price
  72. * @return
  73. * @throws Exception
  74. */
  75. public static String formatPrintOrderItemByFull(String foodName, Integer quantity, Double price) throws Exception {
  76. StringBuilder builder = new StringBuilder();
  77. byte[] itemNames = foodName.getBytes("GBK");
  78. Integer mod = itemNames.length % ROW_MAX_CHAR_LEN;
  79. String quanityStr = quantity.toString();
  80. byte[] itemQuans = quanityStr.getBytes("GBK");
  81. String priceStr = roundByTwo(price);
  82. byte[] itemPrices = (priceStr).getBytes("GBK");
  83. if (mod <= LAST_ROW_MAX_NAME_CHAR_LEN) {
  84. builder.append(foodName);
  85. // 在同一行,留4个英文字符的空格
  86. //if in the same row, fill with 4 spaces at the end of name column
  87. builder.append(StringUtils.repeat(" ", (MAX_NAME_CHAR_LEN - mod)));
  88. builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN - itemQuans.length)));
  89. builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN - itemPrices.length)));
  90. } else {
  91. // 对菜名进行猜分
  92. builder.append(foodName);
  93. // 另起新行
  94. // new line
  95. builder.append("<BR>");
  96. builder.append(orderNameEmpty);
  97. builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN - itemQuans.length)));
  98. builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN - itemPrices.length)));
  99. }
  100. builder.append("<BR>");
  101. return builder.toString();
  102. }
  103. /**
  104. * 格式化菜品列表(用于58mm打印机)
  105. * 注意:默认字体排版,若是字体宽度倍大后不适用
  106. * 58mm打印机一行可打印32个字符 汉子按照2个字符算
  107. * 分3列: 名称20字符一般用16字符4空格填充 数量6字符 单价6字符,不足用英文空格填充 名称过长换行
  108. * Format the dish list (for 58 mm printer)
  109. * Note: this is default font typesetting, not applicable if the font width is doubled
  110. * The 58mm printer can print 32 characters per line
  111. * Divided into 3 columns: name(20 characters), quanity(6 characters),price(6 characters)
  112. * The name column is generally filled with 16 your characters and 4 spaces
  113. * Long name column will cause auto line break
  114. *
  115. * @param foodName 菜品名称
  116. * @param quantity 数量
  117. * @param price 价格
  118. * @throws Exception
  119. */
  120. public static String formatPrintOrderItemForNewLine58(String foodName, Integer quantity, Double price) throws Exception {
  121. StringBuilder builder = new StringBuilder();
  122. byte[] itemNames = foodName.getBytes("GBK");
  123. Integer mod = itemNames.length % ROW_MAX_CHAR_LEN;
  124. if (mod <= LAST_ROW_MAX_NAME_CHAR_LEN) {
  125. builder.append(foodName);
  126. // 在同一行,留4个英文字符的空格
  127. //if in the same row, fill with 4 spaces at the end of name column
  128. builder.append(StringUtils.repeat(" ", (MAX_NAME_CHAR_LEN - mod)));
  129. String quanityStr = quantity.toString();
  130. byte[] itemQuans = quanityStr.getBytes("GBK");
  131. String priceStr = roundByTwo(price);
  132. byte[] itemPrices = (priceStr).getBytes("GBK");
  133. builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN - itemQuans.length)));
  134. builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN - itemPrices.length)));
  135. } else {
  136. getFoodNameSplit58(foodName, builder, quantity, price);
  137. }
  138. builder.append("<BR>");
  139. return builder.toString();
  140. }
  141. /**
  142. * 格式化菜品列表(用于58mm打印机)
  143. * 注意:默认字体排版,若是字体宽度倍大后不适用
  144. * 58mm打印机一行可打印32个字符 汉子按照2个字符算
  145. * 分3列: 名称20字符一般用16字符4空格填充 数量6字符 单价6字符,不足用英文空格填充 名称过长换行
  146. * Format the dish list (for 58 mm printer)
  147. * Note: this is default font typesetting, not applicable if the font width is doubled
  148. * The 58mm printer can print 32 characters per line
  149. * Divided into 3 columns: name(20 characters), quanity(6 characters),price(6 characters)
  150. * The name column is generally filled with 16 your characters and 4 spaces
  151. * Long name column will cause auto line break
  152. *
  153. * @param foodName 菜品名称
  154. * @param quantity 数量
  155. * @param price 价格
  156. * @throws Exception
  157. */
  158. public static String formatPrintOrderItemForNewLine80(String foodName, Double quantity, Double price) throws Exception {
  159. StringBuilder builder = new StringBuilder();
  160. byte[] itemNames = foodName.getBytes("GBK");
  161. Integer mod = itemNames.length % ROW_MAX_CHAR_LEN80;
  162. if (mod <= LAST_ROW_MAX_NAME_CHAR_LEN80) {
  163. builder.append(foodName);
  164. // 在同一行,留4个英文字符的空格
  165. //if in the same row, fill with 4 spaces at the end of name column
  166. builder.append(StringUtils.repeat(" ", (MAX_NAME_CHAR_LEN80 - mod)));
  167. String quanityStr = quantity.toString();
  168. byte[] itemQuans = quanityStr.getBytes("GBK");
  169. String priceStr = roundByTwo(price);
  170. byte[] itemPrices = (priceStr).getBytes("GBK");
  171. builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN80 - itemQuans.length)));
  172. builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN80 - itemPrices.length)));
  173. } else {
  174. getFoodNameSplit80(foodName, builder, quantity, price);
  175. }
  176. builder.append("<BR>");
  177. return builder.toString();
  178. }
  179. private static void getFoodNameSplit58(String foodName, StringBuilder builder, Integer quantity, Double price) throws UnsupportedEncodingException {
  180. String[] foodNames = string2StringArray(foodName, LAST_ROW_MAX_NAME_CHAR_LEN);
  181. String quanityStr = quantity.toString();
  182. byte[] itemQuans = quanityStr.getBytes("GBK");
  183. String priceStr = roundByTwo(price);
  184. byte[] itemPrices = (priceStr).getBytes("GBK");
  185. for (int i = 0; i < foodNames.length; i++) {
  186. if (i == 0) {
  187. byte[] itemNames = foodNames[i].getBytes("GBK");
  188. Integer mod = itemNames.length % ROW_MAX_CHAR_LEN;
  189. builder.append(foodNames[i]);
  190. builder.append(StringUtils.repeat(" ", (MAX_NAME_CHAR_LEN - mod)));
  191. builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN - itemQuans.length)));
  192. builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN - itemPrices.length)));
  193. } else {
  194. builder.append(foodNames[i]).append("<BR>");
  195. }
  196. }
  197. }
  198. private static void getFoodNameSplit80(String foodName, StringBuilder builder, Double quantity, Double price) throws UnsupportedEncodingException {
  199. String[] foodNames = string2StringArray(foodName, LAST_ROW_MAX_NAME_CHAR_LEN80);
  200. String quanityStr = quantity.toString();
  201. byte[] itemQuans = quanityStr.getBytes("GBK");
  202. String priceStr = roundByTwo(price);
  203. byte[] itemPrices = (priceStr).getBytes("GBK");
  204. for (int i = 0; i < foodNames.length; i++) {
  205. if (i == 0) {
  206. byte[] itemNames = foodNames[i].getBytes("GBK");
  207. Integer mod = itemNames.length % ROW_MAX_CHAR_LEN80;
  208. builder.append(foodNames[i]);
  209. builder.append(StringUtils.repeat(" ", (MAX_NAME_CHAR_LEN80 - mod)));
  210. builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN80 - itemQuans.length)));
  211. builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN80 - itemPrices.length)));
  212. } else {
  213. builder.append(foodNames[i]).append("<BR>");
  214. }
  215. }
  216. }
  217. private static String[] string2StringArray(String src, Integer length) {
  218. if (StringUtils.isBlank(src) || length <= 0) {
  219. return null;
  220. }
  221. int n = (src.length() + length - 1) / length;
  222. String[] splits = new String[n];
  223. for (int i = 0; i < n; i++) {
  224. if (i < (n - 1)) {
  225. splits[i] = src.substring(i * length, (i + 1) * length);
  226. } else {
  227. splits[i] = src.substring(i * length);
  228. }
  229. }
  230. return splits;
  231. }
  232. /**
  233. * 将double格式化为指定小数位的String,不足小数位用0补全 (小数点后保留2位)
  234. * Format the double as a String with specified decimal places, fill in with 0 if the decimal place is not enough
  235. *
  236. * @param v - 需要格式化的数字 Number to be formatted
  237. * @return 返回指定位数的字符串 Returns a string with a specified number of digits
  238. */
  239. public static String roundByTwo(double v) {
  240. return roundByScale(v, 2);
  241. }
  242. /**
  243. * 将double格式化为指定小数位的String,不足小数位用0补全
  244. * Format the double as a String with specified decimal places, and use 0 to complete the decimal places
  245. *
  246. * @param v - 需要格式化的数字 number to be formatted
  247. * @param scale - 小数点后保留几位 places after the decimal point
  248. * @return 返回指定位数的字符串 Returns a string with a specified number of digits
  249. */
  250. public static String roundByScale(double v, int scale) {
  251. if (scale == 0) {
  252. return new DecimalFormat("0").format(v);
  253. }
  254. String formatStr = "0.";
  255. for (int i = 0; i < scale; i++) {
  256. formatStr = formatStr + "0";
  257. }
  258. return new DecimalFormat(formatStr).format(v);
  259. }
  260. }