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 committed 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.
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
@@ -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;
}
}
@@ -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.

Expand Up @@ -3,7 +3,8 @@

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

public class PaymentNotifyCallbackRequest
[Serializable]
public class WeChatPayNotificationInput
{
/// <summary>
/// 通知 ID。
Expand Down
@@ -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
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);
}
@@ -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 class WeChatPayController : AbpControllerBase
/// </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 class WeChatPayController : AbpControllerBase
/// </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 Task<ActionResult> RefundNotify4Async([CanBeNull] string tenantId
});
}

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
}
}
@@ -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。");
}
}
}
}
Expand Up @@ -23,10 +23,18 @@ public class WeChatPayApiRequestModel
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
Expand Up @@ -10,6 +10,6 @@ public interface IWeChatPayEventHandler
{
WeChatHandlerType Type { get; }

Task<WeChatRequestHandlingResult> HandleAsync(WeChatPayEventModel model);
Task<WeChatRequestHandlingResult> HandleAsync<TResource>(WeChatPayEventModel<TResource> model);
}
}
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; }
}

0 comments on commit 67c7b97

Please sign in to comment.