Browse Source

Merge pull request #69 from volosoft/payment-module

Payment Module
pull/74/merge
Halil İbrahim Kalkan 5 years ago
committed by GitHub
parent
commit
b102e22392
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 78
      modules/payment/Payment.sln
  2. 68
      modules/payment/README.md
  3. 9
      modules/payment/common.props
  4. 9
      modules/payment/configureawait.props
  5. 13
      modules/payment/docker-compose.migrations.yml
  6. 29
      modules/payment/docker-compose.override.yml
  7. 25
      modules/payment/docker-compose.yml
  8. 3
      modules/payment/src/Payment.Admin.Application.Contracts/FodyWeavers.xml
  9. 30
      modules/payment/src/Payment.Admin.Application.Contracts/FodyWeavers.xsd
  10. 17
      modules/payment/src/Payment.Admin.Application.Contracts/Payment.Admin.Application.Contracts.csproj
  11. 17
      modules/payment/src/Payment.Admin.Application.Contracts/PaymentAdminApplicationContractsModule.cs
  12. 7
      modules/payment/src/Payment.Admin.Application.Contracts/PaymentAdminRemoteServiceConsts.cs
  13. 11
      modules/payment/src/Payment.Admin.Application.Contracts/Payments/IPaymentRequestAdminAppService.cs
  14. 17
      modules/payment/src/Payment.Admin.Application.Contracts/Payments/PaymentRequestGetListInput.cs
  15. 24
      modules/payment/src/Payment.Admin.Application.Contracts/Payments/PaymentRequestWithDetailsDto.cs
  16. 20
      modules/payment/src/Payment.Admin.Application.Contracts/Permissions/PaymentAdminPermissionDefinitionProvider.cs
  17. 12
      modules/payment/src/Payment.Admin.Application.Contracts/Permissions/PaymentAdminPermissions.cs
  18. 3
      modules/payment/src/Payment.Admin.Application/FodyWeavers.xml
  19. 30
      modules/payment/src/Payment.Admin.Application/FodyWeavers.xsd
  20. 17
      modules/payment/src/Payment.Admin.Application/Payment.Admin.Application.csproj
  21. 14
      modules/payment/src/Payment.Admin.Application/PaymentAdminApplicationAutoMapperProfile.cs
  22. 25
      modules/payment/src/Payment.Admin.Application/PaymentAdminApplicationModule.cs
  23. 46
      modules/payment/src/Payment.Admin.Application/Payments/PaymentRequestAdminAppService.cs
  24. 3
      modules/payment/src/Payment.Admin.Blazor/FodyWeavers.xml
  25. 30
      modules/payment/src/Payment.Admin.Blazor/FodyWeavers.xsd
  26. 43
      modules/payment/src/Payment.Admin.Blazor/Navigation/PaymentAdminBlazorMenuContributor.cs
  27. 7
      modules/payment/src/Payment.Admin.Blazor/Navigation/PaymentAdminMenuNames.cs
  28. 89
      modules/payment/src/Payment.Admin.Blazor/Pages/Payment/Requests/Index.razor
  29. 82
      modules/payment/src/Payment.Admin.Blazor/Pages/Payment/Requests/Index.razor.cs
  30. 16
      modules/payment/src/Payment.Admin.Blazor/Payment.Admin.Blazor.csproj
  31. 28
      modules/payment/src/Payment.Admin.Blazor/PaymentAdminBlazorModule.cs
  32. 14
      modules/payment/src/Payment.Admin.Blazor/PaymentAdminComponentBase.cs
  33. 6
      modules/payment/src/Payment.Admin.Blazor/_Imports.razor
  34. 26
      modules/payment/src/Payment.Admin.HttpApi.Client/ClientProxies/PaymentRequestAdminClientProxy.Generated.cs
  35. 8
      modules/payment/src/Payment.Admin.HttpApi.Client/ClientProxies/PaymentRequestAdminClientProxy.cs
  36. 132
      modules/payment/src/Payment.Admin.HttpApi.Client/ClientProxies/paymentAdmin-generate-proxy.json
  37. 3
      modules/payment/src/Payment.Admin.HttpApi.Client/FodyWeavers.xml
  38. 30
      modules/payment/src/Payment.Admin.HttpApi.Client/FodyWeavers.xsd
  39. 21
      modules/payment/src/Payment.Admin.HttpApi.Client/Payment.Admin.HttpApi.Client.csproj
  40. 27
      modules/payment/src/Payment.Admin.HttpApi.Client/PaymentAdminHttpApiClientModule.cs
  41. 3
      modules/payment/src/Payment.Admin.HttpApi/FodyWeavers.xml
  42. 30
      modules/payment/src/Payment.Admin.HttpApi/FodyWeavers.xsd
  43. 16
      modules/payment/src/Payment.Admin.HttpApi/Payment.Admin.HttpApi.csproj
  44. 13
      modules/payment/src/Payment.Admin.HttpApi/PaymentAdminController.cs
  45. 34
      modules/payment/src/Payment.Admin.HttpApi/PaymentAdminHttpApiModule.cs
  46. 26
      modules/payment/src/Payment.Admin.HttpApi/Payments/PaymentRequestAdminController.cs
  47. 1
      modules/payment/src/Payment.Application.Contracts/Payment.Application.Contracts.csproj
  48. 19
      modules/payment/src/Payment.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs
  49. 32
      modules/payment/src/Payment.Application.Contracts/PaymentRequests/PaymentRequestCreationDto.cs
  50. 29
      modules/payment/src/Payment.Application.Contracts/PaymentRequests/PaymentRequestDto.cs
  51. 18
      modules/payment/src/Payment.Application.Contracts/PaymentRequests/StartPaymentDto.cs
  52. 10
      modules/payment/src/Payment.Application.Contracts/PaymentRequests/StartPaymentResultDto.cs
  53. 4
      modules/payment/src/Payment.Application/Payment.Application.csproj
  54. 5
      modules/payment/src/Payment.Application/PaymentApplicationAutoMapperProfile.cs
  55. 16
      modules/payment/src/Payment.Application/PaymentApplicationModule.cs
  56. 173
      modules/payment/src/Payment.Application/PaymentRequests/PaymentRequestAppService.cs
  57. 3
      modules/payment/src/Payment.BackgroundServices/FodyWeavers.xml
  58. 30
      modules/payment/src/Payment.BackgroundServices/FodyWeavers.xsd
  59. 15
      modules/payment/src/Payment.BackgroundServices/Payment.BackgroundServices.csproj
  60. 15
      modules/payment/src/Payment.BackgroundServices/PaymentBackgroundServicesModule.cs
  61. 33
      modules/payment/src/Payment.Domain.Shared/Localization/Payment/en.json
  62. 47
      modules/payment/src/Payment.Domain.Shared/PayPal/PayPalConsts.cs
  63. 3
      modules/payment/src/Payment.Domain.Shared/Payment.Domain.Shared.csproj
  64. 16
      modules/payment/src/Payment.Domain.Shared/PaymentRequests/PaymentRequestCompletedEto.cs
  65. 10
      modules/payment/src/Payment.Domain.Shared/PaymentRequests/PaymentRequestConsts.cs
  66. 18
      modules/payment/src/Payment.Domain.Shared/PaymentRequests/PaymentRequestFailedEto.cs
  67. 9
      modules/payment/src/Payment.Domain.Shared/PaymentRequests/PaymentRequestState.cs
  68. 22
      modules/payment/src/Payment.Domain/PayPal/PayPalOptions.cs
  69. 1
      modules/payment/src/Payment.Domain/Payment.Domain.csproj
  70. 2
      modules/payment/src/Payment.Domain/PaymentDbProperties.cs
  71. 10
      modules/payment/src/Payment.Domain/PaymentDomainModule.cs
  72. 7
      modules/payment/src/Payment.Domain/PaymentOptions.cs
  73. 30
      modules/payment/src/Payment.Domain/PaymentRequests/IPaymentRequestRepository.cs
  74. 87
      modules/payment/src/Payment.Domain/PaymentRequests/PaymentRequest.cs
  75. 8
      modules/payment/src/Payment.EntityFrameworkCore/EntityFrameworkCore/IPaymentDbContext.cs
  76. 5
      modules/payment/src/Payment.EntityFrameworkCore/EntityFrameworkCore/PaymentDbContext.cs
  77. 24
      modules/payment/src/Payment.EntityFrameworkCore/EntityFrameworkCore/PaymentDbContextModelCreatingExtensions.cs
  78. 6
      modules/payment/src/Payment.EntityFrameworkCore/EntityFrameworkCore/PaymentEntityFrameworkCoreModule.cs
  79. 58
      modules/payment/src/Payment.EntityFrameworkCore/EntityFrameworkCore/Repositories/PaymentRequestRepository.cs
  80. 1
      modules/payment/src/Payment.EntityFrameworkCore/Payment.EntityFrameworkCore.csproj
  81. 208
      modules/payment/src/Payment.HttpApi.Client/ClientProxies/Payment-generate-proxy.json
  82. 58
      modules/payment/src/Payment.HttpApi.Client/ClientProxies/PaymentRequestClientProxy.Generated.cs
  83. 8
      modules/payment/src/Payment.HttpApi.Client/ClientProxies/PaymentRequestClientProxy.cs
  84. 28
      modules/payment/src/Payment.HttpApi.Client/ClientProxies/SampleClientProxy.Generated.cs
  85. 8
      modules/payment/src/Payment.HttpApi.Client/ClientProxies/SampleClientProxy.cs
  86. 3
      modules/payment/src/Payment.HttpApi.Client/FodyWeavers.xml
  87. 30
      modules/payment/src/Payment.HttpApi.Client/FodyWeavers.xsd
  88. 21
      modules/payment/src/Payment.HttpApi.Client/Payment.HttpApi.Client.csproj
  89. 27
      modules/payment/src/Payment.HttpApi.Client/PaymentHttpApiClientModule.cs
  90. 1
      modules/payment/src/Payment.HttpApi/Payment.HttpApi.csproj
  91. 61
      modules/payment/src/Payment.HttpApi/PaymentRequests/PaymentRequestController.cs
  92. 17
      modules/payment/src/Payment.Web/Pages/Payment/Index.cshtml
  93. 9
      modules/payment/src/Payment.Web/Pages/Payment/Index.cshtml.cs
  94. 41
      modules/payment/src/Payment.Web/Pages/Payment/PostCheckout.cshtml
  95. 61
      modules/payment/src/Payment.Web/Pages/Payment/PostCheckout.cshtml.cs
  96. 38
      modules/payment/src/Payment.Web/Pages/Payment/PreCheckout.cshtml
  97. 49
      modules/payment/src/Payment.Web/Pages/Payment/PreCheckout.cshtml.cs
  98. 20
      modules/payment/src/Payment.Web/Pages/PaymentPageBase.cs
  99. 3
      modules/payment/src/Payment.Web/Payment.Web.csproj
  100. 11
      modules/payment/src/Payment.Web/PaymentRequest/IPaymentUrlBuilder.cs

