You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

639 lines
26 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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();
/// <summary>
/// 获取系统配置的商品标签打印机
/// </summary>
/// <returns></returns>
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<PrinterItem>(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;
}
/// <summary>
/// 打印订单标签
/// </summary>
/// <param name="order"></param>
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<List<LabelTemplate>>(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("未配置标签打印模板,不打印");
}
}
}
/// <summary>
/// 组装标签数据源
/// </summary>
/// <param name="order"></param>
/// <param name="printLabelItems"></param>
/// <returns></returns>
public static Tuple<List<Dictionary<string, string>>, List<OrderItem>> InstallLabelList(OrderObject order, List<OrderItem> _printLabelItems, PrintTypeEnum printType)
{
List<Dictionary<string, string>> labelList = new List<Dictionary<string, string>>();
decimal totalNum = 0;//待打印标签总数
List<OrderItem> 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<OrderItem> printItemList = new List<OrderItem>();
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<string, string>();
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<Dictionary<string, string>>, List<OrderItem>>(labelList, printItemList);
}
/// <summary>
/// 使用默认标签打印机打印
/// </summary>
/// <param name="template"></param>
/// <param name="list"></param>
public static void PrintLabel(LabelTemplate template, List<Dictionary<string, string>> list)
{
var pObject = GetLabelPrinterObject();
PrintLabel(pObject, template, list);
}
/// <summary>
/// 标签打印
/// </summary>
/// <param name="template"></param>
/// <param name="list"></param>
public static void PrintLabel(PrinterObject pObject, LabelTemplate template, List<Dictionary<string, string>> 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>();
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, "标签打印异常");
}
}
/// <summary>
/// 获取字符串长度
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取指定长度的完整字符串
/// </summary>
/// <param name="str"></param>
/// <param name="length"></param>
/// <returns></returns>
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;
}
}
}