Example #1
0
        public async Task <(string SessionKey, string OpenId)> CodeToSession(string code)
        {
            try
            {
                // https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
                // {"session_key":"aNpIMqbx2dh4s4zikIBKGg==","expires_in":7200,"openid":"o21z-0E5BiJ6QE1QPlo-cyU-TJ78"}
                var html = await _client.GetStringAsync($"https://api.weixin.qq.com/sns/jscode2session?appid={_wxOptions.WxAppId}&secret={_wxOptions.WxSecretKey}&js_code={code}&grant_type=authorization_code");

                var sessionKey = _sessionKeyPattern.Match(html).Groups[1].Value; // // The input is not a valid Base-64 string as it contains a non-base 64 character, sometimes wexin session key returned contains some illegal base 64 character, fixed in sql.
                var openId     = _openIdPattern.Match(html).Groups[1].Value;

                if (string.IsNullOrEmpty(openId) || string.IsNullOrEmpty(sessionKey))
                {
                    _logger.EnqueueMessage($"{_wxOptions.WxAppId} {_wxOptions.WxSecretKey} {nameof(CodeToSession)}: {html}");
                }

                // Weixin bug fix, founded 2019.5.11
                // The input is not a valid Base-64 string as it contains a non-base 64 character
                // fixed in sql
                //if(sessionKey.IndexOf("\\", StringComparison.Ordinal) != -1) sessionKey = sessionKey.Replace("\\", "");

                return(sessionKey, openId);
            }
            catch (Exception ex)
            {
                _logger.EnqueueMessage($"{nameof(global::WeixinPay.Services.WeixinService)}.{nameof(CodeToSession)} error. message: {ex.Message} stackTrace: {ex.StackTrace}");
            }

            // If error, just return empty
            return(string.Empty, string.Empty);
        }
Example #2
0
        public async Task <(bool IsCompleted, string Result)> SendAsync(string receiver, string paramString, string templateCode)
        {
            if (string.IsNullOrEmpty(receiver) || !RegexCache.MobilePattern.IsMatch(receiver))
            {
                throw new ArgumentException("Invalid receiver number", nameof(receiver));
            }
            if (string.IsNullOrEmpty(paramString))
            {
                throw new ArgumentNullException(nameof(paramString));
            }
            if (string.IsNullOrEmpty(templateCode))
            {
                throw new ArgumentNullException(nameof(templateCode));
            }

            var timestamp = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ");
            var nonce     = Guid.NewGuid().ToString();

            StringBuilder builder = new StringBuilder();

            // system and business parameters, already order by asc.
            builder.Append($"AccessKeyId={_options.AliSmsAccessKeyId}&");
            builder.Append("Action=SendSms&");
            builder.Append("Format=XML&");
            builder.Append($"PhoneNumbers={PercentEncode(receiver)}&");
            builder.Append($"RegionId={PercentEncode("cn-hangzhou")}&");
            builder.Append($"SignName={PercentEncode(_options.AliSmsSignName)}&");
            builder.Append("SignatureMethod=HMAC-SHA1&");
            builder.Append($"SignatureNonce={nonce}&");
            builder.Append("SignatureVersion=1.0&");
            builder.Append($"TemplateCode={PercentEncode(templateCode)}&");
            builder.Append($"TemplateParam={PercentEncode(paramString)}&");
            builder.Append($"Timestamp={PercentEncode(timestamp)}&");
            builder.Append("Version=2017-05-25");

            // 计算签名
            var      signString = $"GET&%2F&{Regex.Replace(Encode(builder.ToString()), @"%[a-f\d]{2}", m => m.Value.ToUpperInvariant())}";
            HMACSHA1 hmacsha1   = new HMACSHA1(Encoding.UTF8.GetBytes(_options.AliSmsAccessKeySecret + "&"));
            var      sign       = Convert.ToBase64String(hmacsha1.ComputeHash(Encoding.UTF8.GetBytes(signString)));

            try
            {
                var url    = $"http://dysmsapi.aliyuncs.com/?AccessKeyId={Encode(_options.AliSmsAccessKeyId)}&Action=SendSms&Format=XML&PhoneNumbers={Encode(receiver)}&RegionId={Encode("cn-hangzhou")}&SignatureMethod=HMAC-SHA1&SignatureNonce={Encode(nonce)}&SignatureVersion=1.0&SignName={Encode(_options.AliSmsSignName)}&TemplateCode={Encode(templateCode)}&TemplateParam={Encode(paramString)}&Timestamp={Encode(timestamp)}&Version={Encode("2017-05-25")}&Signature={Encode(sign)}";
                var result = await _client.GetStringAsync(url);

                return(result.EndsWith("<Code>OK</Code></SendSmsResponse>", StringComparison.OrdinalIgnoreCase), result);
            }
            catch (Exception ex)
            {
                _logger.EnqueueMessage($"{nameof(AliSmsSender)}.{nameof(SendAsync)} error. message: {ex.Message} stackTrace: {ex.StackTrace}");
            }

            return(false, "error");
        }
