Browse Source

Merge pull request #47 from abpframework/gterdem/payment

Add payment and payment completed pages.
ipaddr
Galip Tolga Erdem 5 years ago
committed by GitHub
parent
commit
4955b75ad8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      apps/auth-server/src/EShopOnAbp.AuthServer/EShopUserClaimsPrincipalFactory.cs
  2. 35
      apps/public-web/src/EShopOnAbp.PublicWeb/Basket/UserAddressProvider.cs
  3. 21
      apps/public-web/src/EShopOnAbp.PublicWeb/Basket/UserBasketProvider.cs
  4. 48
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/AnonymousUser/AnonymousUserViewComponent.cs
  5. 3
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/AnonymousUser/Default.cshtml
  6. 3
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/Basket/Default.cshtml
  7. 54
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/Payment/Default.cshtml
  8. 15
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/Payment/PaymentWidgetScriptContributor.cs
  9. 12
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/Payment/PaymentWidgetStyleContributor.cs
  10. 43
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/Payment/PaymentWidgetViewComponent.cs
  11. 5
      apps/public-web/src/EShopOnAbp.PublicWeb/EShopOnAbp.PublicWeb.csproj
  12. 13
      apps/public-web/src/EShopOnAbp.PublicWeb/EShopOnAbpPaymentConsts.cs
  13. 18
      apps/public-web/src/EShopOnAbp.PublicWeb/EShopOnAbpPublicAutoMapperProfile.cs
  14. 25
      apps/public-web/src/EShopOnAbp.PublicWeb/EShopOnAbpPublicWebModule.cs
  15. 8
      apps/public-web/src/EShopOnAbp.PublicWeb/EShopOnAbpPublicWebPaymentOptions.cs
  16. 4
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Basket.cshtml
  17. 7
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Basket.cshtml.cs
  18. 15
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Index.cshtml
  19. 17
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Index.cshtml.cs
  20. 8
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Payment.cshtml
  21. 51
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Payment.cshtml.cs
  22. 16
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml
  23. 32
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml.cs
  24. 4
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/_ViewStart.cshtml
  25. 20
      apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/payment/payment-widget.css
  26. 21
      apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/payment/payment-widget.js
  27. 13
      gateways/web-public/src/EShopOnAbp.WebPublicGateway/appsettings.json
  28. 1
      services/basket/src/EShopOnAbp.BasketService.Application.Contracts/IBasketAppService.cs
  29. 9
      services/basket/src/EShopOnAbp.BasketService.Application/BasketAppService.cs
  30. 2
      services/basket/src/EShopOnAbp.BasketService.Application/BasketServiceApplicationAutoMapperProfile.cs
  31. 4
      services/basket/src/EShopOnAbp.BasketService.Domain.Shared/BasketServiceDomainSharedModule.cs
  32. 3
      services/basket/src/EShopOnAbp.BasketService.Domain.Shared/EShopOnAbp.BasketService.Domain.Shared.csproj
  33. 8
      services/basket/src/EShopOnAbp.BasketService.Domain.Shared/OrderAcceptedEto.cs
  34. 9
      services/basket/src/EShopOnAbp.BasketService.Domain.Shared/OrderItemEto.cs
  35. 26
      services/basket/src/EShopOnAbp.BasketService.Domain/Orders/OrderAcceptedEventHandler.cs
  36. 5
      services/basket/src/EShopOnAbp.BasketService.HttpApi.Client/ClientProxies/BasketClientProxy.Generated.cs
  37. 4
      services/catalog/src/EShopOnAbp.CatalogService.Domain.Shared/EShopOnAbp.CatalogService.Domain.Shared.csproj
  38. 1
      services/catalog/src/EShopOnAbp.CatalogService.Domain/EShopOnAbp.CatalogService.Domain.csproj
  39. 1
      services/catalog/src/EShopOnAbp.CatalogService.Domain/OrderHandler.cs
  40. 5
      services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServerDataSeeder.cs
  41. 6
      services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/EShopOnAbp.OrderingService.Domain.Shared.csproj
  42. 4
      services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/OrderingServiceDomainSharedModule.cs
  43. 16
      services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderAcceptedEto.cs
  44. 14
      services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderItemEto.cs
  45. 45
      services/ordering/src/EShopOnAbp.OrderingService.Domain/PaymentRequests/PaymentRequestEventHandler.cs
  46. 11
      services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentCompletedEto.cs
  47. 5
      services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs
  48. 5
      services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServiceApplicationAutoMapperProfile.cs
  49. 2
      services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServiceApplicationModule.cs
  50. 16
      services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestCompletedEto.cs
  51. 2
      services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestFailedEto.cs
  52. 18
      services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestProductEto.cs
  53. 17
      services/payment/src/EShopOnAbp.PaymentService.Domain/PaymentRequests/PaymentRequest.cs
  54. 2
      services/payment/src/EShopOnAbp.PaymentService.Domain/PaymentRequests/PaymentRequestProduct.cs
  55. 9
      services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/PaymentRequests/EfCorePaymentRequestRepository.cs
  56. 50
      services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/PaymentRequestClientProxy.Generated.cs
  57. 8
      services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/PaymentRequestClientProxy.cs
  58. 53
      services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/PaymentService-generate-proxy.json
  59. 15
      services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/SampleClientProxy.Generated.cs
  60. 8
      services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/SampleClientProxy.cs
  61. 171
      services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/payment-generate-proxy.json
  62. 3
      services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/PaymentServiceHttpApiHostModule.cs
  63. 7
      services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/appsettings.json
  64. 1
      shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/en.json
  65. 1
      shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/tr.json

15
apps/auth-server/src/EShopOnAbp.AuthServer/EShopUserClaimsPrincipalFactory.cs

@ -52,14 +52,21 @@ public class EShopUserClaimsPrincipalFactory : AbpUserClaimsPrincipalFactory
{
HttpContext.Request.Cookies.TryGetValue(EShopConstants.AnonymousUserClaimName, out var anonymousUserId);
await _cache.SetAsync(user.Id, new AnonymousUserItem {AnonymousUserId = anonymousUserId}, options: new DistributedCacheEntryOptions()
{
AbsoluteExpiration = DateTimeOffset.UtcNow.AddSeconds(60)
});
await _cache.SetAsync(user.Id, new AnonymousUserItem {AnonymousUserId = anonymousUserId},
options: new DistributedCacheEntryOptions()
{
AbsoluteExpiration = DateTimeOffset.UtcNow.AddSeconds(60)
});
_logger.LogInformation($"Cached anonymousUserId:{anonymousUserId}.");
}
var cachedItem = await _cache.GetAsync(user.Id);
if (cachedItem == null)
{
_logger.LogWarning($"Could not retrieve anonymousUserId from cache.");
return principal;
}
_logger.LogInformation($"Retrieved anonymousUserId:{cachedItem.AnonymousUserId} from cache.");
principal.Identities.First()
.AddClaim(new Claim(EShopConstants.AnonymousUserClaimName, cachedItem.AnonymousUserId));

