Skip to content

Commit

Permalink
Merge pull request #104 from EasyAbp/wechatpay-v3-jspayment
Browse files Browse the repository at this point in the history
Preliminary development of WeChat Pay API V3 has been completed. (JS API)
  • Loading branch information
real-zony authored Jan 10, 2024
2 parents c30acff + 34dc464 commit 67c7b97
Show file tree
Hide file tree
Showing 25 changed files with 345 additions and 191 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ public static string ConvertToQueryString(object obj)
continue;
}

var ignoreAttribute = propertyInfo.GetCustomAttribute<JsonIgnoreAttribute>();
if(ignoreAttribute != null) continue;

var jsonPropertyAttribute = propertyInfo.GetCustomAttribute<JsonPropertyAttribute>();
var name = jsonPropertyAttribute?.PropertyName ?? propertyInfo.Name;
var type = propertyInfo.PropertyType;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace EasyAbp.Abp.WeChat.Pay.RequestHandling.Dtos;

public class NotifyHttpHeaderModel
{
public string SerialNumber { get; set; }

public string Timestamp { get; set; }

public string Nonce { get; set; }

public string Signature { get; set; }

public NotifyHttpHeaderModel(string serialNumber, string timestamp, string nonce, string signature)
{
SerialNumber = serialNumber;
Timestamp = timestamp;
Nonce = nonce;
Signature = signature;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using JetBrains.Annotations;

namespace EasyAbp.Abp.WeChat.Pay.RequestHandling.Dtos;

[Serializable]
public class NotifyInputDto
{
[CanBeNull] public string MchId { get; set; }

public string RequestBodyString { get; set; }

public WeChatPayNotificationInput RequestBody { get; set; }

public NotifyHttpHeaderModel HttpHeader { get; set; }
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

namespace EasyAbp.Abp.WeChat.Pay.RequestHandling.Dtos;

public class PaymentNotifyCallbackRequest
[Serializable]
public class WeChatPayNotificationInput
{
/// <summary>
/// 通知 ID。
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Text.Json.Serialization;

namespace EasyAbp.Abp.WeChat.Pay.RequestHandling.Dtos;

public class PaymentNotifyCallbackResponse
[Serializable]
public class WeChatPayNotificationOutput
{
/// <summary>
/// 返回状态码。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace EasyAbp.Abp.WeChat.Pay.RequestHandling;

public interface IWeChatPayEventRequestHandlingService
{
Task<WeChatRequestHandlingResult> PaidNotifyAsync(PaidNotifyInput input);
Task<WeChatRequestHandlingResult> PaidNotifyAsync(NotifyInputDto inputDto);

Task<WeChatRequestHandlingResult> RefundNotifyAsync(RefundNotifyInput input);
Task<WeChatRequestHandlingResult> RefundNotifyAsync(NotifyInputDto inputDto);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using System;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Common;
using EasyAbp.Abp.WeChat.Pay.RequestHandling;
using EasyAbp.Abp.WeChat.Pay.RequestHandling.Dtos;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;

Expand Down Expand Up @@ -35,33 +35,15 @@ public WeChatPayController(
/// </summary>
[HttpPost]
[Route("notify")]
public virtual async Task<ActionResult> NotifyAsync([CanBeNull] [FromQuery] string tenantId,
public virtual async Task<IActionResult> NotifyAsync([CanBeNull] [FromQuery] string tenantId,
[CanBeNull] [FromQuery] string mchId)
{
using var changeTenant = CurrentTenant.Change(tenantId.IsNullOrWhiteSpace() ? null : Guid.Parse(tenantId!));

var body = await GetPostDataAsync();
// var result = await _eventRequestHandlingService.PaidNotifyAsync(new PaidNotifyInput
// {
// MchId = mchId,
// RequestBodyString = body,
// RequestBody = JsonConvert.DeserializeObject<PaymentNotifyCallbackRequest>(body),
// SerialNumber = Request.Headers["Wechatpay-Serial"],
// Timestamp = Request.Headers["Wechatpay-TimeStamp"],
// Nonce = Request.Headers["Wechatpay-Nonce"],
// Signature = Request.Headers["Wechatpay-Signature"]
// });
//
// if (!result.Success)
// {
// return BadRequest(new PaymentNotifyCallbackResponse
// {
// Code = "FAIL",
// Message = "处理失败"
// });
// }

return Ok();
var result = await _eventRequestHandlingService.PaidNotifyAsync(
BuildNotifyInputDto(await GetPostDataAsync(), mchId));

return !result.Success ? NotifyFailure(result.FailureReason) : NotifySuccess();
}

/// <summary>
Expand All @@ -70,7 +52,7 @@ public virtual async Task<ActionResult> NotifyAsync([CanBeNull] [FromQuery] stri
/// </summary>
[HttpPost]
[Route("notify/tenant-id/{tenantId}")]
public virtual Task<ActionResult> Notify2Async([CanBeNull] string tenantId, [CanBeNull] string mchId)
public virtual Task<IActionResult> Notify2Async([CanBeNull] string tenantId, [CanBeNull] string mchId)
{
return NotifyAsync(tenantId, mchId);
}
Expand All @@ -81,7 +63,7 @@ public virtual Task<ActionResult> Notify2Async([CanBeNull] string tenantId, [Can
/// </summary>
[HttpPost]
[Route("notify/mch-id/{mchId}")]
public virtual Task<ActionResult> Notify3Async([CanBeNull] string tenantId, [CanBeNull] string mchId)
public virtual Task<IActionResult> Notify3Async([CanBeNull] string tenantId, [CanBeNull] string mchId)
{
return NotifyAsync(tenantId, mchId);
}
Expand All @@ -92,7 +74,7 @@ public virtual Task<ActionResult> Notify3Async([CanBeNull] string tenantId, [Can
/// </summary>
[HttpPost]
[Route("notify/tenant-id/{tenantId}/mch-id/{mchId}")]
public virtual Task<ActionResult> Notify4Async([CanBeNull] string tenantId, [CanBeNull] string mchId)
public virtual Task<IActionResult> Notify4Async([CanBeNull] string tenantId, [CanBeNull] string mchId)
{
return NotifyAsync(tenantId, mchId);
}
Expand All @@ -102,22 +84,13 @@ public virtual Task<ActionResult> Notify4Async([CanBeNull] string tenantId, [Can
/// </summary>
[HttpPost]
[Route("refund-notify")]
public virtual async Task<ActionResult> RefundNotifyAsync([CanBeNull] string tenantId, [CanBeNull] string mchId)
public virtual async Task<IActionResult> RefundNotifyAsync([CanBeNull] string tenantId, [CanBeNull] string mchId)
{
using var changeTenant = CurrentTenant.Change(tenantId.IsNullOrWhiteSpace() ? null : Guid.Parse(tenantId!));

var result = await _eventRequestHandlingService.RefundNotifyAsync(new RefundNotifyInput
{
MchId = mchId,
Xml = await GetPostDataAsync()
});
var result = await _eventRequestHandlingService.RefundNotifyAsync(BuildNotifyInputDto(await GetPostDataAsync(), mchId));

if (!result.Success)
{
return BadRequest(BuildFailedXml(result.FailureReason));
}

return Ok(BuildSuccessXml());
return !result.Success ? NotifyFailure(result.FailureReason) : NotifySuccess();
}

/// <summary>
Expand All @@ -126,7 +99,7 @@ public virtual async Task<ActionResult> RefundNotifyAsync([CanBeNull] string ten
/// </summary>
[HttpPost]
[Route("refund-notify/tenant-id/{tenantId}")]
public virtual Task<ActionResult> RefundNotify2Async([CanBeNull] string tenantId, [CanBeNull] string mchId)
public virtual Task<IActionResult> RefundNotify2Async([CanBeNull] string tenantId, [CanBeNull] string mchId)
{
return RefundNotifyAsync(tenantId, mchId);
}
Expand All @@ -137,7 +110,7 @@ public virtual Task<ActionResult> RefundNotify2Async([CanBeNull] string tenantId
/// </summary>
[HttpPost]
[Route("refund-notify/mch-id/{mchId}")]
public virtual Task<ActionResult> RefundNotify3Async([CanBeNull] string tenantId, [CanBeNull] string mchId)
public virtual Task<IActionResult> RefundNotify3Async([CanBeNull] string tenantId, [CanBeNull] string mchId)
{
return RefundNotifyAsync(tenantId, mchId);
}
Expand All @@ -148,7 +121,7 @@ public virtual Task<ActionResult> RefundNotify3Async([CanBeNull] string tenantId
/// </summary>
[HttpPost]
[Route("refund-notify/tenant-id/{tenantId}/mch-id/{mchId}")]
public virtual Task<ActionResult> RefundNotify4Async([CanBeNull] string tenantId, [CanBeNull] string mchId)
public virtual Task<IActionResult> RefundNotify4Async([CanBeNull] string tenantId, [CanBeNull] string mchId)
{
return RefundNotifyAsync(tenantId, mchId);
}
Expand All @@ -161,8 +134,8 @@ public virtual Task<ActionResult> RefundNotify4Async([CanBeNull] string tenantId
/// <param name="mchId">商户 Id</param>
[HttpGet]
[Route("js-sdk-config-parameters")]
public virtual async Task<ActionResult> GetJsSdkWeChatPayParametersAsync(
string mchId, [FromQuery] string appId, string prepayId)
public virtual async Task<IActionResult> GetJsSdkWeChatPayParametersAsync(string mchId,
[FromQuery] string appId, string prepayId)
{
var result = await _clientRequestHandlingService.GetJsSdkWeChatPayParametersAsync(
new GetJsSdkWeChatPayParametersInput
Expand All @@ -182,20 +155,37 @@ public virtual async Task<ActionResult> GetJsSdkWeChatPayParametersAsync(
});
}

private string BuildSuccessXml()
#region > Utilities methods <

private IActionResult NotifySuccess()
{
return @"<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>";
return Ok(new WeChatPayNotificationOutput
{
Code = "SUCCESS"
});
}

private string BuildFailedXml(string failedReason)
private IActionResult NotifyFailure(string message)
{
return $@"<xml>
<return_code><![CDATA[FAIL]]></return_code>
<return_msg><![CDATA[{failedReason}]]></return_msg>
</xml>";
return BadRequest(new WeChatPayNotificationOutput
{
Code = "FAIL",
Message = message
});
}

private NotifyInputDto BuildNotifyInputDto(string requestBody, string mchId)
{
return new NotifyInputDto
{
MchId = mchId,
RequestBodyString = requestBody,
RequestBody = JsonSerializer.Deserialize<WeChatPayNotificationInput>(requestBody),
HttpHeader = new NotifyHttpHeaderModel(Request.Headers["Wechatpay-Serial"],
Request.Headers["Wechatpay-TimeStamp"],
Request.Headers["Wechatpay-Nonce"],
Request.Headers["Wechatpay-Signature"])
};
}

protected virtual async Task<string> GetPostDataAsync()
Expand All @@ -210,5 +200,7 @@ protected virtual async Task<string> GetPostDataAsync()

return postData;
}

#endregion
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Common.Extensions;
using EasyAbp.Abp.WeChat.Pay.Exceptions;
using EasyAbp.Abp.WeChat.Pay.Options;
using EasyAbp.Abp.WeChat.Pay.Security;
using Newtonsoft.Json;
Expand Down Expand Up @@ -113,9 +115,19 @@ private string HandleRequestObject(HttpMethod method, object body)
return WeChatReflectionHelper.ConvertToQueryString(body);
}

protected virtual async Task ValidateResponseAsync(HttpResponseMessage responseMessage)
protected virtual Task ValidateResponseAsync(HttpResponseMessage responseMessage)
{
await Task.CompletedTask;
switch (responseMessage.StatusCode)
{
case HttpStatusCode.OK:
return Task.CompletedTask;
case HttpStatusCode.Accepted:
return Task.CompletedTask;
case HttpStatusCode.NoContent:
return Task.CompletedTask;
default:
throw new CallWeChatPayApiException("微信支付 API 调用失败,状态码为非 200。");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,18 @@ public WeChatPayApiRequestModel(HttpMethod method,
string randomString)
{
Method = method;
Url = url;
Body = body;
Timestamp = timestamp;
RandomString = randomString;
Url = url;
Body = body;

if (method != HttpMethod.Get) return;

Body = null;
if (!string.IsNullOrEmpty(body))
{
Url = $"{url}?{body}";
}
}

public string GetPendingSignatureString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ public interface IWeChatPayEventHandler
{
WeChatHandlerType Type { get; }

Task<WeChatRequestHandlingResult> HandleAsync(WeChatPayEventModel model);
Task<WeChatRequestHandlingResult> HandleAsync<TResource>(WeChatPayEventModel<TResource> model);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace EasyAbp.Abp.WeChat.Pay.RequestHandling;

public class WeChatPayEventModel
public class WeChatPayEventModel<TResource>
{
public AbpWeChatPayOptions Options { get; set; }

public TResource Resource { get; set; }
}
Loading

0 comments on commit 67c7b97

Please sign in to comment.