Magicodes.Pay now supports Volo Abp
Overview
Magicodes.Pay aims to create a unified payment library, with all libraries written using .NET Standard and supporting both .NET Framework and .NET Core. It currently provides encapsulation for Abp and Abp VNext (Volo Abp) modules, allowing immediate use. GitHub: https://github.com/xin-lai/Magicodes.Pay
Nuget
| Name | Description | Nuget |
|---|---|---|
| Magicodes.Pay.Alipay | Alipay payment library | |
| Magicodes.Pay.Notify | General payment callback library | |
| Magicodes.Pay.Wxpay | WeChat payment library | |
| Magicodes.Pay.Alipay.Global | Global Alipay payment library | |
| Magicodes.Pay.Allinpay | Allinpay payment library | |
| Magicodes.Pay.Abp | ABP general payment encapsulation library | |
| Magicodes.Pay.Abp.Allinpay | ABP Allinpay module | |
| Magicodes.Pay.Abp.Wxpay | ABP WeChat payment module | |
| Magicodes.Pay.Abp.Alipay.Global | ABP global Alipay module | |
| Magicodes.Pay.Abp.Alipay | ABP Alipay module | |
| Magicodes.Pay.Volo.Abp | Volo Abp base module | |
| Magicodes.Pay.Volo.Abp.Allinpay | Volo Abp Allinpay module | |
| Magicodes.Pay.Volo.Abp.Wxpay | Volo Abp WeChat payment module | |
| Magicodes.Pay.Volo.Abp.Alipay | Volo Abp Alipay payment module |
Key Features
It currantly provides encapsulation for Abp (including Volo Abp), allowing immediate use. It supports the following payment methods and features:
- Alipay payments
- APP payments
- Wap payments
- Global Alipay payments
- Supports profit sharing
- WeChat payments
- Mini program payments
- APP payments
- Order query
- Corporate transfer (withdrawal)
- Refund request
- Regular red envelopes
- Allinpay
- Mini program payments
- WeChat JSAPI payments
- Unified payment callback handling
- Supports logging function injection (not dependent on the payment library)
- Supports payment configuration function injection, enabling custom configuration logic for different scenarios (e.g., retrieving from configuration files, user settings, or multi-tenant support)
- For ABP, it provides module encapsulation; adding the module dependency allows immediate usage. This includes:
- Unified payment service encapsulation (see IPayAppService)
- Payment manager encapsulation (IPaymentManager), including:
- Payment channel registration (IPaymentRegister)
- Payment callback logic handling (IPaymentCallbackAction)
- Unified payment service implementation (IToPayService)
- Transaction log encapsulation, automatically recording client information and handling and logging exceptions
- Only one callback logic needs to be written to support multiple payment channels
- Business parameters support longer lengths (up to 500)
Getting Started (Volo Abp)
This guide is only applicable to Volo Abp. The main steps are as follows:
- Reference the corresponding Abp payment Nuget package
If only one payment method is needed, reference that specific package. Here's an example of referencing the Allinpay package:
| Name | Description | Nuget |
|---|---|---|
| Magicodes.Pay.Volo.Abp.Allinpay | Volo Abp Allinpay module |
- Add module dependencies
In the relevant Abp module (AbpModule) in your project, add a dependency on "AbpAllinpayModule", like:
[DependsOn(typeof(AbpAllinpayModule))]
- Add a DbSet named "TransactionLogs" in DbContext
Throughout the payment process (whether successful or not), transaction logs will be recorded. These logs store information such as client details, transaction parameters, custom data, and any exceptions. Therefore, you need to add support for TransactionLog in EF. The complete code to add in DbContext is as follows:
public DbSet<TransactionLog> TransactionLogs { get; set; }
- Register callback logic
You need to implement the "IPaymentCallbackAction" interface to write custom callback logic. Each logic requires a separate registration, matched by the business key, such as "payment for fees" or "recharge". Here's an example:
public class TestPaymentCallbackAction : IPaymentCallbackAction
{
/// <summary>
/// Business Key
/// </summary>
public string Key { get; set; } = "payment for fees";
/// <summary>
/// Execute the callback
/// </summary>
/// <returns></returns>
public async Task Process(IUnitOfWorkManager unitOfWork, TransactionLog transactionLog)
{
var data = transactionLog.CustomData.FromJsonString<JObject>();
// business processing
await Task.FromResult(0);
}
}
Note: Ensure the Key is unique.
- Register the callback logic in the container
If automatic registration does not occur, you can manually register it using the following code:
context.Services.AddTransient<IPaymentCallbackAction, TestPaymentCallbackAction>();
Alternatively, you can inject the IPaymentManager object and use its RegisterCallbackAction method to register the custom callback logic.
- Configure payment parameters
Payment parameters can be configured via a configuration file or SettingManager. Here's an example using a configuration file:
"Allinpay": {
"IsEnabled": "true",
"CusId": "testtest",
"ApiGateWay": "https://vsp.allinpay.com/apiweb/unitorder",
"AppKey": "testtesttesttest",
"AppId": "testtesttesttesttesttest",
"Version": "11",
"NotifyUrl": "{domain}/PayNotify/{tenantId?}/{payment provider key}",
"WeChatAppId": "WeChat mini program app ID",
"JsApiAppId":"JSAPI payment app ID"
}
As shown above, the configuration node "Allinpay" corresponds to the provider's key. The keys for various payment providers are as follows:
- Alipay: Alipay
- Global Alipay: Global.alipay
- Allinpay: Allinpay
- WeChat: Wxpay
Notably, by default, the callback is handled by the "PayNotifyController" in the "Magicodes.Pay.Notify" module. Thus, the callback URL format should be:
{domain}/PayNotify/{tenantId?}/
- Initiate Payment
After configuration, you can use the unified IPayAppService to initiate a payment. Simply inject IPayAppService and call the Pay method. You can also further encapsulate it, as shown in the following code:
public async Task<object> Payment(PaymentInput input)
{
return await _payAppService.Pay(new PayInputBase()
{
Body = $"{input.Name} {input.ChargeProjectName}",
CustomData = input.ToJsonString(),
Key = "payment for fees",
OpenId = input.OpenId,
Subject = input.ChargeProjectName,
TotalAmount = input.Amount,
PayChannel = input.PayChannel
});
}
Using IPayAppService offers several advantages:
- Unified payment (regardless of whether it's Alipay or WeChat across different platforms)
- Automatic recording of transaction logs and related processing
- Custom data is stored based on transaction logs, independent of the payment channel, thus supporting payment channels without business parameters and storing more custom data
Old Abp Integration Guide
If you're using Abp modules, the integration is straightforward. You can refer to the unit tests for guidance. The main steps are as follows:
- Reference the corresponding Abp payment Nuget package
If only one payment method is needed, reference that specific package. Here's an example of referencing the Allinpay package:
| Name | Description | Nuget |
|---|---|---|
| Magicodes.Pay.Abp.Allinpay | Abp Allinpay module |
- Add module dependencies
In the relevant Abp module (AbpModule) in your project, add a dependency on "AbpAllinpayModule", like:
[DependsOn(typeof(AbpAllinpayModule))]
- Add a DbSet named "TransactionLogs" in DbContext
Throughout the payment process (whether successful or not), transaction logs will be recorded. These logs store information such as client details, transaction parameters, custom data, and any exceptions. Therefore, you need to add support for TransactionLog in EF. The complete code to add in DbContext is as follows:
public DbSet<TransactionLog> TransactionLogs { get; set; }
- Register callback logic
You need to implement the "IPaymentCallbackAction" interface to write custom callback logic. Each logic requires a separate registration, matched by the business key, such as "payment for fees" or "recharge". Here's an example:
public class TestPaymentCallbackAction : IPaymentCallbackAction
{
/// <summary>
/// Business Key
/// </summary>
public string Key { get; set; } = "payment for fees";
/// <summary>
/// Execute the callback
/// </summary>
/// <returns></returns>
public async Task Process(IUnitOfWorkManager unitOfWork, TransactionLog transactionLog)
{
var data = transactionLog.CustomData.FromJsonString<JObject>();
// business processing
await Task.FromResult(0);
}
}
Note: Insure the Key is unique.
- Register the callback logic in the container
You can place the callback logic in a shared assembly and then register it using the following code:
IocManager.IocContainer.Register(
// Register custom payment callback logic
Classes.FromAssembly(typeof(ApplicationCoreModule).GetAssembly())
.BasedOn<IPaymentCallbackAction>()
.LifestyleTransient()
.Configure(component => component.Named(component.Implementation.FullName))
.WithServiceFromInterface()
);
Alternatively, you can inject the IPaymentManager object and use its RegisterCallbackAction method to register the custom callback logic.
- Configure payment parameters
Payment parameters can be configured via a configuration file or SettingManager. Here's an example using a configuration file:
"Allinpay": {
"IsEnabled": "true",
"CusId": "testtest",
"ApiGateWay": "https://vsp.allinpay.com/apiweb/unitorder",
"AppKey": "testtesttesttest",
"AppId": "testtesttesttesttesttest",
"Version": "11",
"NotifyUrl": "{domain}/PayNotify/{tenantId?}/{payment provider key}",
"WeChatAppId": "WeChat mini program app ID",
"JsApiAppId":"JSAPI payment app ID"
}
As shown above, the configuration node "Allinpay" corresponds to the provider's key. The keys for various payment providers are as follows:
- Alipay: Alipay
- Global Alipay: Global.alipay
- Allinpay: Allinpay
- WeChat: Wxpay
Notably, by default, the callback is handled by the "PayNotifyController" in the "Magicodes.Pay.Notify" module. Thus, the callback URL format should be:
{domain}/PayNotify/{tenantId?}/
- Initiate Payment
After configuration, you can use the unified IPayAppService to initiate a payment. Simply inject IPayAppService and call the Pay method. You can also further encapsulate it, as shown in the following code:
public async Task<object> Payment(PaymentInput input)
{
return await _payAppService.Pay(new PayInputBase()
{
Body = $"{input.Name} {input.ChargeProjectName}",
CustomData = input.ToJsonString(),
Key = "payment for fees",
OpenId = input.OpenId,
Subject = input.ChargeProjectName,
TotalAmount = input.Amount,
PayChannel = input.PayChannel
});
}
Using IPayAppService offers several advantages:
- Unified payment (regardless of whether it's Alipay or WeChat across different platforms)
- Automatic recording of transaction logs and related processing
- Custom data is stored based on transaction logs, independent of the payment channel, thus supporting payment channels without business parameters and storing more custom data
Non-ABP Integration
Refer to the encapsulation of the Abp modules or previous code.
Troubleshooting
Check the logs, as most processes have log outputs. During system initialization, registered payment services and callback logic are printed. When a callback occurs, progress is logged. If a payment has been initiated, check the transaction log table in the database to help troubleshoot issues.
Related QQ Groups
Programming Exchange Group<85318032>