213 lines
8.1 KiB
C#
213 lines
8.1 KiB
C#
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.Extensions.Options;
|
||
using NPOI.SS.Formula.Functions;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Net.Http;
|
||
using System.Text;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using OSS.Clients.Pay.Wechat;
|
||
using OSS.Clients.Pay.Wechat.Basic;
|
||
using StackExchange.Redis;
|
||
|
||
|
||
namespace New_College.Common.Helper
|
||
{
|
||
public static class WeChatPayV3
|
||
{
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 扫码支付-Native下单API
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public static async Task<byte[]> QrCodePay(string outorderNo, decimal Price, string title)
|
||
{
|
||
////使用 Native 支付,输出二维码并展示
|
||
byte[] fileStream = null;//输出图片的URL
|
||
var price = (int)(Price * 100);
|
||
var name = title + "-扫码支付";
|
||
WechatPayHelper.pay_config = new WechatPayConfig()
|
||
{
|
||
app_id = WeixinConfig.Appid,
|
||
mch_id = WeixinConfig.MCHID,
|
||
api_key = WeixinConfig.Secret,
|
||
api_v3_key = WeixinConfig.KEY,
|
||
cert_path = WeixinConfig.PrivateKey,
|
||
cert_password = WeixinConfig.MCHID
|
||
};
|
||
var nResp = await new WechatNativePayReq()
|
||
{
|
||
description = name,
|
||
out_trade_no = outorderNo,
|
||
notify_url = WeixinConfig.NotifyUrl,
|
||
amount = new WechatPayAmount() { currency = "CNY", total = price }
|
||
}
|
||
// .SetContextConfig(new WechatPayConfig(){}) // 可以设置当前上下文的配置信息,设置后本次请求将使用此配置,方便多应用的用户
|
||
//.AddOptionalBodyPara("attach","附加数据") // 添加可选参数
|
||
.SendAsync();//
|
||
//系统创建订单逻辑
|
||
//var result = await basePayApis.NativeAsync(requestData);
|
||
////进行安全签名验证
|
||
if (!string.IsNullOrEmpty(nResp.code_url))
|
||
{
|
||
fileStream = QrCodeHelper.GerQrCodeStream(nResp.code_url);
|
||
}
|
||
else
|
||
{
|
||
// fileStream = QrCodeHelper.GetTextImageStream("Native Pay 未能通过签名验证,无法显示二维码");
|
||
}
|
||
return fileStream;
|
||
}
|
||
|
||
|
||
|
||
|
||
/**
|
||
*
|
||
* 统一下单
|
||
* @param WxPaydata inputObj 提交给统一下单API的参数
|
||
* @param int timeOut 超时时间
|
||
* @throws WePayException
|
||
* @return 成功时返回,其他抛异常
|
||
*/
|
||
public static WxPayData UnifiedOrder(WxPayData inputObj, int timeOut = 60)
|
||
{
|
||
string url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
|
||
//检测必填参数
|
||
if (!inputObj.IsSet("out_trade_no"))
|
||
{
|
||
throw new Exception("缺少统一支付接口必填参数out_trade_no!");
|
||
}
|
||
else if (!inputObj.IsSet("body"))
|
||
{
|
||
throw new Exception("缺少统一支付接口必填参数body!");
|
||
}
|
||
else if (!inputObj.IsSet("total_fee"))
|
||
{
|
||
throw new Exception("缺少统一支付接口必填参数total_fee!");
|
||
}
|
||
else if (!inputObj.IsSet("trade_type"))
|
||
{
|
||
throw new Exception("缺少统一支付接口必填参数trade_type!");
|
||
}
|
||
|
||
//关联参数
|
||
if (inputObj.GetValue("trade_type").ToString() == "JSAPI" && !inputObj.IsSet("openid"))
|
||
{
|
||
throw new Exception("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!");
|
||
}
|
||
if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("product_id"))
|
||
{
|
||
throw new Exception("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!");
|
||
}
|
||
|
||
//异步通知url未设置,则使用配置文件中的url
|
||
if (!inputObj.IsSet("notify_url"))
|
||
{
|
||
inputObj.SetValue("notify_url", WeixinConfig.NotifyUrl);//异步通知url
|
||
}
|
||
|
||
inputObj.SetValue("appid", WeixinConfig.Appid);//公众账号ID
|
||
inputObj.SetValue("mch_id", WeixinConfig.MCHID);//商户号
|
||
inputObj.SetValue("spbill_create_ip", WePayConfig.IP);//终端ip
|
||
inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
|
||
|
||
//签名
|
||
inputObj.SetValue("sign", inputObj.MakeSign());
|
||
string xml = inputObj.ToXml();
|
||
|
||
var start = DateTime.Now;
|
||
|
||
// Log.Info("XcxPayApi", "UnfiedOrder request : " + xml);
|
||
string response = HttpPost(xml, url, "application/xml", timeOut);
|
||
//Log.Info("XcxPayApi", "UnfiedOrder response : " + response);
|
||
// WebHookHelper.WebHookmarkdownSend(response);
|
||
|
||
var end = DateTime.Now;
|
||
int timeCost = (int)((end - start).TotalMilliseconds);
|
||
|
||
WxPayData result = new WxPayData();
|
||
result.FromXml(response);
|
||
// ReportCostTime(url, timeCost, result);//测速上报网络不好时使用
|
||
return result;
|
||
}
|
||
/// <summary>
|
||
/// 生成随机数
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public static string GenerateNonceStr()
|
||
{
|
||
return Guid.NewGuid().ToString().Replace("-", "");
|
||
}
|
||
/// <summary>
|
||
/// POST请求
|
||
/// </summary>
|
||
/// <param name="postData"></param>
|
||
/// <param name="url"></param>
|
||
/// <param name="contentType">application/xml、application/json、application/text、application/x-www-form-urlencoded</param>
|
||
/// <param name="timeOut"></param>
|
||
/// <param name="headers"></param>
|
||
/// <returns></returns>
|
||
public static string HttpPost(string postData, string url, string contentType = null, int timeOut = 30, Dictionary<string, string> headers = null)
|
||
{
|
||
postData = postData ?? "";
|
||
|
||
var httpClientHandler = new HttpClientHandler
|
||
{
|
||
ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true
|
||
};
|
||
using (HttpClient httpClient = new HttpClient(httpClientHandler))
|
||
{
|
||
if (headers != null)
|
||
{
|
||
foreach (var header in headers)
|
||
httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||
}
|
||
using (HttpContent client = new StringContent(postData, Encoding.UTF8))
|
||
{
|
||
if (contentType != null)
|
||
client.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
|
||
|
||
HttpResponseMessage response = httpClient.PostAsync(url, client).Result;
|
||
return response.Content.ReadAsStringAsync().Result;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
public class WePayConfig
|
||
{
|
||
//=======【商户系统后台机器IP】=====================================
|
||
/* 此参数可手动配置也可在程序中自动获取
|
||
*/
|
||
public const string IP = "8.8.8.8";
|
||
|
||
|
||
//=======【代理服务器设置】===================================
|
||
/* 默认IP和端口号分别为0.0.0.0和0,此时不开启代理(如有需要才设置)
|
||
*/
|
||
public const string PROXY_URL = "";
|
||
|
||
//=======【上报信息配置】===================================
|
||
/* 测速上报等级,0.关闭上报; 1.仅错误时上报; 2.全量上报
|
||
*/
|
||
public const int REPORT_LEVENL = 1;
|
||
|
||
//=======【日志级别】===================================
|
||
/* 日志等级,0.不输出日志;1.只输出错误信息; 2.输出错误和正常信息; 3.输出错误信息、正常信息和调试信息
|
||
*/
|
||
public const int LOG_LEVENL = 3;
|
||
}
|
||
}
|