using NLog;
using POSV.Entity;
using POSV.Payment.AllinPay;
using POSV.Payment.AllinPay.Models.ParamModels;
using POSV.Payment.AllinPay.Models.ResponseModels;
using POSV.ShoppingCart;
using POSV.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace POSV.PayApi
{
#region subin 2023-07-01 add
///
/// 通联支付API
///
public class AllinApi
{
private static Logger logger = NLog.LogManager.GetCurrentClassLogger();
public static Tuple> GetAllinParameter(AccountTypeEnum accountType)
{
if (accountType == AccountTypeEnum.门店)
{
var payMode = OrderUtils.GetPayMode("50");
if (payMode.Body == null || payMode.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);
payModelBody.Add("bizUserId", AllinpayLib.BizUserId);
payModelBody.Add("payuserid", AllinpayLib.Payuserid);
payModelBody.Add("vspCusid", AllinpayLib.VspCusid);
payMode.Body = payModelBody;
}
if (payMode != null)
{
var parameter = payMode.Body;
//通联支付参数
string appId = parameter.ContainsKey("appId") ? parameter["appId"].ToString() : "";
string appKey = parameter.ContainsKey("appKey") ? parameter["appKey"].ToString() : "";
string url = parameter.ContainsKey("gatewayUrl") ? parameter["gatewayUrl"].ToString() : "";
string payuserid = parameter.ContainsKey("payuserid") ? parameter["payuserid"].ToString() : "";
string vspCusid = parameter.ContainsKey("vspCusid") ? parameter["vspCusid"].ToString() : "";
string bizUserId = parameter.ContainsKey("bizUserId") ? parameter["bizUserId"].ToString() : "";
if (string.IsNullOrEmpty(appId) || string.IsNullOrEmpty(appKey) || string.IsNullOrEmpty(url))
{
return new Tuple>(false, "通联支付参数配置不完整", null);
}
Dictionary dic = new Dictionary();
dic.Add("appId", appId);
dic.Add("appKey", appKey);
dic.Add("url", url);
dic.Add("vspCusid", vspCusid);
dic.Add("payuserid", payuserid);
dic.Add("bizUserId", bizUserId);
return new Tuple>(true, "获取成功", dic);
}
else
{
return new Tuple>(false, "未启用通联扫码支付", null);
}
}
else
{
return new Tuple>(false, "暂不支持总部通联支付参数查询", null);
}
}
///
/// 通联退款+查询结果
/// 备注:前端支付到统一账号,退款也从统一账号退款
///
///
/// 商户订单号
/// 原订单的实收金额
/// 退款金额
/// 原交易的商户订单号
/// 备注
///
/// 订单类型
/// 付款账号
///
public static Tuple RefundAndQuery(AccountTypeEnum accountType, string tradeNo, decimal paidAmount, decimal refundAmount, string reTradeNo, string reason, OrderType orderType, string payuserId, int timeout = 60)
{
try
{
var _refundList = new List();
var info = GetAllinParameter(accountType);
if (info.Item1)
{
var parameter = info.Item3;
var _bizUserId = parameter["bizUserId"].ToString();
//付款账号为空时,使用配置参数的付款账号
if (string.IsNullOrEmpty(payuserId))
{
payuserId = parameter["payuserid"].ToString();
}
//全额退款,refundList无需上送,原路径返回;部分退款,refundList必须上送.
if (paidAmount > refundAmount)
{
_refundList.Add(new ApplyReciever { bizUserId = _bizUserId, amount = Convert.ToInt16(Math.Abs(refundAmount)) });
}
}
var refundResponse = RefundByAllinpay(accountType, tradeNo, refundAmount, reTradeNo, paidAmount, reason, orderType, payuserId, _refundList);
if (refundResponse.Item1)
{
var refundResult = refundResponse.Item3;
if (refundResult.code == "10000")
{
int queryCount = 0;
int sleepTime = 3000;
if (timeout < 60)
{
timeout = 60;
}
queryCount = (60 * 1000 / sleepTime);
int i = 0; //60秒超时
while (i < queryCount)
{
var queryRefundResponse = QueryAllinpayRefundResult(accountType, tradeNo);
if (queryRefundResponse.Item1 && queryRefundResponse.Item3.code == "10000")
{
//logger.Info("订单[{0}]退款成功!", tradeNo);
//return new Tuple(true, "退款成功!");
var _data = JsonUtils.Deserialize(queryRefundResponse.Item3.data);
// logger.Info("订单[{0}]分店退款成功!", tradeNo);
// return new Tuple(true, "退款成功!");
var flg = false;
var msg = "";
switch (_data.status)
{
case "1":
flg = false;
msg = "未支付";
break;
case "3":
flg = false;
msg = "交易失败,交易过程中出现错误";
break;
case "4":
flg = true;
msg = "交易成功";
break;
case "5":
flg = true;
msg = "交易成功,但是发生了退款";
break;
case "6":
flg = true;
msg = "交易关闭";
break;
case "99":
flg = true;
msg = "进行中";
break;
}
logger.Info($"订单[{tradeNo}]分店退款交易{msg}!");
return new Tuple(flg, msg, queryRefundResponse.Item3.data);
}
i++;
System.Threading.Thread.Sleep(3000);//睡眠3秒
}
if (i == queryCount)
{
logger.Info("订单[{0}]查询退款结果超时,退单失败!", tradeNo);
return new Tuple(false, "查询退款结果超时,退单失败!", "");
}
}
else
{
return new Tuple(false, refundResult.msg, refundResult.subMsg);
}
}
else
{
//请求失败
return new Tuple(false, refundResponse.Item2, "");
}
}
catch (Exception ex)
{
logger.Error(ex, "订单[" + tradeNo + "]通联退款发生异常");
return new Tuple(false, "退款发生异常!", ex.Message);
}
logger.Info("订单[{0}]退款失败!", tradeNo);
return new Tuple(false, "退款失败!", "");
}
///
/// 通联退款+查询结果
/// 备注:前端支付到分店账号,退款也从各个分店账号退款
///
///
/// 退款订单
/// 原交易订单号
/// 原交易订单总金额
/// 原订单付款方userid,当小程序付款时为微信的openid
///
///
public static Tuple RefundAndQuery(AccountTypeEnum accountType, OrderObject backOrder, string oldTradeNo, int oldAmount, string payuserId, int timeout = 60)
{
try
{
var _refundList = new List();
decimal _bizUserAmount = 0;
using (var db = Global.Instance.OpenDataBase)
{
var productIdList = backOrder.Items.Select(item => item.ProductId).Distinct();
var productIds = string.Join(",", productIdList);
StringBuilder sqlBuld = new StringBuilder();
sqlBuld.Append("SELECT ssa.bizUserId,sfa.goodId FROM pos_split_shop_account ssa ");
sqlBuld.Append("LEFT JOIN pos_split_food_account sfa ON sfa.shopId=ssa.id ");
sqlBuld.Append("WHERE sfa.goodId IN ('{0}'); ");
string sql = string.Format(sqlBuld.ToString(), productIds.Replace(",", "','"));
var orderSubStoreDetail = db.Query(sql).ToList();
var subStoreProductIdList = orderSubStoreDetail.Select(item => item.GoodId).Distinct().ToList();
if (productIdList.Count() > orderSubStoreDetail.Count())
{
logger.Info($"订单[{backOrder.TradeNo}]分店退款失败!,退款菜品数量({productIds})>分店关联菜品数量({string.Join(",", subStoreProductIdList)})");
return new Tuple(false, "分店未关联退款菜品!", null);
}
var bizUseIdLst = orderSubStoreDetail.Select(item => item.BizUserId).Distinct().ToList();
foreach (var item in bizUseIdLst)
{
var goodLst = orderSubStoreDetail.Where(m => m.BizUserId == item).ToList().Select(m => m.GoodId);
var goodIds = string.Join(",", goodLst);
var total = backOrder.Items.Where(m => goodIds.Contains(m.ProductId)).Sum(m => m.TotalAmonut);
_bizUserAmount += Math.Abs(total * 100);
_refundList.Add(new ApplyReciever { bizUserId = item, amount = Convert.ToInt32(Math.Abs(total) * 100) });
}
}
var tradeNo = backOrder.StoreId + "_" + backOrder.TradeNo;
var refundAmount = Convert.ToInt32(backOrder.PaidAmount * 100);
var reason = backOrder.RefundCause;
var orderType = backOrder.OrderType;
var refundResponse = RefundByAllinpay(accountType, backOrder.TradeNo, _bizUserAmount, oldTradeNo, oldAmount, reason, orderType, payuserId, _refundList);
if (refundResponse.Item1)
{
var refundResult = refundResponse.Item3;
if (refundResult.code == "10000")
{
int queryCount = 0;
int sleepTime = 3000;
if (timeout < 60)
{
timeout = 60;
}
queryCount = (60 * 1000 / sleepTime);
int i = 0; //60秒超时
while (i < queryCount)
{
var queryRefundResponse = QueryAllinpayRefundResult(accountType, backOrder.TradeNo);
if (queryRefundResponse.Item1 && queryRefundResponse.Item3.code == "10000")
{
var _data = JsonUtils.Deserialize(queryRefundResponse.Item3.data);
// logger.Info("订单[{0}]分店退款成功!", tradeNo);
// return new Tuple(true, "退款成功!");
var flg = false;
var msg = "";
switch (_data.status)
{
case "1":
flg = false;
msg = "未支付";
break;
case "3":
flg = false;
msg = "交易失败,交易过程中出现错误";
break;
case "4":
flg = true;
msg = "交易成功";
break;
case "5":
flg = true;
msg = "交易成功,但是发生了退款";
break;
case "6":
flg = true;
msg = "交易关闭";
break;
case "99":
flg = true;
msg = "进行中";
break;
}
logger.Info($"订单[{tradeNo}]分店退款交易{msg}!");
return new Tuple(flg, msg, queryRefundResponse.Item3.data);
}
i++;
System.Threading.Thread.Sleep(3000);//睡眠3秒
}
if (i == queryCount)
{
logger.Info("订单[{0}]查询分店退款结果超时,退单失败!", tradeNo);
return new Tuple(false, "查询退款结果超时,退单失败!", null);
}
}
else
{
return new Tuple(false, refundResult.msg, "");
}
}
else
{
//请求失败
return new Tuple(false, refundResponse.Item2, "");
}
}
catch (Exception ex)
{
logger.Error(ex, "订单[" + backOrder.TradeNo + "]分店账号通联退款发生异常");
return new Tuple(false, "退款发生异常!", ex.Message);
}
logger.Info("订单[{0}]分店账号退款失败!", backOrder.TradeNo);
return new Tuple(false, "退款失败!", "");
}
///
/// 通联退款
///
///
/// 商户订单号
/// 退款金额
/// 原交易订单号
/// 原交易订单实收金额
/// 退款备注
/// 订单类型
/// 付款账号
/// 托管代收订单中的收款人的退款金额
///
public static Tuple RefundByAllinpay(AccountTypeEnum accountType, string tradeNo, decimal totalAmount, string refundNo, decimal paidAmount, string reason, OrderType orderType, string payuserId, List refundList)
{
lock (Global.Instance.SyncLock)
{
try
{
logger.Info("订单[{0}]开始发起通联退款......", tradeNo);
var info = GetAllinParameter(accountType);
if (info.Item1)
{
var parameter = info.Item3;
//付款账号为空时,使用配置参数的付款账号
if (string.IsNullOrEmpty(payuserId))
{
payuserId = parameter["payuserid"].ToString();
}
var refundModel = new OrderRefundModel
{
reqsn = tradeNo,
oldreqsn = refundNo,
payuserid = payuserId,
amount = Convert.ToInt32(totalAmount),
refundType = "D0",
backUrl = "https://www.baidu.com",
remark = reason
};
#region subin 20230918 由前端支付到统一账号,退款从统一账号退款改为分店账号收款分店账号退款
//subin 20230918 注释掉,由前端支付到统一账号,退款从统一账号退款改为分店账号收款分店账号退款
//if (paidAmount > totalAmount)
//{
// var _refundList = new List();
// _refundList.Add(new ApplyReciever { bizUserId = AllinpayLib.BizUserId, amount = Convert.ToInt16(Math.Abs(totalAmount)) });
// refundModel.refundList = JsonUtils.Serialize(_refundList);
//}
//全额退款,refundList无需上送,原路径返回;部分退款,refundList必须上送.
//if (refundList.Count() > 0)
//{
// refundModel.refundList = JsonUtils.Serialize(refundList);
//}
refundModel.refundList = JsonUtils.Serialize(refundList);
#endregion
var paramInfo = new OrderRefundParamInfo
{
bizContent = JsonUtils.Serialize(refundModel)
};
var _response = AllinpayHelper.OrderRefund(paramInfo);
if (_response.IsSuccess)
{
var _data = JsonUtils.Deserialize(_response.ResultInfo.data);
var flg = false;
string msg = null;
switch (_data.status)
{
case "success":
flg = true;
break;
case "pending":
flg = true;
break;
case "fail":
flg = false;
msg = "退款失败";
break;
}
logger.Info("订单[{0}]通联退款结果:{1}", tradeNo, _response.ResultInfo.data);
return new Tuple(flg, msg, _response.ResultInfo);
}
else
{
logger.Info("订单[{0}]通联退款错误:{1}", tradeNo, _response.ShowUserMsg);
return new Tuple(false, _response.ShowUserMsg, null);
}
}
else
{
return new Tuple(false, info.Item2, null);
}
}
catch (Exception ex)
{
logger.Error(ex, "订单[{0}]调用通联退款接口异常", tradeNo);
return new Tuple(false, "调用通联退款接口异常", null);
}
}
}
///
/// 退款结果查询
///
///
/// 商户订单号
///
public static Tuple QueryAllinpayRefundResult(AccountTypeEnum accountType, string tradeNo)
{
lock (Global.Instance.SyncLock)
{
try
{
logger.Info("订单[{0}]开始发起通联退款查询请求......", tradeNo);
var info = GetAllinParameter(accountType);
if (info.Item1)
{
var parameter = info.Item3;
//AllinpayLib.AppId = parameter.ContainsKey("appId") ? parameter["appId"].ToString() : "";
//AllinpayLib.AppKey = parameter.ContainsKey("appKey") ? parameter["appKey"].ToString() : "";
//AllinpayLib.Url = parameter.ContainsKey("url") ? parameter["url"].ToString() : "";
//AllinpayLib.VspCusid = parameter.ContainsKey("vspCusid") ? parameter["vspCusid"].ToString() : "";
//AllinpayLib.Payuserid = parameter.ContainsKey("payuserid") ? parameter["payuserid"].ToString() : "";
//AllinpayLib.BizUserId = parameter.ContainsKey("bizUserId") ? parameter["bizUserId"].ToString() : "";
var orderDetailModel = new GetOrderDetailModel()
{
reqsn = tradeNo,
};
var paramInfo = new GetOrderDetailParamInfo
{
appId = parameter["appId"].ToString(),
key = parameter["appKey"].ToString(),
bizContent = JsonUtils.Serialize(orderDetailModel)
};
var _response = AllinpayHelper.GetOrderDetail(paramInfo);
if (_response.IsSuccess)
{
var _data = JsonUtils.Deserialize(_response.ResultInfo.data);
logger.Info("订单[{0}]通联退款查询请求结果:{1}", tradeNo, _response.ResultInfo.data);
var _statusDesc = "进行中";
var flg = false;
switch (_data.status)
{
case "1":
_statusDesc = "未支付";
break;
case "3":
_statusDesc = "交易失败";
break;
case "4":
_statusDesc = "交易成功";
break;
case "5":
_statusDesc = "交易成功-发生退款";
break;
case "6":
_statusDesc = "关闭";
break;
case "99":
_statusDesc = "进行中";
break;
}
if (!_statusDesc.Equals("交易成功"))
{
return new Tuple(false, _statusDesc, null);
}
return new Tuple(true, null, _response.ResultInfo);
}
else
{
logger.Info("订单[{0}]通联退款查询请求结果错误:{1}", tradeNo, _response.ShowUserMsg);
return new Tuple(false, _response.ShowUserMsg, null);
}
}
else
{
return new Tuple(false, info.Item2, null);
}
}
catch (Exception ex)
{
logger.Error(ex, "订单[{0}]调用通联退款查询接口异常", tradeNo);
return new Tuple(false, "调用通联退款查询接口异常", null);
}
}
}
}
#endregion
}