35
apps/public-web/src/EShopOnAbp.PublicWeb/Basket/UserAddressProvider.cs

@ -0,0 +1,35 @@
using System.Collections.Generic;
using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.PublicWeb.Basket;
public class UserAddressProvider : ITransientDependency
{
public List<AddressDto> GetDemoAddresses()
{
return new List<AddressDto>()
{
new()
{
Id = 1,
Name = EShopOnAbpPaymentConsts.DemoAddressTypes.Home,
Description = "Cecilia Chapman Senior 711-2880 Nulla St. Mankato Mississippi 96522/USA",
IsDefault = true
},
new()
{
Id = 2,
Name = EShopOnAbpPaymentConsts.DemoAddressTypes.Work,
Description = "Yeşilköy Serbest Bölge Mah. E-Blok Sokak E1 Blok No:2, Bakırköy/İstanbul"
}
};
}
}
public class AddressDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsDefault { get; set; } = false;
}

21
apps/public-web/src/EShopOnAbp.PublicWeb/Basket/UserBasketProvider.cs

@ -5,7 +5,6 @@ using System;
using System.Threading.Tasks;
using EShopOnAbp.Shared.Hosting.AspNetCore;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Users;
namespace EShopOnAbp.PublicWeb.Basket
@ -16,20 +15,17 @@ namespace EShopOnAbp.PublicWeb.Basket
private readonly IHttpContextAccessor httpContextAccessor;
protected readonly ILogger<UserBasketProvider> logger;
protected readonly IGuidGenerator guidGenerator;
protected readonly IBasketAppService basketAppService;
protected readonly ICurrentUser currentUser;
public UserBasketProvider(
IHttpContextAccessor httpContextAccessor,
ILogger<UserBasketProvider> logger,
IGuidGenerator guidGenerator,
IBasketAppService basketAppService,
ICurrentUser currentUser)
{
this.httpContextAccessor = httpContextAccessor;
this.logger = logger;
this.guidGenerator = guidGenerator;
this.basketAppService = basketAppService;
this.currentUser = currentUser;
}
@ -41,30 +37,17 @@ namespace EShopOnAbp.PublicWeb.Basket
// Get anonymous user id from cookie
HttpContext.Request.Cookies.TryGetValue(EShopConstants.AnonymousUserClaimName,
out string anonymousUserId);
logger.LogInformation($"========= Anonymous User Id from Cookie:{anonymousUserId} ========= ");
// Generate new id for anonymous user
if (string.IsNullOrEmpty(anonymousUserId))
{
anonymousUserId = guidGenerator.Create().ToString();
HttpContext.Response.Cookies.Append(EShopConstants.AnonymousUserClaimName, anonymousUserId, new CookieOptions
{
SameSite = SameSiteMode.Lax
});
logger.LogInformation(
$"========= Generated new User Id:{anonymousUserId} ========= APPENDED TO COOKIE ====== ");
}
if (!currentUser.IsAuthenticated)
{
logger.LogInformation(
$"========= Get Basket for Anonymous UserId:{anonymousUserId} ========= ====== ");
logger.LogInformation($"Getting basket for anonymous user id:{anonymousUserId}.");
return await basketAppService.GetByAnonymousUserIdAsync(Guid.Parse(anonymousUserId));
}
//TODO: Merge with anonymously stored cart if exist
var userClaimValue = currentUser.FindClaimValue(EShopConstants.AnonymousUserClaimName);
// Fall-back for having trouble when setting claim on user login
if (string.IsNullOrEmpty(userClaimValue))
{
return await basketAppService.GetAsync();

48
apps/public-web/src/EShopOnAbp.PublicWeb/Components/AnonymousUser/AnonymousUserViewComponent.cs

@ -0,0 +1,48 @@
using System;
using System.Threading.Tasks;
using EShopOnAbp.Shared.Hosting.AspNetCore;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
using Volo.Abp.Guids;
namespace EShopOnAbp.PublicWeb.Components.AnonymousUser;
[Widget(
AutoInitialize = true
)]
public class AnonymousUserViewComponent : AbpViewComponent
{
private readonly ILogger<AnonymousUserViewComponent> _logger;
private readonly IGuidGenerator _guidGenerator;
public AnonymousUserViewComponent(ILogger<AnonymousUserViewComponent> logger, IGuidGenerator guidGenerator)
{
_logger = logger;
_guidGenerator = guidGenerator;
}
public async Task<IViewComponentResult> InvokeAsync()
{
// Get anonymous user id from cookie
HttpContext.Request.Cookies.TryGetValue(EShopConstants.AnonymousUserClaimName,
out string anonymousUserId);
_logger.LogInformation($"========= Anonymous User Id from Cookie:{anonymousUserId} ========= ");
// Generate new id for anonymous user
if (string.IsNullOrEmpty(anonymousUserId))
{
anonymousUserId = _guidGenerator.Create().ToString();
HttpContext.Response.Cookies.Append(EShopConstants.AnonymousUserClaimName, anonymousUserId,
new CookieOptions
{
SameSite = SameSiteMode.Lax
});
_logger.LogInformation(
$"========= Generated new User Id:{anonymousUserId} ========= APPENDED TO COOKIE ====== ");
}
return await Task.FromResult(View("~/Components/AnonymousUser/Default.cshtml"));
}
}

3
apps/public-web/src/EShopOnAbp.PublicWeb/Components/AnonymousUser/Default.cshtml

@ -0,0 +1,3 @@
<div>
</div>

3
apps/public-web/src/EShopOnAbp.PublicWeb/Components/Basket/Default.cshtml

@ -49,9 +49,6 @@
<div class="col-lg-3">
@await Component.InvokeAsync(typeof(PurchaseWidgetViewComponent),
new { Basket = Model, ButtonDescription = "CompletePurchase"})
</div>
</div>
}

54
apps/public-web/src/EShopOnAbp.PublicWeb/Components/Payment/Default.cshtml

