Commit 47b4fc68 authored by gdlcf88's avatar gdlcf88

Close #28: Completed WeChatPay payment service provider.

parent 0fba7074
...@@ -10,7 +10,7 @@ namespace EasyAbp.EShop.Payments.WeChatPay ...@@ -10,7 +10,7 @@ namespace EasyAbp.EShop.Payments.WeChatPay
typeof(EShopPaymentsWeChatPayApplicationContractsModule), typeof(EShopPaymentsWeChatPayApplicationContractsModule),
typeof(AbpDddApplicationModule), typeof(AbpDddApplicationModule),
typeof(AbpAutoMapperModule) typeof(AbpAutoMapperModule)
)] )]
public class EShopPaymentsWeChatPayApplicationModule : AbpModule public class EShopPaymentsWeChatPayApplicationModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
......
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Users;
namespace EasyAbp.EShop.Payments.WeChatPay
{
[Dependency(ServiceLifetime.Singleton, TryRegister = true)]
public class ClaimPaymentOpenIdProvider : IPaymentOpenIdProvider
{
public const string OpenIdClaimType = "WeChatOpenId";
private readonly ICurrentUser _currentUser;
public ClaimPaymentOpenIdProvider(ICurrentUser currentUser)
{
_currentUser = currentUser;
}
public Task<string> FindUserOpenIdAsync(Guid userId)
{
return Task.FromResult(userId == _currentUser.Id
? _currentUser.FindClaim(OpenIdClaimType).Value
: throw new NotSupportedException());
}
}
}
\ No newline at end of file
using Volo.Abp.Modularity; using System.Collections.Generic;
using EasyAbp.Abp.WeChat.Pay;
using EasyAbp.Abp.WeChat.Pay.Infrastructure.OptionResolve;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace EasyAbp.EShop.Payments.WeChatPay namespace EasyAbp.EShop.Payments.WeChatPay
{ {
[DependsOn( [DependsOn(
typeof(EShopPaymentsWeChatPayDomainSharedModule) typeof(EShopPaymentsWeChatPayDomainSharedModule),
)] typeof(AbpWeChatPayModule)
)]
public class EShopPaymentsWeChatPayDomainModule : AbpModule public class EShopPaymentsWeChatPayDomainModule : AbpModule
{ {
public override void PostConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpWeChatPayResolveOptions>(options =>
{
options.ResolveContributors.AddFirst(new SettingOptionResolveContributor());
});
}
} }
} }
using System;
using System.Threading.Tasks;
using System.Xml;
using EasyAbp.Abp.WeChat.Pay.Infrastructure;
using EasyAbp.EShop.Payments.Payments;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
namespace EasyAbp.EShop.Payments.WeChatPay
{
public class EShopWeChatPayHandler : IWeChatPayHandler, ITransientDependency
{
private readonly IClock _clock;
private readonly IPaymentRepository _paymentRepository;
public EShopWeChatPayHandler(
IClock clock,
IPaymentRepository paymentRepository)
{
_clock = clock;
_paymentRepository = paymentRepository;
}
public virtual async Task HandleAsync(XmlDocument xmlDocument)
{
if (xmlDocument.Attributes == null || xmlDocument.Attributes["return_code"].Value != "SUCCESS")
{
return;
}
if (xmlDocument.Attributes["result_code"].Value == "SUCCESS")
{
var orderId = Guid.Parse(xmlDocument.Attributes["out_trade_no"].Value);
var payment = await _paymentRepository.GetAsync(orderId);
payment.SetExternalTradingCode(xmlDocument.Attributes["transaction_id"].Value);
payment.CompletePayment(_clock.Now);
await _paymentRepository.UpdateAsync(payment, true);
}
// Todo: record xml
}
}
}
\ No newline at end of file
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="EasyAbp.Abp.WeChat.Pay" Version="1.0.3" />
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="2.7.0" /> <PackageReference Include="Volo.Abp.Ddd.Domain" Version="2.7.0" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Payments\src\EasyAbp.EShop.Payments.Domain\EasyAbp.EShop.Payments.Domain.csproj" /> <ProjectReference Include="..\..\..\EasyAbp.EShop.Payments\src\EasyAbp.EShop.Payments.Domain\EasyAbp.EShop.Payments.Domain.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Payments.WeChatPay.Domain.Shared\EasyAbp.EShop.Payments.WeChatPay.Domain.Shared.csproj" /> <ProjectReference Include="..\EasyAbp.EShop.Payments.WeChatPay.Domain.Shared\EasyAbp.EShop.Payments.WeChatPay.Domain.Shared.csproj" />
......
using System;
using System.Threading.Tasks;
namespace EasyAbp.EShop.Payments.WeChatPay
{
public interface IPaymentOpenIdProvider
{
Task<string> FindUserOpenIdAsync(Guid userId);
}
}
\ No newline at end of file
using System;
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Pay;
using EasyAbp.Abp.WeChat.Pay.Infrastructure.OptionResolve;
using EasyAbp.EShop.Payments.WeChatPay.Settings;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Settings;
namespace EasyAbp.EShop.Payments.WeChatPay
{
public class SettingOptionResolveContributor : IWeChatPayOptionResolveContributor
{
public const string ContributorName = "Setting";
public string Name => ContributorName;
public virtual async Task ResolveAsync(WeChatPayOptionsResolverContext context)
{
var settingProvider = context.ServiceProvider.GetRequiredService<ISettingProvider>();
context.Options = new AbpWeChatPayOptions
{
ApiKey = await settingProvider.GetOrNullAsync(WeChatPaySettings.WeChatPayPaymentMethod.ApiKey),
MchId = await settingProvider.GetOrNullAsync(WeChatPaySettings.WeChatPayPaymentMethod.MchId),
IsSandBox = Convert.ToBoolean(await settingProvider.GetOrNullAsync(WeChatPaySettings.WeChatPayPaymentMethod.IsSandBox)),
NotifyUrl = await settingProvider.GetOrNullAsync(WeChatPaySettings.WeChatPayPaymentMethod.NotifyUrl),
RefundNotifyUrl = await settingProvider.GetOrNullAsync(WeChatPaySettings.WeChatPayPaymentMethod.RefundNotifyUrl),
CertificatePath = await settingProvider.GetOrNullAsync(WeChatPaySettings.WeChatPayPaymentMethod.CertificatePath),
CertificateSecret = await settingProvider.GetOrNullAsync(WeChatPaySettings.WeChatPayPaymentMethod.CertificateSecret)
};
}
}
}
\ No newline at end of file
using Volo.Abp.Settings; using System;
using Microsoft.Extensions.Configuration;
using Volo.Abp.Settings;
namespace EasyAbp.EShop.Payments.WeChatPay.Settings namespace EasyAbp.EShop.Payments.WeChatPay.Settings
{ {
public class WeChatPaySettingDefinitionProvider : SettingDefinitionProvider public class WeChatPaySettingDefinitionProvider : SettingDefinitionProvider
{ {
private readonly IConfiguration _configuration;
public WeChatPaySettingDefinitionProvider(IConfiguration configuration)
{
_configuration = configuration;
}
public override void Define(ISettingDefinitionContext context) public override void Define(ISettingDefinitionContext context)
{ {
/* Define module settings here. /* Define module settings here.
* Use names from WeChatPaySettings class. * Use names from WeChatPaySettings class.
*/ */
context.Add(
new SettingDefinition(WeChatPaySettings.WeChatPayPaymentMethod.MchId),
new SettingDefinition(WeChatPaySettings.WeChatPayPaymentMethod.ApiKey),
new SettingDefinition(WeChatPaySettings.WeChatPayPaymentMethod.IsSandBox, "false"),
new SettingDefinition(WeChatPaySettings.WeChatPayPaymentMethod.NotifyUrl,
_configuration["App:SelfUrl"].EnsureEndsWith('/') + "WeChatPay/Notify"),
new SettingDefinition(WeChatPaySettings.WeChatPayPaymentMethod.RefundNotifyUrl,
_configuration["App:SelfUrl"].EnsureEndsWith('/') + "WeChatPay/RefundNotify"),
new SettingDefinition(WeChatPaySettings.WeChatPayPaymentMethod.CertificatePath),
new SettingDefinition(WeChatPaySettings.WeChatPayPaymentMethod.CertificateSecret)
);
} }
} }
} }
\ No newline at end of file
...@@ -7,5 +7,18 @@ ...@@ -7,5 +7,18 @@
/* Add constants for setting names. Example: /* Add constants for setting names. Example:
* public const string MySettingName = GroupName + ".MySettingName"; * public const string MySettingName = GroupName + ".MySettingName";
*/ */
public static class WeChatPayPaymentMethod
{
private const string PaymentMethodName = GroupName + ".WeChatPay";
public const string MchId = PaymentMethodName + ".MchId";
public const string ApiKey = PaymentMethodName + ".ApiKey";
public const string IsSandBox = PaymentMethodName + ".IsSandBox";
public const string NotifyUrl = PaymentMethodName + ".NotifyUrl";
public const string RefundNotifyUrl = PaymentMethodName + ".RefundNotifyUrl";
public const string CertificatePath = PaymentMethodName + ".CertificatePath";
public const string CertificateSecret = PaymentMethodName + ".CertificateSecret";
}
} }
} }
\ No newline at end of file
using Volo.Abp;
namespace EasyAbp.EShop.Payments.WeChatPay
{
public class UnifiedOrderFailedException : BusinessException
{
public UnifiedOrderFailedException(string returnCode, string returnMsg) : base(
message: $"Unified order failed, return_code: {returnCode}, return_msg: {returnMsg}")
{
}
public UnifiedOrderFailedException(string returnCode, string returnMsg, string errCode, string errCodeDes) :
base(message: $"Unified order failed, return_code: {returnCode}, return_msg: {returnMsg}, err_code: {errCode}, err_code_des: {errCodeDes}")
{
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Pay.Services.Pay;
using EasyAbp.EShop.Payments.Payments;
using EasyAbp.EShop.Payments.WeChatPay.Settings;
using Microsoft.Extensions.Configuration;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace EasyAbp.EShop.Payments.WeChatPay
{
public class WeChatPayPaymentServiceProvider : IPaymentServiceProvider, ITransientDependency
{
private readonly ServiceProviderPayService _serviceProviderPayService;
private readonly IConfiguration _configuration;
private readonly ISettingProvider _settingProvider;
private readonly IPaymentOpenIdProvider _paymentOpenIdProvider;
private readonly IPaymentRepository _paymentRepository;
public const string PaymentMethod = "WeChatPay";
public WeChatPayPaymentServiceProvider(
ServiceProviderPayService serviceProviderPayService,
IConfiguration configuration,
ISettingProvider settingProvider,
IPaymentOpenIdProvider paymentOpenIdProvider,
IPaymentRepository paymentRepository)
{
_serviceProviderPayService = serviceProviderPayService;
_configuration = configuration;
_settingProvider = settingProvider;
_paymentOpenIdProvider = paymentOpenIdProvider;
_paymentRepository = paymentRepository;
}
public async Task<Payment> PayAsync(Payment payment, Dictionary<string, object> inputExtraProperties,
Dictionary<string, object> payeeConfigurations)
{
if (payment.Currency != "CNY")
{
throw new CurrencyNotSupportedException(payment.PaymentMethod, payment.Currency);
}
var payeeAccount = payeeConfigurations.GetOrDefault("PayeeAccount") as string ??
await _settingProvider.GetOrNullAsync(WeChatPaySettings.WeChatPayPaymentMethod
.MchId);
payment.SetPayeeAccount(payeeAccount);
var openId = await _paymentOpenIdProvider.FindUserOpenIdAsync(payment.UserId);
var outTradeNo = payment.Id.ToString("N");
var result = await _serviceProviderPayService.UnifiedOrderAsync(
appId: inputExtraProperties.GetOrDefault("appid") as string,
subAppId: null,
mchId: payment.PayeeAccount,
subMchId: null,
deviceInfo: payeeConfigurations.GetOrDefault("deviceInfo") as string ?? "EasyAbp Payment Service",
body: payeeConfigurations.GetOrDefault("body") as string ?? "EasyAbp Payment Service",
detail: payeeConfigurations.GetOrDefault("detail") as string,
attach: payeeConfigurations.GetOrDefault("attach") as string,
outTradeNo: outTradeNo,
feeType: payment.Currency,
totalFee: ConvertDecimalToWeChatPayFee(payment.ActualPaymentAmount),
billCreateIp: "127.0.0.1",
timeStart: null,
timeExpire: null,
goodsTag: payeeConfigurations.GetOrDefault("goods_tag") as string,
notifyUrl: payeeConfigurations.GetOrDefault("notify_url") as string
?? _configuration["App:SelfUrl"].EnsureEndsWith('/') + "WeChatPay/Notify",
tradeType: inputExtraProperties.GetOrDefault("trade_type") as string,
productId: null,
limitPay: payeeConfigurations.GetOrDefault("limit_pay") as string,
openId: openId,
subOpenId: null,
receipt: payeeConfigurations.GetOrDefault("receipt") as string ?? "N",
sceneInfo: null);
if (result.Attributes == null || result.Attributes["return_code"].Value != "SUCCESS")
{
throw new UnifiedOrderFailedException(result.Attributes?["return_code"].Value, result.Attributes?["return_msg"].Value);
}
if (result.Attributes["result_code"].Value != "SUCCESS")
{
throw new UnifiedOrderFailedException(result.Attributes["return_code"]?.Value,
result.Attributes["return_msg"]?.Value, result.Attributes["err_code_des"]?.Value,
result.Attributes["err_code"]?.Value);
}
payment.SetProperty("trade_type", result.Attributes["trade_type"]);
payment.SetProperty("prepay_id", result.Attributes["prepay_id"]);
payment.SetProperty("code_url", result.Attributes["code_url"]);
return await _paymentRepository.UpdateAsync(payment, true);
}
private static int ConvertDecimalToWeChatPayFee(decimal paymentActualPaymentAmount)
{
return Convert.ToInt32(decimal.Round(paymentActualPaymentAmount, 2, MidpointRounding.AwayFromZero) * 100);
}
}
}
\ No newline at end of file
using Localization.Resources.AbpUi; using EasyAbp.Abp.WeChat.Pay.HttpApi;
using Localization.Resources.AbpUi;
using EasyAbp.EShop.Payments.WeChatPay.Localization; using EasyAbp.EShop.Payments.WeChatPay.Localization;
using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Localization; using Volo.Abp.Localization;
...@@ -9,7 +10,9 @@ namespace EasyAbp.EShop.Payments.WeChatPay ...@@ -9,7 +10,9 @@ namespace EasyAbp.EShop.Payments.WeChatPay
{ {
[DependsOn( [DependsOn(
typeof(EShopPaymentsWeChatPayApplicationContractsModule), typeof(EShopPaymentsWeChatPayApplicationContractsModule),
typeof(AbpAspNetCoreMvcModule))] typeof(AbpAspNetCoreMvcModule),
typeof(AbpWeChatPayHttpApiModule)
)]
public class EShopPaymentsWeChatPayHttpApiModule : AbpModule public class EShopPaymentsWeChatPayHttpApiModule : AbpModule
{ {
public override void PreConfigureServices(ServiceConfigurationContext context) public override void PreConfigureServices(ServiceConfigurationContext context)
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="EasyAbp.Abp.WeChat.Pay.HttpApi" Version="1.0.3" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="2.7.0" /> <PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="2.7.0" />
<ProjectReference Include="..\EasyAbp.EShop.Payments.WeChatPay.Application.Contracts\EasyAbp.EShop.Payments.WeChatPay.Application.Contracts.csproj" /> <ProjectReference Include="..\EasyAbp.EShop.Payments.WeChatPay.Application.Contracts\EasyAbp.EShop.Payments.WeChatPay.Application.Contracts.csproj" />
</ItemGroup> </ItemGroup>
......
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using EasyAbp.EShop.Orders.Orders; using EasyAbp.EShop.Orders.Orders;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
...@@ -39,6 +40,20 @@ namespace EasyAbp.EShop.Payments.Payments ...@@ -39,6 +40,20 @@ namespace EasyAbp.EShop.Payments.Payments
return false; return false;
} }
var inputStoreIdString = inputExtraProperties.GetOrDefault("StoreId") as string;
if (order.StoreId.ToString() != inputStoreIdString)
{
if (inputStoreIdString == null)
{
inputExtraProperties.Add("StoreId", order.StoreId);
}
else
{
return false;
}
}
return order.OrderStatus == OrderStatus.Pending; return order.OrderStatus == OrderStatus.Pending;
} }
} }
......
...@@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection; ...@@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.Abp.Users;
namespace EasyAbp.EShop.Payments.Payments namespace EasyAbp.EShop.Payments.Payments
{ {
...@@ -31,15 +32,12 @@ namespace EasyAbp.EShop.Payments.Payments ...@@ -31,15 +32,12 @@ namespace EasyAbp.EShop.Payments.Payments
{ {
await CheckCreatePolicyAsync(); await CheckCreatePolicyAsync();
var providerType = await _paymentServiceResolver.GetProviderTypeOrDefaultAsync(input.PaymentMethod); var providerType = await _paymentServiceResolver.GetProviderTypeOrDefaultAsync(input.PaymentMethod) ??
throw new UnknownPaymentMethodException(input.PaymentMethod);
var provider = ServiceProvider.GetService(providerType) as IPaymentServiceProvider;
var provider = ServiceProvider.GetService(providerType) as IPaymentServiceProvider ??
throw new UnknownPaymentMethodException(input.PaymentMethod);
if (providerType == null || provider == null)
{
throw new UnknownPaymentMethodException(input.PaymentMethod);
}
var paymentItems = input.PaymentItems.Select(inputPaymentItem => var paymentItems = input.PaymentItems.Select(inputPaymentItem =>
new PaymentItem(GuidGenerator.Create(), inputPaymentItem.ItemType, inputPaymentItem.ItemKey, new PaymentItem(GuidGenerator.Create(), inputPaymentItem.ItemType, inputPaymentItem.ItemKey,
inputPaymentItem.Currency, inputPaymentItem.OriginalPaymentAmount)).ToList(); inputPaymentItem.Currency, inputPaymentItem.OriginalPaymentAmount)).ToList();
...@@ -49,32 +47,38 @@ namespace EasyAbp.EShop.Payments.Payments ...@@ -49,32 +47,38 @@ namespace EasyAbp.EShop.Payments.Payments
throw new MultiCurrencyNotSupportedException(); throw new MultiCurrencyNotSupportedException();
} }
var payment = new Payment(GuidGenerator.Create(), CurrentTenant.Id, input.PaymentMethod, input.Currency, var payment = new Payment(GuidGenerator.Create(), CurrentTenant.Id, CurrentUser.GetId(),
paymentItems.Select(item => item.OriginalPaymentAmount).Sum(), paymentItems); input.PaymentMethod, input.Currency, paymentItems.Select(item => item.OriginalPaymentAmount).Sum(),
paymentItems);
await Repository.InsertAsync(payment, autoSave: true); await Repository.InsertAsync(payment, autoSave: true);
await CheckPayableAsync(payment, input.ExtraProperties); await CheckPayableAsync(payment, input.ExtraProperties);
await FillPayeeAccountAsync(payment, input.ExtraProperties);
var payeeConfigurations = await GetPayeeConfigurationsAsync(payment, input.ExtraProperties);
// Todo: payment discount // Todo: payment discount
await provider.PayAsync(payment); await provider.PayAsync(payment, input.ExtraProperties, payeeConfigurations);
return MapToGetOutputDto(payment); return MapToGetOutputDto(payment);
} }
protected virtual async Task FillPayeeAccountAsync(Payment payment, Dictionary<string, object> inputExtraProperties) protected virtual Task<Dictionary<string, object>> GetPayeeConfigurationsAsync(Payment payment,
Dictionary<string, object> inputExtraProperties)
{ {
payment.SetPayeeAccount( // Todo: use payee configurations provider.
await _paymentPayeeAccountProvider.GetPayeeAccountAsync(payment, inputExtraProperties)); // Todo: get store side payee configurations.
var payeeConfigurations = new Dictionary<string, object>();
return Task.FromResult(payeeConfigurations);
} }
protected virtual async Task CheckPayableAsync(Payment payment, Dictionary<string, object> inputExtraProperties) protected virtual async Task CheckPayableAsync(Payment payment, Dictionary<string, object> inputExtraProperties)
{ {
var itemSet = new HashSet<PaymentItem>(payment.PaymentItems); var itemSet = new HashSet<PaymentItem>(payment.PaymentItems);
foreach (var authorizer in ServiceProvider.GetServices<IPaymentAuthorizer>()) foreach (var authorizer in ServiceProvider.GetServices<IPaymentAuthorizer>())
{ {
foreach (var item in itemSet.ToList()) foreach (var item in itemSet.ToList())
......
using EasyAbp.EShop.Payments.Payments; using EasyAbp.EShop.Payments.Payments;
using EasyAbp.EShop.Stores; using EasyAbp.EShop.Stores;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.AutoMapper; using Volo.Abp.AutoMapper;
using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Distributed;
...@@ -15,6 +16,11 @@ namespace EasyAbp.EShop.Payments ...@@ -15,6 +16,11 @@ namespace EasyAbp.EShop.Payments
)] )]
public class EShopPaymentsDomainModule : AbpModule public class EShopPaymentsDomainModule : AbpModule
{ {
public override void PostConfigureServices(ServiceConfigurationContext context)
{
context.Services.TryAddTransient<IPaymentServiceProvider, FreePaymentServiceProvider>();
}
public override void OnApplicationInitialization(ApplicationInitializationContext context) public override void OnApplicationInitialization(ApplicationInitializationContext context)
{ {
var resolver = context.ServiceProvider.GetService<IPaymentServiceResolver>(); var resolver = context.ServiceProvider.GetService<IPaymentServiceResolver>();
......
using System;
using Volo.Abp;
namespace EasyAbp.EShop.Payments.Payments
{
public class CurrencyNotSupportedException : BusinessException
{
public CurrencyNotSupportedException(string paymentMethod, string currency) : base(
message: $"Payment method {paymentMethod} does not support currency: {currency}")
{
}
public CurrencyNotSupportedException(string paymentMethod, string currency, Guid storeId) : base(
message: $"Payment method {paymentMethod} in store {storeId} does not support currency: {currency}")
{
}
}
}
\ No newline at end of file
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
...@@ -6,7 +7,8 @@ using Volo.Abp.Timing; ...@@ -6,7 +7,8 @@ using Volo.Abp.Timing;
namespace EasyAbp.EShop.Payments.Payments namespace EasyAbp.EShop.Payments.Payments
{ {
[Dependency(ServiceLifetime.Transient, TryRegister = true)] // [ExposeServices(typeof(IPaymentRepository))]
// [Dependency(ServiceLifetime.Transient, TryRegister = true)]
public class FreePaymentServiceProvider : IPaymentServiceProvider public class FreePaymentServiceProvider : IPaymentServiceProvider
{ {
private readonly IClock _clock; private readonly IClock _clock;
...@@ -20,13 +22,16 @@ namespace EasyAbp.EShop.Payments.Payments ...@@ -20,13 +22,16 @@ namespace EasyAbp.EShop.Payments.Payments
_clock = clock; _clock = clock;
_paymentRepository = paymentRepository; _paymentRepository = paymentRepository;
} }
public async Task<Payment> PayAsync(Payment payment, Dictionary<string, object> extraProperties = null) public async Task<Payment> PayAsync(Payment payment, Dictionary<string, object> inputExtraProperties,
Dictionary<string, object> payeeConfigurations)
{ {
payment.SetExternalTradingCode(payment.Id.ToString()); payment.SetPayeeAccount("None");
payment.SetExternalTradingCode(payment.Id.ToString());
payment.CompletePayment(_clock.Now); payment.CompletePayment(_clock.Now);
return await _paymentRepository.UpdateAsync(payment, true); return await _paymentRepository.UpdateAsync(payment, true);
} }
} }
......
...@@ -6,6 +6,7 @@ namespace EasyAbp.EShop.Payments.Payments ...@@ -6,6 +6,7 @@ namespace EasyAbp.EShop.Payments.Payments
{ {
public interface IPaymentServiceProvider public interface IPaymentServiceProvider
{ {
Task<Payment> PayAsync(Payment payment, Dictionary<string, object> extraProperties = null); Task<Payment> PayAsync(Payment payment, Dictionary<string, object> inputExtraProperties,
Dictionary<string, object> payeeConfigurations);
} }
} }
\ No newline at end of file
using Volo.Abp;
namespace EasyAbp.EShop.Payments.Payments
{
public class PayeeConfigurationMissingValueException : BusinessException
{
public PayeeConfigurationMissingValueException(string paymentMethod, string configurationKey) : base(
message: $"Payment method ({paymentMethod}) is missing configuration: {configurationKey}.")
{
}
}
}
\ No newline at end of file
...@@ -10,6 +10,8 @@ namespace EasyAbp.EShop.Payments.Payments ...@@ -10,6 +10,8 @@ namespace EasyAbp.EShop.Payments.Payments
{ {
public virtual Guid? TenantId { get; protected set; } public virtual Guid? TenantId { get; protected set; }
public virtual Guid UserId { get; protected set; }
[NotNull] [NotNull]
public virtual string PaymentMethod { get; protected set; } public virtual string PaymentMethod { get; protected set; }
...@@ -42,6 +44,7 @@ namespace EasyAbp.EShop.Payments.Payments ...@@ -42,6 +44,7 @@ namespace EasyAbp.EShop.Payments.Payments
public Payment( public Payment(
Guid id, Guid id,
Guid? tenantId, Guid? tenantId,
Guid userId,
[NotNull] string paymentMethod, [NotNull] string paymentMethod,
[NotNull] string currency, [NotNull] string currency,
decimal originalPaymentAmount, decimal originalPaymentAmount,
...@@ -49,10 +52,13 @@ namespace EasyAbp.EShop.Payments.Payments ...@@ -49,10 +52,13 @@ namespace EasyAbp.EShop.Payments.Payments
) :base(id) ) :base(id)
{ {
TenantId = tenantId; TenantId = tenantId;
UserId = userId;
PaymentMethod = paymentMethod; PaymentMethod = paymentMethod;
Currency = currency; Currency = currency;
OriginalPaymentAmount = originalPaymentAmount; OriginalPaymentAmount = originalPaymentAmount;
ActualPaymentAmount = originalPaymentAmount;
PaymentItems = paymentItems; PaymentItems = paymentItems;
RefundAmount = 0;
} }
public void SetPayeeAccount([NotNull] string payeeAccount) public void SetPayeeAccount([NotNull] string payeeAccount)
...@@ -67,16 +73,12 @@ namespace EasyAbp.EShop.Payments.Payments ...@@ -67,16 +73,12 @@ namespace EasyAbp.EShop.Payments.Payments
ExternalTradingCode = externalTradingCode; ExternalTradingCode = externalTradingCode;
} }
public void SetPaymentDiscount( public void SetPaymentDiscount(decimal paymentDiscount)
decimal paymentDiscount,
decimal actualPaymentAmount,
decimal refundAmount)
{ {
CheckPaymentIsNotCompleted(); CheckPaymentIsNotCompleted();
PaymentDiscount = paymentDiscount; PaymentDiscount = paymentDiscount;
ActualPaymentAmount = actualPaymentAmount; ActualPaymentAmount -= paymentDiscount;
RefundAmount = refundAmount;
} }
public void CompletePayment(DateTime completionTime) public void CompletePayment(DateTime completionTime)
......
...@@ -6,7 +6,7 @@ namespace EasyAbp.EShop.Payments.Payments ...@@ -6,7 +6,7 @@ namespace EasyAbp.EShop.Payments.Payments
public class PaymentHasAlreadyBeenCompletedException : BusinessException public class PaymentHasAlreadyBeenCompletedException : BusinessException
{ {
public PaymentHasAlreadyBeenCompletedException(Guid id) : base( public PaymentHasAlreadyBeenCompletedException(Guid id) : base(
message: $"Payment({id}) has already been completed.") message: $"Payment ({id}) has already been completed.")
{ {
} }
} }
......
using EasyAbp.EShop.Baskets; using EasyAbp.EShop.Baskets;
using EasyAbp.EShop.Orders; using EasyAbp.EShop.Orders;
using EasyAbp.EShop.Payments; using EasyAbp.EShop.Payments;
using EasyAbp.EShop.Payments.Payments;
using EasyAbp.EShop.Payments.WeChatPay; using EasyAbp.EShop.Payments.WeChatPay;
using EasyAbp.EShop.Products; using EasyAbp.EShop.Products;
using EasyAbp.EShop.Stores; using EasyAbp.EShop.Stores;
using EasyMall.MultiTenancy; using EasyMall.MultiTenancy;
using EasyMall.ObjectExtending; using EasyMall.ObjectExtending;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.AuditLogging; using Volo.Abp.AuditLogging;
using Volo.Abp.BackgroundJobs; using Volo.Abp.BackgroundJobs;
using Volo.Abp.FeatureManagement; using Volo.Abp.FeatureManagement;
...@@ -52,5 +55,12 @@ namespace EasyMall ...@@ -52,5 +55,12 @@ namespace EasyMall
options.IsEnabled = MultiTenancyConsts.IsEnabled; options.IsEnabled = MultiTenancyConsts.IsEnabled;
}); });
} }
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var resolver = context.ServiceProvider.GetService<IPaymentServiceResolver>();
resolver.TryRegisterProviderAsync(WeChatPayPaymentServiceProvider.PaymentMethod, typeof(WeChatPayPaymentServiceProvider));
}
} }
} }
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace EasyMall.Migrations
{
public partial class AddedUserIdToPayment : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "UserId",
table: "PaymentsPayments",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UserId",
table: "PaymentsPayments");
}
}
}
...@@ -279,6 +279,9 @@ namespace EasyMall.Migrations ...@@ -279,6 +279,9 @@ namespace EasyMall.Migrations
.HasColumnName("TenantId") .HasColumnName("TenantId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<Guid>("UserId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("PaymentsPayments"); b.ToTable("PaymentsPayments");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment