支付宝-自动扣款自动退款
请求体,返回体:
/// <summary>
/// 门票订单支付宝代扣请求类型
/// </summary>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.1026")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://soa.ctrip.com/affiliates/Group/AMSOAService/v1")]
[System.Xml.Serialization.XmlRootAttribute("AlipayWithHoldRequest", Namespace="http://soa.ctrip.com/affiliates/Group/AMSOAService/v1", IsNullable=false)]
[DataContract(Name="AlipayWithHoldRequest", Namespace="http://soa.ctrip.com/affiliates/Group/AMSOAService/v1")]
[ProtoContract()]
public partial class AlipayWithHoldRequestType
{
private string partnerField;
private string signField;
private long ctripOrderIDField;
private string typeCodeField;
private decimal amountField;
private string subjectField;
private string transAccountInField;
private string transAccountOutField;
private System.DateTime createTimeField;
private string operatorIDField;
private string operatorNameField;
/// <summary>
/// 合作者身份ID
/// </summary>
[DataMember()]
[ProtoMember(1)]
public string Partner
{
get
{
return this.partnerField;
}
set
{
this.partnerField = value;
}
}
/// <summary>
/// 私钥
/// </summary>
[DataMember()]
[ProtoMember(2)]
public string Sign
{
get
{
return this.signField;
}
set
{
this.signField = value;
}
}
/// <summary>
/// 携程门票订单号
/// </summary>
[DataMember()]
[ProtoMember(3)]
public long CtripOrderID
{
get
{
return this.ctripOrderIDField;
}
set
{
this.ctripOrderIDField = value;
}
}
/// <summary>
/// 代理业务编号
/// </summary>
[DataMember()]
[ProtoMember(4)]
public string TypeCode
{
get
{
return this.typeCodeField;
}
set
{
this.typeCodeField = value;
}
}
/// <summary>
/// 金额
/// </summary>
[DataMember()]
[ProtoMember(5)]
public decimal Amount
{
get
{
return this.amountField;
}
set
{
this.amountField = value;
}
}
/// <summary>
/// 支付宝标题
/// </summary>
[DataMember()]
[ProtoMember(6)]
public string Subject
{
get
{
return this.subjectField;
}
set
{
this.subjectField = value;
}
}
/// <summary>
/// 转入支付宝账号
/// </summary>
[DataMember()]
[ProtoMember(7)]
public string TransAccountIn
{
get
{
return this.transAccountInField;
}
set
{
this.transAccountInField = value;
}
}
/// <summary>
/// 转出支付宝账号
/// </summary>
[DataMember()]
[ProtoMember(8)]
public string TransAccountOut
{
get
{
return this.transAccountOutField;
}
set
{
this.transAccountOutField = value;
}
}
/// <summary>
/// 订单创建时间
/// </summary>
[DataMember()]
[ProtoMember(9)]
public System.DateTime CreateTime
{
get
{
return this.createTimeField;
}
set
{
this.createTimeField = value;
}
}
/// <summary>
/// 操作员ID
/// </summary>
[DataMember()]
[ProtoMember(10)]
public string OperatorID
{
get
{
return this.operatorIDField;
}
set
{
this.operatorIDField = value;
}
}
/// <summary>
/// 操作员登录名
/// </summary>
[DataMember()]
[ProtoMember(11)]
public string OperatorName
{
get
{
return this.operatorNameField;
}
set
{
this.operatorNameField = value;
}
}
}
/// <summary>
/// 门票订单支付宝代扣返回类型
/// </summary>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.1026")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://soa.ctrip.com/affiliates/Group/AMSOAService/v1")]
[System.Xml.Serialization.XmlRootAttribute("AlipayWithHoldResponse", Namespace="http://soa.ctrip.com/affiliates/Group/AMSOAService/v1", IsNullable=false)]
[DataContract(Name="AlipayWithHoldResponse", Namespace="http://soa.ctrip.com/affiliates/Group/AMSOAService/v1")]
[ProtoContract()]
public partial class AlipayWithHoldResponseType : IHasResponseStatus
{
private ResponseStatusType responseStatusField;
private string tradeNoField;
private int resultCodeField;
private string resultMsgField;
[DataMember()]
[ProtoMember(1)]
public ResponseStatusType ResponseStatus
{
get
{
return this.responseStatusField;
}
set
{
this.responseStatusField = value;
}
}
/// <summary>
/// 支付宝交易号
/// </summary>
[DataMember()]
[ProtoMember(2)]
public string TradeNo
{
get
{
return this.tradeNoField;
}
set
{
this.tradeNoField = value;
}
}
/// <summary>
/// 处理结果 0 失败;1成功
/// </summary>
[System.Xml.Serialization.XmlAttributeAttribute()]
[DataMember()]
[ProtoMember(3)]
public int ResultCode
{
get
{
return this.resultCodeField;
}
set
{
this.resultCodeField = value;
}
}
/// <summary>
/// 处理结果信息
/// </summary>
[System.Xml.Serialization.XmlAttributeAttribute()]
[DataMember()]
[ProtoMember(4)]
public string ResultMsg
{
get
{
return this.resultMsgField;
}
set
{
this.resultMsgField = value;
}
}
}
/// <summary>
/// 门票订单支付宝退款请求类型
/// </summary>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.1026")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://soa.ctrip.com/affiliates/Group/AMSOAService/v1")]
[System.Xml.Serialization.XmlRootAttribute("AlipayRefundRequest", Namespace="http://soa.ctrip.com/affiliates/Group/AMSOAService/v1", IsNullable=false)]
[DataContract(Name="AlipayRefundRequest", Namespace="http://soa.ctrip.com/affiliates/Group/AMSOAService/v1")]
[ProtoContract()]
public partial class AlipayRefundRequestType
{
private string partnerField;
private string signField;
private decimal amountField;
private string tradeNoField;
private string notifyUrlField;
private System.DateTime refundTimeField;
/// <summary>
/// 合作者身份ID
/// </summary>
[DataMember()]
[ProtoMember(1)]
public string Partner
{
get
{
return this.partnerField;
}
set
{
this.partnerField = value;
}
}
/// <summary>
/// 私钥
/// </summary>
[DataMember()]
[ProtoMember(2)]
public string Sign
{
get
{
return this.signField;
}
set
{
this.signField = value;
}
}
/// <summary>
/// 金额
/// </summary>
[DataMember()]
[ProtoMember(3)]
public decimal Amount
{
get
{
return this.amountField;
}
set
{
this.amountField = value;
}
}
/// <summary>
/// 支付宝交易号
/// </summary>
[DataMember()]
[ProtoMember(4)]
public string TradeNo
{
get
{
return this.tradeNoField;
}
set
{
this.tradeNoField = value;
}
}
/// <summary>
/// 服务器异步通知页面路径
/// </summary>
[DataMember()]
[ProtoMember(5)]
public string NotifyUrl
{
get
{
return this.notifyUrlField;
}
set
{
this.notifyUrlField = value;
}
}
/// <summary>
/// 订单退款时间
/// </summary>
[DataMember()]
[ProtoMember(6)]
public System.DateTime RefundTime
{
get
{
return this.refundTimeField;
}
set
{
this.refundTimeField = value;
}
}
}
/// <summary>
/// 门票订单支付宝退款返回类型
/// </summary>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.1026")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://soa.ctrip.com/affiliates/Group/AMSOAService/v1")]
[System.Xml.Serialization.XmlRootAttribute("AlipayRefundResponse", Namespace="http://soa.ctrip.com/affiliates/Group/AMSOAService/v1", IsNullable=false)]
[DataContract(Name="AlipayRefundResponse", Namespace="http://soa.ctrip.com/affiliates/Group/AMSOAService/v1")]
[ProtoContract()]
public partial class AlipayRefundResponseType : IHasResponseStatus
{
private string batchNoField;
private ResponseStatusType responseStatusField;
private int resultCodeField;
private string resultMsgField;
/// <summary>
/// 退款批次号
/// </summary>
[DataMember()]
[ProtoMember(1)]
public string BatchNo
{
get
{
return this.batchNoField;
}
set
{
this.batchNoField = value;
}
}
[DataMember()]
[ProtoMember(2)]
public ResponseStatusType ResponseStatus
{
get
{
return this.responseStatusField;
}
set
{
this.responseStatusField = value;
}
}
/// <summary>
/// 处理结果 0 失败;1成功
/// </summary>
[System.Xml.Serialization.XmlAttributeAttribute()]
[DataMember()]
[ProtoMember(3)]
public int ResultCode
{
get
{
return this.resultCodeField;
}
set
{
this.resultCodeField = value;
}
}
/// <summary>
/// 处理结果信息
/// </summary>
[System.Xml.Serialization.XmlAttributeAttribute()]
[DataMember()]
[ProtoMember(4)]
public string ResultMsg
{
get
{
return this.resultMsgField;
}
set
{
this.resultMsgField = value;
}
}
}
方法:
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("¬ify_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 + "¬ify_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

浙公网安备 33010602011771号