@ -0,0 +1,54 @@
@using EShopOnAbp.Localization
@using EShopOnAbp.PublicWeb.Components.Purchase
@using Microsoft.Extensions.Localization
@model EShopOnAbp.PublicWeb.Components.Payment.PaymentViewModel
@inject IStringLocalizer<EShopOnAbpResource> L
@{
const int defaultColumnSize = 4;
}
<div class="row">
<div class="col-lg-9">
<div class="address-list p-5">
<h3>Select Address</h3>
@for (int i = 0; i < Math.Ceiling(Model.Address.Count / (double) defaultColumnSize); i++)
{
<abp-row>
@for (int j = 0; j < defaultColumnSize; j++)
{
<abp-column size-lg="_3" size-md="_4" size-sm="_6">
@if (i * defaultColumnSize + j < Model.Address.Count)
{
var address = Model.Address[(i * defaultColumnSize) + j];
string isSelected = address.IsDefault ? "is-selected" : string.Empty;
<div class="card @isSelected" data-address-id="@address.Id">
<div class="card-body">
<h4 class="card-title">@address.Name</h4>
<p class="card-text">@address.Description</p>
</div>
</div>
}
</abp-column>
}
</abp-row>
}
</div>
<div class="payment-list p-5">
<h3>Select Payment Method</h3>
<abp-row>
<abp-column size-lg="_3" size-md="_4" size-sm="_6">
<abp-card>
<img class="" src="https://upload.wikimedia.org/wikipedia/commons/b/b5/PayPal.svg" alt="paypal logo">
</abp-card>
</abp-column>
</abp-row>
</div>
</div>
<div class="col-lg-3">
@await Component.InvokeAsync(typeof(PurchaseWidgetViewComponent),
new {Basket = Model.Basket, ButtonDescription = "CompleteOrder"})
</div>
</div>

15
apps/public-web/src/EShopOnAbp.PublicWeb/Components/Payment/PaymentWidgetScriptContributor.cs

@ -0,0 +1,15 @@
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.SignalR;
using Volo.Abp.Modularity;
namespace EShopOnAbp.PublicWeb.Components.Payment;
[DependsOn(typeof(SignalRBrowserScriptContributor))]
public class PaymentWidgetScriptContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/components/payment/payment-widget.js");
}
}

12
apps/public-web/src/EShopOnAbp.PublicWeb/Components/Payment/PaymentWidgetStyleContributor.cs

@ -0,0 +1,12 @@
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace EShopOnAbp.PublicWeb.Components.Payment;
public class PaymentWidgetStyleContributor: BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/components/payment/payment-widget.css");
}
}

43
apps/public-web/src/EShopOnAbp.PublicWeb/Components/Payment/PaymentWidgetViewComponent.cs

@ -0,0 +1,43 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using EShopOnAbp.BasketService;
using EShopOnAbp.PublicWeb.Basket;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
namespace EShopOnAbp.PublicWeb.Components.Payment;
[Widget(
AutoInitialize = true,
RefreshUrl = "/Widgets/Payment",
StyleTypes = new[] {typeof(PaymentWidgetStyleContributor)},
ScriptTypes = new[] {typeof(PaymentWidgetScriptContributor)}
)]
public class PaymentWidgetViewComponent : AbpViewComponent
{
private readonly UserBasketProvider _userBasketProvider;
private readonly UserAddressProvider _userAddressProvider;
public PaymentWidgetViewComponent(UserBasketProvider userBasketProvider, UserAddressProvider userAddressProvider)
{
_userBasketProvider = userBasketProvider;
_userAddressProvider = userAddressProvider;
}
public async Task<IViewComponentResult> InvokeAsync()
{
var viewModel = new PaymentViewModel()
{
Basket = await _userBasketProvider.GetBasketAsync(),
Address = _userAddressProvider.GetDemoAddresses()
};
return View("~/Components/Payment/Default.cshtml", viewModel);
}
}
public class PaymentViewModel
{
public BasketDto Basket { get; set; }
public List<AddressDto> Address { get; set; }
}

5
apps/public-web/src/EShopOnAbp.PublicWeb/EShopOnAbp.PublicWeb.csproj

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
@ -6,6 +6,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="6.0.0" />
<PackageReference Include="Volo.Abp.AutoMapper" Version="5.0.0-rc.1" />
<PackageReference Include="Yarp.ReverseProxy" Version="1.0.0" />
</ItemGroup>
@ -26,6 +27,8 @@
<ProjectReference Include="..\..\..\..\shared\EShopOnAbp.Shared.Localization\EShopOnAbp.Shared.Localization.csproj" />
<ProjectReference Include="..\..\..\..\services\catalog\src\EShopOnAbp.CatalogService.HttpApi.Client\EShopOnAbp.CatalogService.HttpApi.Client.csproj" />
<ProjectReference Include="..\..\..\..\services\basket\src\EShopOnAbp.BasketService.HttpApi.Client\EShopOnAbp.BasketService.HttpApi.Client.csproj" />
<ProjectReference Include="..\..\..\..\services\payment\src\EShopOnAbp.PaymentService.HttpApi.Client\EShopOnAbp.PaymentService.HttpApi.Client.csproj" />
<!-- <ProjectReference Include="..\..\..\..\services\product\src\MyCompanyName.MyProjectName.ProductService.HttpApi.Client\MyCompanyName.MyProjectName.ProductService.HttpApi.Client.csproj" />-->
</ItemGroup>

13
apps/public-web/src/EShopOnAbp.PublicWeb/EShopOnAbpPaymentConsts.cs

@ -0,0 +1,13 @@
namespace EShopOnAbp.PublicWeb
{
public static class EShopOnAbpPaymentConsts
{
public const string Currency = "USD";
public static class DemoAddressTypes
{
public const string Work = "Work";
public const string Home = "Home";
}
}
}

18
apps/public-web/src/EShopOnAbp.PublicWeb/EShopOnAbpPublicAutoMapperProfile.cs

@ -0,0 +1,18 @@
using AutoMapper;
using EShopOnAbp.BasketService;
using EShopOnAbp.PaymentService;
namespace EShopOnAbp.PublicWeb
{
public class EShopOnAbpPublicAutoMapperProfile : Profile
{
public EShopOnAbpPublicAutoMapperProfile()
{
CreateMap<BasketItemDto, PaymentRequestProductCreationDto>()
.ForMember(p => p.ReferenceId, opts => opts.MapFrom(p => p.ProductId.ToString()))
.ForMember(p => p.Name, opts => opts.MapFrom(p => p.ProductName))
.ForMember(p => p.UnitPrice, opts => opts.MapFrom(p => p.TotalPrice / p.Count))
.ForMember(p => p.Quantity, opts => opts.MapFrom(p => p.Count));
}
}
}

25
apps/public-web/src/EShopOnAbp.PublicWeb/EShopOnAbpPublicWebModule.cs