78
modules/payment/Payment.sln

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29001.49
# Visual Studio Version 17
VisualStudioVersion = 17.0.31808.319
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Payment.Domain.Shared", "src\Payment.Domain.Shared\Payment.Domain.Shared.csproj", "{D64C1577-4929-4B60-939E-96DE1534891A}"
EndProject
@ -41,6 +41,22 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "www", "www", "{D3FD0217-A8C
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "admin", "admin", "{FC718EF0-43EB-4767-9578-95FA0B3727A5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Payment.HttpApi.Client", "src\Payment.HttpApi.Client\Payment.HttpApi.Client.csproj", "{3FF65447-69D5-4115-8398-8156FB381215}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Payment.BackgroundServices", "src\Payment.BackgroundServices\Payment.BackgroundServices.csproj", "{98CAA357-46A3-48EC-B5D9-27C706862351}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Payment.Admin.Application.Contracts", "src\Payment.Admin.Application.Contracts\Payment.Admin.Application.Contracts.csproj", "{B4D6C73B-2848-4B0C-BFA5-7EBEA59F6A75}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Payment.Admin.Application", "src\Payment.Admin.Application\Payment.Admin.Application.csproj", "{267E26D0-3401-4945-AD58-30FE482566DD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Payment.Admin.HttpApi", "src\Payment.Admin.HttpApi\Payment.Admin.HttpApi.csproj", "{046100DA-71ED-43C5-8C33-D424D678DBEA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Payment.Admin.HttpApi.Client", "src\Payment.Admin.HttpApi.Client\Payment.Admin.HttpApi.Client.csproj", "{A791943D-3F0B-41E3-AE73-15A60180B4A5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Payment.Admin.Blazor", "src\Payment.Admin.Blazor\Payment.Admin.Blazor.csproj", "{7C6D6C96-0816-43F3-81C8-44CBC18434DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Payment.Admin.Application.Tests", "test\Payment.Admin.Application.Tests\Payment.Admin.Application.Tests.csproj", "{E31DBDFE-1CC7-4E1B-B65C-C3810BF85981}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -91,28 +107,68 @@ Global
{3B7B6317-1B85-4164-8E11-75574F80AE17}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B7B6317-1B85-4164-8E11-75574F80AE17}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B7B6317-1B85-4164-8E11-75574F80AE17}.Release|Any CPU.Build.0 = Release|Any CPU
{3FF65447-69D5-4115-8398-8156FB381215}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3FF65447-69D5-4115-8398-8156FB381215}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3FF65447-69D5-4115-8398-8156FB381215}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3FF65447-69D5-4115-8398-8156FB381215}.Release|Any CPU.Build.0 = Release|Any CPU
{98CAA357-46A3-48EC-B5D9-27C706862351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{98CAA357-46A3-48EC-B5D9-27C706862351}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98CAA357-46A3-48EC-B5D9-27C706862351}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98CAA357-46A3-48EC-B5D9-27C706862351}.Release|Any CPU.Build.0 = Release|Any CPU
{B4D6C73B-2848-4B0C-BFA5-7EBEA59F6A75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B4D6C73B-2848-4B0C-BFA5-7EBEA59F6A75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B4D6C73B-2848-4B0C-BFA5-7EBEA59F6A75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B4D6C73B-2848-4B0C-BFA5-7EBEA59F6A75}.Release|Any CPU.Build.0 = Release|Any CPU
{267E26D0-3401-4945-AD58-30FE482566DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{267E26D0-3401-4945-AD58-30FE482566DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{267E26D0-3401-4945-AD58-30FE482566DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{267E26D0-3401-4945-AD58-30FE482566DD}.Release|Any CPU.Build.0 = Release|Any CPU
{046100DA-71ED-43C5-8C33-D424D678DBEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{046100DA-71ED-43C5-8C33-D424D678DBEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{046100DA-71ED-43C5-8C33-D424D678DBEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{046100DA-71ED-43C5-8C33-D424D678DBEA}.Release|Any CPU.Build.0 = Release|Any CPU
{A791943D-3F0B-41E3-AE73-15A60180B4A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A791943D-3F0B-41E3-AE73-15A60180B4A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A791943D-3F0B-41E3-AE73-15A60180B4A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A791943D-3F0B-41E3-AE73-15A60180B4A5}.Release|Any CPU.Build.0 = Release|Any CPU
{7C6D6C96-0816-43F3-81C8-44CBC18434DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C6D6C96-0816-43F3-81C8-44CBC18434DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C6D6C96-0816-43F3-81C8-44CBC18434DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C6D6C96-0816-43F3-81C8-44CBC18434DE}.Release|Any CPU.Build.0 = Release|Any CPU
{E31DBDFE-1CC7-4E1B-B65C-C3810BF85981}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E31DBDFE-1CC7-4E1B-B65C-C3810BF85981}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E31DBDFE-1CC7-4E1B-B65C-C3810BF85981}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E31DBDFE-1CC7-4E1B-B65C-C3810BF85981}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{E46CF089-D16A-4761-BE24-1B1B1D49225A} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{F2840BC7-0188-4606-9126-DADD0F5ABF7A} = {E46CF089-D16A-4761-BE24-1B1B1D49225A}
{D64C1577-4929-4B60-939E-96DE1534891A} = {E46CF089-D16A-4761-BE24-1B1B1D49225A}
{0CE86223-D31D-4315-A1F5-87BA3EE1B844} = {E46CF089-D16A-4761-BE24-1B1B1D49225A}
{4EF8B98A-E7A3-48A6-9C1F-10DE32001213} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{78040F9E-3501-4A40-82DF-00A597710F35} = {4EF8B98A-E7A3-48A6-9C1F-10DE32001213}
{F2840BC7-0188-4606-9126-DADD0F5ABF7A} = {E46CF089-D16A-4761-BE24-1B1B1D49225A}
{BD65D04F-08D5-40C1-8C24-77CA0BACB877} = {4EF8B98A-E7A3-48A6-9C1F-10DE32001213}
{78040F9E-3501-4A40-82DF-00A597710F35} = {4EF8B98A-E7A3-48A6-9C1F-10DE32001213}
{0CE86223-D31D-4315-A1F5-87BA3EE1B844} = {E46CF089-D16A-4761-BE24-1B1B1D49225A}
{077AA5F8-8B61-420C-A6B5-0150A66FDB34} = {4EF8B98A-E7A3-48A6-9C1F-10DE32001213}
{3B7B6317-1B85-4164-8E11-75574F80AE17} = {4EF8B98A-E7A3-48A6-9C1F-10DE32001213}
{5B39D229-146D-423E-9E50-91471851824E} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{EFBC83DB-A546-471E-99E4-4948C3ADCAA1} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D}
{C5BB573D-3030-4BCB-88B7-F6A85C32766C} = {EFBC83DB-A546-471E-99E4-4948C3ADCAA1}
{527F645C-C1FC-406E-8479-81386C8ECF13} = {EFBC83DB-A546-471E-99E4-4948C3ADCAA1}
{E60895E5-79C4-447D-88B7-85CB5BA336A4} = {EFBC83DB-A546-471E-99E4-4948C3ADCAA1}
{D3FD0217-A8C7-4BAF-BF77-962F1B055515} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D}
{90CB5DC4-C040-45C7-8900-9688B26405BC} = {D3FD0217-A8C7-4BAF-BF77-962F1B055515}
{3B7B6317-1B85-4164-8E11-75574F80AE17} = {4EF8B98A-E7A3-48A6-9C1F-10DE32001213}
{E46CF089-D16A-4761-BE24-1B1B1D49225A} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{4EF8B98A-E7A3-48A6-9C1F-10DE32001213} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{5B39D229-146D-423E-9E50-91471851824E} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{EFBC83DB-A546-471E-99E4-4948C3ADCAA1} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D}
{D3FD0217-A8C7-4BAF-BF77-962F1B055515} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D}
{FC718EF0-43EB-4767-9578-95FA0B3727A5} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D}
{3FF65447-69D5-4115-8398-8156FB381215} = {4EF8B98A-E7A3-48A6-9C1F-10DE32001213}
{98CAA357-46A3-48EC-B5D9-27C706862351} = {E46CF089-D16A-4761-BE24-1B1B1D49225A}
{B4D6C73B-2848-4B0C-BFA5-7EBEA59F6A75} = {5B39D229-146D-423E-9E50-91471851824E}
{267E26D0-3401-4945-AD58-30FE482566DD} = {5B39D229-146D-423E-9E50-91471851824E}
{046100DA-71ED-43C5-8C33-D424D678DBEA} = {5B39D229-146D-423E-9E50-91471851824E}
{A791943D-3F0B-41E3-AE73-15A60180B4A5} = {5B39D229-146D-423E-9E50-91471851824E}
{7C6D6C96-0816-43F3-81C8-44CBC18434DE} = {5B39D229-146D-423E-9E50-91471851824E}
{E31DBDFE-1CC7-4E1B-B65C-C3810BF85981} = {FC718EF0-43EB-4767-9578-95FA0B3727A5}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6AAFA1C6-603E-13FA-45E5-7910AA9F661D}

68
modules/payment/README.md

@ -0,0 +1,68 @@
# Payment Module
Payment module provides an API to make payments via using PayPal easily.
## Installation
TODO
## Usage
1. Create a Payment Request via using `IPaymentRequestAppService`
2. Build an URL to redirect to checkout page via using `IPaymentUrlBuilder`
```csharp
public class MyPageModel : AbpPageModel
{
protected IPaymentRequestAppService PaymentRequestAppService { get; }
protected IPaymentUrlBuilder PaymentUrlBuilder { get; }
public MyPageModel(
IPaymentRequestAppService paymentRequestAppService,
IPaymentUrlBuilder paymentUrlBuilder)
{
PaymentRequestAppService = paymentRequestAppService;
PaymentUrlBuilder = paymentUrlBuilder;
}
public async Task OnPostAsync()
{
var paymentRequest = await PaymentRequestAppService.CreateAsync(new PaymentRequestCreationDto
{
Amount = 9.90m,
CustomerId = CurrentUser.Id.ToString(),
ProductId = "UniqueProductId",
ProductName = "Awesome Product"
});
var checkoutUrl = PaymentUrlBuilder.BuildCheckoutUrl(paymentRequest.Id).AbsoluteUri;
Response.Redirect(checkoutUrl);
}
}
```
---
## Distributed Events
- `Payment.Completed` (**PaymentRequestCompletedEto**): Published when a payment is completed. Completion can be triggered via webhook or callback. Source doesn't affect to the event. Event will be triggered once.
- `PaymentRequestId`: Represents PaymentRequest entity Id.
- `ExtraProperties`: Represents ExtraProperties of PaymentRequest entity. You can use this properties to find your related objects to that payment.
- `Payment.Failed`(**PaymentRequestFailedEto**): Published when a payment is failed.
- `PaymentRequestId`: Represents PaymentRequest entity Id.
- `FailReason`: Reason of failure from payment provider (PayPal)
- `ExtraProperties`: Represents ExtraProperties of PaymentRequest entity.

9
modules/payment/common.props

@ -5,15 +5,6 @@
<NoWarn>$(NoWarn);CS1591</NoWarn>
<AbpProjectType>module</AbpProjectType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ConfigureAwait.Fody" Version="3.3.1" PrivateAssets="All" />
<PackageReference Include="Fody" Version="6.5.3">
<PrivateAssets>All</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<Target Name="NoWarnOnRazorViewImportedTypeConflicts" BeforeTargets="RazorCoreCompile">
<PropertyGroup>

9
modules/payment/configureawait.props

@ -0,0 +1,9 @@
<Project>
<ItemGroup>
<PackageReference Include="ConfigureAwait.Fody" Version="3.3.1" PrivateAssets="All" />
<PackageReference Include="Fody" Version="6.5.3">
<PrivateAssets>All</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

13
modules/payment/docker-compose.migrations.yml

@ -1,13 +0,0 @@
version: '3.4'
services:
migrations:
build:
context: ../../
dockerfile: templates/service/database/Dockerfile
depends_on:
- sqlserver
environment:
- IdentityServer_DB=Payment_Identity
- Payment_DB=Payment_ModuleDb
- SA_PASSWORD=yourStrong(!)Password

29
modules/payment/docker-compose.override.yml

@ -1,29 +0,0 @@
version: '3.4'
services:
sqlserver:
environment:
- SA_PASSWORD=yourStrong(!)Password
- ACCEPT_EULA=Y
ports:
- "51599:1433"
identity-server:
environment:
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionStrings__Default=Server=sqlserver;Database=Payment_Identity;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false
- ConnectionStrings__SqlServerCache=Server=sqlserver;Database=Payment_Cache;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false
ports:
- "51600:80"
payment:
environment:
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionStrings__Default=Server=sqlserver;Database=Payment_ModuleDb;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false
- ConnectionStrings__AbpSettingManagement=Server=sqlserver;Database=Payment_Identity;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false
- ConnectionStrings__AbpPermissionManagement=Server=sqlserver;Database=Payment_Identity;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false
- ConnectionStrings__AbpAuditLogging=Server=sqlserver;Database=Payment_Identity;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false
- ConnectionStrings__SqlServerCache=Server=sqlserver;Database=Payment_Cache;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false
- AuthServer__Authority=http://identity-server
ports:
- "51601:80"

25
modules/payment/docker-compose.yml

@ -1,25 +0,0 @@
version: '3.4'
services:
sqlserver:
image: mcr.microsoft.com/mssql/server
volumes:
- dbdata:/var/opt/mssql
identity-server:
build:
context: ../../
dockerfile: templates/service/host/IdentityServerHost/Dockerfile
depends_on:
- sqlserver
payment:
build:
context: ../../
dockerfile: templates/service/host/Payment.Host/Dockerfile
depends_on:
- sqlserver
- identity-server
volumes:
dbdata:

3
modules/payment/src/Payment.Admin.Application.Contracts/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
modules/payment/src/Payment.Admin.Application.Contracts/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

17
modules/payment/src/Payment.Admin.Application.Contracts/Payment.Admin.Application.Contracts.csproj

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Payment.Admin</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="5.0.0-beta.1" />
<PackageReference Include="Volo.Abp.Authorization" Version="5.0.0-beta.1" />
<ProjectReference Include="..\Payment.Domain.Shared\Payment.Domain.Shared.csproj" />
</ItemGroup>
</Project>

17
modules/payment/src/Payment.Admin.Application.Contracts/PaymentAdminApplicationContractsModule.cs

@ -0,0 +1,17 @@
using System;
using Volo.Abp.Application;
using Volo.Abp.Authorization;
using Volo.Abp.Modularity;
namespace Payment.Admin
{
[DependsOn(
typeof(PaymentDomainSharedModule),
typeof(AbpDddApplicationContractsModule),
typeof(AbpAuthorizationModule)
)]
public class PaymentAdminApplicationContractsModule : AbpModule
{
}
}

7
modules/payment/src/Payment.Admin.Application.Contracts/PaymentAdminRemoteServiceConsts.cs

@ -0,0 +1,7 @@
namespace Payment.Admin
{
public class PaymentAdminRemoteServiceConsts
{
public const string RemoteServiceName = "PaymentAdmin";
}
}

11
modules/payment/src/Payment.Admin.Application.Contracts/Payments/IPaymentRequestAdminAppService.cs

@ -0,0 +1,11 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Payment.Admin.Payments
{
public interface IPaymentRequestAdminAppService : IApplicationService
{
Task<PagedResultDto<PaymentRequestWithDetailsDto>> GetListAsync(PaymentRequestGetListInput input);
}
}

17
modules/payment/src/Payment.Admin.Application.Contracts/Payments/PaymentRequestGetListInput.cs

@ -0,0 +1,17 @@
using System;
using Payment.PaymentRequests;
using Volo.Abp.Application.Dtos;
namespace Payment.Admin.Payments
{
public class PaymentRequestGetListInput : PagedAndSortedResultRequestDto
{
public string ProductName { get; set; }
public DateTime? MaxCreationTime { get; set; }
public DateTime? MinCreationTime { get; set; }
public PaymentRequestState? Status { get; set; }
}
}

24
modules/payment/src/Payment.Admin.Application.Contracts/Payments/PaymentRequestWithDetailsDto.cs

@ -0,0 +1,24 @@
using System;
using Payment.PaymentRequests;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Auditing;
namespace Payment.Admin.Payments
{
public class PaymentRequestWithDetailsDto : ExtensibleEntityDto<Guid>, IHasCreationTime
{
public string CustomerId { get; set; }
public string ProductName { get; set; }
public float Price { get; set; }
public string Currency { get; set; }
public PaymentRequestState State { get; set; }
public string FailReason { get; set; }
public DateTime CreationTime { get; }
}
}

20
modules/payment/src/Payment.Admin.Application.Contracts/Permissions/PaymentAdminPermissionDefinitionProvider.cs

@ -0,0 +1,20 @@
using Payment.Localization;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Localization;
namespace Payment.Admin.Permissions
{
public class PaymentAdminPermissionDefinitionProvider : PermissionDefinitionProvider
{
public override void Define(IPermissionDefinitionContext context)
{
var paymentGroup = context.AddGroup(PaymentAdminPermissions.GroupName, L("Permission:PaymentManagement"));
paymentGroup.AddPermission(PaymentAdminPermissions.Request.Default, L("Permission:PaymentRequest"));
}
private static LocalizableString L(string name)
{
return LocalizableString.Create<PaymentResource>(name);
}
}
}

12
modules/payment/src/Payment.Admin.Application.Contracts/Permissions/PaymentAdminPermissions.cs

@ -0,0 +1,12 @@
namespace Payment.Admin.Permissions
{
public class PaymentAdminPermissions
{
public const string GroupName = "PaymentAdmin";
public static class Request
{
public const string Default = GroupName + ".Request";
}
}
}

3
modules/payment/src/Payment.Admin.Application/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
modules/payment/src/Payment.Admin.Application/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

17
modules/payment/src/Payment.Admin.Application/Payment.Admin.Application.csproj

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Payment.Admin</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="5.0.0-beta.1" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="5.0.0-beta.1" />
<ProjectReference Include="..\Payment.Admin.Application.Contracts\Payment.Admin.Application.Contracts.csproj" />
<ProjectReference Include="..\Payment.Domain\Payment.Domain.csproj" />
</ItemGroup>
</Project>

14
modules/payment/src/Payment.Admin.Application/PaymentAdminApplicationAutoMapperProfile.cs

@ -0,0 +1,14 @@
using AutoMapper;
using Payment.Admin.Payments;
using Payment.PaymentRequests;
namespace Payment.Admin
{
public class PaymentAdminApplicationAutoMapperProfile : Profile
{
public PaymentAdminApplicationAutoMapperProfile()
{
CreateMap<PaymentRequest, PaymentRequestWithDetailsDto>();
}
}
}

25
modules/payment/src/Payment.Admin.Application/PaymentAdminApplicationModule.cs

@ -0,0 +1,25 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Application;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
namespace Payment.Admin
{
[DependsOn(
typeof(PaymentDomainModule),
typeof(PaymentAdminApplicationContractsModule),
typeof(AbpDddApplicationModule),
typeof(AbpAutoMapperModule)
)]
public class PaymentAdminApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<PaymentAdminApplicationModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<PaymentAdminApplicationAutoMapperProfile>(validate: true);
});
}
}
}

46
modules/payment/src/Payment.Admin.Application/Payments/PaymentRequestAdminAppService.cs

@ -0,0 +1,46 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Payment.Admin.Permissions;
using Payment.PaymentRequests;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Payment.Admin.Payments
{
[Authorize(PaymentAdminPermissions.Request.Default)]
public class PaymentRequestAdminAppService : ApplicationService, IPaymentRequestAdminAppService
{
protected IPaymentRequestRepository PaymentRequestRepository { get; }
public PaymentRequestAdminAppService(IPaymentRequestRepository paymentRequestRepository)
{
PaymentRequestRepository = paymentRequestRepository;
}
public async Task<PagedResultDto<PaymentRequestWithDetailsDto>> GetListAsync(PaymentRequestGetListInput input)
{
var paymentRequests = await PaymentRequestRepository.GetListAsync(
input.SkipCount,
input.MaxResultCount,
input.Sorting,
input.ProductName,
input.MaxCreationTime,
input.MinCreationTime,
input.Status
);
var totalCount = await PaymentRequestRepository.GetCountAsync(
input.ProductName,
input.MaxCreationTime,
input.MinCreationTime,
input.Status
);
return new PagedResultDto<PaymentRequestWithDetailsDto>(
totalCount,
ObjectMapper.Map<List<PaymentRequest>, List<PaymentRequestWithDetailsDto>>(paymentRequests)
);
}
}
}

3
modules/payment/src/Payment.Admin.Blazor/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
modules/payment/src/Payment.Admin.Blazor/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

43
modules/payment/src/Payment.Admin.Blazor/Navigation/PaymentAdminBlazorMenuContributor.cs

@ -0,0 +1,43 @@
using System.Threading.Tasks;
using Payment.Admin.Permissions;
using Payment.Localization;
using Volo.Abp.UI.Navigation;
namespace Payment.Admin.Navigation
{
public class PaymentAdminBlazorMenuContributor : IMenuContributor
{
public async Task ConfigureMenuAsync(MenuConfigurationContext context)
{
if (context.Menu.Name == StandardMenus.Main)
{
await ConfigureMainMenuAsync(context);
}
}
private async Task ConfigureMainMenuAsync(MenuConfigurationContext context)
{
await AddPaymentMenuAsync(context);
}
private Task AddPaymentMenuAsync(MenuConfigurationContext context)
{
var l = context.GetLocalizer<PaymentResource>();
var paymentMenu = context.Menu.FindMenuItem(PaymentAdminMenuNames.GroupName);
if (paymentMenu == null)
{
paymentMenu = new ApplicationMenuItem(
PaymentAdminMenuNames.GroupName,
l["Menu:PaymentManagement"],
icon: "fa fa-money-check",
url: "/payment/requests",
requiredPermissionName: PaymentAdminPermissions.Request.Default
);
}
context.Menu.AddItem(paymentMenu);
return Task.CompletedTask;
}
}
}

7
modules/payment/src/Payment.Admin.Blazor/Navigation/PaymentAdminMenuNames.cs

@ -0,0 +1,7 @@
namespace Payment.Admin.Navigation
{
public static class PaymentAdminMenuNames
{
public const string GroupName = "Payment";
}
}

89
modules/payment/src/Payment.Admin.Blazor/Pages/Payment/Requests/Index.razor

@ -0,0 +1,89 @@
@page "/Payment/Requests"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(PaymentAdminPermissions.Request.Default)]
@using global::Payment.Admin.Payments
@using global::Payment.PaymentRequests
@using global::Payment.Admin.Permissions
@using Volo.Abp.BlazoriseUI.Components.ObjectExtending
@inherits PaymentAdminComponentBase
<Card>
<CardHeader>
<h2>@L["PaymentRequests"]</h2>
</CardHeader>
<CardBody>
<Form>
<div id="FilterSection" class="row mt-3">
<Field ColumnSize="ColumnSize.Is3">
<FieldLabel>@L["ProductName"]</FieldLabel>
<TextEdit Placeholder="@L["ProductName"]" @bind-Text="@GetListInput.ProductName"/>
</Field>
<Field ColumnSize="ColumnSize.Is3">
<FieldLabel>@L["Status"]</FieldLabel>
<Select Placeholder="@L["Status"]" TValue="PaymentRequestState?" SelectedValue="@GetListInput.Status" SelectedValueChanged="OnPaymentRequestStateChanged">
<option value="@((PaymentRequestState?) null)">-</option>
@foreach (var item in PaymentRequestStates)
{
<SelectItem Value="@item">@L["Enum:PaymentRequestState:" + item]</SelectItem>
}
</Select>
</Field>
<Field ColumnSize="ColumnSize.Is3">
<FieldLabel>@L["MinCreationTime"]</FieldLabel>
<DateEdit Placeholder="@L["MinCreationTime"]" @bind-Date="@GetListInput.MinCreationTime"/>
</Field>
<Field ColumnSize="ColumnSize.Is3">
<FieldLabel>@L["MaxCreationTime"]</FieldLabel>
<DateEdit Placeholder="@L["MaxCreationTime"]" @bind-Date="@GetListInput.MaxCreationTime"/>
</Field>
<Field ColumnSize="ColumnSize.Is12">
<Row>
<Column ColumnSize="ColumnSize.Is9"></Column>
<Column ColumnSize="ColumnSize.Is3">
<SubmitButton Block="true"
Clicked="@GetPaymentRequestsAsync">
<Icon Name="IconName.Search" />
</SubmitButton>
</Column>
</Row>
</Field>
</div>
</Form>
<DataGrid TItem="PaymentRequestWithDetailsDto"
Data="PaymentRequests"
ReadData="OnDataGridReadAsync"
TotalItems="TotalCount"
ShowPager="true"
PageSize="PageSize"
Responsive="true">
<DataGridColumns>
<DataGridColumn TItem="PaymentRequestWithDetailsDto"
Field="ProductName"
Caption="@L["ProductName"]">
</DataGridColumn>
<DataGridColumn TItem="PaymentRequestWithDetailsDto"
Field="Currency"
Caption="@L["Currency"]">
</DataGridColumn>
<DataGridColumn TItem="PaymentRequestWithDetailsDto"
Field="Price"
Caption="@L["Price"]">
</DataGridColumn>
<DataGridColumn TItem="PaymentRequestWithDetailsDto"
Field="State"
Caption="@L["State"]">
</DataGridColumn>
<DataGridColumn TItem="PaymentRequestWithDetailsDto"
Field="FailReason"
Caption="@L["FailReason"]">
</DataGridColumn>
<DataGridColumn TItem="PaymentRequestWithDetailsDto"
Field="CreationTime"
Caption="@L["CreationTime"]">
</DataGridColumn>
</DataGridColumns>
</DataGrid>
</CardBody>
</Card>

82
modules/payment/src/Payment.Admin.Blazor/Pages/Payment/Requests/Index.razor.cs

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Blazorise;
using Blazorise.DataGrid;
using Microsoft.AspNetCore.Components;
using Payment.Admin.Payments;
using Volo.Abp.Application.Dtos;
using Payment.PaymentRequests;
namespace Payment.Admin.Pages.Payment.Requests
{
public partial class Index
{
[Inject]
protected IPaymentRequestAdminAppService PaymentRequestAdminAppService { get; set; }
protected IReadOnlyList<PaymentRequestWithDetailsDto> PaymentRequests { get; set; }
protected IReadOnlyList<PaymentRequestState> PaymentRequestStates => Enum.GetValues<PaymentRequestState>();
protected PaymentRequestGetListInput GetListInput { get; set; }
protected virtual int PageSize { get; } = LimitedResultRequestDto.DefaultMaxResultCount;
protected int CurrentPage { get; set; } = 1;
protected string CurrentSorting { get; set; }
protected int? TotalCount { get; set; }
public Index()
{
GetListInput = new();
}
protected override async Task OnInitializedAsync()
{
await GetPaymentRequestsAsync();
await InvokeAsync(StateHasChanged);
}
protected virtual async Task GetPaymentRequestsAsync()
{
try
{
GetListInput.Sorting = CurrentSorting;
GetListInput.SkipCount = (CurrentPage - 1) * PageSize;
GetListInput.MaxResultCount = PageSize;
var result = await PaymentRequestAdminAppService.GetListAsync(GetListInput);
PaymentRequests = result.Items.As<IReadOnlyList<PaymentRequestWithDetailsDto>>();
TotalCount = (int?) result.TotalCount;
await InvokeAsync(StateHasChanged);
}
catch (Exception ex)
{
await HandleErrorAsync(ex);
}
}
protected virtual async Task OnDataGridReadAsync(DataGridReadDataEventArgs<PaymentRequestWithDetailsDto> e)
{
CurrentSorting = e.Columns
.Where(c => c.SortDirection != SortDirection.None)
.Select(c => c.Field + (c.SortDirection == SortDirection.Descending ? " DESC" : ""))
.JoinAsString(",");
CurrentPage = e.Page;
await GetPaymentRequestsAsync();
await InvokeAsync(StateHasChanged);
}
private async Task OnPaymentRequestStateChanged(PaymentRequestState? status)
{
GetListInput.Status = status;
await GetPaymentRequestsAsync();
}
}
}

16
modules/payment/src/Payment.Admin.Blazor/Payment.Admin.Blazor.csproj

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Payment.Admin</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AspNetCore.Components.WebAssembly.Theming" Version="5.0.0-beta.1" />
<ProjectReference Include="..\Payment.Admin.HttpApi.Client\Payment.Admin.HttpApi.Client.csproj" />
</ItemGroup>
</Project>

28
modules/payment/src/Payment.Admin.Blazor/PaymentAdminBlazorModule.cs

@ -0,0 +1,28 @@
using Payment.Admin.Navigation;
using Volo.Abp.AspNetCore.Components.Web.Theming.Routing;
using Volo.Abp.AspNetCore.Components.WebAssembly.Theming;
using Volo.Abp.Modularity;
using Volo.Abp.UI.Navigation;
namespace Payment.Admin
{
[DependsOn(
typeof(AbpAspNetCoreComponentsWebAssemblyThemingModule),
typeof(PaymentAdminHttpApiClientModule)
)]
public class PaymentAdminBlazorModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new PaymentAdminBlazorMenuContributor());
});
Configure<AbpRouterOptions>(options =>
{
options.AdditionalAssemblies.Add(typeof(PaymentAdminBlazorModule).Assembly);
});
}
}
}

14
modules/payment/src/Payment.Admin.Blazor/PaymentAdminComponentBase.cs

@ -0,0 +1,14 @@
using Payment.Localization;
using Volo.Abp.AspNetCore.Components;
namespace Payment.Admin
{
public abstract class PaymentAdminComponentBase : AbpComponentBase
{
protected PaymentAdminComponentBase()
{
LocalizationResource = typeof(PaymentResource);
ObjectMapperContext = typeof(PaymentAdminBlazorModule);
}
}
}

6
modules/payment/src/Payment.Admin.Blazor/_Imports.razor

@ -0,0 +1,6 @@
@using Microsoft.AspNetCore.Components.Web
@using Volo.Abp.AspNetCore.Components.Web
@using Volo.Abp.BlazoriseUI
@using Volo.Abp.BlazoriseUI.Components
@using Blazorise
@using Blazorise.DataGrid

26
modules/payment/src/Payment.Admin.HttpApi.Client/ClientProxies/PaymentRequestAdminClientProxy.Generated.cs

@ -0,0 +1,26 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Payment.Admin.Payments;
// ReSharper disable once CheckNamespace
namespace Payment.Admin.Payments.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IPaymentRequestAdminAppService), typeof(PaymentRequestAdminClientProxy))]
public partial class PaymentRequestAdminClientProxy : ClientProxyBase<IPaymentRequestAdminAppService>, IPaymentRequestAdminAppService
{
public virtual async Task<PagedResultDto<PaymentRequestWithDetailsDto>> GetListAsync(PaymentRequestGetListInput input)
{
return await RequestAsync<PagedResultDto<PaymentRequestWithDetailsDto>>(nameof(GetListAsync), new ClientProxyRequestTypeValue
{
{ typeof(PaymentRequestGetListInput), input }
});
}
}
}

8
modules/payment/src/Payment.Admin.HttpApi.Client/ClientProxies/PaymentRequestAdminClientProxy.cs

@ -0,0 +1,8 @@
// This file is part of PaymentRequestAdminClientProxy, you can customize it here
// ReSharper disable once CheckNamespace
namespace Payment.Admin.Payments.ClientProxies
{
public partial class PaymentRequestAdminClientProxy
{
}
}

132
modules/payment/src/Payment.Admin.HttpApi.Client/ClientProxies/paymentAdmin-generate-proxy.json

@ -0,0 +1,132 @@
{
"modules": {
"paymentAdmin": {
"rootPath": "paymentAdmin",
"remoteServiceName": "PaymentAdmin",
"controllers": {
"Payment.Admin.Payments.PaymentRequestAdminController": {
"controllerName": "PaymentRequestAdmin",
"controllerGroupName": "PaymentRequestAdmin",
"type": "Payment.Admin.Payments.PaymentRequestAdminController",
"interfaces": [
{
"type": "Payment.Admin.Payments.IPaymentRequestAdminAppService"
}
],
"actions": {
"GetListAsyncByInput": {
"uniqueName": "GetListAsyncByInput",
"name": "GetListAsync",
"httpMethod": "GET",
"url": "api/payment/requests",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Payment.Admin.Payments.PaymentRequestGetListInput, Payment.Admin.Application.Contracts",
"type": "Payment.Admin.Payments.PaymentRequestGetListInput",
"typeSimple": "Payment.Admin.Payments.PaymentRequestGetListInput",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "ProductName",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "MaxCreationTime",
"jsonName": null,
"type": "System.DateTime?",
"typeSimple": "string?",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "MinCreationTime",
"jsonName": null,
"type": "System.DateTime?",
"typeSimple": "string?",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "Status",
"jsonName": null,
"type": "Payment.PaymentRequests.PaymentRequestState?",
"typeSimple": "Payment.PaymentRequests.PaymentRequestState?",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "Sorting",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "SkipCount",
"jsonName": null,
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
},
{
"nameOnMethod": "input",
"name": "MaxResultCount",
"jsonName": null,
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
}
],
"returnValue": {
"type": "Volo.Abp.Application.Dtos.PagedResultDto<Payment.Admin.Payments.PaymentRequestWithDetailsDto>",
"typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto<Payment.Admin.Payments.PaymentRequestWithDetailsDto>"
},
"allowAnonymous": null,
"implementFrom": "Payment.Admin.Payments.IPaymentRequestAdminAppService"
}
}
}
}
}
},
"types": {}
}

3
modules/payment/src/Payment.Admin.HttpApi.Client/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
modules/payment/src/Payment.Admin.HttpApi.Client/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

21
modules/payment/src/Payment.Admin.HttpApi.Client/Payment.Admin.HttpApi.Client.csproj

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Payment.Admin</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Http.Client" Version="5.0.0-beta.1" />
<ProjectReference Include="..\Payment.Admin.Application.Contracts\Payment.Admin.Application.Contracts.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="**\*generate-proxy.json" />
<Content Remove="**\*generate-proxy.json" />
</ItemGroup>
</Project>

27
modules/payment/src/Payment.Admin.HttpApi.Client/PaymentAdminHttpApiClientModule.cs

@ -0,0 +1,27 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Payment.Admin
{
[DependsOn(
typeof(PaymentAdminApplicationContractsModule),
typeof(AbpHttpClientModule)
)]
public class PaymentAdminHttpApiClientModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddStaticHttpClientProxies(
typeof(PaymentAdminApplicationContractsModule).Assembly,
PaymentAdminRemoteServiceConsts.RemoteServiceName
);
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<PaymentAdminHttpApiClientModule>();
});
}
}
}

3
modules/payment/src/Payment.Admin.HttpApi/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
modules/payment/src/Payment.Admin.HttpApi/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

