コード例 #1
0
        /// <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 = "服务器异常,请联系管理员!" }));
            }
        }
コード例 #2
0
        /**
         * 下载对账单
         * @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 }
                       }
            };
        }
コード例 #3
0
        /**
         *
         * 获取收货地址js函数入口参数,详情请参考收货地址共享接口:http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_9
         * @return string 共享收货地址js函数需要的参数,json格式可以直接做参数使用
         */
        public string JsApiPayAddress(string access_token)
        {
            //参与签名的是网页授权获取用户信息时微信后台回传的完整url
            string url = "http://redirect_uri";

            //构造需要用SHA1算法加密的数据
            SortedDictionary <string, object> data = new SortedDictionary <string, object>
            {
                { "appid", appid },
                { "url", url },
                { "timestamp", PayHelper.Time_stamp },
                { "noncestr", PayHelper.Nonce_str },
                { "accesstoken", access_token }
            };
            string addrSign = EncryptHelper.SHA1(PayHelper.ToUrl(data));

            //获取收货地址js函数入口参数
            SortedDictionary <string, object> afterData = new SortedDictionary <string, object>
            {
                { "appId", appid },
                { "scope", "jsapi_address" },
                { "signType", "sha1" },
                { "addrSign", addrSign },
                { "timeStamp", data["timestamp"] },
                { "nonceStr", data["noncestr"] }
            };

            return(JsonConvert.SerializeObject(afterData));
        }
コード例 #4
0
        /**
         *
         * 查询订单情况
         * @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);
        }
コード例 #5
0
        /**
         *
         * 统一下单
         * @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));
        }
コード例 #6
0
        /**
         *
         * 转换短链接
         * 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(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));;
        }
コード例 #7
0
        /**
         *
         * 撤销订单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));
        }
コード例 #8
0
        /**
         *
         * 关闭订单
         * @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));
        }
コード例 #9
0
        /**
         *
         * 查询退款
         * 提交退款申请后,通过该接口查询退款状态。退款有一定延时,
         * 用零钱支付的退款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));
        }
コード例 #10
0
        /**
         *
         * 申请退款
         * @param WxPayData inputObj 提交给申请退款API的参数
         * @param int timeOut 超时时间
         * @throws Exception
         * @return 成功时返回接口调用结果,其他抛异常
         */
        public static SortedDictionary <string, object> Refund(SortedDictionary <string, object> inputObj, int timeOut = 30)
        {
            //检测必填参数
            if (!inputObj.ContainsKey("out_trade_no") && !inputObj.ContainsKey("transaction_id"))
            {
                throw new Exception("退款申请接口中,out_trade_no、transaction_id至少填一个!");
            }
            else if (!inputObj.ContainsKey("out_refund_no"))
            {
                throw new Exception("退款申请接口中,缺少必填参数out_refund_no!");
            }
            else if (!inputObj.ContainsKey("total_fee"))
            {
                throw new Exception("退款申请接口中,缺少必填参数total_fee!");
            }
            else if (!inputObj.ContainsKey("refund_fee"))
            {
                throw new Exception("退款申请接口中,缺少必填参数refund_fee!");
            }
            else if (!inputObj.ContainsKey("op_user_id"))
            {
                throw new Exception("退款申请接口中,缺少必填参数op_user_id!");
            }

            inputObj.Add("appid", "WeChat_APPID");                                 //公众账号ID
            inputObj.Add("mch_id", "WeChat_MCHID");                                //商户号
            inputObj.Add("nonce_str", Guid.NewGuid().ToString().Replace("-", "")); //随机字符串
            inputObj.Add("sign", inputObj.MakeSign());                             //签名

            string xml   = inputObj.ToXml();
            var    start = DateTime.Now;

            string response = HttpService.Post(xml, "https://api.mch.weixin.qq.com/secapi/pay/refund", true, timeOut);//调用HTTP通信接口提交数据到API

            var end      = DateTime.Now;
            int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时

            return(PayHelper.FromXml(response));
        }
コード例 #11
0
        /// <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);
        }
コード例 #12
0
        /**
         * 刷卡支付完整业务流程逻辑
         * @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));
        }