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#

9 months ago
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;
}
}
}