Example #3
0
        public async Task <bool> SendEmailAsync(string to, string subject, string body, IEnumerable <string> cc = null)
        {
            // Verify
            if (string.IsNullOrEmpty(to))
            {
                throw new ArgumentNullException(nameof(to));
            }
            if (string.IsNullOrEmpty(subject))
            {
                throw new ArgumentNullException(nameof(subject));
            }
            if (string.IsNullOrEmpty(body))
            {
                throw new ArgumentNullException(nameof(body));
            }

            var message = new MailMessage(new MailAddress(_options.AliMailAccount, _options.AliMailDisplayName), new MailAddress(to))
            {
                Subject = subject, Body = body, IsBodyHtml = true
            };

            if (cc != null)
            {
                foreach (string s in cc)
                {
                    message.CC.Add(s);
                }
            }

            try
            {
                using (var smtpClient = new SmtpClient(_options.AliMailSmtp, _options.AliMailPort)
                {
                    Credentials = new NetworkCredential(_options.AliMailAccount, _options.AliMailPassword), DeliveryMethod = SmtpDeliveryMethod.Network, EnableSsl = _options.AliMailEnableSsl
                })
                {
                    //smtpClient.Send(message);
                    await smtpClient.SendMailAsync(message);
                }

                return(true);
            }
            catch (Exception ex)
            {
                _logger.EnqueueMessage($"{nameof(AliMailSender)}.{nameof(SendEmailAsync)} error. details: {ex.Message} stackTrace: {ex.StackTrace}");
            }

            return(false);
        }