@ -1,18 +1,18 @@
using System;
using System.Net.Http.Headers;
using EShopOnAbp.BasketService;
using EShopOnAbp.BasketService;
using EShopOnAbp.CatalogService;
using EShopOnAbp.Localization;
using EShopOnAbp.PaymentService;
using EShopOnAbp.PublicWeb.Menus;
using EShopOnAbp.Shared.Hosting.AspNetCore;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using StackExchange.Redis;
using System;
using System.Net.Http.Headers;
using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.AspNetCore.Authentication.OpenIdConnect;
@ -22,6 +22,7 @@ using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars;
using Volo.Abp.AspNetCore.SignalR;
using Volo.Abp.AutoMapper;
using Volo.Abp.Caching;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.EventBus.RabbitMq;
@ -47,7 +48,9 @@ namespace EShopOnAbp.PublicWeb
typeof(EShopOnAbpSharedLocalizationModule),
typeof(CatalogServiceHttpApiClientModule),
typeof(BasketServiceHttpApiClientModule),
typeof(AbpAspNetCoreSignalRModule)
typeof(AbpAspNetCoreSignalRModule),
typeof(PaymentServiceHttpApiClientModule),
typeof(AbpAutoMapperModule)
)]
public class EShopOnAbpPublicWebModule : AbpModule
{
@ -68,6 +71,12 @@ namespace EShopOnAbp.PublicWeb
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
context.Services.AddAutoMapperObjectMapper<EShopOnAbpPublicWebModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<EShopOnAbpPublicWebModule>(validate: true);
});
Configure<AbpMultiTenancyOptions>(options =>
{
options.IsEnabled = true;
@ -83,6 +92,11 @@ namespace EShopOnAbp.PublicWeb
options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
});
Configure<EShopOnAbpPublicWebPaymentOptions>(options =>
{
options.PaymentSuccessfulCallbackUrl = configuration["App:SelfUrl"].EnsureEndsWith('/') + "PaymentCompleted";
});
context.Services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
@ -110,6 +124,7 @@ namespace EShopOnAbp.PublicWeb
options.Scope.Add("AdministrationService");
options.Scope.Add("BasketService");
options.Scope.Add("CatalogService");
options.Scope.Add("PaymentService");
});
var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);

8
apps/public-web/src/EShopOnAbp.PublicWeb/EShopOnAbpPublicWebPaymentOptions.cs

@ -0,0 +1,8 @@
namespace EShopOnAbp.PublicWeb
{
public class EShopOnAbpPublicWebPaymentOptions
{
public string PaymentSuccessfulCallbackUrl { get; set; }
public string PaymentFailureCallbackUrl { get; set; }
}
}

4
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Basket.cshtml

@ -11,8 +11,8 @@
@inject IStringLocalizer<EShopOnAbpResource> L
<div class="row">
<h3 class="pt-5 pb-4 text-center">@L["YourBasket"]</h3>
<div id="BasketArea">
@* <h3 class="pt-5 pb-4 text-center">@L["YourBasket"]</h3> *@
<div id="BasketArea" class="pt-5">
@await Component.InvokeAsync(typeof(BasketWidgetViewComponent))
</div>
</div>

7
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Basket.cshtml.cs

