支付宝-自动扣款自动退款

请求体,返回体:

 方法:

复制代码
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Xml;
using System.Net;
using System.IO;
using System.Security.Cryptography;
using System.Web.Security;
using Ctrip.Common.Utility;
using Freeway.Logging;
using Arch.CFramework.Utility.Serialize;

namespace Ctrip.AM.SOA.Service.Group
{
    public class AlipayManager
    {
        private const string service = "cae_charge_agent";//扣款接口名称
        private const string service_ref = "refund_fastpay_by_platform_nopwd";//退款接口名称
        private const string _input_charset = "utf-8";//参数编码字符集
        private const string sign_type = "MD5";//签名方式
        private const string charge_type = "trade"; // 代扣模式
        private static ILog logger = Freeway.Logging.LogManager.GetLogger(typeof(AlipayManager));
       
        /// <summary>
        /// 支付宝扣款
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public AlipayWithHoldResponseType AlipayWithHold(AlipayWithHoldRequestType request)
        {
            AlipayWithHoldResponseType resp = new AlipayWithHoldResponseType();
            resp.ResultCode = 0;
            resp.ResultMsg = string.Empty;
            try
            {
                #region 验证参数
                if (string.IsNullOrEmpty(request.Partner))
                {
                    resp.ResultMsg = "合作者身份ID不能为空!";
                }
                if (string.IsNullOrEmpty(request.Sign))
                {
                    resp.ResultMsg = "私钥不能为空!";
                }
                if (string.IsNullOrEmpty(request.OrderID))
                {
                    resp.ResultMsg = "商户订单号不能为空!";
                }
                if (string.IsNullOrEmpty(request.TypeCode))
                {
                    resp.ResultMsg = "代理业务编码不能为空!";
                }
                if (request.Amount < 0)
                {
                    resp.ResultMsg = "代扣金额不能小于0!";
                }
                if (string.IsNullOrEmpty(request.Subject))
                {
                    resp.ResultMsg = "标题不能为空!";
                }
                if (string.IsNullOrEmpty(request.TransAccountIn))
                {
                    resp.ResultMsg = "转入支付宝账号不能为空!";
                }
                if (string.IsNullOrEmpty(request.TransAccountOut))
                {
                    resp.ResultMsg = "转出支付宝账号不能为空!";
                }
                if (!string.IsNullOrEmpty(resp.ResultMsg))
                {
                    logger.Debug("提示", resp.ResultMsg);
                    return resp;
                }
                #endregion
                //处理金额,支付宝2.5可以,2.50就不可以
                if (request.Amount.ToString().Contains('.'))
                {
                    request.Amount = Convert.ToDecimal(request.Amount.ToString().Trim('0'));
                }
                //拼写签名字符串
                StringBuilder strBuilder = new StringBuilder();
                strBuilder.Append("_input_charset=" + _input_charset);
                strBuilder.Append("&amount=" + request.Amount);
                strBuilder.Append("&charge_type=" + charge_type);
                if (request.CreateTime == DateTime.MinValue)
                {
                    request.CreateTime = DateTime.Now;
                }
                strBuilder.Append("&gmt_out_order_create=" + request.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"));
                if (!string.IsNullOrEmpty(request.OperatorID))
                {
                    strBuilder.Append("&operator_id=" + request.OperatorID);
                }
                if (!string.IsNullOrEmpty(request.OperatorName))
                {
                    strBuilder.Append("&operator_name=" + request.OperatorName);
                }
                strBuilder.Append("&out_order_no=" + request.OrderID);
                strBuilder.Append("&partner=" + request.Partner);
                strBuilder.Append("&service=" + service);
                if (!string.IsNullOrEmpty(request.Subject))
                {
                    strBuilder.Append("&subject=" + request.Subject);
                }
                strBuilder.Append("&trans_account_in=" + request.TransAccountIn);
                strBuilder.Append("&trans_account_out=" + request.TransAccountOut);
                strBuilder.Append("&type_code=" + request.TypeCode);
                //最后加上私钥
                strBuilder.Append(request.Sign);
                //签名
                string sign = Sign(strBuilder.ToString(), sign_type, _input_charset);
                //支付宝链接
                string URL = "https://mapi.alipay.com/gateway.do?trans_account_out={0}&operator_id={1}&subject={2}&sign_type={3}&out_order_no={4}&amount={5}&partner={6}&operator_name={7}&charge_type={8}&trans_account_in={9}&gmt_out_order_create={10}&type_code={11}&sign={12}&service={13}&_input_charset={14}";
                URL = string.Format(URL, request.TransAccountOut, request.OperatorID, request.Subject, sign_type, request.OrderID, request.Amount, request.Partner, request.OperatorName, charge_type, request.TransAccountIn, request.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"), request.TypeCode, sign, service, _input_charset);
                string result = "";
                bool isT = SendByGetMethod(URL, out result);
                XMLSerializer xmlSerializer = new XMLSerializer();
                logger.Debug("扣款请求体", xmlSerializer.Serialize<AlipayWithHoldRequestType>(request));
                if (isT)
                {
                    XmlDocument xd = new XmlDocument();
                    xd.LoadXml(result);
                    if (xd.GetElementsByTagName("is_success")[0].InnerXml.ToString() == "T")
                    {
                        if (xd.GetElementsByTagName("out_order_no")[0].InnerText == request.OrderID.ToString() && xd.GetElementsByTagName("status")[0].InnerText == "TRADE_SUCCESS")
                        {
                            //支付宝交易号
                            string trade_no = xd.GetElementsByTagName("trade_no")[0].InnerText.ToString();
                            resp.ResultCode = 1;
                            resp.ResultMsg = "Success";
                            resp.TradeNo = trade_no;
                        }
                        else
                        {
                            resp.ResultMsg = "支付宝扣款返回商户号或状态错误!";
                            logger.Debug("提示", "支付宝扣款返回商户号或状态错误!");
                        }
                    }
                    else
                    {
                        string error = xd.GetElementsByTagName("error")[0].InnerXml.ToString();
                        resp.ResultMsg = "支付宝扣款返回错误!ErrorMsg:" + error;
                        logger.Debug("提示", "支付宝扣款返回错误!ErrorMsg:" + error);
                    }
                }
                else
                {
                    resp.ResultMsg = "支付宝扣款提交失败!";
                    logger.Debug("提示", "支付宝扣款提交失败!");
                }
            }
            catch (Exception ex)
            {
                resp.ResultMsg = ex.Message.ToString();
                logger.Debug("支付宝扣款_AlipayWithHold", ex);
            }
            return resp;
        }

    
        /// <summary>
        /// 支付宝退款
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public AlipayRefundResponseType AlipayRefund(AlipayRefundRequestType request)
        {
            AlipayRefundResponseType resp = new AlipayRefundResponseType();
            resp.ResultCode = 0;
            resp.ResultMsg = "Fail";
            try
            {
                #region 验证参数
                if (string.IsNullOrEmpty(request.Partner))
                {
                    resp.ResultMsg = "合作者身份ID不能为空!";
                    logger.Debug("提示", "合作者身份ID不能为空!");
                    return resp;
                }
                if (string.IsNullOrEmpty(request.Sign))
                {
                    resp.ResultMsg = "私钥不能为空!";
                    logger.Debug("提示", "私钥不能为空!");
                    return resp;
                }
                if (string.IsNullOrEmpty(request.TradeNo))
                {
                    resp.ResultMsg = "支付宝交易号不能为空!";
                    logger.Debug("提示", "支付宝交易号不能为空!");
                    return resp;
                }
                if (request.Amount < 0)
                {
                    resp.ResultMsg = "退款金额不能小于0!";
                    logger.Debug("提示", "退款金额不能小于0!");
                    return resp;
                }
                #endregion
                //处理金额,支付宝2.5可以,2.50就不可以
                if (request.Amount.ToString().Contains('.'))
                {
                    request.Amount = Convert.ToDecimal(request.Amount.ToString().Trim('0'));
                }
                string tradeNo = request.TradeNo.ToString();
                if (tradeNo.Length > 46)
                {
                    tradeNo = tradeNo.Substring(0, 46);
                }
                string batch_num = "1";//退款总笔数
                int length = tradeNo.Length > 6 ? 6 : tradeNo.Length;
                string batch_no = DateTime.Now.ToString("yyyyMMddHHmmssffff") + tradeNo.Substring(0,length);//退款批次号(长度不能超过64位)
                string detaildate = request.TradeNo + "^" + request.Amount.ToString() + "^" + "退款";//单笔数据集 "2014091805343134^2^tuikuan";
                StringBuilder strBuilder = new StringBuilder();
                strBuilder.Append("_input_charset=" + _input_charset);
                strBuilder.Append("&batch_no=" + batch_no);
                strBuilder.Append("&batch_num=" + batch_num);
                strBuilder.Append("&detail_data=" + detaildate);
                if (!string.IsNullOrEmpty(request.NotifyUrl))
                {
                    strBuilder.Append("&notify_url=" + request.NotifyUrl);
                }
                strBuilder.Append("&partner=" + request.Partner);
                strBuilder.Append("&refund_date=" + request.RefundTime.ToString("yyyy-MM-dd HH:mm:ss"));
                strBuilder.Append("&service=" + service_ref);
                //最后加上私钥
                strBuilder.Append(request.Sign);
                string sign = Sign(strBuilder.ToString(), sign_type, _input_charset);
                string URL = "https://mapi.alipay.com/gateway.do?sign=" + sign + "&_input_charset=" + _input_charset + "&batch_no=" + batch_no + "&batch_num=" + batch_num + "&detail_data=" + detaildate + "&notify_url=" + request.NotifyUrl + "&partner=" + request.Partner + "&refund_date=" + request.RefundTime.ToString("yyyy-MM-dd HH:mm:ss") + "&service=" + service_ref + "&sign_type=" + sign_type;
                string result = "";
                bool isT = SendByGetMethod(URL, out result);
                XMLSerializer xmlSerializer = new XMLSerializer();
                logger.Debug("退款请求体", xmlSerializer.Serialize<AlipayRefundRequestType>(request));
                if (isT)
                {
                    XmlDocument xd = new XmlDocument();
                    xd.LoadXml(result);
                    if (xd.GetElementsByTagName("is_success")[0].InnerXml.ToString() == "T")
                    {
                        //退款批次号
                        resp.BatchNo = batch_no;
                        resp.ResultCode = 1;
                        resp.ResultMsg = "Success";
                    }
                    else
                    {
                        string error = xd.GetElementsByTagName("error")[0].InnerXml.ToString();
                        resp.ResultMsg = "支付宝退款返回错误!ErrorMsg:" + error;
                        logger.Debug("提示", "支付宝退款返回错误!ErrorMsg:" + error);
                    }
                }
                else
                {
                    resp.ResultMsg = "支付宝退款提交失败!";
                    logger.Debug("提示", "支付宝退款提交失败!");
                }
            }
            catch (Exception ex)
            {
                resp.ResultMsg = ex.Message.ToString();
                logger.Debug("支付宝退款_AlipayRefund", ex);
            }
            return resp;
        }


        /// <summary>
        /// 签名字符串
        /// </summary>
        /// <param name="prestr">需要签名的字符串</param>
        /// <param name="sign_type">签名类型</param>
        /// <param name="_input_charset">编码格式</param>
        /// <returns>签名结果</returns>
        public static string Sign(string prestr, string sign_type, string _input_charset)
        {
            StringBuilder sb = new StringBuilder(32);
            if (sign_type.ToUpper() == "MD5")
            {
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] t = md5.ComputeHash(Encoding.GetEncoding(_input_charset).GetBytes(prestr));
                for (int i = 0; i < t.Length; i++)
                {
                    sb.Append(t[i].ToString("x").PadLeft(2, '0'));
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// 提交链接
        /// </summary>
        /// <param name="url"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public bool SendByGetMethod(string url, out string result)
        {
            result = string.Empty;
            try
            {
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
                req.Method = "GET";
                //设置代理
                if (CommonFunc.ConvertObjectToString(ConfigurationManager.AppSettings["IsProxy"]).ToUpper() == "T")
                {
                    string ProxyAddress = ConfigurationManager.AppSettings["ProxyAddress"].ToString().Trim();
                    if (!string.IsNullOrEmpty(ProxyAddress))
                    {
                        req.UseDefaultCredentials = true;
                        WebProxy proxy = new WebProxy(ProxyAddress, 8080);
                        req.Proxy = proxy;
                    }
                    logger.Debug("代理", "设置代理服务");
                }
                req.KeepAlive = true;
                req.Timeout = 300000;
                req.ContentType = "application/x-www-form-urlencoded;charset=utf-8";
                HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();
                Encoding encoding = null;
                try
                {
                    encoding = Encoding.GetEncoding(rsp.CharacterSet);
                }
                catch
                {
                    encoding = Encoding.UTF8;
                }
                Stream stream = rsp.GetResponseStream();
                StreamReader reader = new StreamReader(stream, encoding);
                result = reader.ReadToEnd();
                reader.Close();
                stream.Close();
                rsp.Close();
            }
            catch (Exception ex)
            {
                result = ex.ToString();
                logger.Debug("SendByGetMethod", ex);
                return false;
            }
            return true;
        }
    }
}
复制代码

 

调用:

复制代码
  var client = AMSOAServiceClient.GetInstance("http://localhost/AMService/api");
            //AlipayWithHoldRequestType req = new AlipayWithHoldRequestType();
            //req.Amount = 1.5m;
            //req.CreateTime = DateTime.Now;
            //req.OperatorID = "";
            //req.OperatorName = "";
            //req.OrderID = "fping_test_021503";
            //req.Partner = "2088611192328117";
            //req.Sign = "p03xcy9nlivneft9sl4lhd8y35pinaaw";
            //req.Subject = "Subject";
            //req.TransAccountIn = "jpbufxz@ctrip.com";
            //req.TransAccountOut = "fxmp@ctrip.com";
            //req.TypeCode = "20886111923281171000310004";
            //AlipayWithHoldResponseType resp = client.AlipayWithHold(req);


            AlipayRefundRequestType req2 = new AlipayRefundRequestType();
            req2.Amount = 1.5m;
            req2.Partner = "2088611192328117";
            req2.NotifyUrl = "";
            req2.RefundTime = DateTime.Now;
            req2.Sign = "p03xcy9nlivneft9sl4lhd8y35pinaaw";
            req2.TradeNo = "2015022800001000820043913778";
            AlipayRefundResponseType resp2 = client.AlipayRefund(req2);
复制代码

注意项:扣款时,操作员没有在支付宝注册,那么就填空

           扣款时,不能用已经扣过款的订单号

           扣款,退款金额一定要注意,2.5与2.50

 

posted @   hongdada  阅读(1535)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
历史上的今天:
2012-12-04 sql行列转换,字符串相加
点击右上角即可分享
微信分享提示