Example #4
0
        /// <summary>
        ///     Get weixin prepayId
        /// </summary>
        /// <param name="nonceStr"></param>
        /// <param name="orderPaymentId"></param>
        /// <param name="amount"></param>
        /// <param name="wxOpenId"></param>
        /// <param name="attach"></param>
        /// <param name="billCreationIp"></param>
        /// <returns></returns>
        private async Task <string> UnifiedOrder(string nonceStr, string orderPaymentId, decimal amount, string wxOpenId, string billCreationIp, string attach)
        {
            UnifiedOrder unifiedOrder = new UnifiedOrder {
                MchId     = _options.WxMchId,
                AppId     = _options.WxAppId,
                NotifyUrl = _options.WxPaymentNotifyUrl,
                SignType  = "MD5",
                TradeType = "JSAPI",
                Body      = $"{_options.WxPlatformName}订单",

                NonceStr       = nonceStr,
                OutTradeNo     = orderPaymentId,
                TotalFee       = Math.Round(amount * 100).ToString(), // unit: fen max scale is 2
                SPBillCreateIP = billCreationIp,
                OpenId         = wxOpenId,
                Attach         = attach
            };

            // Sign
            unifiedOrder.Sign = BuildSignString(unifiedOrder);

            // Xml
            string requestXml = BuildRequestXml(unifiedOrder);

            if (_options.WxIsDebug)
            {
                _logger.EnqueueMessage($"UnifiedOrder: {requestXml}");
            }

            try
            {
                HttpContent content = new ByteArrayContent(Encoding.UTF8.GetBytes(requestXml));
                var         res     = await _client.PostAsync("https://api.mch.weixin.qq.com/pay/unifiedorder", content);

                string xml = await res.Content.ReadAsStringAsync();

                if (_options.WxIsDebug)
                {
                    _logger.EnqueueMessage(xml);
                }

                //bool isReturnSuccess = xml.IndexOf("<return_code><![CDATA[SUCCESS]]></return_code>", StringComparison.Ordinal) != -1;
                bool isReturnSuccess = xml.StartsWith("<xml><return_code><![CDATA[SUCCESS]]></return_code>", StringComparison.Ordinal);
                if (!isReturnSuccess)
                {
                    return(string.Empty);
                }

                bool isResultSuccess = xml.IndexOf("<result_code><![CDATA[SUCCESS]]></result_code>", StringComparison.Ordinal) != -1;
                return(isResultSuccess ? PrepayIdPattern.Match(xml).Groups[1].Value : string.Empty /*error*/);
            }
            catch (Exception ex)
            {
                _logger.EnqueueMessage($"{nameof(WeixinPay)}.{nameof(UnifiedOrder)} error. Message: {ex.Message} InnerMessage: {ex.InnerException?.Message} StackTrace: {ex.StackTrace}");
            }

            return(string.Empty);

            string BuildRequestXml(UnifiedOrder order)
            {
                StringBuilder xmlBuilder = new StringBuilder("<xml>");

                xmlBuilder.Append($"<appid>{order.AppId}</appid>");

                if (!string.IsNullOrEmpty(order.Attach))
                {
                    xmlBuilder.Append($"<attach>{order.Attach}</attach>");
                }
                if (!string.IsNullOrEmpty(order.Body))
                {
                    xmlBuilder.Append($"<body>{order.Body}</body>");
                }
                if (!string.IsNullOrEmpty(order.Detail))
                {
                    xmlBuilder.Append($"<detail>{order.Detail}</detail>");
                }
                if (!string.IsNullOrEmpty(order.DeviceInfo))
                {
                    xmlBuilder.Append($"<device_info>{order.DeviceInfo}</device_info>");
                }
                if (!string.IsNullOrEmpty(order.FeeType))
                {
                    xmlBuilder.Append($"<fee_type>{order.FeeType}</fee_type>");
                }
                if (!string.IsNullOrEmpty(order.GoodsTag))
                {
                    xmlBuilder.Append($"<goods_tag>{order.GoodsTag}</goods_tag>");
                }
                if (!string.IsNullOrEmpty(order.LimitPay))
                {
                    xmlBuilder.Append($"<limit_pay>{order.LimitPay}</limit_pay>");
                }
                if (!string.IsNullOrEmpty(order.MchId))
                {
                    xmlBuilder.Append($"<mch_id>{order.MchId}</mch_id>");
                }
                if (!string.IsNullOrEmpty(order.NonceStr))
                {
                    xmlBuilder.Append($"<nonce_str>{order.NonceStr}</nonce_str>");
                }
                if (!string.IsNullOrEmpty(order.NotifyUrl))
                {
                    xmlBuilder.Append($"<notify_url>{order.NotifyUrl}</notify_url>");
                }
                if (!string.IsNullOrEmpty(order.OpenId))
                {
                    xmlBuilder.Append($"<openid>{order.OpenId}</openid>");
                }
                if (!string.IsNullOrEmpty(order.OutTradeNo))
                {
                    xmlBuilder.Append($"<out_trade_no>{order.OutTradeNo}</out_trade_no>");
                }
                if (!string.IsNullOrEmpty(order.ProductId))
                {
                    xmlBuilder.Append($"<product_id>{order.ProductId}</product_id>");
                }
                if (!string.IsNullOrEmpty(order.Receipt))
                {
                    xmlBuilder.Append($"<receipt>{order.Receipt}</receipt>");
                }
                if (!string.IsNullOrEmpty(order.SceneInfo))
                {
                    xmlBuilder.Append($"<scene_info>{order.SceneInfo}</scene_info>");
                }
                if (!string.IsNullOrEmpty(order.Sign))
                {
                    xmlBuilder.Append($"<sign>{order.Sign}</sign>");
                }
                if (!string.IsNullOrEmpty(order.SignType))
                {
                    xmlBuilder.Append($"<sign_type>{order.SignType}</sign_type>");
                }
                if (!string.IsNullOrEmpty(order.SPBillCreateIP))
                {
                    xmlBuilder.Append($"<spbill_create_ip>{order.SPBillCreateIP}</spbill_create_ip>");
                }
                if (!string.IsNullOrEmpty(order.TimeExpire))
                {
                    xmlBuilder.Append($"<time_expire>{order.TimeExpire}</time_expire>");
                }
                if (!string.IsNullOrEmpty(order.TimeStart))
                {
                    xmlBuilder.Append($"<time_start>{order.TimeStart}</time_start>");
                }
                if (!string.IsNullOrEmpty(order.TotalFee))
                {
                    xmlBuilder.Append($"<total_fee>{order.TotalFee}</total_fee>");
                }
                if (!string.IsNullOrEmpty(order.TradeType))
                {
                    xmlBuilder.Append($"<trade_type>{order.TradeType}</trade_type>");
                }

                return(xmlBuilder.Append("</xml>").ToString());
            }

            string BuildSignString(UnifiedOrder order)
            {
                StringBuilder signBuilder = new StringBuilder();

                signBuilder.Append($"appid={order.AppId}");

                if (!string.IsNullOrEmpty(order.Attach))
                {
                    signBuilder.Append($"&attach={order.Attach}");
                }
                if (!string.IsNullOrEmpty(order.Body))
                {
                    signBuilder.Append($"&body={order.Body}");
                }
                if (!string.IsNullOrEmpty(order.Detail))
                {
                    signBuilder.Append($"&detail={order.Detail}");
                }
                if (!string.IsNullOrEmpty(order.DeviceInfo))
                {
                    signBuilder.Append($"&device_info={order.DeviceInfo}");
                }
                if (!string.IsNullOrEmpty(order.FeeType))
                {
                    signBuilder.Append($"&fee_type={order.FeeType}");
                }
                if (!string.IsNullOrEmpty(order.GoodsTag))
                {
                    signBuilder.Append($"&goods_tag={order.GoodsTag}");
                }
                if (!string.IsNullOrEmpty(order.LimitPay))
                {
                    signBuilder.Append($"&limit_pay={order.LimitPay}");
                }
                if (!string.IsNullOrEmpty(order.MchId))
                {
                    signBuilder.Append($"&mch_id={order.MchId}");
                }
                if (!string.IsNullOrEmpty(order.NonceStr))
                {
                    signBuilder.Append($"&nonce_str={order.NonceStr}");
                }
                if (!string.IsNullOrEmpty(order.NotifyUrl))
                {
                    signBuilder.Append($"&notify_url={order.NotifyUrl}");
                }
                if (!string.IsNullOrEmpty(order.OpenId))
                {
                    signBuilder.Append($"&openid={order.OpenId}");
                }
                if (!string.IsNullOrEmpty(order.OutTradeNo))
                {
                    signBuilder.Append($"&out_trade_no={order.OutTradeNo}");
                }
                if (!string.IsNullOrEmpty(order.ProductId))
                {
                    signBuilder.Append($"&product_id={order.ProductId}");
                }
                if (!string.IsNullOrEmpty(order.Receipt))
                {
                    signBuilder.Append($"&receipt={order.Receipt}");
                }
                if (!string.IsNullOrEmpty(order.SceneInfo))
                {
                    signBuilder.Append($"&scene_info={order.SceneInfo}");
                }
                if (!string.IsNullOrEmpty(order.SignType))
                {
                    signBuilder.Append($"&sign_type={order.SignType}");
                }
                if (!string.IsNullOrEmpty(order.SPBillCreateIP))
                {
                    signBuilder.Append($"&spbill_create_ip={order.SPBillCreateIP}");
                }
                if (!string.IsNullOrEmpty(order.TimeExpire))
                {
                    signBuilder.Append($"&time_expire={order.TimeExpire}");
                }
                if (!string.IsNullOrEmpty(order.TimeStart))
                {
                    signBuilder.Append($"&time_start={order.TimeStart}");
                }
                if (!string.IsNullOrEmpty(order.TotalFee))
                {
                    signBuilder.Append($"&total_fee={order.TotalFee}");
                }
                if (!string.IsNullOrEmpty(order.TradeType))
                {
                    signBuilder.Append($"&trade_type={order.TradeType}");
                }

                signBuilder.Append($"&key={_options.WxMchKey}");
                return(signBuilder.ToString().GetHashUTF8().ToUpperInvariant());
            }
        }