@ -6,11 +6,8 @@ namespace EShopOnAbp.PublicWeb.Pages;
public class BasketModel : AbpPageModel
{
private readonly ILogger<BasketModel> _logger;
public BasketModel(ILogger<BasketModel> logger)
public BasketModel()
{
_logger = logger;
}
public void OnGet()
@ -21,7 +18,7 @@ public class BasketModel : AbpPageModel
{
if (!CurrentUser.IsAuthenticated)
{
_logger.LogInformation("Redirecting to Login");
Logger.LogInformation("Redirecting to Login..");
return Challenge();
}

15
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Index.cshtml

@ -6,21 +6,28 @@
@{
const int productsColumnSize = 4; // TODO: update abp-column helper to plain html for proper row and columns css
string pageHeader = L["OurProducts"];
}
@section styles{
<abp-style src="/Pages/index.css"/>
}
@section scripts {
<abp-script src="/client-proxies/basket-proxy.js" />
<abp-script src="/Pages/index.js" />
<abp-script src="/client-proxies/basket-proxy.js"/>
<abp-script src="/Pages/index.js"/>
}
@if (Model.HasRemoteServiceError)
{
pageHeader = L["CatalogServiceNotAvailable"];
}
<div class="row">
<div class="col-lg-12">
<h3 class="pt-5 pb-4 text-center">@L["OurProducts"]</h3>
<h3 class="pt-5 pb-4 text-center">@pageHeader</h3>
<div class="product-list">
@for (int i = 0; i < Math.Ceiling(Model.Products.Count / (double)productsColumnSize); i++)
@for (int i = 0; i < Math.Ceiling(Model.Products.Count / (double) productsColumnSize); i++)
{
<abp-row>
@for (int j = 0; j < productsColumnSize; j++)

17
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Index.cshtml.cs

@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using EShopOnAbp.CatalogService.Products;
using Microsoft.AspNetCore.Authentication;
@ -9,6 +11,7 @@ namespace EShopOnAbp.PublicWeb.Pages
public class IndexModel : AbpPageModel
{
public IReadOnlyList<ProductDto> Products { get; private set; }
public bool HasRemoteServiceError { get; set; } = false;
private readonly IPublicProductAppService _productAppService;
public IndexModel(IPublicProductAppService productAppService)
@ -18,7 +21,17 @@ namespace EShopOnAbp.PublicWeb.Pages
public async Task OnGet()
{
Products = (await _productAppService.GetListAsync()).Items;
try
{
Products = (await _productAppService.GetListAsync()).Items;
}
catch (Exception e)
{
Products = new ReadOnlyCollection<ProductDto>(new List<ProductDto>());
HasRemoteServiceError = true;
Console.WriteLine(e);
}
}
public async Task OnPostLoginAsync()

8
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Payment.cshtml

@ -1,10 +1,14 @@
@page
@using EShopOnAbp.Localization
@using EShopOnAbp.PublicWeb.Components.Payment
@using Microsoft.Extensions.Localization
@model EShopOnAbp.PublicWeb.Pages.PaymentModel
@inject IStringLocalizer<EShopOnAbpResource> L
<div class="row">
<h3 class="pt-5 pb-4 text-center">@L["Payment"]</h3>
@* <h3 class="pt-5 pb-4 text-center">@L["Payment"]</h3> *@
<div id="PaymentArea" class="pt-5">
@await Component.InvokeAsync(typeof(PaymentWidgetViewComponent))
</div>
</div>

51
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Payment.cshtml.cs

@ -1,10 +1,59 @@
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using EShopOnAbp.BasketService;
using EShopOnAbp.PaymentService;
using EShopOnAbp.PaymentService.PaymentRequests;
using EShopOnAbp.PublicWeb.Basket;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Volo.Abp.Users;
namespace EShopOnAbp.PublicWeb.Pages;
[Authorize]
public class PaymentModel : AbpPageModel
{
private readonly IPaymentRequestAppService _paymentRequestAppService;
private readonly UserBasketProvider _userBasketProvider;
private readonly EShopOnAbpPublicWebPaymentOptions _publicWebPaymentOptions;
public PaymentModel(
IPaymentRequestAppService paymentRequestAppService,
UserBasketProvider userBasketProvider,
IOptions<EShopOnAbpPublicWebPaymentOptions> publicWebPaymentOptions)
{
_paymentRequestAppService = paymentRequestAppService;
_userBasketProvider = userBasketProvider;
_publicWebPaymentOptions = publicWebPaymentOptions.Value;
}
public void OnGet()
{
}
public async Task<IActionResult> OnPostAsync()
{
Logger.LogInformation("Payment Proceeded...");
var basket = await _userBasketProvider.GetBasketAsync();
var paymentRequest = await _paymentRequestAppService.CreateAsync(new PaymentRequestCreationDto
{
BuyerId = CurrentUser.GetId().ToString(),
Currency = EShopOnAbpPaymentConsts.Currency,
Products = ObjectMapper.Map<List<BasketItemDto>, List<PaymentRequestProductCreationDto>>(basket.Items)
});
var response = await _paymentRequestAppService.StartAsync(new PaymentRequestStartDto
{
PaymentRequestId = paymentRequest.Id,
ReturnUrl = _publicWebPaymentOptions.PaymentSuccessfulCallbackUrl,
CancelUrl = _publicWebPaymentOptions.PaymentFailureCallbackUrl,
});
return Redirect(response.CheckoutLink);
}
}

16
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml

@ -0,0 +1,16 @@
@page
@model EShopOnAbp.PublicWeb.Pages.PaymentCompletedModel
<div>
@if (Model.IsSuccessful)
{
<h1>Thank you for the payment!</h1>
<hr />
<h1>Purchase completed!</h1>
<hr />
<h3>click <a href="/">here</a> to return to home page</h3>
}
</div>

32
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml.cs

@ -0,0 +1,32 @@
using EShopOnAbp.PaymentService.PaymentRequests;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
namespace EShopOnAbp.PublicWeb.Pages;
[Authorize]
public class PaymentCompletedModel : AbpPageModel
{
private readonly IPaymentRequestAppService _paymentRequestAppService;
public PaymentCompletedModel(IPaymentRequestAppService paymentRequestAppService)
{
_paymentRequestAppService = paymentRequestAppService;
}
[BindProperty(SupportsGet = true)]
public string Token { get; set; }
public PaymentRequestDto PaymentRequest { get; private set; }
public bool IsSuccessful { get; private set; }
public async Task OnGetAsync()
{
PaymentRequest = await _paymentRequestAppService.CompleteAsync(Token);
IsSuccessful = PaymentRequest.State == PaymentRequestState.Completed;
}
}

4
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/_ViewStart.cshtml

@ -1,5 +1,7 @@
@using Volo.Abp.AspNetCore.Mvc.UI.Theming
@using EShopOnAbp.PublicWeb.Components.AnonymousUser
@using Volo.Abp.AspNetCore.Mvc.UI.Theming
@inject IThemeManager ThemeManager
@{
Layout = ThemeManager.CurrentTheme.GetPublicLayout();
}
@await Component.InvokeAsync(typeof(AnonymousUserViewComponent))

20
apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/payment/payment-widget.css

@ -0,0 +1,20 @@
.card {
/* Add shadows to create the "card" effect */
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
transition: 0.3s;
}
/* On mouse-over, add a deeper shadow */
.card:hover {
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
cursor: default;
}
/* Add some padding inside the card container */
.card-body {
padding: 2px 16px;
}
.is-selected {
border: solid #bfbfe3;
}

21
apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/payment/payment-widget.js

@ -0,0 +1,21 @@
(function () {
abp.widgets.PaymentWidget = function ($wrapper) {
var widgetManager = $wrapper.data('abp-widget-manager');
var init = function (filters) {
$wrapper
.find('.address-list .card')
.click(function () {
var $this = $(this);
var addressId = $this.attr('data-address-id');
abp.utils.setCookieValue("selected-address", addressId);
$this.parents(".address-list").find('.card').removeClass("is-selected");
$this.addClass("is-selected");
});
};
return {
init: init
};
};
})();

13
gateways/web-public/src/EShopOnAbp.WebPublicGateway/appsettings.json

@ -87,6 +87,19 @@
],
"UpstreamPathTemplate": "/api/ordering/{everything}",
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ]
},
{
"ServiceKey": "Payment Service",
"DownstreamPathTemplate": "/api/payment/{everything}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 44357
}
],
"UpstreamPathTemplate": "/api/payment/{everything}",
"UpstreamHttpMethod": [ "Put", "Delete", "Get", "Post" ]
}
],
"GlobalConfiguration": {

1
services/basket/src/EShopOnAbp.BasketService.Application.Contracts/IBasketAppService.cs

@ -11,5 +11,4 @@ public interface IBasketAppService : IApplicationService
Task<BasketDto> MergeBasketsAsync();
Task<BasketDto> AddProductAsync(AddProductDto input);
Task<BasketDto> RemoveProductAsync(RemoveProductDto input);
Task PurchaseAsync();
}

9
services/basket/src/EShopOnAbp.BasketService.Application/BasketAppService.cs

@ -104,15 +104,6 @@ public class BasketAppService : BasketServiceAppService, IBasketAppService
return await GetBasketDtoAsync(basket);
}
public async Task PurchaseAsync()
{
var basket = await _basketRepository.GetAsync(CurrentUser.GetId());
var orderAcceptedEto = ObjectMapper.Map<Basket, OrderAcceptedEto>(basket);
await _distributedEventBus.PublishAsync(orderAcceptedEto);
basket.Clear();
await _basketRepository.UpdateAsync(basket);
}
private async Task<BasketDto> GetBasketDtoAsync(Basket basket)
{
var products = new Dictionary<Guid, ProductDto>();

2
services/basket/src/EShopOnAbp.BasketService.Application/BasketServiceApplicationAutoMapperProfile.cs

@ -8,8 +8,6 @@ namespace EShopOnAbp.BasketService
public BasketServiceApplicationAutoMapperProfile()
{
CreateMap<ProductEto, ProductDto>();
CreateMap<Basket, OrderAcceptedEto>();
CreateMap<BasketItem, OrderItemEto>();
}
}
}

4
services/basket/src/EShopOnAbp.BasketService.Domain.Shared/BasketServiceDomainSharedModule.cs

