NewGaoKaoApi/New_College.Api/Controllers/Front/WeixinPayController.cs

356 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using New_College.Common;
using New_College.Common.Helper;
using New_College.IRepository;
using New_College.IServices;
using New_College.Model;
using New_College.Model.Models;
using New_College.Model.ViewModels;
using Newtonsoft.Json;
namespace New_College.Api.Controllers.Front
{
[Route("api/front/[controller]/[action]")]
[ApiController]
[Authorize]
public class WeixinPayController : ControllerBase
{
private readonly IV_OrderInfoRepository v_OrderInfoRepository;
private readonly IV_CustomerInfoRepository v_CustomerInfoRepository;
private readonly IV_VipCardInfoRepository v_VipCardInfoRepository;
private readonly IV_VipCardTypeRepository v_VipCardTypeRepository;
private readonly ILogger<V_OrderInfo> logger;
public WeixinPayController(IV_OrderInfoRepository IV_OrderInfoRepository
, IV_CustomerInfoRepository IV_CustomerInfoRepository
, IV_VipCardInfoRepository IV_VipCardInfoRepository
, IV_VipCardTypeRepository IV_VipCardTypeRepository
, ILogger<V_OrderInfo> loggers)
{
v_OrderInfoRepository = IV_OrderInfoRepository;
v_CustomerInfoRepository = IV_CustomerInfoRepository;
v_VipCardInfoRepository = IV_VipCardInfoRepository;
v_VipCardTypeRepository = IV_VipCardTypeRepository;
logger = loggers;
}
/// <summary>
/// 下订单
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<WeixinPayResult> UnifiedOrder(UnifiedOrderQuery query)
{
var resp = new WeixinPayResult();
try
{
DingHookHelper.DingTalkHookMessage("UnifiedOrder=>发起支付", JsonConvert.SerializeObject(query));
Random rd = new Random();
//HttpContext.GetClientUserIp();
//外部商户订单号
var payNum = DateTime.Now.ToString("yyyyMMddHHmmss") + rd.Next(0, 1000).ToString().PadLeft(3, '0');
var data = new WxPayData();
data.SetValue("body", "六纬志愿VIP购买");
data.SetValue("out_trade_no", payNum);
data.SetValue("detail", "志愿好帮手VIP卡购买");
data.SetValue("total_fee", Convert.ToInt32(query.total_fee * 100));
data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
//data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));
data.SetValue("notify_url", WeixinConfig.NotifyUrl);
//data.SetValue("goods_tag", "test");
data.SetValue("trade_type", "JSAPI");
data.SetValue("openid", query.OpenId);
//可以将用户Id和订单Id同时封装在attach中
data.SetValue("attach", string.Format("{0}|{1}", query.OpenId, payNum));
WxPayData result = UnifiedOrder(data);
if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")
{
resp.err_code_des = result.GetValue("err_code_des").ToString();
resp.err_code = result.GetValue("err_code").ToString();
resp.result_code = result.GetValue("result_code").ToString();
return resp;
}
else
{
resp.nonce_str = result.GetValue("nonce_str").ToString();
resp.appid = result.GetValue("appid").ToString();
resp.mchi_id = result.GetValue("mch_id").ToString();
resp.result_code = result.GetValue("result_code").ToString();
resp.prepay_id = "prepay_id=" + result.GetValue("prepay_id").ToString();
//resp.code_url = result.GetValue("code_url").ToString();
resp.trade_type = result.GetValue("trade_type").ToString();
var signType = "MD5";
var timeStamp = ((DateTime.Now.Ticks - TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).Ticks) / 10000).ToString();
WxPayData applet = new WxPayData();
applet.SetValue("appId", resp.appid);
applet.SetValue("nonceStr", resp.nonce_str);
applet.SetValue("package", resp.prepay_id);
applet.SetValue("signType", signType);
applet.SetValue("timeStamp", timeStamp);
resp.sign = applet.MakeSign();
resp.timeStamp = timeStamp;
//NLogHelper.WriteInfo("Signurl" + Newtonsoft.Json.JsonConvert.SerializeObject(resp), DevAuthorNameEnum.Michael, false);
// WebHookHelper.WebHookmarkdownSend("Signurl" + Newtonsoft.Json.JsonConvert.SerializeObject(resp));
var customer = await v_CustomerInfoRepository.Query(x => x.OpenId == query.OpenId && x.IsDelete == false);
if (customer.Count <= 0)
return new WeixinPayResult() { err_code_des = "用户出现错误" };
//添加一张卡
var cardtype = await v_VipCardTypeRepository.QueryById(query.CardTypeId);
if (cardtype == null)
return new WeixinPayResult() { err_code_des = "卡出现错误" };
var code = RadomHelper.GetGuid();
var addcard = await v_VipCardInfoRepository.Add(new V_VipCardInfo()
{
CardTypeId = query.CardTypeId,
CardTypeName = cardtype.Name,
Code = code,
IsBind = 1,
Money = query.total_fee,
Day = cardtype.Day,
EndTime = DateTime.Now.AddDays(cardtype.Day)
});
string OrderNo = OrderGenerateHelper.GenerateOrderNo("ZY");
var baseResult = await v_OrderInfoRepository.Add(new V_OrderInfo
{
out_trade_no = payNum,
PayType = 0,
CardTypeId = query.CardTypeId,
OrderId = OrderNo,
Status = EnumOrderType.payment,
CustomerId = customer.FirstOrDefault().Id,
Price = query.total_fee,
PayPrice = query.total_fee,
Name = "六纬志愿VIP购买",
CardNo = code,
CardId = addcard
});
if (baseResult > 0)
{
//订单号
applet.SetValue("orderid", baseResult);
resp.orderid = baseResult.ToString();
}
}
}
catch (Exception ex)
{
//WebHookHelper.WebHookmarkdownSend(ex.ToString());
//NLogHelper.WriteError(ex, DevAuthorNameEnum.Michael, false);
}
return resp;
}
/// <summary>
/// 支付返回值
/// </summary>
/// <returns></returns>
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> PayNotify()
{
logger.LogInformation("开始回调PayNotify");
DingHookHelper.DingTalkHookMessage("开始回调PayNotify", "开始回调PayNotify");
WxPayData res = new WxPayData();
//接收从微信后台POST过来的数据
//转换数据格式并验证签名
WxPayData data = new WxPayData();
using (var reader = new StreamReader(Request.Body))
{
var builder = reader.ReadToEnd();
//WebHookHelper.WebHookmarkdownSend(builder.ToString());
try
{
data.FromXml(builder.ToString());
}
catch (Exception ex)
{
//若签名错误,则立即返回结果给微信支付后台
DingHookHelper.DingTalkHookMessage("回调PayNotify", ex.Message);
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", ex.Message);
// NLogHelper.WriteError("Sign check error : " + res.ToXml(), DevAuthorNameEnum.Michael, false);
//WebHookHelper.WebHookmarkdownSend(string.Format("return_msg:{0}", ex.Message));
return Content(res.ToXml(), "text/xml");
}
};
// WebHookHelper.WebHookmarkdownSend("Check sign success");
//检查支付结果中transaction_id是否存在
if (!data.IsSet("transaction_id"))
{
DingHookHelper.DingTalkHookMessage("回调PayNotify", "支付结果中微信订单号不存在");
//若transaction_id不存在则立即返回结果给微信支付后台
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", "支付结果中微信订单号不存在");
//WebHookHelper.WebHookmarkdownSend("支付结果中微信订单号不存在");
return Content(res.ToXml(), "text/xml");
}
// 执行订单状态操作
string out_trade_no = data.GetValue("out_trade_no").ToString();
logger.LogInformation("开始回调PayNotify" + out_trade_no);
DingHookHelper.DingTalkHookMessage("回调PayNotify", "开始回调PayNotify" + out_trade_no);
var info = await v_OrderInfoRepository.Query(x => x.out_trade_no == out_trade_no);
if (info.Count <= 0)
{
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", "在自有平台未找到该订单号");
DingHookHelper.DingTalkHookMessage("回调PayNotify", "在自有平台未找到该订单号" + out_trade_no);
//WebHookHelper.WebHookmarkdownSend("支付结果中微信订单号不存在");
return Content(res.ToXml(), "text/xml");
}
var oneinfo = info.FirstOrDefault();
oneinfo.Status = EnumOrderType.payoff;
var rep = await v_OrderInfoRepository.Update(oneinfo);
if (rep)
{
DingHookHelper.DingTalkHookMessage("支付回调成功", oneinfo.out_trade_no + ":修改为VIP");
//修改用户信息 修改为VIp
var customerinfo = await v_CustomerInfoRepository.QueryById(oneinfo.CustomerId);
customerinfo.IsVIP = true;
customerinfo.VipCode = oneinfo.CardNo;
await v_CustomerInfoRepository.Update(customerinfo);
//支付成功后根据用户code找到对应用户修改vip 状态
res.SetValue("return_code", "SUCCESS");
res.SetValue("return_msg", "OK");
}
else
{
// string attach = data.GetValue("attach").ToString();
// WebHookHelper.WebHookmarkdownSend(attach);
DingHookHelper.DingTalkHookMessage("回调PayNotify", "在自有平台未找到该订单号" + out_trade_no);
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", "在自有平台未找到该订单号");
}
return Content(res.ToXml(), "text/xml");
}
/**
*
* 统一下单
* @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("统一支付接口中缺少必填参数openidtrade_type为JSAPI时openid为必填参数");
}
if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("product_id"))
{
throw new Exception("统一支付接口中缺少必填参数product_idtrade_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;
}
}
}
}
}