2025-03-28 09:49:56 +08:00

338 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using WebService.SDK.PayCommon;
namespace WebService.SDK.CCBPay
{
public class CCBPayAPI
{
/// <summary>
/// 建设银行被扫交易接口
/// </summary>
/// <param name="payConfig">接口配置</param>
/// <param name="merchantInfo">平台商户信息</param>
/// <param name="authCode">用户付款授权码</param>
/// <param name="merchantOrderCode">商户交易订单号</param>
/// <param name="payAmount">交易金额(元)</param>
/// <returns></returns>
public static Model.CCBPayResultModel ScanPay(CCBPayConfig payConfig,
MobilePayConfig.PayMerchant merchantInfo, string authCode,
string merchantOrderCode, string payAmount)
{
return ScanPay(payConfig, merchantInfo, authCode, merchantOrderCode, payAmount, null);
}
/// <summary>
/// 建设银行被扫交易接口
/// </summary>
/// <param name="payConfig">接口配置</param>
/// <param name="merchantInfo">平台商户信息</param>
/// <param name="authCode">用户付款授权码</param>
/// <param name="merchantOrderCode">商户交易订单号</param>
/// <param name="payAmount">交易金额(元)</param>
/// <returns></returns>
public static Model.CCBPayResultModel ScanPay(CCBPayConfig payConfig,
MobilePayConfig.PayMerchant merchantInfo, string authCode,
string merchantOrderCode, string payAmount, List<Model.GoodsDetailAlipayModel> goodsDetails)
{
if (payConfig == null)
{
return default(Model.CCBPayResultModel);
}
if (merchantInfo == null || string.IsNullOrWhiteSpace(merchantInfo.MerchantCode) ||
string.IsNullOrWhiteSpace(merchantInfo.MerchantKey) ||
string.IsNullOrWhiteSpace(merchantInfo.MerchantPosCode))
{
return default(Model.CCBPayResultModel);
}
if (!decimal.TryParse(payAmount, out decimal _PayAmount) || _PayAmount <= 0)
{
return default(Model.CCBPayResultModel);
}
Dictionary<string, string> _ApiDictionary = new Dictionary<string, string>
{
//{ "MERCHANTID", merchantInfo.MerchantCode },//平台商户号
//{ "POSID", merchantInfo.MerchantPosCode },//柜台号
//{ "BRANCHID", payConfig.Organization },//分行号
//{ "TERMNO1", "" },//终端编号1
//{ "TERMNO2", "" }, //终端编号2
{ "MERFLAG", "1" },//商户类型
{ "ORDERID", merchantOrderCode },//订单号
{ "QRCODE", authCode},//用户付款码
{ "AMOUNT", payAmount },//交易金额
{ "TXCODE", "PAY100" }//接口名称固定PAY100
};
if (goodsDetails != null)
{
for (int i = 0; i < goodsDetails.Count; i++)
{
goodsDetails[i].quantity = (int)goodsDetails[i].quantity;
goodsDetails[i].price = decimal.Parse(goodsDetails[i].price.ToString("F2"));
if (string.IsNullOrWhiteSpace(goodsDetails[i].goods_name))
{
goodsDetails[i].goods_name = goodsDetails[i].goods_id;
}
}
_ApiDictionary.Add("goods_detail_ali", JsonConvert.SerializeObject(goodsDetails));//支付宝优惠券商品参数
}
LogHelper.WriteReceiveLog("支付反扫-传第三方参数:" +
_ApiDictionary.Select(pair => pair.Key + "=" + pair.Value).
DefaultIfEmpty("").Aggregate((a, b) => a + "&" + b));
//测试用日志记录
LogHelper.WriteSendLog("支付调用的服务地址" + payConfig.ScanURL);
return JsonConvert.DeserializeObject<Model.CCBPayResultModel>(
CommonHelper.HttpUrlPost($"MERCHANTID={merchantInfo.MerchantCode}" +
$"&POSID={merchantInfo.MerchantPosCode}&BRANCHID={payConfig.Organization}" +
$"&ccbParam={ApiParamSign(_ApiDictionary, merchantInfo.MerchantKey)}",
payConfig.ScanURL, "application/x-www-form-urlencoded", payConfig.PlatformTimeout));
}
/// <summary>
/// 建设银行交易查询接口
/// </summary>
/// <param name="payConfig">接口配置</param>
/// <param name="merchantInfo">平台商户信息</param>
/// <param name="merchantOrderCode">商户交易订单号</param>
/// <param name="platformOrderCode">平台交易订单号</param>
/// <param name="payType">交易金额</param>
/// <param name="queryCount">累计查询次数</param>
/// <returns></returns>
public static Model.CCBPayResultModel QueryPay(CCBPayConfig payConfig,
MobilePayConfig.PayMerchant merchantInfo, string merchantOrderCode,
string platformOrderCode, string payType, int queryCount)
{
if (payConfig == null)
{
return default(Model.CCBPayResultModel);
}
if (merchantInfo == null || string.IsNullOrWhiteSpace(merchantInfo.MerchantCode) ||
string.IsNullOrWhiteSpace(merchantInfo.MerchantKey) ||
string.IsNullOrWhiteSpace(merchantInfo.MerchantPosCode))
{
return default(Model.CCBPayResultModel);
}
int QRCodeType = 2;
switch (payType.ToUpper())
{
case "WECHAT":
QRCodeType = 2;
break;
case "ALIPAY":
QRCodeType = 3;
break;
case "UNIONPAY":
QRCodeType = 4;
break;
}
Dictionary<string, string> _ApiDictionary = new Dictionary<string, string>
{
//{ "MERCHANTID", merchantInfo.MerchantCode },//平台商户号
//{ "POSID", merchantInfo.MerchantPosCode },//柜台号
//{ "BRANCHID", payConfig.Organization },//分行号
//{ "TERMNO1", "" },//终端编号1
//{ "TERMNO2", "" }, //终端编号2
{ "MERFLAG", "1" },//商户类型
{ "ORDERID", merchantOrderCode },//订单号
{ "QRYTIME", queryCount.ToString() },//查询次数
{ "QRCODETYPE", QRCodeType.ToString() },//二维码类型
{ "TXCODE", "PAY101" }
};
LogHelper.WriteReceiveLog("支付查询-传第三方参数:" +
_ApiDictionary.Select(pair => pair.Key + "=" + pair.Value).
DefaultIfEmpty("").Aggregate((a, b) => a + "&" + b));
return JsonConvert.DeserializeObject<Model.CCBPayResultModel>(
CommonHelper.HttpUrlPost($"MERCHANTID={merchantInfo.MerchantCode}" +
$"&POSID={merchantInfo.MerchantPosCode}&BRANCHID={payConfig.Organization}" +
$"&ccbParam={ApiParamSign(_ApiDictionary, merchantInfo.MerchantKey)}",
payConfig.ScanURL, "application/x-www-form-urlencoded", payConfig.PlatformTimeout));
}
/// <summary>
/// 建设银行交易退款接口
/// </summary>
/// <param name="payConfig">接口配置</param>
/// <param name="merchantInfo">平台商户信息</param>
/// <param name="platformOrderCode">平台交易订单号</param>
/// <param name="merchantOrderCode">商户交易订单号</param>
/// <param name="refundOrderCode">退款订单号</param>
/// <param name="payAmount">退款金额</param>
/// <returns></returns>
public static Model.CCBRefundModel RefundPay(CCBPayConfig payConfig,
MobilePayConfig.PayMerchant merchantInfo, string platformOrderCode,
string merchantOrderCode, string refundOrderCode, string payAmount)
{
if (payConfig == null)
{
return default(Model.CCBRefundModel);
}
if (merchantInfo == null || string.IsNullOrWhiteSpace(merchantInfo.MerchantCode))
{
return default(Model.CCBRefundModel);
}
if (!decimal.TryParse(payAmount, out decimal _PayAmount) || _PayAmount <= 0)
{
return default(Model.CCBRefundModel);
}
Dictionary<string, string> _ApiDictionary = new Dictionary<string, string>
{
{ "CUST_ID", merchantInfo.MerchantCode },//建设银行平台商户号
{ "ORDER", merchantOrderCode },//原商户订单号
{ "MONEY", _PayAmount.ToString() } //退款款交易金额
};
string str_Refund = $"{merchantInfo.MerchantCode}&{merchantOrderCode}&{_PayAmount.ToString()}";
_ApiDictionary.Add("fundParams", Encry(str_Refund, "503252CD487D3B0ADA6CD0A42EF28CF8"));
LogHelper.WriteReceiveLog("支付退款-传第三方参数:" +
_ApiDictionary.Select(pair => pair.Key + "=" + pair.Value).
DefaultIfEmpty("").Aggregate((a, b) => a + "&" + b));
//测试用日志记录
LogHelper.WriteSendLog("退款调用的服务地址" + payConfig.PayRefundURL);
return JsonConvert.DeserializeObject<Model.CCBRefundModel>(CommonHelper.HttpUrlPost(
$"fundParams={System.Web.HttpUtility.UrlEncode(Encry(str_Refund, "503252CD487D3B0ADA6CD0A42EF28CF8"))}",
payConfig.PayRefundURL, "application/x-www-form-urlencoded", payConfig.PlatformTimeout, Encoding.Default, false));
}
/// <summary>
/// 建设银行支付平台参数签名
/// </summary>
/// <param name="signParm">待签名参数集</param>
/// <param name="mchKey">签名密钥</param>
/// <returns></returns>
private static string ApiParamSign(Dictionary<string, string> signParm, string mchKey)
{
try
{
//拼接待签名参数字符串
string parameter = signParm.Select(pair => $"{pair.Key}={pair.Value}").
DefaultIfEmpty("").Aggregate((a, b) => $"{a}&{b}");
return new CCB_B2CPay_Util.CCBPayUtil().makeCCBParam(parameter, mchKey);
}
catch
{
return "";
}
}
/// <summary>
/// 建设银行参数签名加密
/// </summary>
/// <param name="encryptString">待加密字符串</param>
/// <param name="sKey">密钥</param>
/// <returns></returns>
private static string CCBDESEncrypt(string encryptString, string sKey)
{
byte[] byKey = null;
byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
try
{
byKey = Encoding.UTF8.GetBytes(sKey.Substring(0, 8));
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.Mode = CipherMode.ECB;
byte[] inputByteArray = Encoding.GetEncoding("utf-16be").GetBytes(encryptString);
MemoryStream ms = new MemoryStream();
// byte[] bytes = new byte[inputByteArray.Length + 2];
List<byte> bytes = new List<byte>();
bytes.Add(0xfe);
bytes.Add(0xff);
bytes.AddRange(inputByteArray.ToList());
CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(byKey, IV), CryptoStreamMode.Write);
cs.Write(bytes.ToArray(), 0, bytes.Count);
cs.FlushFinalBlock();
var resultStr = Convert.ToBase64String(ms.ToArray());
int count = resultStr.Length / 76;
count += resultStr.Length % 76 > 0 ? 1 : 0;
StringBuilder result = new StringBuilder();
for (int i = 0; i < count; i++)
{
if (resultStr.Length > (i + 1) * 76)
result.Append(resultStr.Substring(i * 76, 76) + Environment.NewLine);//此处不能撤销换行
else
result.Append(resultStr.Substring(i * 76, resultStr.Length - i * 76));
}
return result.ToString().Replace("+", ",");
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>AES加密</summary>
/// <param name="text">明文</param>
/// <param name="key">密钥,长度为16的字符串</param> s
/// <returns>密文</returns>
public static string Encry(string text, string key)
{
string iv = key;
if (key.Length > 16)
{
// IV为商户MD5密钥后16位
iv = key.Substring(key.Length - 16);
// RES的KEY 为商户MD5密钥的前16位
key = key.Substring(0, 16);
}
return EncodeAES(text, key, iv);
}
/// <summary>AES加密</summary>
/// <param name="text">明文</param>
/// <param name="key">密钥,长度为16的字符串</param>
/// <param name="iv">偏移量,长度为16的字符串</param>
/// <returns>密文</returns>
public static string EncodeAES(string text, string key, string iv)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
rijndaelCipher.KeySize = 128;
rijndaelCipher.BlockSize = 128;
byte[] pwdBytes = System.Text.Encoding.UTF8.GetBytes(key);
byte[] keyBytes = new byte[16];
int len = pwdBytes.Length;
if (len > keyBytes.Length)
len = keyBytes.Length;
System.Array.Copy(pwdBytes, keyBytes, len);
rijndaelCipher.Key = keyBytes;
rijndaelCipher.IV = Encoding.UTF8.GetBytes(iv);
ICryptoTransform transform = rijndaelCipher.CreateEncryptor();
byte[] plainText = Encoding.UTF8.GetBytes(text);
byte[] cipherBytes = transform.TransformFinalBlock(plainText, 0, plainText.Length);
return Convert.ToBase64String(cipherBytes);
}
/// <summary>AES解密</summary>
/// <param name="text">密文</param>
/// <param name="key">密钥,长度为16的字符串</param>
/// <param name="iv">偏移量,长度为16的字符串</param>
/// <returns>明文</returns>
public static string DecodeAES(string text, string key, string iv)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
rijndaelCipher.KeySize = 128;
rijndaelCipher.BlockSize = 128;
byte[] encryptedData = Convert.FromBase64String(text);
byte[] pwdBytes = System.Text.Encoding.UTF8.GetBytes(key);
byte[] keyBytes = new byte[16];
int len = pwdBytes.Length;
if (len > keyBytes.Length)
len = keyBytes.Length;
System.Array.Copy(pwdBytes, keyBytes, len);
rijndaelCipher.Key = keyBytes;
rijndaelCipher.IV = Encoding.UTF8.GetBytes(iv);
ICryptoTransform transform = rijndaelCipher.CreateDecryptor();
byte[] plainText = transform.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
return Encoding.UTF8.GetString(plainText);
}
}
}