@ -1,4 +1,5 @@
using EShopOnAbp.BasketService.Localization;
using EShopOnAbp.OrderingService;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
@ -9,7 +10,8 @@ using Volo.Abp.VirtualFileSystem;
namespace EShopOnAbp.BasketService
{
[DependsOn(
typeof(AbpValidationModule)
typeof(AbpValidationModule),
typeof(OrderingServiceDomainSharedModule)
)]
public class BasketServiceDomainSharedModule : AbpModule
{

3
services/basket/src/EShopOnAbp.BasketService.Domain.Shared/EShopOnAbp.BasketService.Domain.Shared.csproj

@ -16,6 +16,9 @@
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\ordering\src\EShopOnAbp.OrderingService.Domain.Shared\EShopOnAbp.OrderingService.Domain.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\BasketService\*.json" />

8
services/basket/src/EShopOnAbp.BasketService.Domain.Shared/OrderAcceptedEto.cs

@ -1,8 +0,0 @@
using System.Collections.Generic;
namespace EShopOnAbp.BasketService;
public class OrderAcceptedEto
{
public List<OrderItemEto> Items { get; set; }
}

9
services/basket/src/EShopOnAbp.BasketService.Domain.Shared/OrderItemEto.cs

@ -1,9 +0,0 @@
using System;
namespace EShopOnAbp.BasketService;
public class OrderItemEto
{
public Guid ProductId { get; set; }
public int Count { get; set; }
}

26
services/basket/src/EShopOnAbp.BasketService.Domain/Orders/OrderAcceptedEventHandler.cs

@ -0,0 +1,26 @@
using EShopOnAbp.OrderingService.Orders;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
namespace EShopOnAbp.BasketService.Orders
{
public class OrderAcceptedEventHandler :
IDistributedEventHandler<OrderAcceptedEto>,
ITransientDependency
{
private readonly IBasketRepository _basketRepository;
public OrderAcceptedEventHandler(IBasketRepository basketRepository)
{
_basketRepository = basketRepository;
}
public async Task HandleEventAsync(OrderAcceptedEto eventData)
{
var basket = await _basketRepository.GetAsync(eventData.BuyerId);
basket.Clear();
await _basketRepository.UpdateAsync(basket);
}
}
}

5
services/basket/src/EShopOnAbp.BasketService.HttpApi.Client/ClientProxies/BasketClientProxy.Generated.cs

@ -48,10 +48,5 @@ namespace EShopOnAbp.BasketService.ClientProxies
{ typeof(RemoveProductDto), input }
});
}
public virtual async Task PurchaseAsync()
{
await RequestAsync(nameof(PurchaseAsync));
}
}
}

4
services/catalog/src/EShopOnAbp.CatalogService.Domain.Shared/EShopOnAbp.CatalogService.Domain.Shared.csproj

@ -16,6 +16,10 @@
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\basket\src\EShopOnAbp.BasketService.Domain.Shared\EShopOnAbp.BasketService.Domain.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\CatalogService\*.json" />
<Content Remove="Localization\CatalogService\*.json" />

1
services/catalog/src/EShopOnAbp.CatalogService.Domain/EShopOnAbp.CatalogService.Domain.csproj

@ -9,7 +9,6 @@
<ItemGroup>
<ProjectReference Include="..\EShopOnAbp.CatalogService.Domain.Shared\EShopOnAbp.CatalogService.Domain.Shared.csproj" />
<ProjectReference Include="..\..\..\basket\src\EShopOnAbp.BasketService.Domain.Shared\EShopOnAbp.BasketService.Domain.Shared.csproj" />
</ItemGroup>
<ItemGroup>

1
services/catalog/src/EShopOnAbp.CatalogService.Domain/OrderHandler.cs

@ -2,6 +2,7 @@
using System.Threading.Tasks;
using EShopOnAbp.BasketService;
using EShopOnAbp.CatalogService.Products;
using EShopOnAbp.OrderingService.Orders;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus.Distributed;

5
services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServerDataSeeder.cs

@ -217,8 +217,9 @@ namespace EShopOnAbp.IdentityService.DbMigrations
scopes: commonScopes.Union(new[]
{
"AdministrationService",
"CatalogService",
"BasketService"
"CatalogService", // Consider removing this service
"BasketService",
"PaymentService"
}),
grantTypes: new[] { "hybrid" },
secret: "1q2w3e*".Sha256(),

6
services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/EShopOnAbp.OrderingService.Domain.Shared.csproj

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\common.props" />
@ -16,6 +16,10 @@
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\payment\src\EShopOnAbp.PaymentService.Domain.Shared\EShopOnAbp.PaymentService.Domain.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\OrderingService\*.json" />
<Content Remove="Localization\OrderingService\*.json" />

4
services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/OrderingServiceDomainSharedModule.cs

