csharp/52ABP/Yoyosoft-abp-modules/src/Yoyo.Abp.Alipay/DefatultAlipayHelper.cs

DefatultAlipayHelper.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks;
using Abp.Extensions;
using Alipay.AopSdk.AspnetCore;
using Alipay.AopSdk.Core.Domain;
using Alipay.AopSdk.Core.Request;
using Alipay.AopSdk.Core.Response;
using Alipay.AopSdk.F2FPay.Business;
using Alipay.AopSdk.F2FPay.Domain;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using QRCoder;
using Yoyo.Abp.FTF;
using Yoyo.Abp.Other;
using Yoyo.Abp.WapPay;
using Yoyo.Abp.WebPay;
using F2FResultEnum = Alipay.AopSdk.F2FPay.Model.ResultEnum;

namespace Yoyo.Abp
{
    /// 
    /// 支付宝支付默认实现
    /// 
    public clast DefatultAlipayHelper : IAlipayHelper
    {
        private readonly AlipayF2FService _alipayF2FService;
        private readonly AlipayService _alipayService;
        private readonly FTFConfig _fTFConfig;

        public DefatultAlipayHelper(
            AlipayF2FService alipayF2FService,
            AlipayService alipayService,
            IOptions fTFConfigOptions
            )
        {
            _alipayF2FService = alipayF2FService;
            _alipayService = alipayService;
            _fTFConfig = fTFConfigOptions.Value;
        }


        #region 面对面支付


        /// 
        /// 面对面支付(异步消息通知),返回生成的图片二维码byte数组
        /// 
        /// 支付信息
        /// 异步消息通知地址
        /// 面对面支付配置信息(不填则使用全局配置的)
        /// 二维码图片字节数组
        public async Task FTFPay(AlipayTradePrecreateContentBuilder input, string asyncNotifyUrl, FTFConfig fTFConfig = null)
        {
            return await this.FTFGenQRCode(input, asyncNotifyUrl, null, fTFConfig);
        }

        /// 
        /// 面对面支付(轮询),返回生成的图片二维码byte数组
        /// 
        /// 支付信息
        /// 
        /// 面对面支付配置信息(不填则使用全局配置的)
        /// 
        public async Task FTFPay(AlipayTradePrecreateContentBuilder input, Action loopQueryAction, FTFConfig fTFConfig = null)
        {
            return await this.FTFGenQRCode(input, null, loopQueryAction, fTFConfig);
        }

        /// 
        /// 面对面支付结果查询
        /// 
        /// 
        /// 
        public async Task FTFQuery(string outTradeNo)
        {
            return await _alipayF2FService.TradeQueryAsync(outTradeNo);
        }

        #endregion


        #region PC Web 支付

        /// 
        /// PC Web 支付,返回支付宝支付链接
        /// 
        /// 支付信息和回调通知信息
        /// 支付选项,如果为空则使用添加时内置的
        /// 返回支付宝支付链接
        public async Task WebPay(WebPayInput input, AlipayOptions options = null)
        {
            await Task.Yield();

            if (input.Data.ProductCode.IsNullOrWhiteSpace())
            {
                input.Data.ProductCode = YoYoAlipayConsts.ProductCode_FAST_INSTANT_TRADE_PAY;
            }


            var request = new AlipayTradePagePayRequest();

            // 设置同步回调地址
            request.SetReturnUrl(input.SynchronizationCallbackUrl);
            // 设置异步通知接收地址
            request.SetNotifyUrl(input.AsyncNotifyUrl);
            // 将业务model载入到request
            request.SetBizModel(input.Data);

            // 发起支付
            var response = this._alipayService.SdkExecute(request);

            // 返回回调地址
            var tmpOptions = options ?? _alipayService.Options;

            return new WebPayOutput()
            {
                Response = response,
                RedirectUrl = $"{tmpOptions.Gatewayurl}?{response.Body}"
            };
        }

        #endregion


        #region Mobile WAP 支付

        public async Task WapPay(WapPayInput input, AlipayOptions options = null)
        {
            await Task.Yield();

            // 设置产品代码
            if (input.Data.ProductCode.IsNullOrWhiteSpace())
            {
                input.Data.ProductCode = YoYoAlipayConsts.ProductCode_QUICK_WAP_WAY;
            }
            // 设置支付中途退出返回商户网站地址
            if (input.Data.QuitUrl.IsNullOrWhiteSpace())
            {
                input.Data.QuitUrl = input.QuitUrl;
            }

            var request = new AlipayTradeWapPayRequest();
            // 设置同步回调地址
            request.SetReturnUrl(input.SynchronizationCallbackUrl);
            // 设置异步通知接收地址
            request.SetNotifyUrl(input.AsyncNotifyUrl);
            // 将业务model载入到request
            request.SetBizModel(input.Data);

            // 发起支付
            var response = await this._alipayService.PageExecuteAsync(request);

            return new WapPayOutput()
            {
                Response = response,
                Body = response.Body
            };
        }

        #endregion

        #region 订单查询


        /// 
        /// 订单查询
        /// 
        /// 查询数据
        /// 
        public async Task Query(OrderQueryInput input)
        {
            return await this.Query(input.Data);
        }

        /// 
        /// 订单查询
        /// 
        /// 查询数据
        /// 
        public async Task Query(AlipayTradeQueryModel input)
        {
            var request = new AlipayTradeQueryRequest();
            request.SetBizModel(input);

            var response = await _alipayService.ExecuteAsync(request);

            return response;
        }

        /// 
        /// 订单查询
        /// 
        /// 商户系统订单编码
        /// 支付宝订单编码
        /// 
        public async Task Query(string tradeNo, string alipayTradeNo)
        {
            AlipayTradeQueryModel model = new AlipayTradeQueryModel
            {
                OutTradeNo = tradeNo,
                TradeNo = alipayTradeNo
            };

            return await this.Query(model);
        }

        #endregion


        #region 订单退款

        /// 
        /// 订单退款
        /// 
        /// 退款数据
        /// 
        public async Task Refund(RefundInput input)
        {
            return await this.Refund(input.Data);
        }

        /// 
        /// 订单退款
        /// 
        /// 退款数据
        /// 
        public async Task Refund(AlipayTradeRefundModel input)
        {
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            request.SetBizModel(input);

            var response = await _alipayService.ExecuteAsync(request);

            return response;
        }

        /// 
        /// 订单退款
        /// 
        /// 商户订单号
        /// 支付宝交易号
        /// 退款金额
        /// 退款原因
        /// 退款单号
        /// 
        public async Task Refund(string tradeno, string alipayTradeNo, string refundAmount, string refundReason, string refundNo)
        {
            var model = new AlipayTradeRefundModel();
            model.OutTradeNo = tradeno;
            model.TradeNo = alipayTradeNo;
            model.RefundAmount = refundAmount;
            model.RefundReason = refundReason;
            model.OutRequestNo = refundNo;

            return await this.Refund(model);
        }

        #endregion


        #region 订单退款查询

        /// 
        /// 订单退款查询
        /// 
        /// 查询信息
        /// 
        public async Task RefundQuery(RefundQueryInput input)
        {
            return await this.RefundQuery(input.Data);
        }

        /// 
        /// 订单退款查询
        /// 
        /// 查询信息
        /// 
        public async Task RefundQuery(AlipayTradeFastpayRefundQueryModel input)
        {
            if (string.IsNullOrEmpty(input.OutRequestNo))
            {
                input.OutRequestNo = input.OutTradeNo;
            }

            var request = new AlipayTradeFastpayRefundQueryRequest();
            request.SetBizModel(input);

            AlipayTradeFastpayRefundQueryResponse response = await _alipayService.ExecuteAsync(request);
            return response;
        }

        /// 
        /// 订单退款查询
        /// 
        /// 商户订单号
        /// 支付宝交易号
        /// 退款单号
        /// 
        public async Task RefundQuery(string tradeno, string alipayTradeNo, string refundNo)
        {
            var model = new AlipayTradeFastpayRefundQueryModel();
            model.OutTradeNo = tradeno;
            model.TradeNo = alipayTradeNo;
            model.OutRequestNo = refundNo;

            return await this.RefundQuery(model);
        }

        #endregion


        #region 关闭订单


        /// 
        /// 关闭订单
        /// 
        /// 关闭订单数据
        /// 
        public async Task OrderClose(OrderCloseInput input)
        {
            return await this.OrderClose(input.Data);
        }

        /// 
        /// 关闭订单
        /// 
        /// 关闭订单数据
        /// 
        public async Task OrderClose(AlipayTradeCloseModel input)
        {

            var request = new AlipayTradeCloseRequest();
            request.SetBizModel(input);

            var response = await _alipayService.ExecuteAsync(request);

            return response;
        }


        /// 
        /// 关闭订单
        /// 
        /// 商户订单号
        /// 支付宝交易号
        /// 
        public async Task OrderClose(string tradeno, string alipayTradeNo)
        {
            var model = new AlipayTradeCloseModel()
            {
                OutTradeNo = tradeno,
                TradeNo = alipayTradeNo,
            };

            return await this.OrderClose(model);
        }



        #endregion


        #region 回调获取请求数据

        public async Task PayRequestCheck(HttpRequest request)
        {
            await Task.Yield();

            var result = new PayRequestCheckOutput();

            if (request.Method.ToLower() == "post")
            {
                result.SArray = GetRequestPost(request);
            }
            else
            {
                result.SArray = GetRequestGet(request);
            }

            if (result.SArray.Count != 0)
            {
                result.IsSuccess = _alipayService.RSACheckV1(result.SArray);
            }

            return result;
        }

        #endregion


        #region FTF Pay 私有函数

        /// 
        /// 面对面支付生成支付二维码
        /// 
        /// 支付数据
        /// 异步通知地址,为空则表示为同步轮询模式
        /// 同步轮询回调函数
        /// 面对面支付其它配置
        /// 
        private async Task FTFGenQRCode(AlipayTradePrecreateContentBuilder input, string asyncNotifyUrl, Action loopQueryAction, FTFConfig fTFConfig)
        {
            // 参数检测
            var isAsyncNotify = !asyncNotifyUrl.IsNullOrWhiteSpace();
            if (!isAsyncNotify && loopQueryAction == null)
            {
                throw new NullReferenceException("轮询模式下 loopQueryAction 不能为空!");
            }
            // 收款账号检测,如果为空则默认填入全局配置的Uid
            if (input.seller_id.IsNullOrWhiteSpace())
            {
                input.seller_id = this._alipayService.Options.Uid;
            }



            Bitmap bitmap = null;
            MemoryStream memoryStream = null;
            var message = string.Empty;

            //推荐使用轮询撤销机制,不推荐使用异步通知,避免单边账问题发生。
            AlipayF2FPrecreateResult precreateResult = null;
            // 异步通知
            if (isAsyncNotify)
            {
                precreateResult = await _alipayF2FService.TradePrecreateAsync(input, asyncNotifyUrl);

            }// 同步轮询
            else
            {
                precreateResult = await _alipayF2FService.TradePrecreateAsync(input);
            }

            switch (precreateResult.Status)
            {
                case F2FResultEnum.SUCCESS:
                    // 将链接用二维码工具生成二维码打印出来,顾客可以用支付宝钱包扫码支付。
                    bitmap = RenderQrCode(precreateResult.response.QrCode);
                    // 同步轮询模式,触发轮询回调函数
                    if (!isAsyncNotify)
                    {
                        loopQueryAction.Invoke(precreateResult);
                    }
                    break;
                case F2FResultEnum.FAILED:
                    message = $"生成二维码失败: {precreateResult.response.Body}";
                    break;

                case F2FResultEnum.UNKNOWN:
                    message = "生成二维码失败:" + (precreateResult.response == null ? "配置或网络异常,请检查后重试" : "系统异常,请更新外部订单后重新发起请求");
                    break;
            }

            // 如果位图为空,则生成错误提示二维码
            if (bitmap == null)
            {
                bitmap = new Bitmap(fTFConfig == null ? this._fTFConfig?.QRCodeGenErrorImageFullPath : fTFConfig.QRCodeGenErrorImageFullPath);
            }

            // 转换成字节数组
            memoryStream = new MemoryStream();
            bitmap.Save(memoryStream, ImageFormat.Png);
            var imgBuffer = memoryStream.GetBuffer();

            // 释放资源
            memoryStream.Dispose();
            bitmap.Dispose();

            return new FTFOutput()
            {
                QRCodeImageBuffer = imgBuffer,
                IsSuccess = precreateResult.Status == F2FResultEnum.SUCCESS,
                Message = message
            };
        }


        /// 
        /// FTF渲染二维码
        /// 
        /// 
        /// 
        private Bitmap RenderQrCode(string str, FTFConfig fTFConfig = null)
        {
            var eccLevel = QRCodeGenerator.ECCLevel.L;
            using (var qrGenerator = new QRCodeGenerator())
            {
                using (var qrCodeData = qrGenerator.CreateQrCode(str, eccLevel))
                {
                    using (var qrCode = new QRCode(qrCodeData))
                    {

                        var bp = qrCode.GetGraphic(20, Color.Black, Color.White,
                            new Bitmap(fTFConfig == null ? this._fTFConfig?.QRCodeIconFullPath : fTFConfig.QRCodeIconFullPath),
                            15);
                        return bp;
                    }
                }
            }

        }


        #endregion


        #region 解析请求参数

        private Dictionary GetRequestGet(HttpRequest request)
        {
            Dictionary sArray = new Dictionary();

            ICollection requessatem = request.Query.Keys;
            foreach (var item in requessatem)
            {
                sArray.Add(item, request.Query[item]);

            }
            return sArray;

        }

        private Dictionary GetRequestPost(HttpRequest request)
        {
            Dictionary sArray = new Dictionary();

            ICollection requessatem = request.Form.Keys;
            foreach (var item in requessatem)
            {
                sArray.Add(item, request.Form[item]);

            }
            return sArray;

        }

        #endregion
    }
}