16
modules/payment/src/Payment.Admin.HttpApi/Payment.Admin.HttpApi.csproj

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Payment.Admin</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="5.0.0-beta.1" />
<ProjectReference Include="..\Payment.Admin.Application.Contracts\Payment.Admin.Application.Contracts.csproj" />
</ItemGroup>
</Project>

13
modules/payment/src/Payment.Admin.HttpApi/PaymentAdminController.cs

@ -0,0 +1,13 @@
using Payment.Localization;
using Volo.Abp.AspNetCore.Mvc;
namespace Payment.Admin
{
public abstract class PaymentAdminController : AbpControllerBase
{
protected PaymentAdminController()
{
LocalizationResource = typeof(PaymentResource);
}
}
}

34
modules/payment/src/Payment.Admin.HttpApi/PaymentAdminHttpApiModule.cs

@ -0,0 +1,34 @@
using Localization.Resources.AbpUi;
using Microsoft.Extensions.DependencyInjection;
using Payment.Localization;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
namespace Payment.Admin
{
[DependsOn(
typeof(PaymentAdminApplicationContractsModule),
typeof(AbpAspNetCoreMvcModule)
)]
public class PaymentAdminHttpApiModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(PaymentAdminHttpApiModule).Assembly);
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<PaymentResource>()
.AddBaseTypes(typeof(AbpUiResource));
});
}
}
}

26
modules/payment/src/Payment.Admin.HttpApi/Payments/PaymentRequestAdminController.cs

@ -0,0 +1,26 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
namespace Payment.Admin.Payments
{
[RemoteService(Name = PaymentAdminRemoteServiceConsts.RemoteServiceName)]
[Area("paymentAdmin")]
[Route("api/payment/requests")]
public class PaymentRequestAdminController : PaymentAdminController, IPaymentRequestAdminAppService
{
protected IPaymentRequestAdminAppService PaymentRequestAdminAppService { get; }
public PaymentRequestAdminController(IPaymentRequestAdminAppService paymentRequestAdminAppService)
{
PaymentRequestAdminAppService = paymentRequestAdminAppService;
}
[HttpGet]
public Task<PagedResultDto<PaymentRequestWithDetailsDto>> GetListAsync(PaymentRequestGetListInput input)
{
return PaymentRequestAdminAppService.GetListAsync(input);
}
}
}

1
modules/payment/src/Payment.Application.Contracts/Payment.Application.Contracts.csproj

@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>

19
modules/payment/src/Payment.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs

@ -0,0 +1,19 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace Payment.PaymentRequests
{
public interface IPaymentRequestAppService : IApplicationService
{
Task<PaymentRequestDto> GetAsync(Guid id);
Task<PaymentRequestDto> CreateAsync(PaymentRequestCreationDto input);
Task<StartPaymentResultDto> StartPaymentAsync(StartPaymentDto input);
Task<PaymentRequestDto> CompleteAsync(string token);
Task<bool> HandleWebhookAsync(string payload);
}
}

32
modules/payment/src/Payment.Application.Contracts/PaymentRequests/PaymentRequestCreationDto.cs

@ -0,0 +1,32 @@
using JetBrains.Annotations;
using System;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.ObjectExtending;
using Volo.Abp.Validation;
namespace Payment.PaymentRequests
{
[Serializable]
public class PaymentRequestCreationDto : ExtensibleObject
{
[DynamicMaxLength(typeof(PaymentRequestConsts), nameof(PaymentRequestConsts.MaxCustomerIdLength))]
public string CustomerId { get; set; }
[DynamicMaxLength(typeof(PaymentRequestConsts), nameof(PaymentRequestConsts.MaxProductIdLength))]
public string ProductId { get; set; }
[Required]
[DynamicMaxLength(typeof(PaymentRequestConsts), nameof(PaymentRequestConsts.MaxProductNameLength))]
public string ProductName { get; set; }
public decimal Price { get; set; }
/// <summary>
/// 3 Letter Language Code in ISO 4217 Standards.
/// For example: USD, EUR.
/// </summary>
[StringLength(PaymentRequestConsts.MaxCurrencyLength)]
[CanBeNull]
public string Currency { get; set; }
}
}

29
modules/payment/src/Payment.Application.Contracts/PaymentRequests/PaymentRequestDto.cs

@ -0,0 +1,29 @@
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Data;
namespace Payment.PaymentRequests
{
[Serializable]
public class PaymentRequestDto : CreationAuditedEntityDto<Guid>, IHasExtraProperties
{
public string CustomerId { get; set; }
public string ProductId { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
public string Currency { get; set; }
public PaymentRequestState State { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; set; }
public PaymentRequestDto()
{
ExtraProperties = new ExtraPropertyDictionary();
}
}
}

18
modules/payment/src/Payment.Application.Contracts/PaymentRequests/StartPaymentDto.cs

@ -0,0 +1,18 @@
using JetBrains.Annotations;
using System;
using System.ComponentModel.DataAnnotations;
namespace Payment.PaymentRequests
{
[Serializable]
public class StartPaymentDto
{
public Guid PaymentRequestId { get; set; }
[NotNull]
[Required]
public string ReturnUrl { get; set; }
public string CancelUrl { get; set; }
}
}

10
modules/payment/src/Payment.Application.Contracts/PaymentRequests/StartPaymentResultDto.cs

@ -0,0 +1,10 @@
using System;
namespace Payment.PaymentRequests
{
[Serializable]
public class StartPaymentResultDto
{
public string CheckoutLink { get; set; }
}
}

4
modules/payment/src/Payment.Application/Payment.Application.csproj

@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
@ -14,4 +15,7 @@
<ProjectReference Include="..\Payment.Domain\Payment.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="PayPalCheckoutSdk" Version="1.0.4" />
</ItemGroup>
</Project>

5
modules/payment/src/Payment.Application/PaymentApplicationAutoMapperProfile.cs

@ -1,4 +1,5 @@
using AutoMapper;
using Payment.PaymentRequests;
namespace Payment
{
@ -6,9 +7,7 @@ namespace Payment
{
public PaymentApplicationAutoMapperProfile()
{
/* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */
CreateMap<PaymentRequest, PaymentRequestDto>();
}
}
}

16
modules/payment/src/Payment.Application/PaymentApplicationModule.cs

@ -2,6 +2,10 @@
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
using Volo.Abp.Application;
using Microsoft.Extensions.Options;
using Payment.PayPal;
using System;
using PayPalCheckoutSdk.Core;
namespace Payment
{
@ -20,6 +24,18 @@ namespace Payment
{
options.AddMaps<PaymentApplicationModule>(validate: true);
});
context.Services.AddTransient(provider =>
{
var options = provider.GetService<IOptions<PayPalOptions>>().Value;
if (options.Environment.IsNullOrWhiteSpace() || options.Environment == PayPalConsts.Environment.Sandbox)
{
return new PayPalHttpClient(new SandboxEnvironment(options.ClientId, options.Secret));
}
return new PayPalHttpClient(new LiveEnvironment(options.ClientId, options.Secret));
});
}
}
}

173
modules/payment/src/Payment.Application/PaymentRequests/PaymentRequestAppService.cs

@ -0,0 +1,173 @@
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using Payment.PayPal;
using PayPalCheckoutSdk.Core;
using PayPalCheckoutSdk.Orders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.ObjectExtending;
namespace Payment.PaymentRequests
{
public class PaymentRequestAppService : PaymentAppService, IPaymentRequestAppService
{
protected readonly IPaymentRequestRepository _paymentRequestRepository;
protected readonly PaymentOptions _paymentOptions;
protected readonly PayPalHttpClient _payPalHttpClient;
public PaymentRequestAppService(
IPaymentRequestRepository paymentRequestRepository,
IOptions<PaymentOptions> paymentOptions,
PayPalHttpClient payPalHttpClient)
{
_paymentRequestRepository = paymentRequestRepository;
_paymentOptions = paymentOptions.Value;
_payPalHttpClient = payPalHttpClient;
}
public async Task<PaymentRequestDto> GetAsync(Guid id)
{
var paymentRequest = await _paymentRequestRepository.GetAsync(id);
return ObjectMapper.Map<PaymentRequest, PaymentRequestDto>(paymentRequest);
}
public async Task<PaymentRequestDto> CreateAsync(PaymentRequestCreationDto input)
{
var paymentRequest = new PaymentRequest(
GuidGenerator.Create(),
input.CustomerId,
input.ProductId,
input.ProductName,
input.Price,
input.Currency ?? _paymentOptions.DefaultCurrency
);
foreach (var extraProperty in input.ExtraProperties)
{
paymentRequest.SetProperty(extraProperty.Key, extraProperty.Value);
}
await _paymentRequestRepository.InsertAsync(paymentRequest);
return ObjectMapper.Map<PaymentRequest, PaymentRequestDto>(paymentRequest);
}
public async Task<StartPaymentResultDto> StartPaymentAsync(StartPaymentDto input)
{
var paymentRequest = await _paymentRequestRepository.GetAsync(input.PaymentRequestId);
var order = new OrderRequest
{
CheckoutPaymentIntent = "CAPTURE",
ApplicationContext = new ApplicationContext
{
ReturnUrl = input.ReturnUrl,
CancelUrl = input.CancelUrl,
},
PurchaseUnits = new List<PurchaseUnitRequest>
{
new PurchaseUnitRequest
{
AmountWithBreakdown = new AmountWithBreakdown
{
AmountBreakdown = new AmountBreakdown
{
ItemTotal = new Money
{
CurrencyCode = paymentRequest.Currency,
Value = paymentRequest.Price.ToString(".00")
}
},
CurrencyCode = paymentRequest.Currency,
Value = paymentRequest.Price.ToString(".00"),
},
Items = new List<Item>
{
new Item
{
Quantity = 1.ToString(),
Name = paymentRequest.ProductName,
UnitAmount = new Money
{
CurrencyCode = paymentRequest.Currency,
Value = paymentRequest.Price.ToString(".00")
}
}
},
ReferenceId = paymentRequest.Id.ToString()
}
}
};
var request = new OrdersCreateRequest();
request.Prefer("return=representation");
request.RequestBody(order);
var result = (await _payPalHttpClient.Execute(request)).Result<Order>();
return new StartPaymentResultDto
{
CheckoutLink = result.Links.First(x => x.Rel == "approve").Href
};
}
public async Task<PaymentRequestDto> CompleteAsync(string token)
{
var request = new OrdersCaptureRequest(token);
request.RequestBody(new OrderActionRequest());
var order = (await _payPalHttpClient.Execute(request)).Result<Order>();
var paymentRequest = await UpdatePaymentRequestStateAsync(order);
return ObjectMapper.Map<PaymentRequest, PaymentRequestDto>(paymentRequest);
}
public async Task<bool> HandleWebhookAsync(string payload)
{
var jObject = JObject.Parse(payload);
//// TODO: Find way to parse with System.Text.Json instead of Newtonsoft
var order = jObject["resource"].ToObject<Order>();
var request = new OrdersGetRequest(order.Id);
// Ensure order object comes from PayPal
var response = await _payPalHttpClient.Execute(request);
order = response.Result<Order>();
await UpdatePaymentRequestStateAsync(order);
// PayPal doesn't accept Http 204 (NoContent) result and tries to execute webhook again.
// So with following value, API returns Http 200 (OK) result.
return true;
}
private async Task<PaymentRequest> UpdatePaymentRequestStateAsync(Order order)
{
var paymentRequestId = Guid.Parse(order.PurchaseUnits.First().ReferenceId);
var paymentRequest = await _paymentRequestRepository.GetAsync(paymentRequestId);
if (order.Status is PayPalConsts.OrderStatus.Completed or PayPalConsts.OrderStatus.Approved)
{
paymentRequest.SetAsCompleted();
}
else
{
paymentRequest.SetAsFailed(order.Status);
}
paymentRequest.ExtraProperties[PayPalConsts.OrderIdPropertyName] = order.Id;
paymentRequest.ExtraProperties[nameof(order.Status)] = order.Status;
await _paymentRequestRepository.UpdateAsync(paymentRequest);
return paymentRequest;
}
}
}