@ -5,11 +5,13 @@ using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Validation;
using Volo.Abp.Validation.Localization;
using Volo.Abp.VirtualFileSystem;
using EShopOnAbp.PaymentService;
namespace EShopOnAbp.OrderingService
{
[DependsOn(
typeof(AbpValidationModule)
typeof(AbpValidationModule),
typeof(PaymentServiceDomainSharedModule)
)]
public class OrderingServiceDomainSharedModule : AbpModule
{

16
services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderAcceptedEto.cs

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus;
namespace EShopOnAbp.OrderingService.Orders
{
[Serializable]
[EventName("EShopOnAbp.Order.Accepted")]
public class OrderAcceptedEto : EtoBase
{
public Guid OrderId { get; set; }
public Guid BuyerId { get; set; }
public List<OrderItemEto> Items { get; set; }
}
}

14
services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderItemEto.cs

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EShopOnAbp.OrderingService.Orders
{
public class OrderItemEto
{
public Guid ProductId { get; set; }
public int Count { get; set; }
}
}

45
services/ordering/src/EShopOnAbp.OrderingService.Domain/PaymentRequests/PaymentRequestEventHandler.cs

@ -0,0 +1,45 @@
using EShopOnAbp.OrderingService.Orders;
using EShopOnAbp.PaymentService.PaymentRequests;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus.Distributed;
namespace EShopOnAbp.OrderingService.PaymentRequests
{
public class PaymentRequestEventHandler :
IDistributedEventHandler<PaymentRequestCompletedEto>,
ITransientDependency
{
private readonly IDistributedEventBus _eventBus;
public PaymentRequestEventHandler(IDistributedEventBus eventBus)
{
_eventBus = eventBus;
}
public async Task HandleEventAsync(PaymentRequestCompletedEto eventData)
{
// TODO: Insert Order here.
//throw new NotImplementedException();
await _eventBus.PublishAsync(new OrderAcceptedEto
{
Items = eventData.Products.Select(MapProductToOrderItem).ToList(),
BuyerId = Guid.Parse(eventData.BuyerId),
OrderId = Guid.Empty, // TODO: Inserted OrderId,
});
}
private static OrderItemEto MapProductToOrderItem(PaymentRequestProductEto arg)
{
return new OrderItemEto
{
Count = arg.Quantity,
ProductId = Guid.Parse(arg.ReferenceId)
};
}
}
}

11
services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentCompletedEto.cs

@ -0,0 +1,11 @@
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus;
namespace EShopOnAbp.PaymentService.PaymentRequests
{
[EventName("EShopOnAbp.Payment.Completed")]
public class PaymentCompletedEto : EtoBase
{
public PaymentRequestDto PaymentRequest { get; set; }
}
}

5
services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs

@ -28,6 +28,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
foreach (var paymentRequestProduct in input.Products
.Select(s => new PaymentRequestProduct(
GuidGenerator.Create(),
paymentRequest.Id,
s.Name,
s.UnitPrice,
@ -38,12 +39,14 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
paymentRequest.Products.Add(paymentRequestProduct);
}
await PaymentRequestRepository.InsertAsync(paymentRequest);
return ObjectMapper.Map<PaymentRequest, PaymentRequestDto>(paymentRequest);
}
public async Task<PaymentRequestStartResultDto> StartAsync(PaymentRequestStartDto input)
{
var paymentRequest = await PaymentRequestRepository.GetAsync(input.PaymentRequestId);
var paymentRequest = await PaymentRequestRepository.GetAsync(input.PaymentRequestId, includeDetails: true);
var totalCheckoutPrice = paymentRequest.Products.Sum(s => s.TotalPrice);

5
services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServiceApplicationAutoMapperProfile.cs

@ -1,4 +1,6 @@
using AutoMapper;
using EShopOnAbp.PaymentService.PaymentRequests;
using Volo.Abp.AutoMapper;
namespace EShopOnAbp.PaymentService
{
@ -6,6 +8,9 @@ namespace EShopOnAbp.PaymentService
{
public PaymentServiceApplicationAutoMapperProfile()
{
CreateMap<PaymentRequest, PaymentRequestDto>();
CreateMap<PaymentRequestProduct, PaymentRequestProductDto>();
/* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */

2
services/payment/src/EShopOnAbp.PaymentService.Application/PaymentServiceApplicationModule.cs

@ -25,6 +25,8 @@ namespace EShopOnAbp.PaymentService
options.AddMaps<PaymentServiceApplicationModule>(validate: true);
});
Configure<PayPalOptions>(context.Services.GetConfiguration().GetSection("Payment:PayPal"));
context.Services.AddTransient(provider =>
{
var options = provider.GetService<IOptions<PayPalOptions>>().Value;

16
services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestCompletedEto.cs

@ -1,15 +1,25 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus;
namespace EShopOnAbp.PaymentService
namespace EShopOnAbp.PaymentService.PaymentRequests
{
[Serializable]
[EventName("Payment.Completed")]
public class PaymentRequestCompletedEto: EtoBase, IHasExtraProperties
[EventName("EShopOnAbp.Payment.Completed")]
public class PaymentRequestCompletedEto : EtoBase, IHasExtraProperties
{
public Guid PaymentRequestId { get; set; }
public string Currency { get; set; }
public string BuyerId { get; set; }
public PaymentRequestState State { get; set; }
public ICollection<PaymentRequestProductEto> Products { get; set; } = new List<PaymentRequestProductEto>();
public ExtraPropertyDictionary ExtraProperties { get; set; }
}
}

2
services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestFailedEto.cs

@ -6,7 +6,7 @@ using Volo.Abp.EventBus;
namespace EShopOnAbp.PaymentService
{
[Serializable]
[EventName("Payment.Completed")]
[EventName("EShopOnAbp.Payment.Completed")]
public class PaymentRequestFailedEto : EtoBase, IHasExtraProperties
{
public Guid PaymentRequestId { get; set; }

18
services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestProductEto.cs

@ -0,0 +1,18 @@
using System;
namespace EShopOnAbp.PaymentService.PaymentRequests
{
[Serializable]
public class PaymentRequestProductEto
{
public string ReferenceId { get; set; }
public string Name { get; set; }
public decimal UnitPrice { get; set; }
public int Quantity { get; set; }
public decimal TotalPrice { get; set; }
}
}

17
services/payment/src/EShopOnAbp.PaymentService.Domain/PaymentRequests/PaymentRequest.cs

@ -1,6 +1,7 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;
@ -48,6 +49,10 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
AddDistributedEvent(new PaymentRequestCompletedEto
{
PaymentRequestId = Id,
BuyerId = BuyerId,
Currency = Currency,
State = State,
Products = Products.Select(MapProductToEto).ToList(),
ExtraProperties = ExtraProperties
});
}
@ -69,5 +74,17 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
ExtraProperties = ExtraProperties
});
}
private static PaymentRequestProductEto MapProductToEto(PaymentRequestProduct product)
{
return new PaymentRequestProductEto
{
Name = product.Name,
Quantity = product.Quantity,
ReferenceId = product.ReferenceId,
TotalPrice = product.TotalPrice,
UnitPrice = product.UnitPrice,
};
}
}
}

2
services/payment/src/EShopOnAbp.PaymentService.Domain/PaymentRequests/PaymentRequestProduct.cs

@ -19,6 +19,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
public decimal TotalPrice { get; set; }
public PaymentRequestProduct(
Guid id,
Guid paymentRequestId,
[NotNull] string name,
decimal unitPrice,
@ -26,6 +27,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
decimal totalPrice,
[CanBeNull] string referenceId = null)
{
Id = id;
PaymentRequestId = paymentRequestId;
Name = name;
UnitPrice = unitPrice;

9
services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/PaymentRequests/EfCorePaymentRequestRepository.cs

@ -1,5 +1,8 @@
using EShopOnAbp.PaymentService.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
@ -18,5 +21,11 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
{
}
public override async Task<IQueryable<PaymentRequest>> WithDetailsAsync()
{
return (await base.WithDetailsAsync())
.Include(p => p.Products);
}
}
}

50
services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/PaymentRequestClientProxy.Generated.cs

@ -0,0 +1,50 @@
// 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 EShopOnAbp.PaymentService.PaymentRequests;
// ReSharper disable once CheckNamespace
namespace EShopOnAbp.PaymentService.Controllers.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<bool> HandleWebhookAsync(string payload)
{
return await RequestAsync<bool>(nameof(HandleWebhookAsync), new ClientProxyRequestTypeValue
{
{ typeof(string), payload }
});
}
public virtual async Task<PaymentRequestStartResultDto> StartAsync(PaymentRequestStartDto input)
{
return await RequestAsync<PaymentRequestStartResultDto>(nameof(StartAsync), new ClientProxyRequestTypeValue
{
{ typeof(PaymentRequestStartDto), input }
});
}
}
}

