diff --git a/common.props b/common.props index 0a7d15b..1dfc07a 100644 --- a/common.props +++ b/common.props @@ -1,7 +1,7 @@ latest - 3.0.0 + 3.0.1 $(NoWarn);CS1591 true EasyAbp Team diff --git a/docs/WeChatPay.md b/docs/WeChatPay.md index 0f525ba..5ca8963 100644 --- a/docs/WeChatPay.md +++ b/docs/WeChatPay.md @@ -140,11 +140,9 @@ public override void ConfigureServices (ServiceConfigurationContext context) 用户如果需要对支付结果进行处理,只需要实现一个或多个 `IWeChatPayEventHandler` 处理器即可。当框架接受到微信通知时,会触发开发人员编写的处理器,并将微信结果传递给这些处理器。 ```csharp - public class PaidWeChatPayEventHandler : IWeChatPayEventHandler + public class PaidWeChatPayEventHandler : WeChatPayPaidEventHandlerBase { - public WeChatHandlerType Type => WeChatHandlerType.Paid; - - public Task HandleAsync(WeChatPayEventModel model) + public Task HandleAsync(WeChatPayEventModel model) { Console.WriteLine("支付成功。"); return Task.FromResult(new WeChatRequestHandlingResult(true)); @@ -175,11 +173,9 @@ WeChatPay 模块默认提供了参数校验处理器,各个处理器的调用 用户如果需要对退款通知进行处理,只需要实现一个或多个 `IWeChatPayEventHandler` 处理器即可。当框架接受到微信通知时,会触发开发人员编写的处理器,并将微信结果传递给这些处理器。 ```csharp - public class RefundWeChatPayEventHandler : IWeChatPayEventHandler + public class RefundWeChatPayEventHandler : WeChatPayRefundEventHandlerBase { - public WeChatHandlerType Type => WeChatHandlerType.Refund; - - public Task HandleAsync(WeChatPayEventModel model) + public Task HandleAsync(WeChatPayEventModel model) { Console.WriteLine("退款成功。"); return Task.FromResult(new WeChatRequestHandlingResult(true)); diff --git a/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/IWeChatPayEventHandler.cs b/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/IWeChatPayEventHandler.cs index 71b1e2e..7e793ee 100644 --- a/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/IWeChatPayEventHandler.cs +++ b/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/IWeChatPayEventHandler.cs @@ -6,10 +6,10 @@ namespace EasyAbp.Abp.WeChat.Pay.RequestHandling /// /// 定义了微信支付回调处理器。 /// - public interface IWeChatPayEventHandler + public interface IWeChatPayEventHandler { WeChatHandlerType Type { get; } - Task HandleAsync(WeChatPayEventModel model); + Task HandleAsync(WeChatPayEventModel model); } } \ No newline at end of file diff --git a/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/Models/WeChatPayPaidEventModel.cs b/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/Models/WeChatPayPaidEventModel.cs new file mode 100644 index 0000000..7683001 --- /dev/null +++ b/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/Models/WeChatPayPaidEventModel.cs @@ -0,0 +1,457 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.Enums; +using Newtonsoft.Json; + +namespace EasyAbp.Abp.WeChat.Pay.RequestHandling.Models; + +public class WeChatPayPaidEventModel +{ + /// + /// 应用 ID。 + /// + /// + /// 直连商户申请的公众号或移动应用 appid。 + /// + /// + /// 示例值: wxd678efh567hg6787。 + /// + [Required] + [StringLength(32, MinimumLength = 1)] + [JsonProperty("appid")] + public string AppId { get; set; } + + /// + /// 直连商户号。 + /// + /// + /// 直连商户的商户号,由微信支付生成并下发。 + /// + /// + /// 示例值: 1230000109。 + /// + [Required] + [StringLength(32, MinimumLength = 1)] + [JsonProperty("mchid")] + public string MchId { get; set; } + + /// + /// 商户订单号。 + /// + /// + /// 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一,详见【商户订单号】。 + /// + /// + /// 示例值: 1217752501201407033233368018。 + /// + [Required] + [StringLength(32, MinimumLength = 6)] + [JsonProperty("out_trade_no")] + public string OutTradeNo { get; set; } + + /// + /// 微信支付订单号。 + /// + /// + /// 微信支付系统生成的订单号。 + /// + /// + /// 示例值: 1217752501201407033233368018。 + /// + [StringLength(32)] + [JsonProperty("transaction_id")] + public string TransactionId { get; set; } + + /// + /// 交易类型。 + /// + /// + /// 交易类型为枚举值,具体值可参考 中找到对应的定义。 + /// + /// + /// 示例值: MICROPAY。()。 + /// + [StringLength(16)] + [JsonProperty("trade_type")] + public string TradeType { get; set; } + + /// + /// 交易状态。 + /// + /// + /// 交易状态为枚举值,具体值可以参考 中找到对应的定义。 + /// + /// + /// 示例值: SUCCESS()。 + /// + [Required] + [StringLength(32)] + [JsonProperty("trade_state")] + public string TradeState { get; set; } + + /// + /// 交易状态描述。 + /// + /// + /// 交易状态描述。 + /// + /// + /// 示例值: 支付成功。 + /// + [Required] + [StringLength(256)] + [JsonProperty("trade_state_desc")] + public string TradeStateDesc { get; set; } + + /// + /// 付款银行。 + /// + /// + /// 银行类型,采用字符串类型的银行标识。银行标识请参考 《银行类型对照表》。 + /// + /// + /// 示例值: CMC。 + /// + [StringLength(32)] + [JsonProperty("bank_type")] + public string BankType { get; set; } + + /// + /// 附加数据。 + /// + /// + /// 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段。 + /// + /// + /// 示例值: 自定义数据。 + /// + [StringLength(128)] + [JsonProperty("attach")] + public string Attach { get; set; } + + /// + /// 支付完成时间。 + /// + /// + /// 遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE。
+ /// 开发人员只需要传递 DateTime 对象,底层的 Newtonsoft.Json 库会自动将其转换为符合微信支付要求的格式。 + ///
+ /// + /// 示例值: 2018-06-08T10:34:56+08:00。 + /// + [StringLength(64)] + [JsonProperty("success_time")] + public DateTime? SuccessTime { get; set; } + + /// + /// 支付者。 + /// + /// + /// 支付者信息。 + /// + [Required] + [JsonProperty("payer")] + public QueryOrderPayerModel Payer { get; set; } + + /// + /// 订单金额。 + /// + /// + /// 订单金额信息,当支付成功时返回该字段。 + /// + [JsonProperty("amount")] + public QueryOrderAmountModel Amount { get; set; } + + /// + /// 场景信息。 + /// + /// + /// 支付场景描述。 + /// + [JsonProperty("scene_info")] + public QueryOrderSceneInfoModel SceneInfo { get; set; } + + /// + /// 优惠功能。 + /// + /// + /// 优惠功能,享受优惠时返回该字段。 + /// + [JsonProperty("promotion_detail")] + public List PromotionDetails { get; set; } + + public class QueryOrderPayerModel + { + /// + /// 用户标识。 + /// + /// + /// 用户在直连商户 appid 下的唯一标识。 + /// + /// + /// 示例值: oUpF8uMuAJO_M2pxb1Q9zNjWeS6o。 + /// + [Required] + [StringLength(128, MinimumLength = 1)] + [JsonProperty("openid")] + public string OpenId { get; set; } + } + + public class QueryOrderAmountModel + { + /// + /// 总金额。 + /// + /// + /// 订单总金额,单位为分。 + /// + /// + /// 示例值: 100。 + /// + [JsonProperty("total")] + public int Total { get; set; } + + /// + /// 用户支付金额。 + /// + /// + /// 用户支付金额,单位为分。(指使用优惠券的情况下,这里等于总金额-优惠券金额) + /// + /// + /// 示例值: 100。 + /// + [JsonProperty("payer_total")] + public int PayerTotal { get; set; } + + /// + /// 货币类型。 + /// + /// + /// CNY: 人民币,境内商户号仅支持人民币。 + /// + /// + /// 示例值: CNY。 + /// + [StringLength(16)] + [JsonProperty("currency")] + public string Currency { get; set; } + + /// + /// 用户支付币种。 + /// + /// + /// 用户支付币种。 + /// + /// + /// 示例值: CNY。 + /// + [StringLength(16)] + [JsonProperty("payer_currency")] + public string PayerCurrency { get; set; } + } + + public class QueryOrderSceneInfoModel + { + /// + /// 商户端设备号。 + /// + /// + /// 商户端设备号 (发起扣款请求的商户服务器设备号)。 + /// + /// + /// 示例值: 013467007045764。 + /// + [StringLength(32)] + [JsonProperty("device_id")] + public string DeviceId { get; set; } + } +} + +public class QueryOrderPromotionDetailModel +{ + /// + /// 券 ID。 + /// + /// + /// 示例值: 109519。 + /// + [Required] + [StringLength(32)] + [JsonProperty("coupon_id")] + public string CouponId { get; set; } + + /// + /// 优惠名称。 + /// + /// + /// 示例值: 单品惠-6。 + /// + [StringLength(64)] + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// 优惠范围。 + /// + /// + /// 枚举值,取值范围请参考 。 + /// + /// + /// 示例值: GLOBAL。() + /// + [StringLength(32)] + [JsonProperty("scope")] + public string Scope { get; set; } + + /// + /// 优惠类型。 + /// + /// + /// 枚举值,取值范围请参考 。 + /// + /// + /// 示例值: CASH。() + /// + [StringLength(32)] + [JsonProperty("type")] + public string Type { get; set; } + + /// + /// 优惠券面额。 + /// + /// + /// 示例值: 100。 + /// + [Required] + [JsonProperty("amount")] + public int Amount { get; set; } + + /// + /// 活动 ID。 + /// + /// + /// 示例值: 931386。 + /// + [StringLength(32)] + [JsonProperty("stock_id")] + public string StockId { get; set; } + + /// + /// 微信出资。 + /// + /// + /// 微信出资,单位为分。 + /// + /// + /// 示例值: 0 + /// + [JsonProperty("wechatpay_contribute")] + public int WechatpayContribute { get; set; } + + /// + /// 商户出资。 + /// + /// + /// 商户出资,单位为分。 + /// + /// + /// 示例值: 0 + /// + [JsonProperty("merchant_contribute")] + public int MerchantContribute { get; set; } + + /// + /// 其他出资。 + /// + /// + /// 其他出资,单位为分。 + /// + /// + /// 示例值: 0 + /// + [JsonProperty("other_contribute")] + public int OtherContribute { get; set; } + + /// + /// 优惠币种。 + /// + /// + /// CNY: 人民币,境内商户号仅支持人民币。 + /// + /// + /// 示例值: CNY + /// + [StringLength(16)] + [JsonProperty("currency")] + public string Currency { get; set; } + + /// + /// 单品列表。 + /// + /// + /// 单品列表信息。 + /// + [JsonProperty("goods_detail")] + public List GoodsDetails { get; set; } + + public class QueryOrderPromotionDetailGoodsDetail + { + /// + /// 商品编码。 + /// + /// + /// 示例值: M1006 + /// + [Required] + [StringLength(32)] + [JsonProperty("goods_id")] + public string GoodsId { get; set; } + + /// + /// 商品数量。 + /// + /// + /// 用户购买的数量。 + /// + /// + /// 示例值: 1 + /// + [Required] + [JsonProperty("quantity")] + public int Quantity { get; set; } + + /// + /// 商品单价。 + /// + /// + /// 商品单价,单位为分。 + /// + /// + /// 示例值: 100 + /// + [Required] + [JsonProperty("unit_price")] + public int UnitPrice { get; set; } + + /// + /// 商品优惠金额。 + /// + /// + /// 示例值: 0 + /// + [Required] + [JsonProperty("discount_amount")] + public int DiscountAmount { get; set; } + + /// + /// 商品备注。 + /// + /// + /// 示例值: 商品备注信息 + /// + [StringLength(128)] + [JsonProperty("goods_remark")] + public string GoodsRemark { get; set; } + } +} \ No newline at end of file diff --git a/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/Models/WeChatPayRefundEventModel.cs b/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/Models/WeChatPayRefundEventModel.cs new file mode 100644 index 0000000..20c386c --- /dev/null +++ b/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/Models/WeChatPayRefundEventModel.cs @@ -0,0 +1,201 @@ +using System; +using System.ComponentModel.DataAnnotations; +using EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.Enums; +using Newtonsoft.Json; + +namespace EasyAbp.Abp.WeChat.Pay.RequestHandling.Models; + +public class WeChatPayRefundEventModel +{ + /// + /// 直连商户号。 + /// + /// + /// 直连商户的商户号,由微信支付生成并下发。 + /// + /// 示例值: 1230000109。 + [JsonProperty("mchid")] + [Required] + [StringLength(32, MinimumLength = 1)] + public string MchId { get; set; } + + /// + /// 商户订单号。 + /// + /// + /// 原支付交易对应的商户订单号。 + /// + /// + /// 示例值: 1217752501201407033233368018 + /// + [JsonProperty("out_trade_no")] + [Required] + [StringLength(32, MinimumLength = 1)] + public string OutTradeNo { get; set; } + + /// + /// 微信支付订单号。 + /// + /// + /// 微信支付交易订单号。 + /// + /// + /// 示例值: 1217752501201407033233368018 + /// + [JsonProperty("transaction_id")] + [Required] + [StringLength(32, MinimumLength = 1)] + + public string TransactionId { get; set; } + + /// + /// 商户退款单号。 + /// + /// + /// 商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。 + /// + /// + /// 示例值: 1217752501201407033233368018 + /// + [JsonProperty("out_refund_no")] + [Required] + [StringLength(64, MinimumLength = 1)] + public string OutRefundNo { get; set; } + + /// + /// 微信支付退款单号。 + /// + /// + /// 微信支付退款单号。 + /// + /// + /// 示例值: 50000000382019052709732678859 + /// + [JsonProperty("refund_id")] + [Required] + [StringLength(32, MinimumLength = 1)] + public string RefundId { get; set; } + + /// + /// 退款状态。 + /// + /// + /// 退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款。
+ /// 具体状态值可以参考类型 的定义(事件中不会包含 PROCESSING 状态)。 + ///
+ /// + /// 示例值: SUCCESS + /// + [JsonProperty("refund_status")] + [Required] + [StringLength(32, MinimumLength = 1)] + public string RefundStatus { get; set; } + + /// + /// 退款成功时间。 + /// + /// + /// 退款成功时间,当退款状态为退款成功时有返回。 + /// + /// + /// 示例值: 2020-12-01T16:18:12+08:00 + /// + [JsonProperty("success_time")] + [StringLength(64, MinimumLength = 1)] + public DateTime? SuccessTime { get; set; } + + /// + /// 退款入账账户。 + /// + /// + /// 取当前退款单的退款入账方,有以下几种情况:
+ /// 1. 退回银行卡: {银行名称}{卡类型}{卡尾号}
+ /// 2. 退回支付用户零钱: 支付用户零钱
+ /// 3. 退还商户: 商户基本账户商户结算银行账户
+ /// 4. 退回支付用户零钱通:支付用户零钱通 + ///
+ /// + /// 示例值: 招商银行信用卡0403 + /// + [JsonProperty("user_received_account")] + [Required] + [StringLength(64, MinimumLength = 1)] + public string UserReceivedAccount { get; set; } + + /// + /// 退款创建时间。 + /// + /// + /// 退款受理时间。 + /// + /// 示例值: 2020-12-01T16:18:12+08:00 + [JsonProperty("create_time")] + [Required] + [StringLength(64, MinimumLength = 1)] + public DateTime? CreateTime { get; set; } + + /// + /// 金额信息。 + /// + /// + /// 金额详细信息。 + /// + [JsonProperty("amount")] + [Required] + public AmountInfo Amount { get; set; } + + public class AmountInfo + { + /// + /// 订单金额。 + /// + /// + /// 订单总金额,单位为分。 + /// + /// + /// 示例值: 100 + /// + [JsonProperty("total")] + [Required] + public int Total { get; set; } + + /// + /// 退款金额。 + /// + /// + /// 退款标价金额,单位为分,可以做部分退款。 + /// + /// + /// 示例值: 100 + /// + [JsonProperty("refund")] + [Required] + public int Refund { get; set; } + + /// + /// 用户支付金额。 + /// + /// + /// 现金支付金额,单位为分,只能为整数。 + /// + /// + /// 示例值: 90 + /// + [JsonProperty("payer_total")] + [Required] + public int PayerTotal { get; set; } + + /// + /// 用户退款金额。 + /// + /// + /// 退款给用户的金额,不包含所有优惠券金额。 + /// + /// + /// 示例值: 90 + /// + [JsonProperty("payer_refund")] + [Required] + public int PayerRefund { get; set; } + } +} \ No newline at end of file diff --git a/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/WeChatPayPaidEventHandlerBase.cs b/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/WeChatPayPaidEventHandlerBase.cs new file mode 100644 index 0000000..99f87fa --- /dev/null +++ b/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/WeChatPayPaidEventHandlerBase.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using EasyAbp.Abp.WeChat.Common.RequestHandling; +using EasyAbp.Abp.WeChat.Pay.RequestHandling.Models; + +namespace EasyAbp.Abp.WeChat.Pay.RequestHandling; + +public abstract class WeChatPayPaidEventHandlerBase : IWeChatPayEventHandler +{ + public virtual WeChatHandlerType Type => WeChatHandlerType.Paid; + + public abstract Task HandleAsync(WeChatPayEventModel model); +} \ No newline at end of file diff --git a/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/WeChatPayRefundEventHandlerBase.cs b/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/WeChatPayRefundEventHandlerBase.cs new file mode 100644 index 0000000..2bdf7bd --- /dev/null +++ b/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/WeChatPayRefundEventHandlerBase.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using EasyAbp.Abp.WeChat.Common.RequestHandling; +using EasyAbp.Abp.WeChat.Pay.RequestHandling.Models; + +namespace EasyAbp.Abp.WeChat.Pay.RequestHandling; + +public abstract class WeChatPayRefundEventHandlerBase : IWeChatPayEventHandler +{ + public virtual WeChatHandlerType Type => WeChatHandlerType.Refund; + + public abstract Task HandleAsync(WeChatPayEventModel model); +} \ No newline at end of file