Example #5
0
        /// <summary>
        ///     Weixin refund
        /// </summary>
        /// <param name="device_info1">设备号 否 终端设备号</param>
        /// <param name="out_refund_no1">
        ///     商户退款单号	out_refund_no	是	String(64)	1217752501201407033233368018
        ///     商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。
        /// </param>
        /// <param name="out_trade_no1">
        ///     商户订单号	out_trade_no	String(32)	1217752501201407033233368018
        ///     商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
        /// </param>
        /// <param name="refund_account1">
        ///     退款资金来源	refund_account	否	String(30)	REFUND_SOURCE_RECHARGE_FUNDS
        ///     仅针对老资金流商户使用
        ///     REFUND_SOURCE_UNSETTLED_FUNDS---未结算资金退款(默认使用未结算资金退款)
        ///     REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款
        /// </param>
        /// <param name="refund_desc1">
        ///     退款原因	refund_desc	否	String(80)	商品已售完
        ///     若商户传入,会在下发给用户的退款消息中体现退款原因
        ///     注意:若订单退款金额≤1元,且属于部分退款,则不会在退款消息中体现退款原因
        /// </param>
        /// <param name="refund_fee1">退款金额	refund_fee	是	Int	100	退款总金额,订单总金额,单位为分,只能为整数,详见支付金额</param>
        /// <param name="refund_fee_type1">货币种类	refund_fee_type	否	String(8)	CNY	货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型</param>
        /// <param name="total_fee1">订单金额	total_fee	是	Int	100	订单总金额,单位为分,只能为整数,详见支付金额</param>
        /// <param name="transaction_id1">微信订单号	transaction_id	二选一	String(32)	1217752501201407033233368018	微信生成的订单号,在支付通知中有返回</param>
        /// <returns>微信退款单号</returns>
        public async Task <string> Refund(string out_refund_no1, string out_trade_no1, string total_fee1, string transaction_id1, string refund_fee1, string refund_account1 = "", string refund_desc1 = "", string refund_fee_type1 = "CNY", string device_info1 = "")
        {
            string nonce_str1 = out_refund_no1.GetHashUTF8(); // 随机字符串,不长于32位
            var    hash       = BuildSignString(_options.WxAppId, device_info1, _options.WxMchId, nonce_str1, _options.WxRefundNotifyUrl, out_refund_no1, out_trade_no1, refund_account1, refund_desc1, refund_fee1, refund_fee_type1, "MD5", total_fee1, transaction_id1);
            var    requestXml = BuildRequestXml(_options.WxAppId, device_info1, _options.WxMchId, nonce_str1, _options.WxRefundNotifyUrl, out_refund_no1, out_trade_no1, refund_account1, refund_desc1, refund_fee1, refund_fee_type1, hash, "MD5", total_fee1, transaction_id1);

            if (_options.WxIsDebug)
            {
                _logger.EnqueueMessage($"WxRefundXml: {requestXml}");
            }

            try
            {
                HttpContent content = new ByteArrayContent(Encoding.UTF8.GetBytes(requestXml));
                var         res     = await _client.PostAsync("https://api.mch.weixin.qq.com/secapi/pay/refund", content);

                var xml = await res.Content.ReadAsStringAsync();

                if (_options.WxIsDebug)
                {
                    _logger.EnqueueMessage($"WxRefundRes: {xml}");
                }

                // no sign validation note: must be validated before using
                bool isReturnSuccess = xml.IndexOf("<return_code><![CDATA[SUCCESS]]></return_code>", StringComparison.Ordinal) != -1;
                //bool isReturnSuccess = xml.StartsWith("<xml><return_code><![CDATA[SUCCESS]]></return_code>", StringComparison.Ordinal);
                if (!isReturnSuccess)
                {
                    return(string.Empty);
                }

                bool isResultSuccess = xml.IndexOf("<result_code><![CDATA[SUCCESS]]></result_code>", StringComparison.Ordinal) != -1;
                return(isResultSuccess ? RefundIdPattern.Match(xml).Groups[1].Value : string.Empty /*error*/);
            }
            catch (Exception ex)
            {
                _logger.EnqueueMessage($"{nameof(WeixinPay)}.{nameof(Refund)} error. Message: {ex.Message} InnerMessage: {ex.InnerException?.Message} StackTrace: {ex.StackTrace}");
            }

            return(string.Empty);

            string BuildSignString(string appid, string device_info, string mch_id, string nonce_str, string notify_url, string out_refund_no, string out_trade_no, string refund_account, string refund_desc, string refund_fee, string refund_fee_type, string sign_type, string total_fee, string transaction_id)
            {
                StringBuilder signBuilder = new StringBuilder();

                signBuilder.Append($"appid={appid}");

                if (!string.IsNullOrEmpty(device_info))
                {
                    signBuilder.Append($"&device_info={device_info}");
                }
                if (!string.IsNullOrEmpty(mch_id))
                {
                    signBuilder.Append($"&mch_id={mch_id}");
                }
                if (!string.IsNullOrEmpty(nonce_str))
                {
                    signBuilder.Append($"&nonce_str={nonce_str}");
                }
                if (!string.IsNullOrEmpty(notify_url))
                {
                    signBuilder.Append($"&notify_url={notify_url}");
                }
                if (!string.IsNullOrEmpty(out_refund_no))
                {
                    signBuilder.Append($"&out_refund_no={out_refund_no}");
                }
                if (!string.IsNullOrEmpty(out_trade_no))
                {
                    signBuilder.Append($"&out_trade_no={out_trade_no}");
                }
                if (!string.IsNullOrEmpty(refund_account))
                {
                    signBuilder.Append($"&refund_account={refund_account}");
                }
                if (!string.IsNullOrEmpty(refund_desc))
                {
                    signBuilder.Append($"&refund_desc={refund_desc}");
                }
                if (!string.IsNullOrEmpty(refund_fee))
                {
                    signBuilder.Append($"&refund_fee={refund_fee}");
                }
                if (!string.IsNullOrEmpty(refund_fee_type))
                {
                    signBuilder.Append($"&refund_fee_type={refund_fee_type}");
                }
                if (!string.IsNullOrEmpty(sign_type))
                {
                    signBuilder.Append($"&sign_type={sign_type}");
                }
                if (!string.IsNullOrEmpty(total_fee))
                {
                    signBuilder.Append($"&total_fee={total_fee}");
                }
                if (!string.IsNullOrEmpty(transaction_id))
                {
                    signBuilder.Append($"&transaction_id={transaction_id}");
                }

                signBuilder.Append($"&key={_options.WxMchKey}");
                return(signBuilder.ToString().GetHashUTF8().ToUpperInvariant());
            }

            string BuildRequestXml(string appid, string device_info, string mch_id, string nonce_str, string notify_url, string out_refund_no, string out_trade_no, string refund_account, string refund_desc, string refund_fee, string refund_fee_type, string sign, string sign_type, string total_fee, string transaction_id)
            {
                StringBuilder xmlBuilder = new StringBuilder("<xml>");

                xmlBuilder.Append($"<appid>{appid}</appid>");

                if (!string.IsNullOrEmpty(device_info))
                {
                    xmlBuilder.Append($"<device_info>{device_info}</device_info>");
                }
                if (!string.IsNullOrEmpty(mch_id))
                {
                    xmlBuilder.Append($"<mch_id>{mch_id}</mch_id>");
                }
                if (!string.IsNullOrEmpty(nonce_str))
                {
                    xmlBuilder.Append($"<nonce_str>{nonce_str}</nonce_str>");
                }
                if (!string.IsNullOrEmpty(notify_url))
                {
                    xmlBuilder.Append($"<notify_url>{notify_url}</notify_url>");
                }
                if (!string.IsNullOrEmpty(out_refund_no))
                {
                    xmlBuilder.Append($"<out_refund_no>{out_refund_no}</out_refund_no>");
                }
                if (!string.IsNullOrEmpty(out_trade_no))
                {
                    xmlBuilder.Append($"<out_trade_no>{out_trade_no}</out_trade_no>");
                }
                if (!string.IsNullOrEmpty(refund_account))
                {
                    xmlBuilder.Append($"<refund_account>{refund_account}</refund_account>");
                }
                if (!string.IsNullOrEmpty(refund_desc))
                {
                    xmlBuilder.Append($"<refund_desc>{refund_desc}</refund_desc>");
                }
                if (!string.IsNullOrEmpty(refund_fee))
                {
                    xmlBuilder.Append($"<refund_fee>{refund_fee}</refund_fee>");
                }
                if (!string.IsNullOrEmpty(refund_fee_type))
                {
                    xmlBuilder.Append($"<refund_fee_type>{refund_fee_type}</refund_fee_type>");
                }
                if (!string.IsNullOrEmpty(sign))
                {
                    xmlBuilder.Append($"<sign>{sign}</sign>");
                }
                if (!string.IsNullOrEmpty(sign_type))
                {
                    xmlBuilder.Append($"<sign_type>{sign_type}</sign_type>");
                }
                if (!string.IsNullOrEmpty(total_fee))
                {
                    xmlBuilder.Append($"<total_fee>{total_fee}</total_fee>");
                }
                if (!string.IsNullOrEmpty(transaction_id))
                {
                    xmlBuilder.Append($"<transaction_id>{transaction_id}</transaction_id>");
                }

                return(xmlBuilder.Append("</xml>").ToString());
            }
        }