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.

701 lines
31 KiB
C#

9 months ago
using DevComponents.DotNetBar;
using DevComponents.DotNetBar.SuperGrid;
using POSV.Card;
using POSV.Entity;
using POSV.Helper;
using POSV.PayApi;
using POSV.Payment.Saobei;
using POSV.Payment.Saobei.Parameter;
using POSV.ShoppingCart;
using POSV.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace POSV.Member
{
public partial class GiftCardFormTicket : BusinessForm
{
public GiftCardFormTicket()
{
InitializeComponent();
this.controlBox1.Text = "礼品卡销售记录";
this.controlBox1.ShowApplicationVersion = false;
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (this.DesignMode) return;
this.startPicker.Value = DateTime.Parse(Global.Instance.BusinessPlan.StartTimeSimple);
this.endPicker.Value = DateTime.Parse(Global.Instance.BusinessPlan.EndTimeSimple);
this.Focus();
this.txtTradeNo.Focus();
this.txtTradeNo.SelectAll();
this.ActiveControl = this.txtTradeNo;
//第一步获取订单列表
List<CardSale> detail = getBusTicketList(this.startPicker.Value.ToString("yyyy-MM-dd HH:mm:ss"), this.endPicker.Value.ToString("yyyy-MM-dd HH:mm:ss"));
CardSaleTable.PrimaryGrid.DataSource = detail;
}
/// <summary>
/// 关闭窗口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnControlBoxCloseClick(object sender, EventArgs e)
{
OnCloseTouchClick(sender, e);
}
private void OnCloseTouchClick(object sender, EventArgs e)
{
//先关闭父窗体
if (this.Owner != null)
{
this.Owner.Close();
}
//再关闭当前窗体
this.Close();
}
/// <summary>
/// 最小化
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnControlBoxMinClick(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Minimized;
}
private void BtnExitClick(object sender, EventArgs e)
{
OnCloseTouchClick(sender, e);
}
/// <summary>
/// 时间选择
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnTimeClick(object sender, EventArgs e)
{
var obj = sender as ButtonX;
var typeStr = obj.Tag as string;
var type = (ReportQuickDate)Enum.Parse(typeof(ReportQuickDate), typeStr);
var res = DateTimeUtils.CalculateBusinessPlanDate(type, this.startPicker.Value, this.endPicker.Value);
this.startPicker.Value = res.Item1;
this.endPicker.Value = res.Item2;
List<CardSale> detail = getBusTicketList(this.startPicker.Value.ToString("yyyy-MM-dd HH:mm:ss"), this.endPicker.Value.ToString("yyyy-MM-dd HH:mm:ss"));
CardSaleTable.PrimaryGrid.DataSource = detail;
}
private void OnTicketRowActivated(object sender, DevComponents.DotNetBar.SuperGrid.GridRowActivatedEventArgs e)
{
GridPanel grid = e.GridPanel;
if (e.NewActiveRow != null)
{
payListTable.PrimaryGrid.Rows.Clear();
//先清除其他表数据
GridRow row = e.NewActiveRow as GridRow;
grid.SetSelected(e.NewActiveRow, false);
grid.SetActiveRow(e.NewActiveRow);
var ticketId = row.Cells["id"].Value.ToString();
List<CardSalePay> pays = getOrderPayListByTradeNo(ticketId);
payListTable.PrimaryGrid.DataSource = pays;
}
else
{
payListTable.PrimaryGrid.Rows.Clear();
}
}
/// <summary>
/// 退销售单
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnBackTicketClick(object sender, EventArgs e)
{
this.RefundOrderCheck();
}
private void RefundOrderCheck()
{
var panel = CardSaleTable.PrimaryGrid;
if (panel.ActiveRow == null)
{
this.ShowToastNotify(this, "请选择要操作的单据");
return;
}
//提示
var row = panel.ActiveRow as GridRow;
var ticketId = row.Cells["id"].Value.ToString();
var busNo = row.Cells["busNo"].Value.ToString();
bool allowBackPayHistory = Global.Instance.GlobalConfigBoolValue(ConfigConstant.CASHIER_ALLOW_BACKPAY_HISTORY, true);
//不允许退历史单据
if (!allowBackPayHistory)
{
//判断是否是隔天的单据
var createDate = row.Cells["createDate"].Value.ToString();
string ticketDate = DateTime.Parse(createDate).ToString("yyyy-MM-dd");
if (!ticketDate.Equals(DateTime.Now.ToString("yyyy-MM-dd")))
{
//不是同一天,查询设置
this.ShowToastNotify(this, "只能退款当日单据!");
return;
}
}
//有销售流水不允许退单
var dialog = new DialogForm("礼品卡退单确认提醒", string.Format("确定退<{0}>单?", busNo), MessageBoxIcon.Question, MessageBoxButtons.OKCancel);
if (dialog.ShowDialog(this) == DialogResult.OK)
{
LOGGER.Info("礼品卡销售记录<{0}>确定退单", busNo);
Task.Factory.StartNew(() =>
{
return DoRefund(busNo, ticketId); ;
}).ContinueWith(task =>
{
if (task.IsFaulted)
{
LOGGER.Error(task.Exception.GetBaseException());
}
else
{
if (!task.Result.Item1)
{
this.ShowToastNotify(this, "退款失败!");
LOGGER.Info("退单失败![{0}]", task.Result.Item2);
if (this.IsDisposed || !this.IsHandleCreated) return;
this.Invoke(new Action(() =>
{
dialog = new DialogForm("退款提醒", "退款失败!" + task.Result.Item2, MessageBoxIcon.Warning, MessageBoxButtons.OK);
dialog.TopLevel = true;
dialog.ShowDialog(this);
}));
}
else
{
this.ShowToastNotify(this, "退单成功!");
LOGGER.Info("退单交易完成");
if (this.IsDisposed || !this.IsHandleCreated) return;
this.Invoke(new Action(() =>
{
dialog = new DialogForm("退款提醒", "退款成功(金额原路退回)!", MessageBoxIcon.Warning, MessageBoxButtons.OK);
dialog.TopLevel = true;
dialog.ShowDialog(this);
QueryTicket();
}));
//退单打印
List<CardSalePay> salePay = getOrderPayListByTradeNo(task.Result.Item3);
CardSale cardSale = GetOrderById(task.Result.Item3);
SaleGiftCardRecordRequest request = new SaleGiftCardRecordRequest();
if (salePay != null && salePay.Count > 0)
{
CardSalePay cardSalePay = salePay[0];
request.SaleAmount = cardSalePay.Amount;
request.PayType = cardSalePay.PayName;
}
SaleGiftCardRecordResponse response = new SaleGiftCardRecordResponse();
if (cardSale != null)
{
response.TicketNo = cardSale.TicketNo;
response.CardNo = cardSale.CardNo;
response.SchemeName = cardSale.PlanName;
response.RetailPrice = cardSale.RetailPrice;
response.RealAmount = cardSale.RealAmount;
}
//退款成功打单
this.ShowToastNotify(this, "开始打印");
//构建收银小票模版参数打印
var vars = CardHelper.BuilderGiftCardVariable(request, response, false,true);
bool openCashbox = false;
//充值打印份数
int ticketCount = Global.Instance.GlobalConfigIntValue(ConfigConstant.PERIPHERAL_CASHIER_RECHARGE_COUNT, 1);
//打印延迟
int delaySecond = Global.Instance.GlobalConfigIntValue(ConfigConstant.PERIPHERAL_CASHIER_CARD_PRINT_DELAY, 1);
//执行收银小票打印
Tuple<bool, string> result = CardHelper.PrinterTicket("礼品卡销售", vars, true, openCashbox, 1, 0);
this.ShowToastNotify(this, string.Format("{0}", result.Item2));
}
}
});
}
}
private Tuple<bool, string,string> DoRefund(string busNo,string ticketId)
{
//获取主单数据
CardSale cardSale = GetOrderById(ticketId);
//获取明细单数据
List<CardSalePay> salePay = getOrderPayListByTradeNo(ticketId);
if (cardSale.PayStatus ==2 || !string.IsNullOrEmpty(cardSale.OrgBusNo) )
{
return new Tuple<bool, string,string>(false, "订单已完全退单",null);
}
string backTradeNo = string.Format("{0}_{1}{2}", Global.Instance.Authc.StoreNo, Global.Instance.Authc.PosNo, DateTime.Now.ToString("yyyyMMddHHmmss"));
//生成新单
CardSale _BackCardSale = ObjectUtils.Copy(cardSale);
_BackCardSale.Id = IdWorkerUtils.Instance.NextId();
_BackCardSale.PayStatus = 2;
_BackCardSale.BusNo = backTradeNo.Split('_')[1];
_BackCardSale.CreateDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
_BackCardSale.Money = 0-cardSale.Money;
_BackCardSale.OrgBusNo = cardSale.BusNo;
//第一步先发起退单请求
try
{
var request = new RefundGiftCardRecordRequest();
request.CardNo = cardSale.CardNo;
request.PayVoucherNo = string.Format("{0}_{1}", Global.Instance.Authc.StoreNo, cardSale.BusNo);
request.ShopNo = Global.Instance.Authc.StoreNo;
request.PosNo = Global.Instance.Authc.PosNo;
request.WorkerNo = Global.Instance.Worker.No;
var response = CardUtils.RefundGiftCardRecord(request);
//成功
if (response.Item1)
{
RefundGiftCardRecordResponse saleGiftCardRecordResponse = response.Item3.Data;
_BackCardSale.TicketNo = saleGiftCardRecordResponse.TicketNo;
_BackCardSale.ShiftName = Global.Instance.BusinessPlanLog.Name;
_BackCardSale.ShiftNo = Global.Instance.BusinessPlanLog.No;
_BackCardSale.WorkerId = Global.Instance.BusinessPlanLog.WorkerId;
_BackCardSale.WorkerName = Global.Instance.BusinessPlanLog.WorkerName;
_BackCardSale.WorkerNo = Global.Instance.BusinessPlanLog.WorkerNo;
}
else
{
return new Tuple<bool, string, string>(false, response.Item2, null);
}
}
catch (Exception ex)
{
LOGGER.Error(ex, "礼品卡退单异常");
return new Tuple<bool, string, string>(false, "礼品卡退单异常", null);
}
//第二步组装支付方式
List<CardSalePay> backPay = new List<CardSalePay>();
foreach (CardSalePay pay in salePay)
{
switch (pay.PayNo)
{
case "04"://支付宝
{
this.ShowToastNotify(this, "正在进行支付宝退款...请勿关闭!", 30000);
switch (pay.PayChannel)
{
case PayChannelEnum.:
{
var result = AlipayApi.RefundAndQuery(AccountTypeEnum., pay.VoucherNo, pay.Amount, backTradeNo, "正常退款");
if (!result.Item1)
{
return new Tuple<bool, string, string>(false, result.Item2,null);
}
}
break;
case PayChannelEnum.:
{
var res = SaobeiApi.GetSaobeiParameter(AccountTypeEnum.);
if (res.Item1)
{
var parameter = res.Item3;
//银联商务支付参数
string merchant_no = parameter.ContainsKey("merchant_no") ? parameter["merchant_no"].ToString() : "";
string terminal_id = parameter.ContainsKey("terminal_id") ? parameter["terminal_id"].ToString() : "";
string signKey = parameter.ContainsKey("signKey") ? parameter["signKey"].ToString() : "";
string gatewayUrl = parameter.ContainsKey("gatewayUrl") ? parameter["gatewayUrl"].ToString() : "";
string requestNum = string.Format("{0}_{1}", Global.Instance.Authc.StoreNo, backTradeNo);
SaobeiRefundParam request = new SaobeiRefundParam();
request.Pay_type = "020";
request.Terminal_trace = pay.VoucherNo;
request.Refund_fee = string.Format("{0}", Convert.ToInt32(Math.Abs(pay.Amount) * 100));
request.Out_trade_no = pay.Memo;
var upayPayment = SaobeiUtils.SaobeiRefund(merchant_no, terminal_id, signKey, gatewayUrl, request);
if (!upayPayment.Item1)
{
return new Tuple<bool, string, string>(false, upayPayment.Item2, null);
}
else
{
pay.Memo = "扫呗支付:该订单已全额退款,";
}
}
else
{
return new Tuple<bool, string, string>(false, res.Item2, null);
}
}
break;
default:
{
return new Tuple<bool, string, string>(false, "暂未开放该渠道退款",null);
}
}
}
break;
case "05"://微信支付
{
this.ShowToastNotify(this, "正在进行微信退款...时间很长预计1-2分钟请勿关闭", 100000);
switch (pay.PayChannel)
{
case PayChannelEnum.:
{
var result = WeixinApi.RefundAndQuery(AccountTypeEnum., pay.VoucherNo, pay.Amount, pay.Amount, backTradeNo, "正常退款", 100);
if (!result.Item1)
{
return new Tuple<bool, string, string>(false, result.Item2,null);
}
}
break;
case PayChannelEnum.:
{
var res = SaobeiApi.GetSaobeiParameter(AccountTypeEnum.);
if (res.Item1)
{
var parameter = res.Item3;
//银联商务支付参数
string merchant_no = parameter.ContainsKey("merchant_no") ? parameter["merchant_no"].ToString() : "";
string terminal_id = parameter.ContainsKey("terminal_id") ? parameter["terminal_id"].ToString() : "";
string signKey = parameter.ContainsKey("signKey") ? parameter["signKey"].ToString() : "";
string gatewayUrl = parameter.ContainsKey("gatewayUrl") ? parameter["gatewayUrl"].ToString() : "";
string requestNum = string.Format("{0}_{1}", Global.Instance.Authc.StoreNo, backTradeNo);
SaobeiRefundParam request = new SaobeiRefundParam();
request.Pay_type = "010";
request.Terminal_trace = pay.VoucherNo;
request.Refund_fee = string.Format("{0}", Convert.ToInt32(Math.Abs(pay.Amount) * 100));
request.Out_trade_no = pay.Memo;
var upayPayment = SaobeiUtils.SaobeiRefund(merchant_no, terminal_id, signKey, gatewayUrl, request);
if (!upayPayment.Item1)
{
return new Tuple<bool, string, string>(false, upayPayment.Item2, null);
}
else
{
pay.Memo = "扫呗支付:该订单已全额退款,";
}
}
else
{
return new Tuple<bool, string, string>(false, res.Item2, null);
}
}
break;
default:
{
return new Tuple<bool, string, string>(false, "暂未开放该渠道退款" , null);
}
break;
}
}
break;
}
//组装支付方式
pay.Id = IdWorkerUtils.Instance.NextId();
pay.TicketId = _BackCardSale.Id;
pay.Amount = 0 - pay.Amount;
pay.CreateDate = _BackCardSale.CreateDate;
backPay.Add(pay);
}
_BackCardSale.Pay = backPay;
//第三部保存单据
try
{
lock (Global.Instance.SyncLock)
{
using (var db = Global.Instance.OpenDataBase)
{
using (var transaction = db.GetTransaction())
{
//更新主单的退单状态
string updateSql = string.Format("update pos_card_sale set orgBusNo='{0}' where id = '{1}';", _BackCardSale.BusNo, cardSale.Id);
LOGGER.Info("单号:[{0}]更新主单状态......开始", cardSale.BusNo);
db.Execute(updateSql);
LOGGER.Info("单号:[{0}]保存礼品卡销售退单......开始", _BackCardSale.BusNo);
// 保存主单数据
db.Save<CardSale>(_BackCardSale);
// 保存支付明细
List<CardSalePay> detail = _BackCardSale.Pay;
if (detail != null && detail.Count > 0)
{
foreach (CardSalePay detailEntity in detail)
{
db.Save<CardSalePay>(detailEntity);
}
}
transaction.Complete();
LOGGER.Info("单号:[{0}]保存礼品卡销售退单......成功", _BackCardSale.BusNo);
}
}
}
return new Tuple<bool, string, string>(true, "礼品卡退单成功", _BackCardSale.Id);
}
catch (Exception ex)
{
LOGGER.Error(ex);
return new Tuple<bool, string, string>(false, "礼品卡销售退单保存失败", null);
}
}
private void BtnQueryClick(object sender, EventArgs e)
{
QueryTicket();
}
public void QueryTicket()
{
//获取选择的订单
List<CardSale> detail = getBusTicketList(this.startPicker.Value.ToString("yyyy-MM-dd HH:mm:ss"), this.endPicker.Value.ToString("yyyy-MM-dd HH:mm:ss"));
CardSaleTable.PrimaryGrid.DataSource = detail;
}
public List<CardSale> getBusTicketList(string startTime, string endTime)
{
List<CardSale> list = null;
string busNo = StringUtils.GetString(this.txtTradeNo.Text);
string cardNo = StringUtils.GetString(this.txtInput.Text);
try
{
using (var db = Global.Instance.OpenDataBase)
{
StringBuilder sqlBuld = new StringBuilder();
sqlBuld.Append(" select * ");
sqlBuld.Append(" from pos_card_sale ");
sqlBuld.Append(" where createDate >= '{0}' and createDate <= '{1}'");
if (busNo != null && !"".Equals(busNo))
{
sqlBuld.Append(" and busNo like '%" + busNo + "%' ");
}
if (cardNo != null && !"".Equals(cardNo))
{
sqlBuld.Append(" and cardNo like '%" + cardNo + "%' ");
}
sqlBuld.Append(" order by createDate desc");
string sql = string.Format(sqlBuld.ToString(), startTime, endTime);
list = db.Query<CardSale>(sql).ToList();
foreach (CardSale cardSaleEntity in list) {
if (cardSaleEntity.PayStatus == 2 || !string.IsNullOrEmpty(cardSaleEntity.OrgBusNo)) {
cardSaleEntity.StatusDesc = "已退单";
}
else {
cardSaleEntity.StatusDesc = "已支付";
}
}
}
}
catch (Exception ex)
{
LOGGER.Error(ex);
}
if (list == null)
{
list = new List<CardSale>();
}
return list;
}
public List<CardSalePay> getOrderPayListByTradeNo(string ticketId)
{
List<CardSalePay> list = null;
try
{
using (var db = Global.Instance.OpenDataBase)
{
StringBuilder sqlBuld = new StringBuilder();
sqlBuld.Append(" select * ");
sqlBuld.Append(" from pos_card_sale_pay ");
sqlBuld.Append(" where ticketId = '{0}' ");
string sql = string.Format(sqlBuld.ToString(), ticketId);
list = db.Query<CardSalePay>(sql).ToList();
}
}
catch (Exception ex)
{
LOGGER.Error(ex);
}
if (list == null)
{
list = new List<CardSalePay>();
}
return list;
}
public CardSale GetOrderById(string ticketId)
{
CardSale cardSale = null;
try
{
using (var db = Global.Instance.OpenDataBase)
{
StringBuilder sqlBuld = new StringBuilder();
sqlBuld.Append(" select * ");
sqlBuld.Append(" from pos_card_sale ");
sqlBuld.Append(" where id = '{0}' ");
string sql = string.Format(sqlBuld.ToString(), ticketId);
cardSale = db.FirstOrDefault<CardSale>(sql, null);
}
}
catch (Exception ex)
{
LOGGER.Error(ex);
}
return cardSale;
}
/// <summary>
/// 数据源绑定
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnBind(object sender, GridDataBindingCompleteEventArgs e)
{
var panel = e.GridPanel;
foreach (var r in panel.Rows)
{
var row = r as GridRow;
//设置单据内容字体颜色
if ("已退单".Equals(row.Cells["statusDesc"].Value.ToString()))
{
row.CellStyles.Default.TextColor = Color.Red;
}
else
{
row.CellStyles.Default.TextColor = Color.Black;
}
}
}
/// <summary>
/// 读卡
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnReadCardClick(object sender, EventArgs e)
{
var result = CardOperateUtils.Instance.ReadCardNo();
if (result.Item1)
{
this.txtInput.Text = result.Item2;
//读卡成功,模拟回车事件
InputSimulatorUtils.SendKey(KeyCodes.Map["return"]);
}
else
{
result = CardOperateUtilsOther.Instance.ReadCardNo();
if (result.Item1)
{
this.txtInput.Text = result.Item2;
//读卡成功,模拟回车事件
InputSimulatorUtils.SendKey(KeyCodes.Map["return"]);
}
else
{
this.ShowToastNotify(this, result.Item2);
}
}
}
private void OnFinishedClick(object sender, Component.EnterEventArg e)
{
var isVerify = InputVerify();
if (isVerify)
{
QueryTicket();
}
}
/// <summary>
/// 输入是否验证通过
/// </summary>
private bool InputVerify()
{
if (string.IsNullOrEmpty(this.txtInput.Text.Trim()))
{
this.ShowToastNotify(this, "请输入卡号信息");
return false;
}
return true;
}
/// <summary>
/// 订单补打
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnPrintClick(object sender, EventArgs e)
{
var panel = CardSaleTable.PrimaryGrid;
if (panel.ActiveRow == null)
{
this.ShowToastNotify(this, "请选择要操作的单据");
return;
}
//提示
var row = panel.ActiveRow as GridRow;
var ticketId = row.Cells["id"].Value.ToString();
var busNo = row.Cells["busNo"].Value.ToString();
List<CardSalePay> salePay = getOrderPayListByTradeNo(ticketId);
CardSale cardSale = GetOrderById(ticketId);
SaleGiftCardRecordRequest request = new SaleGiftCardRecordRequest();
if (salePay!=null && salePay.Count>0) {
CardSalePay cardSalePay = salePay[0];
request.SaleAmount = cardSalePay.Amount;
request.PayType = cardSalePay.PayName;
}
SaleGiftCardRecordResponse response = new SaleGiftCardRecordResponse();
if (cardSale!=null) {
response.TicketNo = cardSale.TicketNo;
response.CardNo = cardSale.CardNo;
response.SchemeName = cardSale.PlanName;
response.RetailPrice = cardSale.RetailPrice;
response.RealAmount = cardSale.RealAmount;
}
bool isBack = false;
if (cardSale.PayStatus==2) {
isBack = true;
}
//成功以后打印
this.ShowToastNotify(this, "开始打印");
//构建收银小票模版参数打印
var vars = CardHelper.BuilderGiftCardVariable(request, response, true, isBack);
bool openCashbox = false;
//充值打印份数
int ticketCount = Global.Instance.GlobalConfigIntValue(ConfigConstant.PERIPHERAL_CASHIER_RECHARGE_COUNT, 1);
//打印延迟
int delaySecond = Global.Instance.GlobalConfigIntValue(ConfigConstant.PERIPHERAL_CASHIER_CARD_PRINT_DELAY, 1);
//执行收银小票打印
Tuple<bool, string> result = CardHelper.PrinterTicket("礼品卡销售", vars, true, openCashbox, 1, 0);
this.ShowToastNotify(this, string.Format("{0}", result.Item2));
}
}
}