using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using DevComponents.DotNetBar; using NLog; using POS.Language.Language; using POSV.Bill; using POSV.Card; using POSV.Entity; using POSV.MessageEvent; using POSV.Payment.AllinPay; using POSV.ShoppingCart; using POSV.Utils; namespace POSV { public partial class BillFormExt : BusinessForm { /// /// 收银方式集合 /// private Dictionary _tabs = null; /// /// 当前选择的收银方式 /// private SuperTabItem _currentTabItem = null; /// /// 收银标识列表 /// private List _payTypeList = null; /// /// 支付方式列表 /// private List _payModeList = null; /// /// 当前选择的收银方式 /// private PayType _currentPayType = null; /// /// 当前选择的付款类型 /// private PayMode _currentPayMode = null; /// /// 当前选择的付款类型 /// private string _defaultSelected = string.Empty; /// /// 当期订单对象的复制对象,避免取消结账污染元数据 /// private OrderObject _orderObject = null; public BillFormExt() { InitializeComponent(); MsgEvent.RemoveListener(Constant.PAY_MESSAGE_EVENT_NOTIFY, MessageEventNotify); MsgEvent.Receive(Constant.PAY_MESSAGE_EVENT_NOTIFY, MessageEventNotify); MsgEvent.RemoveListener(Constant.PAY_AUTO_EVENT_NOTIFY, FinishedEventNotify); MsgEvent.Receive(Constant.PAY_AUTO_EVENT_NOTIFY, FinishedEventNotify); this._tabs = new Dictionary(); this.ImeMode = ImeMode.Disable; InitializePayType(); //第一次加载的时候触发切换标签事件 this.tabPayType.SelectedTab = null; ButtonAccept.Text = LangProxy.ToLang(ButtonAccept.Text); ButtonCancel.Text = LangProxy.ToLang(ButtonCancel.Text); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); if (this.DesignMode) return; } private void InitializePayType() { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); try { //获取付款方式列表 this._payTypeList = OrderUtils.GetPayTypeList(); //获取收银方式列表,获取前台展示 排除抹零 this._payModeList = OrderUtils.GetPayModeList().FindAll(x => x.FrontFlag == 1 && x.No != "06"); #region subin 2023-07-01 增加通联付款方式、通联收银方式 TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); //var allinPayType = new PayType //{ // Id = ts.TotalSeconds.ToString(), // Name = "通联支付", // TenantId = Global.Instance.BusinessPlanLog.TenantId, // No = "50", // Sign = "allinpay", // CreateUser = "sync", // CreateDate = DateTime.Now.ToString() //}; //this._payTypeList.Add(allinPayType); var allinPayType = this._payModeList.FirstOrDefault(m => m.No == "50"); if (allinPayType != null) { if (allinPayType.Body.Count() == 0) { var payModelBody = new Dictionary(); payModelBody.Add("channel", "allinpay"); payModelBody.Add("appId", AllinpayLib.AppId); payModelBody.Add("appKey", AllinpayLib.AppKey); payModelBody.Add("gatewayUrl", AllinpayLib.Url); var store = Global.Instance.Worker.StoreInfo; if (store == null) { using (var db = Global.Instance.OpenDataBase) { store = db.FirstOrDefault("where id = @0", Global.Instance.Authc.StoreId); } } if (!string.IsNullOrEmpty(store.Ext1)) { var storeAllinParams = JsonUtils.Deserialize(store.Ext1); AllinpayLib.Payuserid = storeAllinParams.PayuserId; AllinpayLib.VspCusid = storeAllinParams.VspCusid; AllinpayLib.BizUserId = storeAllinParams.BizUserId; } payModelBody.Add("payuserid", AllinpayLib.Payuserid); payModelBody.Add("vspCusid", AllinpayLib.VspCusid); payModelBody.Add("bizUserId", AllinpayLib.BizUserId); allinPayType.Body = payModelBody; } } //var p = this._payModeList.Find(m => m.No == "50"); //if (p == null) //{ // this._payModeList.Add(new PayMode // { // Id = ts.TotalSeconds.ToString(), // TenantId = Global.Instance.BusinessPlanLog.TenantId, // TypeId = allinPayType.Id, // Name = "通联支付", // No = "50", // Body = payModelBody, // CertText = null, // CreateUser = "sync", // CreateDate = DateTime.Now.ToString(), // Discount = 100, // FrontFlag = 1, // PointFlag = 1, // RechargeFlag = 0, // Shortcut = "", // FixeAmount = 0, // IncomeFlag = 0, // OtherRateType = 0, // OtherRateValue = 0 // }); //} //else //{ // p.TypeId = allinPayType.Id; // p.Body = payModelBody; //} #endregion //获取默认的收银 if (!string.IsNullOrEmpty(this._defaultSelected)) { if (Constant.HEMA_CODE.Equals(this._defaultSelected)) { this._currentPayMode = this._payModeList.FirstOrDefault(x => Constant.HEMA_PAY.Contains(x.No)); } else { this._currentPayMode = this._payModeList.FirstOrDefault(x => x.No.Equals(this._defaultSelected)); } } //选择默认 if (this._currentPayMode == null) { this._currentPayMode = OrderUtils.GetDefaultPayMode(); } foreach (var type in this._payTypeList) { //如果收银标识中有可用的支付方式 if (this._payModeList.Exists(x => x.TypeId == type.Id)) { var tabText = type.Name; //如果只有一个支付方式 if (this._payModeList.Count(x => x.TypeId == type.Id) == 1) { var mode = this._payModeList.First(x => x.TypeId == type.Id); tabText = mode.Name; } var tab = this.tabPayType.CreateTab(tabText); //支付方式压入 tab.Tag = type; tab.FixedTabSize = new Size(100, 45); tab.Text = LangProxy.ToLang(tab.Text); this._tabs.Add(type.Id, tab); //选择默认付款类型 if (type.Id.Equals(this._currentPayMode.TypeId)) { this._currentTabItem = tab; this._currentPayType = type; } } } this.tabPayType.SelectedTabChanging -= OnTabPayTypeSelectedTabChanging; this.tabPayType.SelectedTabChanging += OnTabPayTypeSelectedTabChanging; this.tabPayType.SelectedTabChanged -= OnTabPayTypeSelectedTabChanged; this.tabPayType.SelectedTabChanged += OnTabPayTypeSelectedTabChanged; } catch (Exception ex) { LOGGER.Error(ex, "初始化收银方式异常"); } finally { sw.Stop(); LOGGER.Info("PayType耗时<{0}>", sw.ElapsedMilliseconds); } } public void RefreshUi(string payModeNo, OrderObject orderObject) { try { this._orderObject = orderObject; //默认选择的付款标识 this._defaultSelected = payModeNo; //复制新对象,避免取消后污染原对象 this._orderObject = ObjectUtils.Copy(orderObject); //获取默认的收银 if (!string.IsNullOrEmpty(this._defaultSelected)) { if (Constant.HEMA_CODE.Equals(this._defaultSelected)) { this._currentPayMode = this._payModeList.FirstOrDefault(x => Constant.HEMA_PAY.Contains(x.No)); } else { this._currentPayMode = this._payModeList.FirstOrDefault(x => x.No.Equals(this._defaultSelected)); } } //选择默认 if (this._currentPayMode == null) { this._currentPayMode = OrderUtils.GetDefaultPayMode(); } LOGGER.Info("选择的支付方式<{0},{1}>", _currentPayMode.No, _currentPayMode.Name); foreach (var type in this._payTypeList) { //如果收银标识中有可用的支付方式 if (this._payModeList.Exists(x => x.TypeId == type.Id)) { //选择默认付款类型 if (type.Id.Equals(this._currentPayMode.TypeId)) { this._currentPayType = type; this._currentTabItem = this._tabs[type.Id]; } } } LOGGER.Info("选择的支付方式后<{0}>", this._currentPayType.Name); } catch (Exception ex) { LOGGER.Error(ex, "RefreshUi异常"); } } private void RefreshUi(PayType payType) { this._currentTabItem = this._tabs[payType.Id]; BillControl bill = null; int attached = this.tabPayType.SelectedTab.AttachedControl.Controls.Count; if (attached == 0) { bill = new BillControl(); bill.Dock = DockStyle.Fill; this.tabPayType.SelectedTab.AttachedControl.Controls.Add(bill); LOGGER.Info("注册支付模块"); } else { bill = this.tabPayType.SelectedTab.AttachedControl.Controls[0] as BillControl; LOGGER.Info("加载支付模块"); } //获取收银方式列表 var data = this._payModeList.FindAll(x => x.TypeId == payType.Id); bill.RefreshUi(data, this._currentPayMode, this._orderObject); this.ActiveControl = bill; } private void OnTabPayTypeSelectedTabChanged(object sender, SuperTabStripSelectedTabChangedEventArgs e) { if (e.NewValue != null && e.NewValue.Tag != null) { var payType = e.NewValue.Tag as PayType; this.RefreshUi(payType); } } private void OnTabPayTypeSelectedTabChanging(object sender, SuperTabStripSelectedTabChangingEventArgs e) { if (e.NewValue != null && e.NewValue.Tag != null) { var payType = e.NewValue.Tag as PayType; //获取当前付款类型下的全部收银方式 var modes = this._payModeList.FindAll(x => x.TypeId == payType.Id); //判断当前收银方式是否包含,如果不包含自动选择第一个为当前收银方式 if (!modes.Exists(x => x.No == this._currentPayMode.No)) { this._currentPayMode = modes.OrderByDescending(m=>m.No).First(); } } } /// /// 操作提示 /// /// /// protected virtual void MessageEventNotify(object sender, MsgEventArgs args) { if (args.Data != null && args.Data is Tuple) { var data = args.Data as Tuple; this.ShowMessage(this.lblInfo, data.Item2, data.Item1); } } /// /// /// /// /// protected virtual void FinishedEventNotify(object sender, MsgEventArgs args) { this.Invoke(new Action(() => { this.OnFinishedClick(this.ButtonAccept, EventArgs.Empty); })); } private void OnControlBoxCloseClick(object sender, EventArgs e) { if (this.Owner != null) { this.Owner.Close(); } #region subin 20231011 add 关闭时清理数据 if (((System.Windows.Forms.Control)sender).Tag == null) { //通知结账缓存界面清理数据,无论支付完成还是取消都要调用 MsgEvent.Send(Constant.ORDER_PAYMENT_FINISHED, this._orderObject.TradeNo); } #endregion this.Close(); } protected void OnEscapeClick(object sender, EventArgs e) { //通知结账缓存界面清理数据,无论支付完成还是取消都要调用 MsgEvent.Send(Constant.ORDER_PAYMENT_FINISHED, this._orderObject.TradeNo); OnControlBoxCloseClick(sender, e); } protected void OnFinishedClick(object sender, EventArgs e) { Stopwatch watch = Stopwatch.StartNew(); try { var billControl = this._currentTabItem.AttachedControl.Controls[0] as BillControl; billControl.SimulateKeyboard(); var button = sender as ButtonX; //输入是否满足结账条件:消费金额 = 实收金额 + 优惠金额 + 抹零金额 //bool isVerify = this._orderObject.Amount == this._orderObject.PaidAmount + this._orderObject.DiscountAmount + this._orderObject.MalingAmount; //重新计算人民币的应收金额 RefreshCashShouldAmount(); //输入是否满足结账条件:消费明细中实收金额的合计 = 主单中的实收金额 var isVerify = this._orderObject.Pays.Sum(x => x.PaidAmount) >= this._orderObject.PaidAmount; //支付金额为零,不需要支付方式,这时添加默认支付方式,主要是弹框无支付方式情况的特殊处理 if (isVerify && this._orderObject.Pays.Count == 0) { //构建现金支付方式 var cashPayMode = OrderUtils.GetDefaultPayMode(); PayItem item = OrderUtils.ToPayItem(cashPayMode); //订单ID item.OrderId = this._orderObject.Id; //收银票号 item.TradeNo = this._orderObject.TradeNo; //实收金额 item.Amount = 0.00M; //操作员输入的金额 item.PaidAmount = 0.00M; //找零金额 item.ChangeAmount = 0.00M; item.CardNo = ""; item.Memo = "弹框现金快速结账"; item.Status = (int)OrderPaymentStatus.已付款; item.StatusDesc = "弹框默认现金快速结账"; item.PayTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); //将支付方式压入整单支付明细中 this._orderObject.Pays.Add(item); } //满足结账条件 if (isVerify) { this.ShowMessage(this.lblInfo, "满足结账条件", false); //默认支付成功 bool isPaySuccess = true; //查找会员卡支付列表,如果有会员卡先扣会员卡钱 var cards = this._orderObject.Pays.FindAll(x => x.No.Equals("02") || x.No.Equals("49")); //包含会员卡支付,构建会员卡扣款列表 if (cards != null && cards.Count > 0) { LOGGER.Warn("满足结账条件,共{0}张会员卡参与支付", cards.Count); //交易参考号 string tradeVoucherNo = string.Empty; //扣款卡列表 var payCards = new List(); foreach (var card in cards) { if (card.Amount <= 0) { continue; } PayInfo c = new PayInfo(); c.PrePayment = cards[cards.Count - 1].PrePayNo; c.CardNo = card.CardNo; c.Amount = Convert.ToInt32(card.Amount * 100); c.IsNoPwd = card.UseConfirmed ? 0 : 1; c.Passwd = card.Passwd; payCards.Add(c); tradeVoucherNo = card.TradeVoucherNo; LOGGER.Warn("卡号:{0},扣款:{1}", c.CardNo, c.Amount); } //记积分金额 var pointAmount = this._orderObject.Pays.FindAll(x => x.PointFlag == 1).Sum(x => x.Amount); var request = new CardTradePayRequest(); request.TradeNo = this._orderObject.TradeNo; request.MemberId = this._orderObject.Member == null ? string.Empty : this._orderObject.Member.Id; request.Mobile = this._orderObject.Member == null ? string.Empty : this._orderObject.Member.Mobile; request.TradeVoucherNo = tradeVoucherNo; request.TotalAmount = Convert.ToInt32(this._orderObject.Amount * 100); //实收金额 request.RealAmount = Convert.ToInt32(this._orderObject.PaidAmount * 100); request.PointAmount = this._orderObject.Member == null ? 0 : Convert.ToInt32(pointAmount * 100); request.PayCardAmount = payCards.Sum(x => x.Amount); request.DiscountAmount = Convert.ToInt32(this._orderObject.DiscountAmount * 100); request.PointFlag = 2;//以卡系统计算为准 request.PointValue = 0; request.PayInfo = payCards; var pays = new List(); foreach (var p in this._orderObject.Pays) { var pay = new Pay(); pay.PayTypeNo = p.No; pay.PayType = p.Name; pay.Money = Convert.ToInt32(p.Amount * 100); pay.PointRule = string.Empty; pay.Point = 0; pays.Add(pay); } //特殊处理 if (Integral(this._orderObject)) { var item = OrderUtils.GetPayTypeList().FirstOrDefault(f => f.No.Equals("02")); if (item != null) { var pay = new Pay(); pay.PayTypeNo = item.No; pay.PayType = item.Name; pay.Money = 0; pay.PointRule = string.Empty; pay.Point = 0; pays.Add(pay); request.PointAmount = (int)(this._orderObject.Pays.Sum(x => x.Amount) * 100); } } request.Pay = pays; int couponTotalAmount = 0; var coupons = new List(); if (this._orderObject.Promotions != null) { foreach (PromotionOrder promotionOrder in this._orderObject.Promotions) { if (PromotionType.电子代金券 == promotionOrder.PromotionType) { Coupon coupon = new Coupon(); coupon.CouponId = promotionOrder.CouponId; coupon.CouponType = "CASH"; coupon.Title = promotionOrder.PlanName; coupon.Code = promotionOrder.PlanNo; coupon.Discount = String.Format("{0}", promotionOrder.DiscountRate); coupon.Cash = String.Format("{0}", promotionOrder.DiscountAmount); coupon.Gift = promotionOrder.PlanName; coupon.Memo = String.Format("电子代金券,优惠{0}", promotionOrder.DiscountAmount); couponTotalAmount += Convert.ToInt32(promotionOrder.DiscountAmount * 100); coupons.Add(coupon); } else if (PromotionType.电子折扣券 == promotionOrder.PromotionType) { Coupon coupon = new Coupon(); coupon.CouponId = promotionOrder.CouponId; coupon.CouponType = "DISCOUNT"; coupon.Title = promotionOrder.PlanName; coupon.Code = promotionOrder.PlanNo; coupon.Discount = String.Format("{0}", promotionOrder.DiscountRate); coupon.Cash = String.Format("{0}", promotionOrder.DiscountAmount); coupon.Gift = promotionOrder.PlanName; coupon.Memo = String.Format("电子折扣券,优惠{0}", promotionOrder.DiscountAmount); couponTotalAmount += Convert.ToInt32(promotionOrder.DiscountAmount * 100); coupons.Add(coupon); } } } if (this._orderObject.Items != null) { foreach (OrderItem orderItem in this._orderObject.Items) { if (orderItem.Promotions != null) { foreach (PromotionItem promotionItem in orderItem.Promotions) { if (PromotionType.电子兑换券 == promotionItem.PromotionType) { Coupon coupon = new Coupon(); coupon.CouponId = promotionItem.CouponId; coupon.CouponType = "GIFT"; coupon.Title = promotionItem.PlanName; coupon.Code = promotionItem.PlanNo; coupon.Discount = String.Format("{0}", promotionItem.DiscountRate); coupon.Cash = String.Format("{0}", promotionItem.DiscountAmount); coupon.Gift = promotionItem.PlanName; coupon.Memo = String.Format("电子兑换券,优惠{0}", promotionItem.DiscountAmount); couponTotalAmount += Convert.ToInt32(promotionItem.DiscountAmount * 100); coupons.Add(coupon); } } } } } request.Coupon = coupons; request.CouponTotalAmount = couponTotalAmount; request.ShopNo = Global.Instance.Authc.StoreNo; request.WorkerNo = Global.Instance.Worker.No; request.PosNo = Global.Instance.Authc.PosNo; //var _data = ObjectUtils.Copy(this._orderObject); ////_data. = OrderUtils.Instance.GenerateTicketNo(); //var result = BusinessUtils.Instance.AddCardPoint4Order(this._orderObject); //if (result.Item1) //{ // isPaySuccess = true; //} //else //{ // MsgEvent.Send(Constant.PAY_MESSAGE_EVENT_NOTIFY, new Tuple(true, result.Item2)); // isPaySuccess = false; //} LOGGER.Warn("发起会员卡扣款....."); var payResult = CardUtils.CardTradePay(request); LOGGER.Warn("会员卡扣款耗时<{0}>毫秒", watch.ElapsedMilliseconds); if (payResult.Item1) { //会员卡扣款清单,用于打印 this._orderObject.CardPayResult = payResult.Item3; var payRes = payResult.Item3; //刷卡后积分计入主单 this._orderObject.PrePoint = OrderUtils.ToRound(payRes.PrePoint / 100.00M); this._orderObject.AddPoint = OrderUtils.ToRound(payRes.GiftPoint / 100.00M); this._orderObject.AftPoint = OrderUtils.ToRound(payRes.AftPoint / 100.00M); //调整每张卡的扣款状态 foreach (var card in cards) { var payCard = payRes.CardList.Find(x => x.CardNo == card.CardNo); if (payCard == null) { LOGGER.Error(string.Format("会员卡[{0}]支付成功后返回结果未包含该卡支付信息", card.CardNo)); } else { card.CardBeforeBalance = OrderUtils.ToRound(payCard.PreAmount / 100.00M); card.CardAftAmount = OrderUtils.ToRound(payCard.AftAmount / 100.00M); } card.Status = (int)OrderPaymentStatus.已付款; card.StatusDesc = payResult.Item2; card.PayTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); this.ShowMessage(this.lblInfo, payResult.Item2, false); } //会员卡扣款成功 isPaySuccess = true; } else { //会员卡扣款失败 isPaySuccess = false; this.ShowMessage(this.lblInfo, payResult.Item2, true); } } else { //不包含会员卡,进行判断是否使用会员,会员充值积分 if (this._orderObject.IsMember == 1) { var result = BusinessUtils.Instance.AddCardPoint4Order(this._orderObject); if (result.Item1) { isPaySuccess = true; } else { MsgEvent.Send(Constant.PAY_MESSAGE_EVENT_NOTIFY, new Tuple(true, result.Item2)); isPaySuccess = false; } } } //会员卡支付成功,核销美团券支付方式 if (isPaySuccess) { LOGGER.Info("检测是否有美团券需要核销......"); //zhangy 2020-04-24 优先核销美团团购券 var meituanCouponResult = BusinessUtils.Instance.MeituanCouponConsume(this._orderObject); if (meituanCouponResult.Item1) { //美团团购券核销成功 isPaySuccess = true; } else { MsgEvent.Send(Constant.PAY_MESSAGE_EVENT_NOTIFY, new Tuple(true, meituanCouponResult.Item2)); isPaySuccess = false; LOGGER.Info("美团券需要核销失败,原因:" + meituanCouponResult.Item2); } } //支付成功 if (isPaySuccess) { //整单状态 this._orderObject.OrderStatus = OrderStatus.已完成; //整单支付状态 this._orderObject.PaymentStatus = OrderPaymentStatus.已付款; //通知主界面结账成功 MsgEvent.Send(Constant.ORDER_PAYMENT_NOTIFY, this._orderObject); //关闭界面,清理资源 this.OnEscapeClick(this.ButtonCancel, EventArgs.Empty); } } else { this.ShowMessage(this.lblInfo, "不满足结账条件", false); } } catch (Exception ex) { this.ShowMessage(this.lblInfo, "结账操作发生异常", false); LOGGER.Error(ex, "结账操作发生异常"); ///上报异常信息 Global.Instance.BugReport(ex); } finally { LOGGER.Warn("调用完成结账方法,耗时<{0}>毫秒", watch.ElapsedMilliseconds); } } private bool Integral(OrderObject _orderObject) { var _why = _orderObject.Pays.FirstOrDefault(f => f.No.Equals("02")); var _xmk = _orderObject.Pays.FirstOrDefault(f => f.No.Equals("49")); if (_xmk == null) { return false; } if (_why != null) { return false; } if (_orderObject.Member == null) { return false; } return true; } /// /// 人民币付款方式的应收在混合支付中,应该在最后重新计算应收。 /// 比如订单金额10元,付款方式和顺序如下 /// 人民币付款5元,这时人民币的应收为10元 /// 其他付款5元,这时其他付款的应收为5元 /// 这样,支付方式合计应收为15元,不正确了,而且人民币的找零金额计算方式为实收 - 应收 = -5元,不正确 /// private void RefreshCashShouldAmount() { var cashPay = this._orderObject.Pays.Find(x => x.No == "01"); if (cashPay != null) { //现金应收 = 订单实收 - 除现金以外的支付金额 var cashShould = this._orderObject.PaidAmount - this._orderObject.Pays.FindAll(x => x.No != "01").Sum(x => x.PaidAmount); cashPay.Amount = cashShould; } } protected override void OnVisibleChanged(EventArgs e) { base.OnVisibleChanged(e); if (this.Visible) { this.tabPayType.SelectedTab = this._currentTabItem; //this.RefreshUi(this._currentPayType); LOGGER.Info("选择支付界面<{0}>", this._currentTabItem.Text); } else { this.tabPayType.SelectedTab = null; } } protected override void OnFormClosing(FormClosingEventArgs e) { base.OnFormClosing(e); e.Cancel = true; this.Visible = false; } } }