3
modules/payment/src/Payment.BackgroundServices/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait />
</Weavers>

30
modules/payment/src/Payment.BackgroundServices/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

15
modules/payment/src/Payment.BackgroundServices/Payment.BackgroundServices.csproj

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Payment</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Payment.Domain\Payment.Domain.csproj" />
</ItemGroup>
</Project>

15
modules/payment/src/Payment.BackgroundServices/PaymentBackgroundServicesModule.cs

@ -0,0 +1,15 @@
using Volo.Abp.Modularity;
namespace Payment
{
[DependsOn(
typeof(PaymentDomainModule)
)]
public class PaymentBackgroundServicesModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
}
}

33
modules/payment/src/Payment.Domain.Shared/Localization/Payment/en.json

@ -1,7 +1,36 @@
{
"culture": "en",
"texts": {
"MyAccount": "My account",
"SamplePageMessage": "A sample page for the Payment module"
"CompletePayment": "Complete the Payment",
"Enum:PaymentRequestState:Completed": "Completed",
"Enum:PaymentRequestState:Failed": "Failed",
"Enum:PaymentRequestState:Waiting": "Waiting",
"GoBack": "Go Back",
"MyAccount": "My account",
"PaymentRequestIsNotWaiting": "The state isn't 'Waiting', so you can't pay this Payment Request at this time.",
"PaymentResult": "Payment Result",
"Price": "Price",
"ProductInformation": "Product Information",
"ProductName": "Product Name",
"SamplePageMessage": "A sample page for the Payment module",
"Status": "State",
"YourPaymentCompletedSuccessfully": "Your payment has been completed successfully!",
"YourPaymentFailed": "Your payment has been failed unfortunetely!",
"Permission:Payment": "Payment",
"Menu:PaymentManagement": "Payment",
"PaymentRequests": "Payment Requests",
"PaymentRequestState:0": "Waiting",
"PaymentRequestState:1": "Completed",
"PaymentRequestState:2": "Failed",
"MinCreationTime": "Min Creation Time",
"MaxCreationTime": "Max Creation Time",
"CustomerId": "Customer Id",
"Currency": "Currency",
"State": "State",
"FailReason": "Fail Reason",
"CreationTime": "Creation Time",
"Permission:PaymentManagement": "Payment Management",
"Permission:PaymentRequest": "Payment Requests"
}
}

47
modules/payment/src/Payment.Domain.Shared/PayPal/PayPalConsts.cs

@ -0,0 +1,47 @@
namespace Payment.PayPal
{
public static class PayPalConsts
{
public const string OrderIdPropertyName = "OrderId";
public static class OrderStatus
{
/// <summary>
/// The order was created with the specified context.
/// </summary>
public const string Created = "CREATED";
/// <summary>
/// The order was saved and persisted. The order status continues to be in progress until a capture is made with final_capture = true for all purchase units within the order.
/// </summary>
public const string Saved = "SAVED";
/// <summary>
/// The customer approved the payment through the PayPal wallet or another form of guest or unbranded payment. For example, a card, bank account, or so on.
/// </summary>
public const string Approved = "APPROVED";
/// <summary>
/// All purchase units in the order are voided.
/// </summary>
public const string Voided = "VOIDED";
/// <summary>
/// The payment was authorized or the authorized payment was captured for the order.
/// </summary>
public const string Completed = "COMPLETED";
/// <summary>
/// The order requires an action from the payer (e.g. 3DS authentication). Redirect the payer to the "rel":"payer-action" HATEOAS link returned as part of the response prior to authorizing or capturing the order.
/// </summary>
public const string PlayerActionRequired = "PAYER_ACTION_REQUIRED";
}
public static class Environment
{
public const string Sandbox = "Sandbox";
public const string Live = "Live";
}
}
}

3
modules/payment/src/Payment.Domain.Shared/Payment.Domain.Shared.csproj

@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
@ -13,7 +14,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.0-rc.*" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.0-rc.1.*" />
</ItemGroup>
<ItemGroup>

16
modules/payment/src/Payment.Domain.Shared/PaymentRequests/PaymentRequestCompletedEto.cs

@ -0,0 +1,16 @@
using System;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus;
namespace Payment.PaymentRequests
{
[Serializable]
[EventName("Payment.Completed")]
public class PaymentRequestCompletedEto : EtoBase, IHasExtraProperties
{
public Guid PaymentRequestId { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; set; }
}
}

10
modules/payment/src/Payment.Domain.Shared/PaymentRequests/PaymentRequestConsts.cs

@ -0,0 +1,10 @@
namespace Payment.PaymentRequests
{
public static class PaymentRequestConsts
{
public const int MaxCurrencyLength = 100;
public static int MaxCustomerIdLength { get; set; } = 100;
public static int MaxProductIdLength { get; set; } = 100;
public static int MaxProductNameLength { get; set; } = 200;
}
}

18
modules/payment/src/Payment.Domain.Shared/PaymentRequests/PaymentRequestFailedEto.cs

@ -0,0 +1,18 @@
using System;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus;
namespace Payment.PaymentRequests
{
[Serializable]
[EventName("Payment.Failed")]
public class PaymentRequestFailedEto : EtoBase, IHasExtraProperties
{
public Guid PaymentRequestId { get; set; }
public string FailReason { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; set; }
}
}

9
modules/payment/src/Payment.Domain.Shared/PaymentRequests/PaymentRequestState.cs

@ -0,0 +1,9 @@
namespace Payment.PaymentRequests
{
public enum PaymentRequestState : byte
{
Waiting = 0,
Completed,
Failed
}
}

22
modules/payment/src/Payment.Domain/PayPal/PayPalOptions.cs

@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace Payment.PayPal
{
public class PayPalOptions
{
public string ClientId { get; set; }
public string Secret { get; set; }
public string Locale { get; set; }
/// <summary>
/// "Sandbox" or "Live". Default value is "Sandbox"
/// </summary>
public string Environment { get; set; } = PayPalConsts.Environment.Sandbox;
public bool Recommended { get; set; }
public List<string> ExtraInfos { get; set; } = new();
}
}

1
modules/payment/src/Payment.Domain/Payment.Domain.csproj

@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>

2
modules/payment/src/Payment.Domain/PaymentDbProperties.cs

@ -2,7 +2,7 @@
{
public static class PaymentDbProperties
{
public static string DbTablePrefix { get; set; } = "Payment";
public static string DbTablePrefix { get; set; } = "Pay";
public static string DbSchema { get; set; } = null;

10
modules/payment/src/Payment.Domain/PaymentDomainModule.cs

@ -1,4 +1,6 @@
using Volo.Abp.Domain;
using Microsoft.Extensions.DependencyInjection;
using Payment.PayPal;
using Volo.Abp.Domain;
using Volo.Abp.Modularity;
namespace Payment
@ -9,6 +11,12 @@ namespace Payment
)]
public class PaymentDomainModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<PayPalOptions>(configuration.GetSection("Payment:PayPal"));
Configure<PaymentOptions>(configuration.GetSection("Payment"));
}
}
}

7
modules/payment/src/Payment.Domain/PaymentOptions.cs

@ -0,0 +1,7 @@
namespace Payment
{
public class PaymentOptions
{
public string DefaultCurrency { get; set; } = "USD";
}
}

30
modules/payment/src/Payment.Domain/PaymentRequests/IPaymentRequestRepository.cs

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace Payment.PaymentRequests
{
public interface IPaymentRequestRepository : IRepository<PaymentRequest, Guid>
{
Task<List<PaymentRequest>> GetListAsync(
int skipCount,
int maxResultCount,
string sorting,
string productName = null,
DateTime? maxCreationTime = null,
DateTime? minCreationTime = null,
PaymentRequestState? state = null,
CancellationToken cancellationToken = default
);
Task<int> GetCountAsync(
string productName = null,
DateTime? maxCreationTime = null,
DateTime? minCreationTime = null,
PaymentRequestState? state = null,
CancellationToken cancellationToken = default
);
}
}

87
modules/payment/src/Payment.Domain/PaymentRequests/PaymentRequest.cs

@ -0,0 +1,87 @@
using System;
using System.Linq;
using JetBrains.Annotations;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;
namespace Payment.PaymentRequests
{
public class PaymentRequest : CreationAuditedAggregateRoot<Guid>, ISoftDelete
{
[CanBeNull]
public string CustomerId { get; protected set; }
[CanBeNull]
public string ProductId { get; protected set; }
[NotNull]
public string ProductName { get; protected set; }
public decimal Price { get; protected set; }
public string Currency { get; protected set; }
public PaymentRequestState State { get; protected set; }
public bool IsDeleted { get; set; }
[CanBeNull]
public string FailReason { get; protected set; }
private PaymentRequest()
{
}
public PaymentRequest(
Guid id,
[CanBeNull] string customerId,
[CanBeNull] string productId,
[NotNull] string productName,
decimal price,
[NotNull] string currency)
: base(id)
{
CustomerId = Check.NotNullOrEmpty(customerId, nameof(customerId), maxLength: PaymentRequestConsts.MaxCustomerIdLength);
ProductId = Check.NotNullOrEmpty(productId, nameof(productId), maxLength: PaymentRequestConsts.MaxProductIdLength);
ProductName = Check.NotNullOrWhiteSpace(productName, nameof(productName), maxLength: PaymentRequestConsts.MaxProductNameLength);
Price = price;
Currency = currency;
}
public virtual void SetAsCompleted()
{
if (State == PaymentRequestState.Completed)
{
return;
}
State = PaymentRequestState.Completed;
FailReason = null;
AddDistributedEvent(new PaymentRequestCompletedEto
{
PaymentRequestId = Id,
ExtraProperties = ExtraProperties
});
}
public virtual void SetAsFailed(string failReason)
{
if (State == PaymentRequestState.Failed)
{
return;
}
State = PaymentRequestState.Failed;
FailReason = failReason;
AddDistributedEvent(new PaymentRequestFailedEto
{
PaymentRequestId = Id,
FailReason = failReason,
ExtraProperties = ExtraProperties
});
}
}
}

8
modules/payment/src/Payment.EntityFrameworkCore/EntityFrameworkCore/IPaymentDbContext.cs

@ -1,4 +1,6 @@
using Volo.Abp.Data;
using Microsoft.EntityFrameworkCore;
using Payment.PaymentRequests;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
namespace Payment.EntityFrameworkCore
@ -6,8 +8,6 @@ namespace Payment.EntityFrameworkCore
[ConnectionStringName(PaymentDbProperties.ConnectionStringName)]
public interface IPaymentDbContext : IEfCoreDbContext
{
/* Add DbSet for each Aggregate Root here. Example:
* DbSet<Question> Questions { get; }
*/
DbSet<PaymentRequest> PaymentRequests { get; }
}
}

5
modules/payment/src/Payment.EntityFrameworkCore/EntityFrameworkCore/PaymentDbContext.cs

