Commit 45386763 authored by gdlcf88's avatar gdlcf88

Complete basic payment feature

parent 01d73b8a
......@@ -10,6 +10,7 @@
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="2.5.0" />
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="2.5.0" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Payments\src\EasyAbp.EShop.Payments.Domain.Shared\EasyAbp.EShop.Payments.Domain.Shared.csproj" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Products\src\EasyAbp.EShop.Products.Domain.Shared\EasyAbp.EShop.Products.Domain.Shared.csproj" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Stores\src\EasyAbp.EShop.Stores.Domain.Shared\EasyAbp.EShop.Stores.Domain.Shared.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Orders.Domain.Shared\EasyAbp.EShop.Orders.Domain.Shared.csproj" />
......
......@@ -26,7 +26,6 @@ namespace EasyAbp.EShop.Orders
Configure<AbpDistributedEventBusOptions>(options =>
{
options.EtoMappings.Add<Order, OrderEto>(typeof(EShopOrdersDomainModule));
options.EtoMappings.Add<OrderLine, OrderLineEto>(typeof(EShopOrdersDomainModule));
});
}
}
......
using EasyAbp.EShop.Payments.Payments;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus.Distributed;
namespace EasyAbp.EShop.Orders.Orders
{
public interface IOrderPaymentCompletedEventHandler : IDistributedEventHandler<EntityUpdatedEto<PaymentEto>>
{
}
}
\ No newline at end of file
using EasyAbp.EShop.Payments.Payments;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus.Distributed;
namespace EasyAbp.EShop.Orders.Orders
{
public interface IOrderPaymentCreatedEventHandler : IDistributedEventHandler<EntityCreatedEto<PaymentEto>>
{
}
}
\ No newline at end of file
......@@ -34,6 +34,8 @@ namespace EasyAbp.EShop.Orders.Orders
[CanBeNull]
public virtual string StaffRemark { get; protected set; }
public virtual Guid? PaymentId { get; protected set; }
public virtual DateTime? PaidTime { get; protected set; }
public virtual DateTime? CompletionTime { get; protected set; }
......@@ -92,5 +94,25 @@ namespace EasyAbp.EShop.Orders.Orders
{
ReducedInventoryAfterPaymentTime = time;
}
public void SetPaymentId(Guid? paymentId)
{
PaymentId = paymentId;
}
public void SetPaidTime(DateTime? paidTime)
{
PaidTime = paidTime;
}
public void SetOrderStatus(OrderStatus orderStatus)
{
OrderStatus = orderStatus;
}
public void SetCompletionTime(DateTime? completionTime)
{
CompletionTime = completionTime;
}
}
}
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Payments.Payments;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Timing;
using Volo.Abp.Uow;
namespace EasyAbp.EShop.Orders.Orders
{
public class OrderPaymentCompletedEventHandler : IOrderPaymentCompletedEventHandler, ITransientDependency
{
private readonly IClock _clock;
private readonly IOrderRepository _orderRepository;
public OrderPaymentCompletedEventHandler(
IClock clock,
IOrderRepository orderRepository)
{
_clock = clock;
_orderRepository = orderRepository;
}
[UnitOfWork(true)]
public virtual async Task HandleEventAsync(EntityUpdatedEto<PaymentEto> eventData)
{
if (!eventData.Entity.CompletionTime.HasValue)
{
return;
}
foreach (var item in eventData.Entity.PaymentItems.Where(item => item.ItemType == "EasyAbpEShopOrder"))
{
var order = await _orderRepository.FindAsync(item.ItemKey);
if (order == null || order.PaidTime.HasValue)
{
continue;
}
order.SetPaidTime(_clock.Now);
order.SetOrderStatus(OrderStatus.Processing);
await _orderRepository.UpdateAsync(order, true);
}
}
}
}
\ No newline at end of file
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Payments.Payments;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Uow;
namespace EasyAbp.EShop.Orders.Orders
{
public class OrderPaymentCreatedEventHandler : IOrderPaymentCreatedEventHandler, ITransientDependency
{
private readonly IOrderRepository _orderRepository;
public OrderPaymentCreatedEventHandler(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
[UnitOfWork(true)]
public virtual async Task HandleEventAsync(EntityCreatedEto<PaymentEto> eventData)
{
foreach (var item in eventData.Entity.PaymentItems.Where(item => item.ItemType == "EasyAbpEShopOrder"))
{
var order = await _orderRepository.FindAsync(item.ItemKey);
if (order == null || order.PaymentId.HasValue)
{
continue;
}
order.SetPaymentId(eventData.Entity.Id);
await _orderRepository.UpdateAsync(order, true);
}
}
}
}
\ No newline at end of file
$(function () {
var l = abp.localization.getResource('Orders');
var l = abp.localization.getResource('EasyAbpEShopOrders');
var service = easyAbp.eShop.orders.orders.order;
......@@ -21,7 +21,7 @@ $(function () {
{
text: l('Detail'),
action: function (data) {
editModal.open({ id: data.record.id });
detailModal.open({ id: data.record.id });
}
}
]
......@@ -32,17 +32,4 @@ $(function () {
{ data: "totalPrice" },
]
}));
createModal.onResult(function () {
dataTable.ajax.reload();
});
editModal.onResult(function () {
dataTable.ajax.reload();
});
$('#NewOrderButton').click(function (e) {
e.preventDefault();
createModal.open();
});
});
\ No newline at end of file
......@@ -4,7 +4,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>EasyAbp.EShop.Payments</RootNamespace>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
......
......@@ -8,7 +8,17 @@ namespace EasyAbp.EShop.Payments.Authorization
{
public override void Define(IPermissionDefinitionContext context)
{
//var moduleGroup = context.AddGroup(PaymentsPermissions.GroupName, L("Permission:Payments"));
var moduleGroup = context.AddGroup(PaymentsPermissions.GroupName, L("Permission:Payments"));
var payment = moduleGroup.AddPermission(PaymentsPermissions.Payments.Default, L("Permission:Payment"));
payment.AddChild(PaymentsPermissions.Payments.Manage, L("Permission:Manage"));
payment.AddChild(PaymentsPermissions.Payments.CrossStore, L("Permission:CrossStore"));
payment.AddChild(PaymentsPermissions.Payments.Create, L("Permission:Create"));
var refund = moduleGroup.AddPermission(PaymentsPermissions.Refunds.Default, L("Permission:Refund"));
refund.AddChild(PaymentsPermissions.Refunds.Manage, L("Permission:Manage"));
refund.AddChild(PaymentsPermissions.Refunds.CrossStore, L("Permission:CrossStore"));
refund.AddChild(PaymentsPermissions.Refunds.Create, L("Permission:Create"));
}
private static LocalizableString L(string name)
......
......@@ -10,5 +10,21 @@ namespace EasyAbp.EShop.Payments.Authorization
{
return ReflectionHelper.GetPublicConstantsRecursively(typeof(PaymentsPermissions));
}
public class Payments
{
public const string Default = GroupName + ".Payment";
public const string Manage = Default + ".Manage";
public const string CrossStore = Default + ".CrossStore";
public const string Create = Default + ".Create";
}
public class Refunds
{
public const string Default = GroupName + ".Refund";
public const string Manage = Default + ".Manage";
public const string CrossStore = Default + ".CrossStore";
public const string Create = Default + ".Create";
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace EasyAbp.EShop.Payments.Payments.Dtos
{
public class CreatePaymentDto
{
[DisplayName("PaymentPaymentMethod")]
public string PaymentMethod { get; set; }
[DisplayName("PaymentCurrency")]
public string Currency { get; set; }
[DisplayName("PaymentExtraProperties")]
public Dictionary<string, object> ExtraProperties { get; set; }
[DisplayName("PaymentItem")]
public List<CreatePaymentItemDto> PaymentItems { get; set; }
}
}
\ No newline at end of file
using System;
using System.ComponentModel;
namespace EasyAbp.EShop.Payments.Payments.Dtos
{
public class CreatePaymentItemDto
{
[DisplayName("PaymentItemItemType")]
public string ItemType { get; set; }
[DisplayName("PaymentItemItemKey")]
public Guid ItemKey { get; set; }
[DisplayName("PaymentItemCurrency")]
public string Currency { get; set; }
[DisplayName("PaymentItemOriginalPaymentAmount")]
public decimal OriginalPaymentAmount { get; set; }
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Payments.Payments.Dtos
{
public class PaymentDto : ExtensibleFullAuditedEntityDto<Guid>
{
public string PaymentMethod { get; set; }
public string ExternalTradingCode { get; set; }
public string Currency { get; set; }
public decimal OriginalPaymentAmount { get; set; }
public decimal PaymentDiscount { get; set; }
public decimal ActualPaymentAmount { get; set; }
public decimal RefundAmount { get; set; }
public DateTime? CompletionTime { get; set; }
public List<PaymentItemDto> PaymentItems { get; set; }
}
}
\ No newline at end of file
using System;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Payments.Payments.Dtos
{
public class PaymentItemDto : FullAuditedEntityDto<Guid>
{
public string ItemType { get; set; }
public Guid ItemKey { get; set; }
public string Currency { get; set; }
public decimal OriginalPaymentAmount { get; set; }
public decimal PaymentDiscount { get; set; }
public decimal ActualPaymentAmount { get; set; }
public decimal RefundAmount { get; set; }
}
}
\ No newline at end of file
using System;
using EasyAbp.EShop.Payments.Payments.Dtos;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace EasyAbp.EShop.Payments.Payments
{
public interface IPaymentAppService :
ICrudAppService<
PaymentDto,
Guid,
PagedAndSortedResultRequestDto,
CreatePaymentDto,
object>
{
}
}
\ No newline at end of file
using System;
using System.ComponentModel;
namespace EasyAbp.EShop.Payments.Refunds.Dtos
{
public class CreateRefundDto
{
[DisplayName("RefundStoreId")]
public Guid StoreId { get; set; }
[DisplayName("RefundOrderId")]
public Guid OrderId { get; set; }
[DisplayName("RefundRefundPaymentMethod")]
public string RefundPaymentMethod { get; set; }
[DisplayName("RefundExternalTradingCode")]
public string ExternalTradingCode { get; set; }
[DisplayName("RefundCurrency")]
public string Currency { get; set; }
[DisplayName("RefundRefundAmount")]
public decimal RefundAmount { get; set; }
[DisplayName("RefundCustomerRemark")]
public string CustomerRemark { get; set; }
[DisplayName("RefundStaffRemark")]
public string StaffRemark { get; set; }
}
}
\ No newline at end of file
using System;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Payments.Refunds.Dtos
{
public class RefundDto : FullAuditedEntityDto<Guid>
{
public Guid StoreId { get; set; }
public Guid OrderId { get; set; }
public string RefundPaymentMethod { get; set; }
public string ExternalTradingCode { get; set; }
public string Currency { get; set; }
public decimal RefundAmount { get; set; }
public string CustomerRemark { get; set; }
public string StaffRemark { get; set; }
}
}
\ No newline at end of file
using System;
using EasyAbp.EShop.Payments.Refunds.Dtos;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace EasyAbp.EShop.Payments.Refunds
{
public interface IRefundAppService :
ICrudAppService<
RefundDto,
Guid,
PagedAndSortedResultRequestDto,
CreateRefundDto,
object>
{
}
}
\ No newline at end of file
......@@ -4,12 +4,13 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>EasyAbp.EShop.Payments</RootNamespace>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="2.5.0" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="2.5.0" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Orders\src\EasyAbp.EShop.Orders.Application.Contracts\EasyAbp.EShop.Orders.Application.Contracts.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Payments.Application.Contracts\EasyAbp.EShop.Payments.Application.Contracts.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Payments.Domain\EasyAbp.EShop.Payments.Domain.csproj" />
</ItemGroup>
......
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyAbp.EShop.Orders.Orders;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Users;
namespace EasyAbp.EShop.Payments.Payments
{
public class EShopOrderPaymentAuthorizer : IPaymentAuthorizer, ITransientDependency
{
private readonly ICurrentUser _currentUser;
private readonly IOrderAppService _orderAppService;
public EShopOrderPaymentAuthorizer(
ICurrentUser currentUser,
IOrderAppService orderAppService)
{
_currentUser = currentUser;
_orderAppService = orderAppService;
}
public virtual async Task<bool> IsPaymentItemAllowedAsync(Payment payment, PaymentItem paymentItem,
Dictionary<string, object> inputExtraProperties)
{
if (paymentItem.ItemType != "EasyAbpEShopOrder")
{
return false;
}
var order = await _orderAppService.GetAsync(paymentItem.ItemKey);
if (order.CustomerUserId != _currentUser.Id)
{
return false;
}
if (order.TotalPrice != paymentItem.OriginalPaymentAmount)
{
return false;
}
return order.OrderStatus == OrderStatus.Pending;
}
}
}
\ No newline at end of file
using System.Collections.Generic;
using System.Threading.Tasks;
namespace EasyAbp.EShop.Payments.Payments
{
public interface IPaymentAuthorizer
{
Task<bool> IsPaymentItemAllowedAsync(Payment payment, PaymentItem paymentItem,
Dictionary<string, object> inputExtraProperties);
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using Volo.Abp;
namespace EasyAbp.EShop.Payments.Payments
{
public class MultiCurrencyNotSupportedException : BusinessException
{
public MultiCurrencyNotSupportedException() : base(message: $"Multi-currency is not supported.")
{
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Payments.Payments.Dtos;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace EasyAbp.EShop.Payments.Payments
{
public class PaymentAppService : CrudAppService<Payment, PaymentDto, Guid, PagedAndSortedResultRequestDto, CreatePaymentDto, object>,
IPaymentAppService
{
private readonly IPaymentPayeeAccountProvider _paymentPayeeAccountProvider;
private readonly IPaymentServiceResolver _paymentServiceResolver;
private readonly IPaymentRepository _repository;
public PaymentAppService(
IPaymentPayeeAccountProvider paymentPayeeAccountProvider,
IPaymentServiceResolver paymentServiceResolver,
IPaymentRepository repository) : base(repository)
{
_paymentPayeeAccountProvider = paymentPayeeAccountProvider;
_paymentServiceResolver = paymentServiceResolver;
_repository = repository;
}
public override async Task<PaymentDto> CreateAsync(CreatePaymentDto input)
{
await CheckCreatePolicyAsync();
var providerType = await _paymentServiceResolver.GetProviderTypeOrDefaultAsync(input.PaymentMethod);
var provider = ServiceProvider.GetService(providerType) as IPaymentServiceProvider;
if (providerType == null || provider == null)
{
throw new UnknownPaymentMethodException(input.PaymentMethod);
}
var paymentItems = input.PaymentItems.Select(inputPaymentItem =>
new PaymentItem(GuidGenerator.Create(), inputPaymentItem.ItemType, inputPaymentItem.ItemKey,
inputPaymentItem.Currency, inputPaymentItem.OriginalPaymentAmount)).ToList();
if (paymentItems.Select(item => item.Currency).Any(c => c != input.Currency))
{
throw new MultiCurrencyNotSupportedException();
}
var payment = new Payment(GuidGenerator.Create(), CurrentTenant.Id, input.PaymentMethod, input.Currency,
paymentItems.Select(item => item.OriginalPaymentAmount).Sum(), paymentItems);
await Repository.InsertAsync(payment, autoSave: true);
await CheckPayableAsync(payment, input.ExtraProperties);
await FillPayeeAccountAsync(payment, input.ExtraProperties);
// Todo: payment discount
await provider.PayAsync(payment);
return MapToGetOutputDto(payment);
}
protected virtual async Task FillPayeeAccountAsync(Payment payment, Dictionary<string, object> inputExtraProperties)
{
payment.SetPayeeAccount(
await _paymentPayeeAccountProvider.GetPayeeAccountAsync(payment, inputExtraProperties));
}
protected virtual async Task CheckPayableAsync(Payment payment, Dictionary<string, object> inputExtraProperties)
{
var itemSet = new HashSet<PaymentItem>(payment.PaymentItems);
foreach (var authorizer in ServiceProvider.GetServices<IPaymentAuthorizer>())
{
foreach (var item in itemSet.ToList())
{
if (await authorizer.IsPaymentItemAllowedAsync(payment, item, inputExtraProperties))
{
itemSet.Remove(item);
}
}
}
if (!itemSet.IsNullOrEmpty())
{
throw new PaymentItemNotPayableException(itemSet.Select(item => item.ItemKey).ToList());
}
}
[RemoteService(false)]
public override Task<PaymentDto> UpdateAsync(Guid id, object input)
{
throw new NotSupportedException();
}
[RemoteService(false)]
public override Task DeleteAsync(Guid id)
{
throw new NotSupportedException();
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using Volo.Abp;
namespace EasyAbp.EShop.Payments.Payments
{
public class PaymentItemNotPayableException : BusinessException
{
public PaymentItemNotPayableException(Guid itemKey) : base(
message: $"Payment item ({itemKey}) is not payable")
{
}
public PaymentItemNotPayableException(IEnumerable<Guid> itemKeys) : base(
message: $"Payment item ({itemKeys.JoinAsString(", ")}) is not payable")
{
}
}
}
\ No newline at end of file
using EasyAbp.EShop.Payments.Payments;
using EasyAbp.EShop.Payments.Payments.Dtos;
using EasyAbp.EShop.Payments.Refunds;
using EasyAbp.EShop.Payments.Refunds.Dtos;
using AutoMapper;
using Volo.Abp.AutoMapper;
namespace EasyAbp.EShop.Payments
{
public class PaymentsApplicationAutoMapperProfile : Profile
{
public PaymentsApplicationAutoMapperProfile()
{
/* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */
CreateMap<Payment, PaymentDto>();
CreateMap<Refund, RefundDto>();
CreateMap<CreateRefundDto, Refund>(MemberList.Source);
CreateMap<PaymentItem, PaymentItemDto>();
}
}
}
using System;
using EasyAbp.EShop.Payments.Refunds.Dtos;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace EasyAbp.EShop.Payments.Refunds
{
public class RefundAppService : CrudAppService<Refund, RefundDto, Guid, PagedAndSortedResultRequestDto, CreateRefundDto, object>,
IRefundAppService
{
private readonly IRefundRepository _repository;
public RefundAppService(IRefundRepository repository) : base(repository)
{
_repository = repository;
}
}
}
\ No newline at end of file
......@@ -4,7 +4,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>EasyAbp.EShop.Payments</RootNamespace>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
......@@ -12,8 +12,8 @@
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\Payments\*.json" />
<Content Remove="Localization\Payments\*.json" />
<EmbeddedResource Include="EasyAbp\EShop\Payments\Localization\Payments\*.json" />
<Content Remove="EasyAbp\EShop\Payments\Localization\Payments\*.json" />
</ItemGroup>
</Project>
......@@ -17,7 +17,7 @@ namespace EasyAbp.EShop.Payments
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<EShopPaymentsDomainSharedModule>("EasyAbp.EShop.Payments");
options.FileSets.AddEmbedded<EShopPaymentsDomainSharedModule>();
});
Configure<AbpLocalizationOptions>(options =>
......@@ -25,12 +25,12 @@ namespace EasyAbp.EShop.Payments
options.Resources
.Add<PaymentsResource>("en")
.AddBaseTypes(typeof(AbpValidationResource))
.AddVirtualJson("/Localization/Payments");
.AddVirtualJson("/EasyAbp/EShop/Payments/Localization/Payments");
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace("Payments", typeof(PaymentsResource));
options.MapCodeNamespace("EasyAbp.EShop.Payments", typeof(PaymentsResource));
});
}
}
......
{
"culture": "cs",
"texts": {
"Menu:Payment": "MenuPayment",
"Payment": "Payment",
"PaymentTenantId": "PaymentTenantId",
"PaymentPaymentMethod": "PaymentPaymentMethod",
"PaymentExternalTradingCode": "PaymentExternalTradingCode",
"PaymentCurrency": "PaymentCurrency",
"PaymentOriginalPaymentAmount": "PaymentOriginalPaymentAmount",
"PaymentExtraProperties": "PaymentExtraProperties",
"PaymentPaymentDiscount": "PaymentPaymentDiscount",
"PaymentActualPaymentAmount": "PaymentActualPaymentAmount",
"PaymentRefundAmount": "PaymentRefundAmount",
"PaymentCompletionTime": "PaymentCompletionTime",
"CreatePayment": "CreatePayment",
"EditPayment": "EditPayment",
"PaymentDeletionConfirmationMessage": "Are you sure to delete the payment {0}?",
"SuccessfullyDeleted": "Successfully deleted",
"Menu:Refund": "MenuRefund",
"Refund": "Refund",
"RefundTenantId": "RefundTenantId",
"RefundStoreId": "RefundStoreId",
"RefundOrderId": "RefundOrderId",
"RefundRefundPaymentMethod": "RefundRefundPaymentMethod",
"RefundExternalTradingCode": "RefundExternalTradingCode",
"RefundCurrency": "RefundCurrency",
"RefundRefundAmount": "RefundRefundAmount",
"RefundCustomerRemark": "RefundCustomerRemark",
"RefundStaffRemark": "RefundStaffRemark",
"CreateRefund": "CreateRefund",
"EditRefund": "EditRefund",
"RefundDeletionConfirmationMessage": "Are you sure to delete the refund {0}?",
"Menu:PaymentItem": "MenuPaymentItem",
"PaymentItem": "PaymentItem",
"PaymentItemItemType": "PaymentItemItemType",
"PaymentItemItemKey": "PaymentItemItemKey",
"PaymentItemCurrency": "PaymentItemCurrency",
"PaymentItemOriginalPaymentAmount": "PaymentItemOriginalPaymentAmount",
"PaymentItemPaymentDiscount": "PaymentItemPaymentDiscount",
"PaymentItemActualPaymentAmount": "PaymentItemActualPaymentAmount",
"PaymentItemRefundAmount": "PaymentItemRefundAmount",
"CreatePaymentItem": "CreatePaymentItem",
"EditPaymentItem": "EditPaymentItem",
"PaymentItemDeletionConfirmationMessage": "Are you sure to delete the PaymentItem {0}?"
}
}
\ No newline at end of file
{
"culture": "en",
"texts": {
"ManageYourProfile": "Manage your profile",
"Menu:Payment": "MenuPayment",
"Payment": "Payment",
"PaymentTenantId": "PaymentTenantId",
"PaymentPaymentMethod": "PaymentPaymentMethod",
"PaymentExternalTradingCode": "PaymentExternalTradingCode",
"PaymentCurrency": "PaymentCurrency",
"PaymentOriginalPaymentAmount": "PaymentOriginalPaymentAmount",
"PaymentExtraProperties": "PaymentExtraProperties",
"PaymentPaymentDiscount": "PaymentPaymentDiscount",
"PaymentActualPaymentAmount": "PaymentActualPaymentAmount",
"PaymentRefundAmount": "PaymentRefundAmount",
"PaymentCompletionTime": "PaymentCompletionTime",
"CreatePayment": "CreatePayment",
"EditPayment": "EditPayment",
"PaymentDeletionConfirmationMessage": "Are you sure to delete the payment {0}?",
"SuccessfullyDeleted": "Successfully deleted",
"Menu:Refund": "MenuRefund",
"Refund": "Refund",
"RefundTenantId": "RefundTenantId",
"RefundStoreId": "RefundStoreId",
"RefundOrderId": "RefundOrderId",
"RefundRefundPaymentMethod": "RefundRefundPaymentMethod",
"RefundExternalTradingCode": "RefundExternalTradingCode",
"RefundCurrency": "RefundCurrency",
"RefundRefundAmount": "RefundRefundAmount",
"RefundCustomerRemark": "RefundCustomerRemark",
"RefundStaffRemark": "RefundStaffRemark",
"CreateRefund": "CreateRefund",
"EditRefund": "EditRefund",
"RefundDeletionConfirmationMessage": "Are you sure to delete the refund {0}?",
"Menu:PaymentItem": "MenuPaymentItem",
"PaymentItem": "PaymentItem",
"PaymentItemItemType": "PaymentItemItemType",
"PaymentItemItemKey": "PaymentItemItemKey",
"PaymentItemCurrency": "PaymentItemCurrency",
"PaymentItemOriginalPaymentAmount": "PaymentItemOriginalPaymentAmount",
"PaymentItemPaymentDiscount": "PaymentItemPaymentDiscount",
"PaymentItemActualPaymentAmount": "PaymentItemActualPaymentAmount",
"PaymentItemRefundAmount": "PaymentItemRefundAmount",
"CreatePaymentItem": "CreatePaymentItem",
"EditPaymentItem": "EditPaymentItem",
"PaymentItemDeletionConfirmationMessage": "Are you sure to delete the PaymentItem {0}?"
}
}
\ No newline at end of file
{
"culture": "pl",
"texts": {
"Menu:Payment": "MenuPayment",
"Payment": "Payment",
"PaymentTenantId": "PaymentTenantId",
"PaymentPaymentMethod": "PaymentPaymentMethod",
"PaymentExternalTradingCode": "PaymentExternalTradingCode",
"PaymentCurrency": "PaymentCurrency",
"PaymentOriginalPaymentAmount": "PaymentOriginalPaymentAmount",
"PaymentExtraProperties": "PaymentExtraProperties",
"PaymentPaymentDiscount": "PaymentPaymentDiscount",
"PaymentActualPaymentAmount": "PaymentActualPaymentAmount",
"PaymentRefundAmount": "PaymentRefundAmount",
"PaymentCompletionTime": "PaymentCompletionTime",
"CreatePayment": "CreatePayment",
"EditPayment": "EditPayment",
"PaymentDeletionConfirmationMessage": "Are you sure to delete the payment {0}?",
"SuccessfullyDeleted": "Successfully deleted",
"Menu:Refund": "MenuRefund",
"Refund": "Refund",
"RefundTenantId": "RefundTenantId",
"RefundStoreId": "RefundStoreId",
"RefundOrderId": "RefundOrderId",
"RefundRefundPaymentMethod": "RefundRefundPaymentMethod",
"RefundExternalTradingCode": "RefundExternalTradingCode",
"RefundCurrency": "RefundCurrency",
"RefundRefundAmount": "RefundRefundAmount",
"RefundCustomerRemark": "RefundCustomerRemark",
"RefundStaffRemark": "RefundStaffRemark",
"CreateRefund": "CreateRefund",
"EditRefund": "EditRefund",
"RefundDeletionConfirmationMessage": "Are you sure to delete the refund {0}?",
"Menu:PaymentItem": "MenuPaymentItem",
"PaymentItem": "PaymentItem",
"PaymentItemItemType": "PaymentItemItemType",
"PaymentItemItemKey": "PaymentItemItemKey",
"PaymentItemCurrency": "PaymentItemCurrency",
"PaymentItemOriginalPaymentAmount": "PaymentItemOriginalPaymentAmount",
"PaymentItemPaymentDiscount": "PaymentItemPaymentDiscount",
"PaymentItemActualPaymentAmount": "PaymentItemActualPaymentAmount",
"PaymentItemRefundAmount": "PaymentItemRefundAmount",
"CreatePaymentItem": "CreatePaymentItem",
"EditPaymentItem": "EditPaymentItem",
"PaymentItemDeletionConfirmationMessage": "Are you sure to delete the PaymentItem {0}?"
}
}
\ No newline at end of file
{
"culture": "pt-BR",
"texts": {
"Menu:Payment": "MenuPayment",
"Payment": "Payment",
"PaymentTenantId": "PaymentTenantId",
"PaymentPaymentMethod": "PaymentPaymentMethod",
"PaymentExternalTradingCode": "PaymentExternalTradingCode",
"PaymentCurrency": "PaymentCurrency",
"PaymentOriginalPaymentAmount": "PaymentOriginalPaymentAmount",
"PaymentExtraProperties": "PaymentExtraProperties",
"PaymentPaymentDiscount": "PaymentPaymentDiscount",
"PaymentActualPaymentAmount": "PaymentActualPaymentAmount",
"PaymentRefundAmount": "PaymentRefundAmount",
"PaymentCompletionTime": "PaymentCompletionTime",
"CreatePayment": "CreatePayment",
"EditPayment": "EditPayment",
"PaymentDeletionConfirmationMessage": "Are you sure to delete the payment {0}?",
"SuccessfullyDeleted": "Successfully deleted",
"Menu:Refund": "MenuRefund",
"Refund": "Refund",
"RefundTenantId": "RefundTenantId",
"RefundStoreId": "RefundStoreId",
"RefundOrderId": "RefundOrderId",
"RefundRefundPaymentMethod": "RefundRefundPaymentMethod",
"RefundExternalTradingCode": "RefundExternalTradingCode",
"RefundCurrency": "RefundCurrency",
"RefundRefundAmount": "RefundRefundAmount",
"RefundCustomerRemark": "RefundCustomerRemark",
"RefundStaffRemark": "RefundStaffRemark",
"CreateRefund": "CreateRefund",
"EditRefund": "EditRefund",
"RefundDeletionConfirmationMessage": "Are you sure to delete the refund {0}?",
"Menu:PaymentItem": "MenuPaymentItem",
"PaymentItem": "PaymentItem",
"PaymentItemItemType": "PaymentItemItemType",
"PaymentItemItemKey": "PaymentItemItemKey",
"PaymentItemCurrency": "PaymentItemCurrency",
"PaymentItemOriginalPaymentAmount": "PaymentItemOriginalPaymentAmount",
"PaymentItemPaymentDiscount": "PaymentItemPaymentDiscount",
"PaymentItemActualPaymentAmount": "PaymentItemActualPaymentAmount",
"PaymentItemRefundAmount": "PaymentItemRefundAmount",
"CreatePaymentItem": "CreatePaymentItem",
"EditPaymentItem": "EditPaymentItem",
"PaymentItemDeletionConfirmationMessage": "Are you sure to delete the PaymentItem {0}?"
}
}
\ No newline at end of file
{
"culture": "sl",
"texts": {
"ManageYourProfile": "Upravljajte svojim profilom",
"Menu:Payment": "MenuPayment",
"Payment": "Payment",
"PaymentTenantId": "PaymentTenantId",
"PaymentPaymentMethod": "PaymentPaymentMethod",
"PaymentExternalTradingCode": "PaymentExternalTradingCode",
"PaymentCurrency": "PaymentCurrency",
"PaymentOriginalPaymentAmount": "PaymentOriginalPaymentAmount",
"PaymentExtraProperties": "PaymentExtraProperties",
"PaymentPaymentDiscount": "PaymentPaymentDiscount",
"PaymentActualPaymentAmount": "PaymentActualPaymentAmount",
"PaymentRefundAmount": "PaymentRefundAmount",
"PaymentCompletionTime": "PaymentCompletionTime",
"CreatePayment": "CreatePayment",
"EditPayment": "EditPayment",
"PaymentDeletionConfirmationMessage": "Are you sure to delete the payment {0}?",
"SuccessfullyDeleted": "Successfully deleted",
"Menu:Refund": "MenuRefund",
"Refund": "Refund",
"RefundTenantId": "RefundTenantId",
"RefundStoreId": "RefundStoreId",
"RefundOrderId": "RefundOrderId",
"RefundRefundPaymentMethod": "RefundRefundPaymentMethod",
"RefundExternalTradingCode": "RefundExternalTradingCode",
"RefundCurrency": "RefundCurrency",
"RefundRefundAmount": "RefundRefundAmount",
"RefundCustomerRemark": "RefundCustomerRemark",
"RefundStaffRemark": "RefundStaffRemark",
"CreateRefund": "CreateRefund",
"EditRefund": "EditRefund",
"RefundDeletionConfirmationMessage": "Are you sure to delete the refund {0}?",
"Menu:PaymentItem": "MenuPaymentItem",
"PaymentItem": "PaymentItem",
"PaymentItemItemType": "PaymentItemItemType",
"PaymentItemItemKey": "PaymentItemItemKey",
"PaymentItemCurrency": "PaymentItemCurrency",
"PaymentItemOriginalPaymentAmount": "PaymentItemOriginalPaymentAmount",
"PaymentItemPaymentDiscount": "PaymentItemPaymentDiscount",
"PaymentItemActualPaymentAmount": "PaymentItemActualPaymentAmount",
"PaymentItemRefundAmount": "PaymentItemRefundAmount",
"CreatePaymentItem": "CreatePaymentItem",
"EditPaymentItem": "EditPaymentItem",
"PaymentItemDeletionConfirmationMessage": "Are you sure to delete the PaymentItem {0}?"
}
}
\ No newline at end of file
{
"culture": "tr",
"texts": {
"ManageYourProfile": "Profil y�netimi",
"Menu:Payment": "MenuPayment",
"Payment": "Payment",
"PaymentTenantId": "PaymentTenantId",
"PaymentPaymentMethod": "PaymentPaymentMethod",
"PaymentExternalTradingCode": "PaymentExternalTradingCode",
"PaymentCurrency": "PaymentCurrency",
"PaymentOriginalPaymentAmount": "PaymentOriginalPaymentAmount",
"PaymentExtraProperties": "PaymentExtraProperties",
"PaymentPaymentDiscount": "PaymentPaymentDiscount",
"PaymentActualPaymentAmount": "PaymentActualPaymentAmount",
"PaymentRefundAmount": "PaymentRefundAmount",
"PaymentCompletionTime": "PaymentCompletionTime",
"CreatePayment": "CreatePayment",
"EditPayment": "EditPayment",
"PaymentDeletionConfirmationMessage": "Are you sure to delete the payment {0}?",
"SuccessfullyDeleted": "Successfully deleted",
"Menu:Refund": "MenuRefund",
"Refund": "Refund",
"RefundTenantId": "RefundTenantId",
"RefundStoreId": "RefundStoreId",
"RefundOrderId": "RefundOrderId",
"RefundRefundPaymentMethod": "RefundRefundPaymentMethod",
"RefundExternalTradingCode": "RefundExternalTradingCode",
"RefundCurrency": "RefundCurrency",
"RefundRefundAmount": "RefundRefundAmount",
"RefundCustomerRemark": "RefundCustomerRemark",
"RefundStaffRemark": "RefundStaffRemark",
"CreateRefund": "CreateRefund",
"EditRefund": "EditRefund",
"RefundDeletionConfirmationMessage": "Are you sure to delete the refund {0}?",
"Menu:PaymentItem": "MenuPaymentItem",
"PaymentItem": "PaymentItem",
"PaymentItemItemType": "PaymentItemItemType",
"PaymentItemItemKey": "PaymentItemItemKey",
"PaymentItemCurrency": "PaymentItemCurrency",
"PaymentItemOriginalPaymentAmount": "PaymentItemOriginalPaymentAmount",
"PaymentItemPaymentDiscount": "PaymentItemPaymentDiscount",
"PaymentItemActualPaymentAmount": "PaymentItemActualPaymentAmount",
"PaymentItemRefundAmount": "PaymentItemRefundAmount",
"CreatePaymentItem": "CreatePaymentItem",
"EditPaymentItem": "EditPaymentItem",
"PaymentItemDeletionConfirmationMessage": "Are you sure to delete the PaymentItem {0}?"
}
}
\ No newline at end of file
{
"culture": "vi",
"texts": {
"Menu:Payment": "MenuPayment",
"Payment": "Payment",
"PaymentTenantId": "PaymentTenantId",
"PaymentPaymentMethod": "PaymentPaymentMethod",
"PaymentExternalTradingCode": "PaymentExternalTradingCode",
"PaymentCurrency": "PaymentCurrency",
"PaymentOriginalPaymentAmount": "PaymentOriginalPaymentAmount",
"PaymentExtraProperties": "PaymentExtraProperties",
"PaymentPaymentDiscount": "PaymentPaymentDiscount",
"PaymentActualPaymentAmount": "PaymentActualPaymentAmount",
"PaymentRefundAmount": "PaymentRefundAmount",
"PaymentCompletionTime": "PaymentCompletionTime",
"CreatePayment": "CreatePayment",
"EditPayment": "EditPayment",
"PaymentDeletionConfirmationMessage": "Are you sure to delete the payment {0}?",
"SuccessfullyDeleted": "Successfully deleted",
"Menu:Refund": "MenuRefund",
"Refund": "Refund",
"RefundTenantId": "RefundTenantId",
"RefundStoreId": "RefundStoreId",
"RefundOrderId": "RefundOrderId",
"RefundRefundPaymentMethod": "RefundRefundPaymentMethod",
"RefundExternalTradingCode": "RefundExternalTradingCode",
"RefundCurrency": "RefundCurrency",
"RefundRefundAmount": "RefundRefundAmount",
"RefundCustomerRemark": "RefundCustomerRemark",
"RefundStaffRemark": "RefundStaffRemark",
"CreateRefund": "CreateRefund",
"EditRefund": "EditRefund",
"RefundDeletionConfirmationMessage": "Are you sure to delete the refund {0}?",
"Menu:PaymentItem": "MenuPaymentItem",
"PaymentItem": "PaymentItem",
"PaymentItemItemType": "PaymentItemItemType",
"PaymentItemItemKey": "PaymentItemItemKey",
"PaymentItemCurrency": "PaymentItemCurrency",
"PaymentItemOriginalPaymentAmount": "PaymentItemOriginalPaymentAmount",
"PaymentItemPaymentDiscount": "PaymentItemPaymentDiscount",
"PaymentItemActualPaymentAmount": "PaymentItemActualPaymentAmount",
"PaymentItemRefundAmount": "PaymentItemRefundAmount",
"CreatePaymentItem": "CreatePaymentItem",
"EditPaymentItem": "EditPaymentItem",
"PaymentItemDeletionConfirmationMessage": "Are you sure to delete the PaymentItem {0}?"
}
}
\ No newline at end of file
{
"culture": "zh-Hans",
"texts": {
"ManageYourProfile": "管理个人资料",
"Menu:Payment": "MenuPayment",
"Payment": "Payment",
"PaymentTenantId": "PaymentTenantId",
"PaymentPaymentMethod": "PaymentPaymentMethod",
"PaymentExternalTradingCode": "PaymentExternalTradingCode",
"PaymentCurrency": "PaymentCurrency",
"PaymentOriginalPaymentAmount": "PaymentOriginalPaymentAmount",
"PaymentExtraProperties": "PaymentExtraProperties",
"PaymentPaymentDiscount": "PaymentPaymentDiscount",
"PaymentActualPaymentAmount": "PaymentActualPaymentAmount",
"PaymentRefundAmount": "PaymentRefundAmount",
"PaymentCompletionTime": "PaymentCompletionTime",
"CreatePayment": "CreatePayment",
"EditPayment": "EditPayment",
"PaymentDeletionConfirmationMessage": "Are you sure to delete the payment {0}?",
"SuccessfullyDeleted": "Successfully deleted",
"Menu:Refund": "MenuRefund",
"Refund": "Refund",
"RefundTenantId": "RefundTenantId",
"RefundStoreId": "RefundStoreId",
"RefundOrderId": "RefundOrderId",
"RefundRefundPaymentMethod": "RefundRefundPaymentMethod",
"RefundExternalTradingCode": "RefundExternalTradingCode",
"RefundCurrency": "RefundCurrency",
"RefundRefundAmount": "RefundRefundAmount",
"RefundCustomerRemark": "RefundCustomerRemark",
"RefundStaffRemark": "RefundStaffRemark",
"CreateRefund": "CreateRefund",
"EditRefund": "EditRefund",
"RefundDeletionConfirmationMessage": "Are you sure to delete the refund {0}?",
"Menu:PaymentItem": "MenuPaymentItem",
"PaymentItem": "PaymentItem",
"PaymentItemItemType": "PaymentItemItemType",
"PaymentItemItemKey": "PaymentItemItemKey",
"PaymentItemCurrency": "PaymentItemCurrency",
"PaymentItemOriginalPaymentAmount": "PaymentItemOriginalPaymentAmount",
"PaymentItemPaymentDiscount": "PaymentItemPaymentDiscount",
"PaymentItemActualPaymentAmount": "PaymentItemActualPaymentAmount",
"PaymentItemRefundAmount": "PaymentItemRefundAmount",
"CreatePaymentItem": "CreatePaymentItem",
"EditPaymentItem": "EditPaymentItem",
"PaymentItemDeletionConfirmationMessage": "Are you sure to delete the PaymentItem {0}?"
}
}
\ No newline at end of file
{
"culture": "zh-Hant",
"texts": {
"ManageYourProfile": "管理個人資料",
"Menu:Payment": "MenuPayment",
"Payment": "Payment",
"PaymentTenantId": "PaymentTenantId",
"PaymentPaymentMethod": "PaymentPaymentMethod",
"PaymentExternalTradingCode": "PaymentExternalTradingCode",
"PaymentCurrency": "PaymentCurrency",
"PaymentOriginalPaymentAmount": "PaymentOriginalPaymentAmount",
"PaymentExtraProperties": "PaymentExtraProperties",
"PaymentPaymentDiscount": "PaymentPaymentDiscount",
"PaymentActualPaymentAmount": "PaymentActualPaymentAmount",
"PaymentRefundAmount": "PaymentRefundAmount",
"PaymentCompletionTime": "PaymentCompletionTime",
"CreatePayment": "CreatePayment",
"EditPayment": "EditPayment",
"PaymentDeletionConfirmationMessage": "Are you sure to delete the payment {0}?",
"SuccessfullyDeleted": "Successfully deleted",
"Menu:Refund": "MenuRefund",
"Refund": "Refund",
"RefundTenantId": "RefundTenantId",
"RefundStoreId": "RefundStoreId",
"RefundOrderId": "RefundOrderId",
"RefundRefundPaymentMethod": "RefundRefundPaymentMethod",
"RefundExternalTradingCode": "RefundExternalTradingCode",
"RefundCurrency": "RefundCurrency",
"RefundRefundAmount": "RefundRefundAmount",
"RefundCustomerRemark": "RefundCustomerRemark",
"RefundStaffRemark": "RefundStaffRemark",
"CreateRefund": "CreateRefund",
"EditRefund": "EditRefund",
"RefundDeletionConfirmationMessage": "Are you sure to delete the refund {0}?",
"Menu:PaymentItem": "MenuPaymentItem",
"PaymentItem": "PaymentItem",
"PaymentItemItemType": "PaymentItemItemType",
"PaymentItemItemKey": "PaymentItemItemKey",
"PaymentItemCurrency": "PaymentItemCurrency",
"PaymentItemOriginalPaymentAmount": "PaymentItemOriginalPaymentAmount",
"PaymentItemPaymentDiscount": "PaymentItemPaymentDiscount",
"PaymentItemActualPaymentAmount": "PaymentItemActualPaymentAmount",
"PaymentItemRefundAmount": "PaymentItemRefundAmount",
"CreatePaymentItem": "CreatePaymentItem",
"EditPaymentItem": "EditPaymentItem",
"PaymentItemDeletionConfirmationMessage": "Are you sure to delete the PaymentItem {0}?"
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
namespace EasyAbp.EShop.Payments.Payments
{
[Serializable]
public class PaymentEto
{
public Guid Id { get; set; }
public Guid? TenantId { get; set; }
public string PaymentMethod { get; set; }
public string ExternalTradingCode { get; set; }
public string Currency { get; set; }
public decimal OriginalPaymentAmount { get; set; }
public decimal PaymentDiscount { get; set; }
public decimal ActualPaymentAmount { get; set; }
public decimal RefundAmount { get; set; }
public DateTime? CompletionTime { get; set; }
public List<PaymentItemEto> PaymentItems { get; set; }
}
}
\ No newline at end of file
using System;
namespace EasyAbp.EShop.Payments.Payments
{
[Serializable]
public class PaymentItemEto
{
public Guid Id { get; set; }
public string ItemType { get; set; }
public Guid ItemKey { get; set; }
public string Currency { get; set; }
public decimal OriginalPaymentAmount { get; set; }
public decimal PaymentDiscount { get; set; }
public decimal ActualPaymentAmount { get; set; }
public decimal RefundAmount { get; set; }
}
}
\ No newline at end of file
{
"culture": "en",
"texts": {
"ManageYourProfile": "Manage your profile"
}
}
\ No newline at end of file
{
"culture": "sl",
"texts": {
"ManageYourProfile": "Upravljajte svojim profilom"
}
}
\ No newline at end of file
{
"culture": "tr",
"texts": {
"ManageYourProfile": "Profil ynetimi"
}
}
\ No newline at end of file
{
"culture": "zh-Hans",
"texts": {
"ManageYourProfile": "管理个人资料"
}
}
\ No newline at end of file
{
"culture": "zh-Hant",
"texts": {
"ManageYourProfile": "管理個人資料"
}
}
\ No newline at end of file
......@@ -4,10 +4,11 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>EasyAbp.EShop.Payments</RootNamespace>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="2.5.0" />
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="2.5.0" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Stores\src\EasyAbp.EShop.Stores.Domain.Shared\EasyAbp.EShop.Stores.Domain.Shared.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Payments.Domain.Shared\EasyAbp.EShop.Payments.Domain.Shared.csproj" />
......
......@@ -2,11 +2,14 @@
using EasyAbp.EShop.Stores;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.AutoMapper;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Modularity;
namespace EasyAbp.EShop.Payments
{
[DependsOn(
typeof(AbpAutoMapperModule),
typeof(EShopPaymentsDomainSharedModule),
typeof(EShopStoresDomainSharedModule)
)]
......@@ -18,5 +21,20 @@ namespace EasyAbp.EShop.Payments
resolver.TryRegisterProviderAsync(FreePaymentServiceProvider.PaymentMethod, typeof(FreePaymentServiceProvider));
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<EShopPaymentsDomainModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<PaymentsDomainAutoMapperProfile>(validate: true);
});
Configure<AbpDistributedEventBusOptions>(options =>
{
options.EtoMappings.Add<Payment, PaymentEto>(typeof(EShopPaymentsDomainModule));
});
}
}
}
......@@ -2,22 +2,32 @@
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
namespace EasyAbp.EShop.Payments.Payments
{
[Dependency(ServiceLifetime.Transient, TryRegister = true)]
public class FreePaymentServiceProvider : IPaymentServiceProvider
{
private readonly IClock _clock;
private readonly IPaymentRepository _paymentRepository;
public const string PaymentMethod = "Free";
public FreePaymentServiceProvider()
public FreePaymentServiceProvider(
IClock clock,
IPaymentRepository paymentRepository)
{
_clock = clock;
_paymentRepository = paymentRepository;
}
public async Task<Payment> PayForOrderAsync(Payment payment, Dictionary<string, object> extraProperties = null)
public async Task<Payment> PayAsync(Payment payment, Dictionary<string, object> extraProperties = null)
{
throw new System.NotImplementedException();
payment.SetExternalTradingCode(payment.Id.ToString());
payment.CompletePayment(_clock.Now);
return await _paymentRepository.UpdateAsync(payment, true);
}
}
}
\ No newline at end of file
using System.Collections.Generic;
using System.Threading.Tasks;
namespace EasyAbp.EShop.Payments.Payments
{
public interface IPaymentPayeeAccountProvider
{
Task<string> GetPayeeAccountAsync(Payment payment, Dictionary<string, object> inputExtraProperties);
}
}
\ No newline at end of file
using System;
using Volo.Abp.Domain.Repositories;
namespace EasyAbp.EShop.Payments.Payments
{
public interface IPaymentRepository : IRepository<Payment, Guid>
{
}
}
\ No newline at end of file
......@@ -6,6 +6,6 @@ namespace EasyAbp.EShop.Payments.Payments
{
public interface IPaymentServiceProvider
{
Task<Payment> PayForOrderAsync(Payment payment, Dictionary<string, object> extraProperties = null);
Task<Payment> PayAsync(Payment payment, Dictionary<string, object> extraProperties = null);
}
}
\ No newline at end of file
using Volo.Abp;
namespace EasyAbp.EShop.Payments.Payments
{
public class PayeeAccountNotFoundException : BusinessException
{
public PayeeAccountNotFoundException(string paymentMethod) : base(
message: $"Cannot find the payee account of payment method {paymentMethod}.")
{
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace EasyAbp.EShop.Payments.Payments
{
public class Payment : FullAuditedAggregateRoot<Guid>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
[NotNull]
public virtual string PaymentMethod { get; protected set; }
[CanBeNull]
public virtual string PayeeAccount { get; protected set; }
[CanBeNull]
public virtual string ExternalTradingCode { get; protected set; }
[NotNull]
public virtual string Currency { get; protected set; }
public virtual decimal OriginalPaymentAmount { get; protected set; }
public virtual decimal PaymentDiscount { get; protected set; }
public virtual decimal ActualPaymentAmount { get; protected set; }
public virtual decimal RefundAmount { get; protected set; }
public virtual DateTime? CompletionTime { get; protected set; }
public virtual List<PaymentItem> PaymentItems { get; protected set; }
protected Payment()
{
PaymentItems = new List<PaymentItem>();
}
public Payment(
Guid id,
Guid? tenantId,
[NotNull] string paymentMethod,
[NotNull] string currency,
decimal originalPaymentAmount,
List<PaymentItem> paymentItems
) :base(id)
{
TenantId = tenantId;
PaymentMethod = paymentMethod;
Currency = currency;
OriginalPaymentAmount = originalPaymentAmount;
PaymentItems = paymentItems;
}
public void SetPayeeAccount([NotNull] string payeeAccount)
{
PayeeAccount = payeeAccount;
}
public void SetExternalTradingCode([NotNull] string externalTradingCode)
{
CheckPaymentIsNotCompleted();
ExternalTradingCode = externalTradingCode;
}
public void SetPaymentDiscount(
decimal paymentDiscount,
decimal actualPaymentAmount,
decimal refundAmount)
{
CheckPaymentIsNotCompleted();
PaymentDiscount = paymentDiscount;
ActualPaymentAmount = actualPaymentAmount;
RefundAmount = refundAmount;
}
public void CompletePayment(DateTime completionTime)
{
CheckPaymentIsNotCompleted();
CompletionTime = completionTime;
}
private void CheckPaymentIsNotCompleted()
{
if (CompletionTime.HasValue)
{
throw new PaymentHasAlreadyBeenCompletedException(Id);
}
}
}
}
using System;
using Volo.Abp;
namespace EasyAbp.EShop.Payments.Payments
{
public class PaymentHasAlreadyBeenCompletedException : BusinessException
{
public PaymentHasAlreadyBeenCompletedException(Guid id) : base(
message: $"Payment({id}) has already been completed.")
{
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace EasyAbp.EShop.Payments.Payments
{
public class Payment : FullAuditedAggregateRoot<Guid>, IMultiTenant
public class PaymentItem : FullAuditedEntity<Guid>
{
public virtual Guid? TenantId { get; protected set; }
[NotNull]
public virtual string PaymentMethod { get; protected set; }
public virtual string ItemType { get; protected set; }
[NotNull]
public virtual string ExternalTradingCode { get; protected set; }
public virtual Guid ItemKey { get; protected set; }
[NotNull]
public virtual string Currency { get; protected set; }
......@@ -26,7 +21,33 @@ namespace EasyAbp.EShop.Payments.Payments
public virtual decimal ActualPaymentAmount { get; protected set; }
public virtual decimal RefundAmount { get; protected set; }
public virtual List<PaymentOrder> PaymentOrders { get; protected set; }
protected PaymentItem()
{
}
public PaymentItem(
Guid id,
[NotNull] string itemType,
Guid itemKey,
[NotNull] string currency,
decimal originalPaymentAmount
) :base(id)
{
ItemType = itemType;
ItemKey = itemKey;
Currency = currency;
OriginalPaymentAmount = originalPaymentAmount;
}
public void CompletePayment(
decimal paymentDiscount,
decimal actualPaymentAmount,
decimal refundAmount)
{
PaymentDiscount = paymentDiscount;
ActualPaymentAmount = actualPaymentAmount;
RefundAmount = refundAmount;
}
}
}
\ No newline at end of file
}
using System.Collections.Generic;
using System.Threading.Tasks;
using EasyAbp.EShop.Payments.Settings;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace EasyAbp.EShop.Payments.Payments
{
public class PaymentPayeeAccountProvider : IPaymentPayeeAccountProvider, ITransientDependency
{
private readonly IPaymentRepository _paymentRepository;
private readonly ISettingProvider _settingProvider;
public PaymentPayeeAccountProvider(
IPaymentRepository paymentRepository,
ISettingProvider settingProvider)
{
_paymentRepository = paymentRepository;
_settingProvider = settingProvider;
}
public async Task<string> GetPayeeAccountAsync(Payment payment, Dictionary<string, object> inputExtraProperties)
{
// Todo: support multi-store.
var payeeAccount = await _settingProvider.GetOrNullAsync(
PaymentsSettings.GroupName + "." + payment.PaymentMethod + ".DefaultPayeeAccount");
if (payeeAccount == null)
{
throw new PayeeAccountNotFoundException(payment.PaymentMethod);
}
return payeeAccount;
}
}
}
\ No newline at end of file
using Volo.Abp;
namespace EasyAbp.EShop.Payments.Payments
{
public class UnknownPaymentMethodException : BusinessException
{
public UnknownPaymentMethodException(string paymentMethod) : base(
message: $"Payment method {paymentMethod} does not exist.")
{
}
}
}
\ No newline at end of file
using AutoMapper;
using EasyAbp.EShop.Payments.Payments;
namespace EasyAbp.EShop.Payments
{
public class PaymentsApplicationAutoMapperProfile : Profile
public class PaymentsDomainAutoMapperProfile : Profile
{
public PaymentsApplicationAutoMapperProfile()
public PaymentsDomainAutoMapperProfile()
{
/* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */
CreateMap<Payment, PaymentEto>();
CreateMap<PaymentItem, PaymentItemEto>();
}
}
}
\ No newline at end of file
}
using System;
using Volo.Abp.Domain.Repositories;
namespace EasyAbp.EShop.Payments.Refunds
{
public interface IRefundRepository : IRepository<Refund, Guid>
{
}
}
\ No newline at end of file
using System;
using System;
using EasyAbp.EShop.Stores.Stores;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities.Auditing;
......@@ -30,5 +30,33 @@ namespace EasyAbp.EShop.Payments.Refunds
[CanBeNull]
public virtual string StaffRemark { get; protected set; }
protected Refund()
{
}
public Refund(
Guid id,
Guid? tenantId,
Guid storeId,
Guid orderId,
string refundPaymentMethod,
string externalTradingCode,
string currency,
decimal refundAmount,
string customerRemark,
string staffRemark
) :base(id)
{
TenantId = tenantId;
StoreId = storeId;
OrderId = orderId;
RefundPaymentMethod = refundPaymentMethod;
ExternalTradingCode = externalTradingCode;
Currency = currency;
RefundAmount = refundAmount;
CustomerRemark = customerRemark;
StaffRemark = staffRemark;
}
}
}
\ No newline at end of file
}
......@@ -9,6 +9,10 @@ namespace EasyAbp.EShop.Payments.Settings
/* Define module settings here.
* Use names from PaymentsSettings class.
*/
context.Add(
new SettingDefinition(PaymentsSettings.FreePaymentMethod.DefaultPayeeAccount, "None")
);
}
}
}
\ No newline at end of file
......@@ -7,5 +7,13 @@
/* Add constants for setting names. Example:
* public const string MySettingName = GroupName + ".MySettingName";
*/
public static class FreePaymentMethod
{
private const string PaymentMethodName = GroupName + ".Free";
public const string DefaultPayeeAccount = PaymentMethodName + ".DefaultPayeeAccount";
}
}
}
\ No newline at end of file
using System;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities.Auditing;
namespace EasyAbp.EShop.Payments.Payments
{
public class PaymentOrder : FullAuditedEntity<Guid>
{
public virtual Guid OrderId { get; protected set; }
[NotNull]
public virtual string Currency { get; protected set; }
public virtual decimal OriginalPaymentAmount { get; protected set; }
public virtual decimal PaymentDiscount { get; protected set; }
public virtual decimal ActualPaymentAmount { get; protected set; }
public virtual decimal RefundAmount { get; protected set; }
}
}
\ No newline at end of file
......@@ -4,7 +4,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>EasyAbp.EShop.Payments</RootNamespace>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
......@@ -12,4 +12,8 @@
<ProjectReference Include="..\EasyAbp.EShop.Payments.Domain\EasyAbp.EShop.Payments.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="EasyAbp\EShop\Payments" />
</ItemGroup>
</Project>
using Microsoft.Extensions.DependencyInjection;
using EasyAbp.EShop.Payments.Refunds;
using EasyAbp.EShop.Payments.Payments;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
......@@ -17,7 +19,9 @@ namespace EasyAbp.EShop.Payments.EntityFrameworkCore
/* Add custom repositories here. Example:
* options.AddRepository<Question, EfCoreQuestionRepository>();
*/
options.AddRepository<Payment, PaymentRepository>();
options.AddRepository<Refund, RefundRepository>();
});
}
}
}
\ No newline at end of file
}
using Volo.Abp.Data;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using EasyAbp.EShop.Payments.Payments;
using EasyAbp.EShop.Payments.Refunds;
namespace EasyAbp.EShop.Payments.EntityFrameworkCore
{
......@@ -9,5 +12,8 @@ namespace EasyAbp.EShop.Payments.EntityFrameworkCore
/* Add DbSet for each Aggregate Root here. Example:
* DbSet<Question> Questions { get; }
*/
DbSet<Payment> Payments { get; set; }
DbSet<Refund> Refunds { get; set; }
DbSet<PaymentItem> PaymentItems { get; set; }
}
}
\ No newline at end of file
}
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using EasyAbp.EShop.Payments.Payments;
using EasyAbp.EShop.Payments.Refunds;
namespace EasyAbp.EShop.Payments.EntityFrameworkCore
{
......@@ -10,6 +12,9 @@ namespace EasyAbp.EShop.Payments.EntityFrameworkCore
/* Add DbSet for each Aggregate Root here. Example:
* public DbSet<Question> Questions { get; set; }
*/
public DbSet<Payment> Payments { get; set; }
public DbSet<Refund> Refunds { get; set; }
public DbSet<PaymentItem> PaymentItems { get; set; }
public PaymentsDbContext(DbContextOptions<PaymentsDbContext> options)
: base(options)
......@@ -24,4 +29,4 @@ namespace EasyAbp.EShop.Payments.EntityFrameworkCore
builder.ConfigurePayments();
}
}
}
\ No newline at end of file
}
using System;
using EasyAbp.EShop.Payments.Refunds;
using EasyAbp.EShop.Payments.Payments;
using System;
using Microsoft.EntityFrameworkCore;
using Volo.Abp;
using Volo.Abp.EntityFrameworkCore.Modeling;
namespace EasyAbp.EShop.Payments.EntityFrameworkCore
{
......@@ -38,6 +41,36 @@ namespace EasyAbp.EShop.Payments.EntityFrameworkCore
b.HasIndex(q => q.CreationTime);
});
*/
builder.Entity<Payment>(b =>
{
b.ToTable(options.TablePrefix + "Payments", options.Schema);
b.ConfigureByConvention();
/* Configure more properties here */
b.Property(x => x.ActualPaymentAmount).HasColumnType("decimal(18,6)");
b.Property(x => x.OriginalPaymentAmount).HasColumnType("decimal(18,6)");
b.Property(x => x.PaymentDiscount).HasColumnType("decimal(18,6)");
b.Property(x => x.RefundAmount).HasColumnType("decimal(18,6)");
});
builder.Entity<Refund>(b =>
{
b.ToTable(options.TablePrefix + "Refunds", options.Schema);
b.ConfigureByConvention();
/* Configure more properties here */
b.Property(x => x.RefundAmount).HasColumnType("decimal(18,6)");
});
builder.Entity<PaymentItem>(b =>
{
b.ToTable(options.TablePrefix + "PaymentItems", options.Schema);
b.ConfigureByConvention();
/* Configure more properties here */
b.Property(x => x.ActualPaymentAmount).HasColumnType("decimal(18,6)");
b.Property(x => x.OriginalPaymentAmount).HasColumnType("decimal(18,6)");
b.Property(x => x.PaymentDiscount).HasColumnType("decimal(18,6)");
b.Property(x => x.RefundAmount).HasColumnType("decimal(18,6)");
});
}
}
}
\ No newline at end of file
}
using System;
using EasyAbp.EShop.Payments.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace EasyAbp.EShop.Payments.Payments
{
public class PaymentRepository : EfCoreRepository<PaymentsDbContext, Payment, Guid>, IPaymentRepository
{
public PaymentRepository(IDbContextProvider<PaymentsDbContext> dbContextProvider) : base(dbContextProvider)
{
}
}
}
\ No newline at end of file
using System;
using EasyAbp.EShop.Payments.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace EasyAbp.EShop.Payments.Refunds
{
public class RefundRepository : EfCoreRepository<PaymentsDbContext, Refund, Guid>, IRefundRepository
{
public RefundRepository(IDbContextProvider<PaymentsDbContext> dbContextProvider) : base(dbContextProvider)
{
}
}
}
\ No newline at end of file
......@@ -4,7 +4,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>EasyAbp.EShop.Payments</RootNamespace>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
......
......@@ -4,7 +4,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>EasyAbp.EShop.Payments</RootNamespace>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
......
......@@ -4,7 +4,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>EasyAbp.EShop.Payments</RootNamespace>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
......@@ -12,4 +12,8 @@
<ProjectReference Include="..\EasyAbp.EShop.Payments.Domain\EasyAbp.EShop.Payments.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="EasyAbp\EShop\Payments" />
</ItemGroup>
</Project>
......@@ -39,4 +39,10 @@
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="Pages\Payments\PaymentOrder\Index.cshtml" />
<_ContentIncludedByDefault Remove="Pages\Payments\Payment\Index.cshtml" />
<_ContentIncludedByDefault Remove="Pages\Refunds\Refund\Index.cshtml" />
</ItemGroup>
</Project>
@page
@inherits EasyAbp.EShop.Payments.Web.Pages.PaymentsPage
@model EasyAbp.EShop.Payments.Web.Pages.Payments.IndexModel
@model EasyAbp.EShop.Payments.Web.Pages.EShop.Payments.IndexModel
@{
}
<h1>Payments</h1>
......
namespace EasyAbp.EShop.Payments.Web.Pages.Payments
namespace EasyAbp.EShop.Payments.Web.Pages.EShop.Payments
{
public class IndexModel : PaymentsPageModel
{
......
@page
@using Volo.Abp.AspNetCore.Mvc.UI.Layout
@inherits EasyAbp.EShop.Payments.Web.Pages.PaymentsPage
@model EasyAbp.EShop.Payments.Web.Pages.EShop.Payments.Payments.Payment.IndexModel
@inject IPageLayout PageLayout
@{
PageLayout.Content.Title = L["Payment"].Value;
PageLayout.Content.BreadCrumb.Add(L["Menu:Payment"].Value);
PageLayout.Content.MenuItemName = "Payment";
}
@section scripts
{
<abp-script src="/Pages/EShop/Payments/Payments/Payment/index.js" />
}
@section styles
{
<abp-style src="/Pages/EShop/Payments/Payments/Payment/index.css"/>
}
<abp-card>
<abp-card-header>
<abp-row>
<abp-column size-md="_6">
<abp-card-title>@L["Payment"]</abp-card-title>
</abp-column>
</abp-row>
</abp-card-header>
<abp-card-body>
<abp-table striped-rows="true" id="PaymentTable" class="nowrap">
<thead>
<tr>
<th>@L["Actions"]</th>
<th>@L["PaymentPaymentMethod"]</th>
<th>@L["PaymentExternalTradingCode"]</th>
<th>@L["PaymentCurrency"]</th>
<th>@L["PaymentOriginalPaymentAmount"]</th>
<th>@L["PaymentPaymentDiscount"]</th>
<th>@L["PaymentActualPaymentAmount"]</th>
<th>@L["PaymentRefundAmount"]</th>
<th>@L["PaymentCompletionTime"]</th>
</tr>
</thead>
</abp-table>
</abp-card-body>
</abp-card>
\ No newline at end of file
using System.Threading.Tasks;
namespace EasyAbp.EShop.Payments.Web.Pages.EShop.Payments.Payments.Payment
{
public class IndexModel : PaymentsPageModel
{
public async Task OnGetAsync()
{
await Task.CompletedTask;
}
}
}
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