/** * 下载对账单 * @param WxPayData inputObj 提交给下载对账单API的参数 * @param int timeOut 接口超时时间 * @throws Exception * @return 成功时返回,其他抛异常 */ public SortedDictionary <string, object> DownloadBill(SortedDictionary <string, object> inputObj, int timeOut = 6) { //检测必填参数 if (!inputObj.ContainsKey("bill_date")) { throw new Exception("对账单接口中,缺少必填参数bill_date!"); } inputObj.Add("appid", appid); //公众账号ID inputObj.Add("mch_id", mch_id); //商户号 inputObj.Add("nonce_str", PayHelper.Nonce_str); //随机字符串 inputObj.Add("sign", PayHelper.MakeSign(inputObj)); //签名 string xml = inputObj.ToXml(); string response = HttpService.Post(xml, "https://api.mch.weixin.qq.com/pay/downloadbill", false, timeOut);//调用HTTP通信接口以提交数据到API if (response.Substring(0, 5) == "<xml>") { return(PayHelper.FromXml(response)); } else { return new SortedDictionary <string, object>() { { "result", response } } }; }
/// <summary> /// 扫码支付(模式一) /// 官方文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1 /// </summary> /// <returns></returns> public ActionResult NativePayOne(string productId) { try { if (string.IsNullOrEmpty(productId)) { return(Json(new { Code = 1, Msg = "产品不能为空!" })); } SortedDictionary <string, object> data = new SortedDictionary <string, object> { { "appid", appid }, { "mch_id", mch_id }, { "time_stamp", PayHelper.Time_stamp }, { "nonce_str", PayHelper.Nonce_str }, { "product_id", productId } }; data.Add("sign", PayHelper.MakeSign(data)); return(Json(new { Code = 0, Msg = "weixin://wxpay/bizpayurl?" + PayHelper.ToUrl(data) })); } catch (Exception ex) { LogHelper.SaveLog(ex); return(Json(new { Code = 1, Msg = "服务器异常,请联系管理员!" })); } }
/** * * 查询订单情况 * @param string out_trade_no 商户订单号 * @param int succCode 查询订单结果:0表示订单不成功,1表示订单成功,2表示继续查询 * @return 订单查询接口返回的数据,参见协议接口 */ private SortedDictionary <string, object> MicroPayQuery(string out_trade_no, out int succCode) { string url = "https://api.mch.weixin.qq.com/pay/orderquery"; string appid = "WeChat_APPID"; string MCHID = "WeChat_MCHID"; SortedDictionary <string, object> data = new SortedDictionary <string, object> { { "out_trade_no", out_trade_no }, { "appid", appid }, //公众账号ID { "mch_id", MCHID }, //商户号 { "nonce_str", PayHelper.Nonce_str }//随机字符串 }; data.Add("sign", PayHelper.MakeSign(data));//签名 string xml = data.ToXml(); string response = HttpService.Post(xml, url, false, 10);//调用HTTP通信接口提交数据 //将xml格式的数据转化为对象以返回 var result = PayHelper.FromXml(response); if (result["return_code"].ToString() == "SUCCESS" && result["result_code"].ToString() == "SUCCESS") { //支付成功 if (result["trade_state"].ToString() == "SUCCESS") { succCode = 1; return(result); } //用户支付中,需要继续查询 else if (result["trade_state"].ToString() == "USERPAYING") { succCode = 2; return(result); } } //如果返回错误码为“此交易订单号不存在”则直接认定失败 if (result["err_code"].ToString() == "ORDERNOTEXIST") { succCode = 0; } else { //如果是系统错误,则后续继续 succCode = 2; } return(result); }
/** * * 统一下单 * @param WxPaydata inputObj 提交给统一下单API的参数 * @param int timeOut 超时时间 * @throws Exception * @return 成功时返回,其他抛异常 */ public SortedDictionary <string, object> UnifiedOrder(SortedDictionary <string, object> inputObj, int timeOut = 6) { //检测必填参数 if (!inputObj.ContainsKey("out_trade_no")) { throw new Exception("缺少统一支付接口必填参数out_trade_no!"); } else if (!inputObj.ContainsKey("body")) { throw new Exception("缺少统一支付接口必填参数body!"); } else if (!inputObj.ContainsKey("total_fee")) { throw new Exception("缺少统一支付接口必填参数total_fee!"); } else if (!inputObj.ContainsKey("trade_type")) { throw new Exception("缺少统一支付接口必填参数trade_type!"); } //关联参数 if (inputObj["trade_type"].ToString() == "JSAPI" && !inputObj.ContainsKey("openid")) { throw new Exception("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!"); } if (inputObj["trade_type"].ToString() == "NATIVE" && !inputObj.ContainsKey("product_id")) { throw new Exception("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!"); } //异步通知url未设置,则使用配置文件中的url if (!inputObj.ContainsKey("notify_url")) { inputObj.Add("notify_url", "http://url");//异步通知url } inputObj.Add("appid", appid); //公众账号ID inputObj.Add("mch_id", mch_id); //商户号 inputObj.Add("spbill_create_ip", ip); //终端ip inputObj.Add("nonce_str", PayHelper.Nonce_str); //随机字符串 inputObj.Add("sign", PayHelper.MakeSign(inputObj, key)); string response = HttpService.Post(PayHelper.ToXml(inputObj), "https://api.mch.weixin.qq.com/pay/unifiedorder", false, timeOut); return(PayHelper.FromXml(response, key)); }
/** * * 转换短链接 * 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX), * 减小二维码数据量,提升扫描速度和精确度。 * @param WxPayData inputObj 提交给转换短连接API的参数 * @param int timeOut 接口超时时间 * @throws Exception * @return 成功时返回,其他抛异常 */ public SortedDictionary <string, object> ShortUrl(SortedDictionary <string, object> inputObj, int timeOut = 6) { //检测必填参数 if (!inputObj.ContainsKey("long_url")) { throw new Exception("需要转换的URL,签名用原串,传输需URL encode!"); } inputObj.Add("appid", appid); //公众账号ID inputObj.Add("mch_id", mch_id); //商户号 inputObj.Add("nonce_str", PayHelper.Nonce_str); //随机字符串 inputObj.Add("sign", PayHelper.MakeSign(inputObj)); //签名 string xml = inputObj.ToXml(); string response = HttpService.Post(xml, "https://api.mch.weixin.qq.com/tools/shorturl", false, timeOut); return(PayHelper.FromXml(response));; }
/** * * 撤销订单API接口 * @param WxPayData inputObj 提交给撤销订单API接口的参数,out_trade_no和transaction_id必填一个 * @param int timeOut 接口超时时间 * @throws Exception * @return 成功时返回API调用结果,其他抛异常 */ public SortedDictionary <string, object> Reverse(SortedDictionary <string, object> inputObj, int timeOut = 6) { //检测必填参数 if (!inputObj.ContainsKey("out_trade_no") && !inputObj.ContainsKey("transaction_id")) { throw new Exception("撤销订单API接口中,参数out_trade_no和transaction_id必须填写一个!"); } inputObj.Add("appid", appid); //公众账号ID inputObj.Add("mch_id", mch_id); //商户号 inputObj.Add("nonce_str", PayHelper.Nonce_str); //随机字符串 inputObj.Add("sign", PayHelper.MakeSign(inputObj)); //签名 string xml = inputObj.ToXml(); string response = HttpService.Post(xml, "https://api.mch.weixin.qq.com/secapi/pay/reverse", true, timeOut); return(PayHelper.FromXml(response)); }
/** * * 关闭订单 * @param WxPayData inputObj 提交给关闭订单API的参数 * @param int timeOut 接口超时时间 * @throws Exception * @return 成功时返回,其他抛异常 */ public SortedDictionary <string, object> CloseOrder(SortedDictionary <string, object> inputObj, int timeOut = 6) { //检测必填参数 if (!inputObj.ContainsKey("out_trade_no")) { throw new Exception("关闭订单接口中,out_trade_no必填!"); } inputObj.Add("appid", appid); //公众账号ID inputObj.Add("mch_id", mch_id); //商户号 inputObj.Add("nonce_str", PayHelper.Nonce_str); //随机字符串 inputObj.Add("sign", PayHelper.MakeSign(inputObj)); //签名 string xml = PayHelper.ToXml(inputObj); string response = HttpService.Post(xml, "https://api.mch.weixin.qq.com/pay/closeorder", false, timeOut); return(PayHelper.FromXml(response)); }
/** * * 查询退款 * 提交退款申请后,通过该接口查询退款状态。退款有一定延时, * 用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。 * out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个 * @param WxPayData inputObj 提交给查询退款API的参数 * @param int timeOut 接口超时时间 * @throws Exception * @return 成功时返回,其他抛异常 */ public SortedDictionary <string, object> RefundQuery(SortedDictionary <string, object> inputObj, int timeOut = 6) { //检测必填参数 if (!inputObj.ContainsKey("out_refund_no") && !inputObj.ContainsKey("out_trade_no") && !inputObj.ContainsKey("transaction_id") && !inputObj.ContainsKey("refund_id")) { throw new Exception("退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!"); } inputObj.Add("appid", appid); //公众账号ID inputObj.Add("mch_id", mch_id); //商户号 inputObj.Add("nonce_str", PayHelper.Nonce_str); //随机字符串 inputObj.Add("sign", PayHelper.MakeSign(inputObj)); //签名 string xml = inputObj.ToXml(); string response = HttpService.Post(xml, "https://api.mch.weixin.qq.com/pay/refundquery", false, timeOut);//调用HTTP通信接口以提交数据到API return(PayHelper.FromXml(response)); }
/// <summary> /// 统一下单,返回微信浏览器支付参数 /// </summary> /// <param name="openid">openid</param> /// <param name="total_fee">金额</param> /// <returns></returns> public SortedDictionary <string, object> JsApiPayOrder(string openid, int total_fee) { //统一下单 SortedDictionary <string, object> data = new SortedDictionary <string, object> { { "body", "test" }, { "attach", "test" }, { "out_trade_no", PayHelper.Out_trade_no }, { "total_fee", total_fee }, { "time_start", DateTime.Now.ToString("yyyyMMddHHmmss") }, { "time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss") }, { "goods_tag", "test" }, { "trade_type", "JSAPI" }, { "openid", openid } }; var result = UnifiedOrder(data); if (!result.ContainsKey("appid") || !result.ContainsKey("prepay_id") || result["prepay_id"].ToString() == "") { throw new Exception("UnifiedOrder response error!"); } SortedDictionary <string, object> jsApiParam = new SortedDictionary <string, object> { { "appId", result["appid"] }, { "timeStamp", PayHelper.Time_stamp }, { "nonceStr", PayHelper.Nonce_str }, { "package", "prepay_id=" + result["prepay_id"] }, { "signType", "MD5" } }; jsApiParam.Add("paySign", PayHelper.MakeSign(jsApiParam)); return(jsApiParam); }
/** * 刷卡支付完整业务流程逻辑 * @param body 商品描述 * @param total_fee 总金额 * @param auth_code 支付授权码 * @throws WxPayException * @return 刷卡支付结果 */ public ActionResult MicroPay(string body, string total_fee, string auth_code) { SortedDictionary <string, object> data = new SortedDictionary <string, object> { { "auth_code", auth_code }, //用户出示授权码 { "body", body }, //商品描述 { "total_fee", int.Parse(total_fee) }, //总金额 { "out_trade_no", PayHelper.Out_trade_no }, //产生随机的商户订单号 { "spbill_create_ip", ip }, //终端ip { "appid", appid }, { "mch_id", mch_id }, { "nonce_str", PayHelper.Nonce_str }//随机字符串 }; data.Add("sign", PayHelper.MakeSign(data));//签名 string xml = PayHelper.ToXml(data); string url = "https://api.mch.weixin.qq.com/pay/micropay"; string response = HttpService.Post(xml, url, false, 10);//调用HTTP通信接口以提交数据到API //将xml格式的结果转换为对象以返回 SortedDictionary <string, object> result = PayHelper.FromXml(response); //如果提交被扫支付接口调用失败,则抛异常 if (!result.ContainsKey("return_code") || result["return_code"].ToString() == "FAIL") { string returnMsg = result.ContainsKey("return_msg") ? result["return_msg"].ToString() : ""; throw new Exception("Micropay API interface call failure, return_msg : " + returnMsg); } //签名验证 result.CheckSign(); //刷卡支付直接成功 if (result["return_code"].ToString() == "SUCCESS" && result["result_code"].ToString() == "SUCCESS") { return(Json(result)); } /****************************************************************** * 剩下的都是接口调用成功,业务失败的情况 * ****************************************************************/ //1)业务结果明确失败 if (result["err_code"].ToString() != "USERPAYING" && result["err_code"].ToString() != "SYSTEMERROR") { return(Json(result)); } //2)不能确定是否失败,需查单 //用商户订单号去查单 string out_trade_no = data["out_trade_no"].ToString(); //确认支付是否成功,每隔一段时间查询一次订单,共查询10次 int queryTimes = 10;//查询次数计数器 while (queryTimes-- > 0) { SortedDictionary <string, object> queryResult = MicroPayQuery(out_trade_no, out int succResult); //如果需要继续查询,则等待2s后继续 if (succResult == 2) { Thread.Sleep(2000); continue; } else if (succResult == 1) { //查询成功,返回订单查询接口返回的数据 return(Json(queryResult)); } else { //订单交易失败,直接返回刷卡支付接口返回的结果,失败原因会在err_code中描述 return(Json(result)); } } //确认失败,则撤销订单 if (!MicroPayCancel(out_trade_no)) { throw new Exception("Reverse order failure!"); } return(Json(result)); }