@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
using Payment.PaymentRequests;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
@ -7,9 +8,7 @@ namespace Payment.EntityFrameworkCore
[ConnectionStringName(PaymentDbProperties.ConnectionStringName)]
public class PaymentDbContext : AbpDbContext<PaymentDbContext>, IPaymentDbContext
{
/* Add DbSet for each Aggregate Root here. Example:
* public DbSet<Question> Questions { get; set; }
*/
public DbSet<PaymentRequest> PaymentRequests { get; set; }
public PaymentDbContext(DbContextOptions<PaymentDbContext> options)
: base(options)

24
modules/payment/src/Payment.EntityFrameworkCore/EntityFrameworkCore/PaymentDbContextModelCreatingExtensions.cs

@ -1,5 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Payment.PaymentRequests;
using Volo.Abp;
using Volo.Abp.EntityFrameworkCore.Modeling;
namespace Payment.EntityFrameworkCore
{
@ -10,25 +12,17 @@ namespace Payment.EntityFrameworkCore
{
Check.NotNull(builder, nameof(builder));
/* Configure all entities here. Example:
builder.Entity<Question>(b =>
builder.Entity<PaymentRequest>(b =>
{
//Configure table & schema name
b.ToTable(PaymentDbProperties.DbTablePrefix + "Questions", PaymentDbProperties.DbSchema);
b.ToTable(PaymentDbProperties.DbTablePrefix + "PaymentRequests", PaymentDbProperties.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.CustomerId).HasMaxLength(PaymentRequestConsts.MaxCustomerIdLength);
b.Property(x => x.ProductId).HasMaxLength(PaymentRequestConsts.MaxProductIdLength);
b.Property(x => x.ProductName).IsRequired().HasMaxLength(PaymentRequestConsts.MaxProductNameLength);
//Properties
b.Property(q => q.Title).IsRequired().HasMaxLength(QuestionConsts.MaxTitleLength);
//Relations
b.HasMany(question => question.Tags).WithOne().HasForeignKey(qt => qt.QuestionId);
//Indexes
b.HasIndex(q => q.CreationTime);
b.HasIndex(x => x.CustomerId);
b.HasIndex(x => x.State);
});
*/
}
}
}

6
modules/payment/src/Payment.EntityFrameworkCore/EntityFrameworkCore/PaymentEntityFrameworkCoreModule.cs

@ -1,4 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using Payment.EntityFrameworkCore.Repositories;
using Payment.PaymentRequests;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
@ -14,9 +16,7 @@ namespace Payment.EntityFrameworkCore
{
context.Services.AddAbpDbContext<PaymentDbContext>(options =>
{
/* Add custom repositories here. Example:
* options.AddRepository<Question, EfCoreQuestionRepository>();
*/
options.AddRepository<PaymentRequest, PaymentRequestRepository>();
});
}
}

58
modules/payment/src/Payment.EntityFrameworkCore/EntityFrameworkCore/Repositories/PaymentRequestRepository.cs

@ -0,0 +1,58 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Payment.PaymentRequests;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace Payment.EntityFrameworkCore.Repositories
{
public class PaymentRequestRepository : EfCoreRepository<IPaymentDbContext, PaymentRequest, Guid>, IPaymentRequestRepository
{
public PaymentRequestRepository(IDbContextProvider<IPaymentDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task<List<PaymentRequest>> GetListAsync(
int skipCount,
int maxResultCount,
string sorting,
string productName = null,
DateTime? maxCreationTime = null,
DateTime? minCreationTime = null,
PaymentRequestState? state = null,
CancellationToken cancellationToken = default
)
{
return await (await GetQueryableAsync())
.WhereIf(!string.IsNullOrWhiteSpace(productName), x => x.ProductName.Contains(productName))
.WhereIf(maxCreationTime != null, p => p.CreationTime <= maxCreationTime)
.WhereIf(minCreationTime != null, p => p.CreationTime >= minCreationTime)
.WhereIf(state != null, p => p.State == state)
.OrderBy(string.IsNullOrWhiteSpace(sorting) ? nameof(PaymentRequest.ProductName) : sorting)
.PageBy(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task<int> GetCountAsync(
string productName = null,
DateTime? maxCreationTime = null,
DateTime? minCreationTime = null,
PaymentRequestState? state = null,
CancellationToken cancellationToken = default
)
{
return await (await GetQueryableAsync())
.WhereIf(!string.IsNullOrWhiteSpace(productName), x => x.ProductName.Contains(productName))
.WhereIf(maxCreationTime != null, p => p.CreationTime <= maxCreationTime)
.WhereIf(minCreationTime != null, p => p.CreationTime >= minCreationTime)
.WhereIf(state != null, p => p.State == state)
.CountAsync(GetCancellationToken(cancellationToken));
}
}
}

1
modules/payment/src/Payment.EntityFrameworkCore/Payment.EntityFrameworkCore.csproj

@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>

208
modules/payment/src/Payment.HttpApi.Client/ClientProxies/Payment-generate-proxy.json

@ -0,0 +1,208 @@
{
"modules": {
"payment": {
"rootPath": "payment",
"remoteServiceName": "Payment",
"controllers": {
"Payment.PaymentRequests.PaymentRequestController": {
"controllerName": "PaymentRequest",
"controllerGroupName": "PaymentRequest",
"type": "Payment.PaymentRequests.PaymentRequestController",
"interfaces": [
{
"type": "Payment.PaymentRequests.IPaymentRequestAppService"
}
],
"actions": {
"CompleteAsyncByToken": {
"uniqueName": "CompleteAsyncByToken",
"name": "CompleteAsync",
"httpMethod": "POST",
"url": "api/payment/requests/complete/{token}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "token",
"typeAsString": "System.String, System.Private.CoreLib",
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "token",
"name": "token",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "Payment.PaymentRequests.PaymentRequestDto",
"typeSimple": "Payment.PaymentRequests.PaymentRequestDto"
},
"allowAnonymous": null,
"implementFrom": "Payment.PaymentRequests.IPaymentRequestAppService"
},
"CreateAsyncByInput": {
"uniqueName": "CreateAsyncByInput",
"name": "CreateAsync",
"httpMethod": "POST",
"url": "api/payment/requests",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Payment.PaymentRequests.PaymentRequestCreationDto, Payment.Application.Contracts",
"type": "Payment.PaymentRequests.PaymentRequestCreationDto",
"typeSimple": "Payment.PaymentRequests.PaymentRequestCreationDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "Payment.PaymentRequests.PaymentRequestCreationDto",
"typeSimple": "Payment.PaymentRequests.PaymentRequestCreationDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Payment.PaymentRequests.PaymentRequestDto",
"typeSimple": "Payment.PaymentRequests.PaymentRequestDto"
},
"allowAnonymous": null,
"implementFrom": "Payment.PaymentRequests.IPaymentRequestAppService"
},
"GetAsyncById": {
"uniqueName": "GetAsyncById",
"name": "GetAsync",
"httpMethod": "GET",
"url": "api/payment/requests/{id}",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"descriptorName": ""
}
],
"returnValue": {
"type": "Payment.PaymentRequests.PaymentRequestDto",
"typeSimple": "Payment.PaymentRequests.PaymentRequestDto"
},
"allowAnonymous": null,
"implementFrom": "Payment.PaymentRequests.IPaymentRequestAppService"
},
"StartPaymentAsyncByInput": {
"uniqueName": "StartPaymentAsyncByInput",
"name": "StartPaymentAsync",
"httpMethod": "POST",
"url": "api/payment/requests/start",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "Payment.PaymentRequests.StartPaymentDto, Payment.Application.Contracts",
"type": "Payment.PaymentRequests.StartPaymentDto",
"typeSimple": "Payment.PaymentRequests.StartPaymentDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "Payment.PaymentRequests.StartPaymentDto",
"typeSimple": "Payment.PaymentRequests.StartPaymentDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Payment.PaymentRequests.StartPaymentResultDto",
"typeSimple": "Payment.PaymentRequests.StartPaymentResultDto"
},
"allowAnonymous": null,
"implementFrom": "Payment.PaymentRequests.IPaymentRequestAppService"
},
"HandleWebhookAsyncByPayload": {
"uniqueName": "HandleWebhookAsyncByPayload",
"name": "HandleWebhookAsync",
"httpMethod": "POST",
"url": "api/payment/requests/webhook",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "payload",
"typeAsString": "System.String, System.Private.CoreLib",
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "payload",
"name": "payload",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": ""
}
],
"returnValue": {
"type": "System.Boolean",
"typeSimple": "boolean"
},
"allowAnonymous": null,
"implementFrom": "Payment.PaymentRequests.IPaymentRequestAppService"
}
}
}
}
}
},
"types": {}
}

58
modules/payment/src/Payment.HttpApi.Client/ClientProxies/PaymentRequestClientProxy.Generated.cs

@ -0,0 +1,58 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Payment.PaymentRequests;
// ReSharper disable once CheckNamespace
namespace Payment.PaymentRequests.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IPaymentRequestAppService), typeof(PaymentRequestClientProxy))]
public partial class PaymentRequestClientProxy : ClientProxyBase<IPaymentRequestAppService>, IPaymentRequestAppService
{
public virtual async Task<PaymentRequestDto> CompleteAsync(string token)
{
return await RequestAsync<PaymentRequestDto>(nameof(CompleteAsync), new ClientProxyRequestTypeValue
{
{ typeof(string), token }
});
}
public virtual async Task<PaymentRequestDto> CreateAsync(PaymentRequestCreationDto input)
{
return await RequestAsync<PaymentRequestDto>(nameof(CreateAsync), new ClientProxyRequestTypeValue
{
{ typeof(PaymentRequestCreationDto), input }
});
}
public virtual async Task<PaymentRequestDto> GetAsync(Guid id)
{
return await RequestAsync<PaymentRequestDto>(nameof(GetAsync), new ClientProxyRequestTypeValue
{
{ typeof(Guid), id }
});
}
public virtual async Task<StartPaymentResultDto> StartPaymentAsync(StartPaymentDto input)
{
return await RequestAsync<StartPaymentResultDto>(nameof(StartPaymentAsync), new ClientProxyRequestTypeValue
{
{ typeof(StartPaymentDto), input }
});
}
public virtual async Task<bool> HandleWebhookAsync(string payload)
{
return await RequestAsync<bool>(nameof(HandleWebhookAsync), new ClientProxyRequestTypeValue
{
{ typeof(string), payload }
});
}
}
}

8
modules/payment/src/Payment.HttpApi.Client/ClientProxies/PaymentRequestClientProxy.cs

@ -0,0 +1,8 @@
// This file is part of PaymentRequestClientProxy, you can customize it here
// ReSharper disable once CheckNamespace
namespace Payment.PaymentRequests.ClientProxies
{
public partial class PaymentRequestClientProxy
{
}
}

28
modules/payment/src/Payment.HttpApi.Client/ClientProxies/SampleClientProxy.Generated.cs

@ -0,0 +1,28 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Modeling;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Payment.Samples;
// ReSharper disable once CheckNamespace
namespace Payment.Samples.ClientProxies
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ISampleAppService), typeof(SampleClientProxy))]
public partial class SampleClientProxy : ClientProxyBase<ISampleAppService>, ISampleAppService
{
public virtual async Task<SampleDto> GetAsync()
{
return await RequestAsync<SampleDto>(nameof(GetAsync));
}
public virtual async Task<SampleDto> GetAuthorizedAsync()
{
return await RequestAsync<SampleDto>(nameof(GetAuthorizedAsync));
}
}
}

8
modules/payment/src/Payment.HttpApi.Client/ClientProxies/SampleClientProxy.cs

@ -0,0 +1,8 @@
// This file is part of SampleClientProxy, you can customize it here
// ReSharper disable once CheckNamespace
namespace Payment.Samples.ClientProxies
{
public partial class SampleClientProxy
{
}
}

