using NLog; using POS.Language.Language; using POSV.Bean; using POSV.Entity; using POSV.Printer; using POSV.ShoppingCart; using POSV.Utils; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading; namespace POSV.Helper { public class LabelPrintHelper { private static Logger logger = NLog.LogManager.GetCurrentClassLogger(); /// /// 获取系统配置的商品标签打印机 /// /// public static PrinterObject GetLabelPrinterObject() { var json = Global.Instance.GlobalConfigStringValue(ConfigConstant.PERIPHERAL_LABEL_PRINTER); if (string.IsNullOrEmpty(json)) { json = JsonUtils.Serialize(ConfigConstant.PeripheralGroupDefaultValue()); } var printer = JsonUtils.Deserialize(json); return Trans2PrinterObject(printer); } public static PrinterObject Trans2PrinterObject(PrinterItem printer) { var pobject = new PrinterObject(); pobject.Id = printer.Id; pobject.Name = printer.Name; pobject.PortType = (PortType)Enum.Parse(typeof(PortType), printer.Port); pobject.DynamicLibrary = (DynamicLibrary)Enum.Parse(typeof(DynamicLibrary), printer.DynamicLibrary); pobject.PageWidth = printer.PageWidth; pobject.CutPager = false; pobject.OpenCashbox = false; if (printer.Dpi == 0) { pobject.Dpi = 203; } else { pobject.Dpi = printer.Dpi; } pobject.Data[PrinterObject.COM_PORT_NAME] = printer.Data[Constant.COM_PORT_NAME]; pobject.Data[PrinterObject.COM_PORT_BAUD] = printer.Data[Constant.COM_PORT_BAUD]; pobject.Data[PrinterObject.LPT_NAME] = printer.Data[Constant.LPT_NAME]; pobject.Data[PrinterObject.DRIVE_NAME] = printer.Data[Constant.DRIVE_NAME]; pobject.Data[PrinterObject.NET_IP_ADDRESS] = printer.Data[Constant.NET_IP_ADDRESS]; pobject.Data[PrinterObject.USB_PID] = printer.Data[Constant.USB_PID]; pobject.Data[PrinterObject.USB_VID] = printer.Data[Constant.USB_VID]; return pobject; } /// /// 打印订单标签 /// /// public static void PrintOrderLabel(OrderObject order, bool updateDbPrintNum = true) { if (order.OrderType == OrderType.饿了么 || order.OrderType == OrderType.美团外卖 || order.OrderType == OrderType.百度外卖) { var enablePrintLabel = Global.Instance.GlobalConfigBoolValue(ConfigConstant.PERIPHERAL_LABEL_WMPRINT, false); if (!enablePrintLabel) { logger.Info("标签打印:未启用外卖打印标签"); return; } } else { var enablePrintLabel = Global.Instance.GlobalConfigBoolValue(ConfigConstant.PERIPHERAL_LABEL_PRINT_ONSALE, false); if (!enablePrintLabel) { logger.Info("标签打印:未启用销售打印标签"); return; } } //打印标签的item var printLabelItems = order.Items.FindAll(x => x.LabelPrintFlag == 1 && x.RowState != OrderRowState.套餐主); var labelRes = LabelPrintHelper.InstallLabelList(order, printLabelItems, PrintTypeEnum.标签); var labelList = labelRes.Item1; var printItemList = labelRes.Item2; if (labelList.Count > 0) { var tems = Global.Instance.GlobalConfigStringValue(ConfigConstant.PERIPHERAL_LABEL_TEMPLATE); if (!string.IsNullOrEmpty(tems)) { var temObj = JsonUtils.Deserialize>(tems); if (temObj != null) { var tem = temObj.Find(x => x.Name == "普通标签"); if (tem != null) { PrintLabel(tem, labelList); logger.Info("打印订单所有标签完成"); //更新标签打印内容 if (printItemList.Count > 0) { foreach (var item in printItemList) { item.LabelQty = item.Quantity; } if (updateDbPrintNum) { lock (Global.Instance.SyncLock) { using (var db = Global.Instance.OpenDataBase) { using (var transaction = db.GetTransaction()) { foreach (var item in printItemList) { db.Update(item); } transaction.Complete(); } } } } } } } else { logger.Error("未配置标签打印模板,不打印"); } } else { logger.Error("未配置标签打印模板,不打印"); } } } /// /// 组装标签数据源 /// /// /// /// public static Tuple>, List> InstallLabelList(OrderObject order, List _printLabelItems, PrintTypeEnum printType) { List> labelList = new List>(); decimal totalNum = 0;//待打印标签总数 List printLabelItems = null; if (order.OrderType == OrderType.美团外卖) printLabelItems = _printLabelItems.Where(f => !f.Name.Equals("打包费") && !f.Name.Equals("配送费")).ToList(); else printLabelItems = _printLabelItems; if (order.RPrint) { //重打,全部打印 totalNum = printLabelItems.Sum(x => x.Quantity); } else { if (printType == PrintTypeEnum.厨打标签) { totalNum = printLabelItems.Sum(x => x.Quantity - x.ChuDaLabelQty); } else { totalNum = printLabelItems.Sum(x => x.Quantity - x.LabelQty); } } var tradeNo = order.TradeNo; //票号长度 int length = Global.Instance.GlobalConfigIntValue(ConfigConstant.CONFIG_CASHIER_TICKETNO_LENGTH, 0); //随机票号 bool isRandom = Global.Instance.GlobalConfigBoolValue(ConfigConstant.CONFIG_CASHIER_RANDOM_TICKETNO, false); if (isRandom) { tradeNo = order.ObjectId; } if (length > 0 && (tradeNo.Length - length > 0)) { tradeNo = tradeNo.Substring(tradeNo.Length - length); } //时间格式 var dateFormat = Global.Instance.GlobalConfigStringValue(ConfigConstant.PERIPHERAL_LABEL_DATEFORMAT, "MM-dd HH:mm"); //门店电话 var phone = Global.Instance.Worker.StoreInfo.OrderTel; //小数位数 var digit = Global.Instance.GlobalConfigIntValue(ConfigConstant.PERIPHERAL_LABEL_DIGIT); var _NoPrintSpec = Global.Instance.GlobalConfigBoolValue(ConfigConstant.PERIPHERAL_LABEL_NOPRINTSPEC, false); //练习模式 string studyName = string.Empty; if (Global.Instance.IsStudyMode()) { studyName = Constant.STUDYMODE_PRINTSTR; } //执行打印的订单项 List printItemList = new List(); int seq = 1; //组装打印标签数据 foreach (var item in printLabelItems) { if (order.OrderType == OrderType.美团外卖 && item.Name.Contains("打包费")) { continue; } //金额,使用原价 + 做法金额 decimal price = 0; if (item.Quantity != 0) { price = StringUtils.GetDecimal(StringUtils.FormatDataSwitch((item.Price + item.FlavorAmount / item.Quantity), digit)); } if (order.OrderType == OrderType.美团外卖) { price = StringUtils.GetDecimal(StringUtils.FormatDataSwitch(item.Price, digit)); } bool isDoPrint = false; decimal preparePrintQuantity = 0; if (order.RPrint) { //重打,全部打印 preparePrintQuantity = item.Quantity; } else { if (printType == PrintTypeEnum.厨打标签) { preparePrintQuantity = item.Quantity - item.ChuDaLabelQty; } else { preparePrintQuantity = item.Quantity - item.LabelQty; } } for (int i = 0; i < preparePrintQuantity; i++) { var dic = new Dictionary(); dic["#桌号#"] = order.TableName; dic["#营业模式#"] = LangProxy.ToLang(order.OrderType.ToString()); dic["#产品序号#"] = string.Format("[{0}/{1}]", seq, totalNum); dic["#订单序号#"] = order.OrderNo; if (Global.Instance.IsStudyMode())//练习模式固定序号 { dic["#订单序号#"] = Constant.STUDYMODE_DEFAULT_ORDERNO; } if (order.RPrint) { //重打,加标识 dic["#订单序号#"] = Constant.REPRINT_SIGN + order.OrderNo; } //var storeName = string.IsNullOrEmpty(Global.Instance.Worker.StoreInfo.PrintName) ? order.StoreName : Global.Instance.Worker.StoreInfo.PrintName; dic["#门店#"] = Global.Instance.Worker.StoreInfo.PrintName; dic["#金额#"] = string.Format("¥{0}", price); if (order.OrderType == OrderType.饿了么) { dic["#票号#"] = order.OrderNo; //将饿了么品名后面的中括号中的做法截取出来 int firstIndex = item.OtherWaimaiPrintName.LastIndexOf('['); int endIndex = item.OtherWaimaiPrintName.LastIndexOf(']'); string makeName = string.Empty; string productName = string.Empty; if (firstIndex > 0 && endIndex > 0 && firstIndex < endIndex) { makeName = item.OtherWaimaiPrintName.Substring(firstIndex + 1, endIndex - firstIndex - 1); productName = item.OtherWaimaiPrintName.Substring(0, firstIndex); } else { makeName = ""; productName = item.OtherWaimaiPrintName; } dic["#做法#"] = makeName; dic["#品名#"] = productName; } else if (order.OrderType == OrderType.美团外卖) { dic["#票号#"] = order.OrderNo; //if (item.SpecName != null && !"".Equals(item.SpecName)) //{ // item.OtherWaimaiPrintName = item.Name + "[" + item.SpecName + "]"; //} //else //{ // item.OtherWaimaiPrintName = item.Name; //} //item.OtherWaimaiPrintMake = item.LabelFlavorNames == null ? "" : "[" + item.LabelFlavorNames + "]"; dic["#做法#"] = string.Join(",", item.Flavors.Where(f => !f.Description.Equals("打包费") && !f.Description.Equals("餐盒费") && !f.Description.Equals("配送费") && !f.Description.Equals("商家优惠")).ToList()); var name = item.ShortName; if (!string.IsNullOrEmpty(item.SpecName)) { if (!_NoPrintSpec) { if (!string.IsNullOrEmpty(item.SpecName)) { name = string.Format("{0}[{1}]", item.ShortName, item.SpecName); } } dic["#品名#"] = name; } else { dic["#品名#"] = string.Format("{0}", item.DisplayName); } } else if (order.OrderType == OrderType.微信点餐) { var name = item.ShortName; if (!string.IsNullOrEmpty(item.SpecName)) { if (!_NoPrintSpec) { if (!string.IsNullOrEmpty(item.SpecName)) { name = string.Format("{0}[{1}]", item.ShortName, item.SpecName); } } dic["#品名#"] = name; } else { dic["#品名#"] = string.Format("{0}", item.DisplayName); } dic["#票号#"] = order.OrderNo; dic["#做法#"] = item.LabelFlavorNames; } else { dic["#票号#"] = tradeNo; dic["#做法#"] = item.LabelFlavorNames; var name = item.ShortName; if (!_NoPrintSpec) { if (!string.IsNullOrEmpty(item.SpecName)) { name = string.Format("{0}[{1}]", item.ShortName, item.SpecName); } } dic["#品名#"] = studyName + name; } dic["#时间#"] = Convert.ToDateTime(order.FinishDate).ToString(dateFormat); dic["#电话#"] = phone; seq++; labelList.Add(dic); isDoPrint = true; } if (isDoPrint) { printItemList.Add(item); } } return new Tuple>, List>(labelList, printItemList); } /// /// 使用默认标签打印机打印 /// /// /// public static void PrintLabel(LabelTemplate template, List> list) { var pObject = GetLabelPrinterObject(); PrintLabel(pObject, template, list); } /// /// 标签打印 /// /// /// public static void PrintLabel(PrinterObject pObject, LabelTemplate template, List> list) { try { var LabeRotate = Global.Instance.GlobalConfigBoolValue(ConfigConstant.PERIPHERAL_LABEL_ROTATE, false); int labelPrinterDpi = pObject.Dpi; var control = template.LabelControl; var paddingTop = control.PaddingTop; var paddingLeft = control.PaddingLeft; StringBuilder header = new StringBuilder(); header.AppendLine("CLS");//清除缓存 header.AppendLine(string.Format("SIZE {0} mm,{1} mm", control.Width, control.Height)); header.AppendLine(string.Format("GAP {0} mm,0 mm", control.RowGap));//两张标签的垂直距离 if (LabeRotate)//是否选择180 { header.AppendLine("DIRECTION 0,0");//出纸方向 } else { header.AppendLine("DIRECTION 1,0");//出纸方向 } StringBuilder bottom = new StringBuilder(); bottom.AppendLine("PRINT 1");//将打印机缓存输出 bottom.AppendLine("EOP");//程序结束 string printerFont = "\"TSS24.BF2\"";//中文 foreach (var dic in list) { StringBuilder printContent = new StringBuilder(); foreach (var tem in template.LabelContentList) { //xy转换为打印机对应的坐标 var dotX = DpiUtils.PixelsToDots(control.ScreenDpi, tem.X, labelPrinterDpi) + DpiUtils.MillimetersToDots(labelPrinterDpi, Convert.ToDouble(paddingLeft)); var dotY = DpiUtils.PixelsToDots(control.ScreenDpi, tem.Y, labelPrinterDpi) + DpiUtils.MillimetersToDots(labelPrinterDpi, Convert.ToDouble(paddingTop)); var textTem = string.Format("TEXT {0},{1},{2},0,{3},{4},", dotX, dotY, printerFont, tem.X_multiplication, tem.Y_multiplication); MatchCollection mc = Regex.Matches(tem.Text, "#(.*)#"); if (mc.Count > 0) { var temText = tem.Text; bool isPrinted = false; string targetStr = mc[0].ToString(); if (dic.ContainsKey(targetStr)) { if (!string.IsNullOrEmpty(dic[targetStr])) { if ("#做法#".Equals(targetStr) || "#品名#".Equals(targetStr)) { int maxRowLength = DpiUtils.GetStrNumOneRow(labelPrinterDpi, Convert.ToDouble(control.Width)) - 1; var makeText = tem.Text.Replace(targetStr, dic[targetStr]); var makeLength = GetPrintStringLength(makeText); //倍宽,字体宽度加倍 makeLength = tem.X_multiplication == 2 ? makeLength * 2 : makeLength; if (makeLength > maxRowLength) { //换行打印 //倍宽字体,截取长度减半 var currRowLength = tem.X_multiplication == 2 ? maxRowLength / 2 : maxRowLength; var index = GetCompleteStringLength(makeText, currRowLength); printContent.Append(textTem).AppendLine("\"" + makeText.Substring(0, index) + "\""); //再打印一行,倍高,行高加倍 var lineHeight = tem.Y_multiplication == 2 ? 48 : 24; printContent.Append(string.Format("TEXT {0},{1},{2},0,{3},{4},", dotX, dotY + lineHeight, printerFont, tem.X_multiplication, tem.Y_multiplication)) .AppendLine("\"" + makeText.Substring(index) + "\""); isPrinted = true; } else { temText = tem.Text.Replace(targetStr, dic[targetStr]); } } else { temText = tem.Text.Replace(targetStr, dic[targetStr]); } } else { temText = tem.Text.Replace(targetStr, ""); } } else { temText = tem.Text.Replace(targetStr, ""); } if (!isPrinted) { printContent.Append(textTem).AppendLine("\"" + temText + "\""); } } else { printContent.Append(textTem).AppendLine("\"" + tem.Text + "\""); } } //组装整个打印内容 StringBuilder allContent = new StringBuilder(); allContent.Append(header); allContent.Append(printContent); allContent.Append(bottom); var pContentList = new List(); PrintContent pContent = new PrintContent(); pContent.Content = allContent; pContent.Format = RowFormat.None; pContentList.Add(pContent); logger.Info("向打印机发送打印标签:" + allContent); //向打印机发送打印 LabelPrinterUtils.PrintContent(pObject, pContentList); logger.Info("打印标签完成"); var delay = Global.Instance.GlobalConfigIntValue(ConfigConstant.PERIPHERAL_LABEL_PRINT_DELAY, 1); //延迟 logger.Info("标签打印延迟时长:<" + delay + ">"); if (delay > 0) { Thread.Sleep(delay * 1000); } } } catch (Exception ex) { logger.Error(ex, "标签打印异常"); } } /// /// 获取字符串长度 /// /// /// public static int GetPrintStringLength(string str) { int valueLength = 0; //排除str为null str = str ?? ""; string chinese = @"^[\u0391-\uFFE5]+$"; // 获取字段值的长度,如果含中文字符,则每个中文字符长度为2,否则为1 for (int i = 0; i < str.Length; i++) { // 获取一个字符 string temp = str[i].ToString(); // 判断是否为中文字符 if (Regex.IsMatch(temp, chinese)) { valueLength += 2; } else { valueLength += 1; } } // 进位取整 return valueLength; } /// /// 获取指定长度的完整字符串 /// /// /// /// public static int GetCompleteStringLength(string str, int length) { int valueLength = 0; //排除str为null str = str ?? ""; string chinese = @"^[\u0391-\uFFE5]+$"; // 获取字段值的长度,如果含中文字符,则每个中文字符长度为2,否则为1 for (int i = 0; i < str.Length && valueLength < length; i++) { // 获取一个字符 string temp = str[i].ToString(); // 判断是否为中文字符 if (Regex.IsMatch(temp, chinese)) { if (valueLength + 2 > length) { return i - 1; } else { valueLength += 2; } } else { valueLength += 1; } if (valueLength == length) { return i; } } return str.Length; } } }