8
services/payment/src/EShopOnAbp.PaymentService.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 EShopOnAbp.PaymentService.Controllers.ClientProxies
{
public partial class PaymentRequestClientProxy
{
}
}

53
services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/PaymentService-generate-proxy.json

@ -1,53 +0,0 @@
{
"modules": {
"PaymentService": {
"rootPath": "PaymentService",
"remoteServiceName": "PaymentService",
"controllers": {
"EShopOnAbp.PaymentService.Samples.SampleController": {
"controllerName": "Sample",
"controllerGroupName": "Sample",
"type": "EShopOnAbp.PaymentService.Samples.SampleController",
"interfaces": [
{
"type": "EShopOnAbp.PaymentService.Samples.ISampleAppService"
}
],
"actions": {
"GetAsync": {
"uniqueName": "GetAsync",
"name": "GetAsync",
"httpMethod": "GET",
"url": "api/PaymentService/sample",
"supportedVersions": [],
"parametersOnMethod": [],
"parameters": [],
"returnValue": {
"type": "EShopOnAbp.PaymentService.Samples.SampleDto",
"typeSimple": "EShopOnAbp.PaymentService.Samples.SampleDto"
},
"allowAnonymous": null,
"implementFrom": "EShopOnAbp.PaymentService.Samples.ISampleAppService"
},
"GetAuthorizedAsync": {
"uniqueName": "GetAuthorizedAsync",
"name": "GetAuthorizedAsync",
"httpMethod": "GET",
"url": "api/PaymentService/sample/authorized",
"supportedVersions": [],
"parametersOnMethod": [],
"parameters": [],
"returnValue": {
"type": "EShopOnAbp.PaymentService.Samples.SampleDto",
"typeSimple": "EShopOnAbp.PaymentService.Samples.SampleDto"
},
"allowAnonymous": false,
"implementFrom": "EShopOnAbp.PaymentService.Samples.ISampleAppService"
}
}
}
}
}
},
"types": {}
}

15
services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/SampleClientProxy.Generated.cs

@ -1,15 +0,0 @@
// 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 EShopOnAbp.PaymentService.Samples;
// ReSharper disable once CheckNamespace
namespace EShopOnAbp.PaymentService.Samples.ClientProxies
{
}

8
services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/SampleClientProxy.cs

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

171
services/payment/src/EShopOnAbp.PaymentService.HttpApi.Client/ClientProxies/payment-generate-proxy.json

@ -0,0 +1,171 @@
{
"modules": {
"payment": {
"rootPath": "payment",
"remoteServiceName": "PaymentService",
"controllers": {
"EShopOnAbp.PaymentService.Controllers.PaymentRequestController": {
"controllerName": "PaymentRequest",
"controllerGroupName": "PaymentRequest",
"type": "EShopOnAbp.PaymentService.Controllers.PaymentRequestController",
"interfaces": [
{
"type": "EShopOnAbp.PaymentService.PaymentRequests.IPaymentRequestAppService"
}
],
"actions": {
"CompleteAsyncByToken": {
"uniqueName": "CompleteAsyncByToken",
"name": "CompleteAsync",
"httpMethod": "POST",
"url": "api/payment/requests/complete",
"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": null,
"bindingSourceId": "ModelBinding",
"descriptorName": ""
}
],
"returnValue": {
"type": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestDto",
"typeSimple": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestDto"
},
"allowAnonymous": null,
"implementFrom": "EShopOnAbp.PaymentService.PaymentRequests.IPaymentRequestAppService"
},
"CreateAsyncByInput": {
"uniqueName": "CreateAsyncByInput",
"name": "CreateAsync",
"httpMethod": "POST",
"url": "api/payment/requests",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestCreationDto, EShopOnAbp.PaymentService.Application.Contracts",
"type": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestCreationDto",
"typeSimple": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestCreationDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestCreationDto",
"typeSimple": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestCreationDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestDto",
"typeSimple": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestDto"
},
"allowAnonymous": null,
"implementFrom": "EShopOnAbp.PaymentService.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": "EShopOnAbp.PaymentService.PaymentRequests.IPaymentRequestAppService"
},
"StartAsyncByInput": {
"uniqueName": "StartAsyncByInput",
"name": "StartAsync",
"httpMethod": "POST",
"url": "api/payment/requests/start",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestStartDto, EShopOnAbp.PaymentService.Application.Contracts",
"type": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestStartDto",
"typeSimple": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestStartDto",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "input",
"jsonName": null,
"type": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestStartDto",
"typeSimple": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestStartDto",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestStartResultDto",
"typeSimple": "EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestStartResultDto"
},
"allowAnonymous": null,
"implementFrom": "EShopOnAbp.PaymentService.PaymentRequests.IPaymentRequestAppService"
}
}
}
}
}
},
"types": {}
}

3
services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/PaymentServiceHttpApiHostModule.cs

@ -1,5 +1,6 @@
using EShopOnAbp.PaymentService.DbMigrations;
using EShopOnAbp.PaymentService.EntityFrameworkCore;
using EShopOnAbp.PaymentService.PayPal;
using EShopOnAbp.Shared.Hosting.AspNetCore;
using EShopOnAbp.Shared.Hosting.Microservices;
using Microsoft.AspNetCore.Builder;
@ -25,6 +26,8 @@ namespace EShopOnAbp.PaymentService
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();

7
services/payment/src/EShopOnAbp.PaymentService.HttpApi.Host/appsettings.json

@ -40,5 +40,12 @@
},
"ElasticSearch": {
"Url": "http://localhost:9200"
},
"Payment": {
"PayPal": {
"ClientId": "PAYPAL_CLIENT_ID",
"Secret": "PAYPAL_SECRET",
"Environment": "Sandbox"
}
}
}

1
shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/en.json

@ -6,6 +6,7 @@
"YourBasket": "Your Basket",
"Total": "Total",
"OurProducts": "Our Products",
"CatalogServiceNotAvailable": "Catalog Service is unavailable right now! Try again later...",
"StockCount": "Stock Count",
"RemoveFromBasket": "Remove from basket",
"CompletePurchase": "Complete purchase",

1
shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/tr.json

@ -6,6 +6,7 @@
"YourBasket": "Sepetiniz",
"Total": "Toplam",
"OurProducts": "Ürünlerimiz",
"CatalogServiceNotAvailable": "Ürün servisine şu anda ulaşılamıyor! Lütfen sonra tekrar deneyiniz...",
"StockCount": "Stokta",
"RemoveFromBasket": "Sepetten kaldır",
"CompletePurchase": "Alışverişi tamamla",

Loading…
Cancel
Save