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 logger; public WeixinPayController(IV_OrderInfoRepository IV_OrderInfoRepository , IV_CustomerInfoRepository IV_CustomerInfoRepository , IV_VipCardInfoRepository IV_VipCardInfoRepository , IV_VipCardTypeRepository IV_VipCardTypeRepository , ILogger loggers) { v_OrderInfoRepository = IV_OrderInfoRepository; v_CustomerInfoRepository = IV_CustomerInfoRepository; v_VipCardInfoRepository = IV_VipCardInfoRepository; v_VipCardTypeRepository = IV_VipCardTypeRepository; logger = loggers; } /// /// 下订单 /// /// [HttpPost] public async Task 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; } /// /// 支付返回值 /// /// [HttpPost] [AllowAnonymous] public async Task 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("统一支付接口中,缺少必填参数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; } /// /// 生成随机数 /// /// public static string GenerateNonceStr() { return Guid.NewGuid().ToString().Replace("-", ""); } /// /// POST请求 /// /// /// /// application/xml、application/json、application/text、application/x-www-form-urlencoded /// /// /// public static string HttpPost(string postData, string url, string contentType = null, int timeOut = 30, Dictionary 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; } } } } }