3
modules/payment/src/Payment.HttpApi.Client/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
modules/payment/src/Payment.HttpApi.Client/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

21
modules/payment/src/Payment.HttpApi.Client/Payment.HttpApi.Client.csproj

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Payment</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Http.Client" Version="5.0.0-beta.1" />
<ProjectReference Include="..\Payment.Application.Contracts\Payment.Application.Contracts.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="**\*generate-proxy.json" />
<Content Remove="**\*generate-proxy.json" />
</ItemGroup>
</Project>

27
modules/payment/src/Payment.HttpApi.Client/PaymentHttpApiClientModule.cs

@ -0,0 +1,27 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Payment
{
[DependsOn(
typeof(PaymentApplicationContractsModule),
typeof(AbpHttpClientModule))]
public class PaymentHttpApiClientModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddStaticHttpClientProxies(
typeof(PaymentApplicationContractsModule).Assembly,
PaymentRemoteServiceConsts.RemoteServiceName
);
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<PaymentHttpApiClientModule>();
});
}
}
}

1
modules/payment/src/Payment.HttpApi/Payment.HttpApi.csproj

@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>

61
modules/payment/src/Payment.HttpApi/PaymentRequests/PaymentRequestController.cs

@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
namespace Payment.PaymentRequests
{
[RemoteService(Name = PaymentRemoteServiceConsts.RemoteServiceName)]
[Area("payment")]
[Route("api/payment/requests")]
public class PaymentRequestController : PaymentController, IPaymentRequestAppService
{
protected IPaymentRequestAppService PaymentRequestAppService { get; }
public PaymentRequestController(IPaymentRequestAppService paymentRequestAppService)
{
PaymentRequestAppService = paymentRequestAppService;
}
[HttpPost]
[Route("complete/{token}")]
public Task<PaymentRequestDto> CompleteAsync([FromRoute] string token)
{
return PaymentRequestAppService.CompleteAsync(token);
}
[HttpPost]
public Task<PaymentRequestDto> CreateAsync(PaymentRequestCreationDto input)
{
return PaymentRequestAppService.CreateAsync(input);
}
[HttpGet]
[Route("{id}")]
public Task<PaymentRequestDto> GetAsync(Guid id)
{
return PaymentRequestAppService.GetAsync(id);
}
[HttpPost]
[Route("start")]
public Task<StartPaymentResultDto> StartPaymentAsync(StartPaymentDto input)
{
return PaymentRequestAppService.StartPaymentAsync(input);
}
[ApiExplorerSettings(IgnoreApi = true)]
[HttpPost]
[Route("webhook")]
public async Task<bool> HandleWebhookAsync(string payload)
{
var bytes = await Request.Body.GetAllBytesAsync();
payload = Encoding.UTF8.GetString(bytes);
return await PaymentRequestAppService.HandleWebhookAsync(payload);
}
}
}

17
modules/payment/src/Payment.Web/Pages/Payment/Index.cshtml

@ -1,17 +0,0 @@
@page
@using Microsoft.Extensions.Localization
@using Payment.Localization
@using Payment.Web.Pages.Payment
@model Payment.Web.Pages.Payment.IndexModel
@inject IStringLocalizer<PaymentResource> L
@section scripts {
<abp-script-bundle name="@typeof(IndexModel).FullName">
<abp-script src="/client-proxies/Payment-proxy.js" />
</abp-script-bundle>
}
@{
}
<h1>Payment</h1>
<p>@L["SamplePageMessage"]</p>

9
modules/payment/src/Payment.Web/Pages/Payment/Index.cshtml.cs

@ -1,9 +0,0 @@
namespace Payment.Web.Pages.Payment
{
public class IndexModel : PaymentPageModel
{
public void OnGet()
{
}
}
}

41
modules/payment/src/Payment.Web/Pages/Payment/PostCheckout.cshtml

@ -0,0 +1,41 @@
@page
@using Payment.Web.Pages.Payment
@using Payment.PaymentRequests
@inherits Payment.Web.Pages.PaymentPageBase
@model Payment.Web.Pages.Payment.PostCheckoutPageModel
@{
PageLayout.Content.Title = L["PaymentResult"] + L["Enum:PaymentRequestState:" + Model.PaymentRequest.State];
}
<main class="static-page container mt-5">
<abp-card class="m-5">
<abp-card-header>
<h2>@L["PaymentResult"]</h2>
</abp-card-header>
<abp-card-body>
@if (Model.PaymentRequest.State == PaymentRequestState.Completed)
{
<abp-alert alert-type="Success" dismissible="false">
<h3 class="d-inline">
<i class="fa fa-check-circle"></i>
@L["YourPaymentCompletedSuccessfully"]
</h3>>
</abp-alert>
}
else
{
<abp-alert alert-type="Danger" dismissible="false">
<h3 class="d-inline">
<i class="fa fa-times"></i>
@L["YourPaymentFailed"]
</h3>
</abp-alert>
<abp-button href="@Model.GoBackLink" text="@L["GoBack"]" />
}
</abp-card-body>
</abp-card>
</main>

61
modules/payment/src/Payment.Web/Pages/Payment/PostCheckout.cshtml.cs

@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Payment.PaymentRequests;
using Payment.Web.PaymentRequest;
using System;
using System.Threading.Tasks;
namespace Payment.Web.Pages.Payment
{
public class PostCheckoutPageModel : PaymentPageModel
{
[BindProperty(SupportsGet = true)]
public string Token { get; set; }
public PaymentRequestDto PaymentRequest { get; protected set; }
public string GoBackLink { get; set; }
private readonly IPaymentRequestAppService _paymentRequestAppService;
private readonly PaymentWebOptions _paymentWebOptions;
private readonly IPaymentUrlBuilder _paymentUrlBuilder;
public PostCheckoutPageModel(
IPaymentRequestAppService appService,
IOptions<PaymentWebOptions> paymentWebOptions,
IPaymentUrlBuilder paymentUrlBuilder)
{
_paymentRequestAppService = appService;
_paymentWebOptions = paymentWebOptions.Value;
_paymentUrlBuilder = paymentUrlBuilder;
}
public async Task<IActionResult> OnGetAsync()
{
if (Token.IsNullOrWhiteSpace())
{
return BadRequest();
}
PaymentRequest = await _paymentRequestAppService.CompleteAsync(Token);
GoBackLink = _paymentUrlBuilder.BuildCheckoutUrl(PaymentRequest.Id).AbsoluteUri;
if (PaymentRequest.State == PaymentRequestState.Completed
&& !_paymentWebOptions.PaymentSuccessfulCallbackUrl.IsNullOrWhiteSpace())
{
var callbackUrl = _paymentWebOptions.PaymentSuccessfulCallbackUrl + "?paymentRequestId=" + PaymentRequest.Id;
Response.Redirect(callbackUrl);
}
if (PaymentRequest.State == PaymentRequestState.Failed
&& !_paymentWebOptions.PaymentFailureCallbackUrl.IsNullOrWhiteSpace())
{
var callbackUrl = _paymentWebOptions.PaymentFailureCallbackUrl + "?paymentRequestId=" + PaymentRequest.Id;
Response.Redirect(callbackUrl);
}
return Page();
}
}
}

38
modules/payment/src/Payment.Web/Pages/Payment/PreCheckout.cshtml

@ -0,0 +1,38 @@
@page
@using Payment.Web.Pages.Payment
@using Payment.PaymentRequests
@inherits Payment.Web.Pages.PaymentPageBase
@model Payment.Web.Pages.Payment.PreCheckoutPageModel
@section scripts {
<abp-script-bundle name="@typeof(PreCheckoutPageModel).FullName">
<abp-script src="/client-proxies/Payment-proxy.js" />
</abp-script-bundle>
}
<main class="static-page container mt-5">
<abp-card class="m-5">
<abp-card-header>
<h2>@L["ProductInformation"]</h2>
</abp-card-header>
<abp-card-body>
<ul>
<li>@L["ProductName"]: @Model.PaymentRequest.ProductName</li>
<li>@L["Price"]: @Model.PaymentRequest.Price @Model.PaymentRequest.Currency</li>
<li>@L["State"]: @L["Enum:PaymentRequestState:" + Model.PaymentRequest.State]</li>
</ul>
</abp-card-body>
<abp-card-footer>
<form method="post">
@if (Model.PaymentRequest.State != PaymentRequestState.Waiting)
{
<abp-alert alert-type="Warning">@L["PaymentRequestIsNotWaiting"]</abp-alert>
}
else
{
<abp-button type="submit" button-type="Primary">@L["CompletePayment"]</abp-button>
}
</form>
</abp-card-footer>
</abp-card>
</main>

49
modules/payment/src/Payment.Web/Pages/Payment/PreCheckout.cshtml.cs

@ -0,0 +1,49 @@
using Microsoft.AspNetCore.Mvc;
using Payment.PaymentRequests;
using Payment.Web.PaymentRequest;
using System;
using System.Threading.Tasks;
using Volo.Abp;
namespace Payment.Web.Pages.Payment
{
public class PreCheckoutPageModel : PaymentPageModel
{
[BindProperty(SupportsGet = true)]
public Guid PaymentRequestId { get; set; }
public PaymentRequestDto PaymentRequest { get; set; }
private readonly IPaymentRequestAppService _paymentRequestAppService;
private readonly IPaymentUrlBuilder _paymentUrlBuilder;
public PreCheckoutPageModel(
IPaymentRequestAppService paymentRequestAppService,
IPaymentUrlBuilder paymentUrlBuilder)
{
_paymentRequestAppService = paymentRequestAppService;
_paymentUrlBuilder = paymentUrlBuilder;
}
public async Task<IActionResult> OnGetAsync()
{
PaymentRequest = await _paymentRequestAppService.GetAsync(PaymentRequestId);
return Page();
}
public async Task OnPostAsync()
{
PaymentRequest = await _paymentRequestAppService.GetAsync(PaymentRequestId);
var result = await _paymentRequestAppService.StartPaymentAsync(new StartPaymentDto
{
PaymentRequestId = PaymentRequest.Id,
ReturnUrl = _paymentUrlBuilder.BuildReturnUrl(PaymentRequestId).AbsoluteUri,
CancelUrl = _paymentUrlBuilder.BuildCheckoutUrl(PaymentRequestId).AbsoluteUri
});
Response.Redirect(result.CheckoutLink);
}
}
}

20
modules/payment/src/Payment.Web/Pages/PaymentPageBase.cs

@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.Extensions.Localization;
using Payment.Localization;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc.UI.Layout;
namespace Payment.Web.Pages
{
public class PaymentPageBase : Microsoft.AspNetCore.Mvc.RazorPages.Page
{
[RazorInject] public IStringLocalizer<PaymentResource> L { get; set; }
[RazorInject] public IPageLayout PageLayout { get; set; }
public override Task ExecuteAsync()
{
return Task.CompletedTask; // Will be overriden by razor pages. (.cshtml)
}
}
}

3
modules/payment/src/Payment.Web/Payment.Web.csproj

@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Import Project="..\..\common.props" />
<Import Project="..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
@ -21,7 +22,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.0-rc.*" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.0-rc.1.*" />
</ItemGroup>
<ItemGroup>

11
modules/payment/src/Payment.Web/PaymentRequest/IPaymentUrlBuilder.cs

@ -0,0 +1,11 @@
using System;
namespace Payment.Web.PaymentRequest
{
public interface IPaymentUrlBuilder
{
Uri BuildCheckoutUrl(Guid paymentRequestId);
Uri BuildReturnUrl(Guid paymentRequestId);
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save