Browse Source

Merge pull request #56 from abpframework/gterdem/my_order

eShopOnAbp: Create my orders page
pull/58/head
Galip Tolga Erdem 5 years ago
committed by GitHub
parent
commit
a9a607c714
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      apps/auth-server/src/EShopOnAbp.AuthServer/appsettings.json
  2. 4
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/Basket/BasketWidgetViewComponent.cs
  3. 2
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/Payment/PaymentWidgetViewComponent.cs
  4. 1
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/Purchase/Default.cshtml
  5. 4
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/Toolbar/Cart/CartWidgetViewComponent.cs
  6. 76
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/Default.cshtml
  7. 12
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/UserOrderWidgetScriptContributor.cs
  8. 12
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/UserOrderWidgetStyleContributor.cs
  9. 48
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/UserOrderWidgetViewComponent.cs
  10. 2
      apps/public-web/src/EShopOnAbp.PublicWeb/Menus/EShopOnAbpPublicWebMenuContributor.cs
  11. 43
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/MyOrders.cshtml
  12. 14
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/MyOrders.cshtml.cs
  13. 59
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/OrderReceived.cshtml
  14. 23
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/OrderReceived.cshtml.cs
  15. 39
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Payment.cshtml.cs
  16. 24
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml
  17. 11
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml.cs
  18. 2
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/index.js
  19. 33
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/myOrders.css
  20. 26
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/myOrders.js
  21. 19
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/orderReceived.css
  22. 2
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/payment.js
  23. 9
      apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/DiscountProvider.cs
  24. 2
      apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserAddressProvider.cs
  25. 10
      apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserBasketProvider.cs
  26. 47
      apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/client-proxies/ordering-proxy.js
  27. 19
      apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/basket/basket-widget.css
  28. 0
      apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/user-orders/user-order-widget.css
  29. 0
      apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/user-orders/user-order-widget.js
  30. 6
      services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/GetMyOrdersInput.cs
  31. 2
      services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/IOrderAppService.cs
  32. 1
      services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/OrderDto.cs
  33. 1
      services/ordering/src/EShopOnAbp.OrderingService.Application/OrderingServiceApplicationAutoMapperProfile.cs
  34. 57
      services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs
  35. 1
      services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderPlacedEto.cs
  36. 8
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/IOrderRepository.cs
  37. 18
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs
  38. 2
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/OrderManager.cs
  39. 2
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/PaymentType.cs
  40. 16
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/Last30DaysSpecification.cs
  41. 21
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/MonthsAgoSpecification.cs
  42. 29
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/SpecificationFactory.cs
  43. 20
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/YearSpecification.cs
  44. 1
      services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderServiceDataSeedContributor.cs
  45. 1
      services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderingServiceDbContext.cs
  46. 24
      services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs
  47. 22
      services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/OrderEfCoreQueryableExtensions.cs
  48. 17
      services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/OrderClientProxy.Generated.cs
  49. 74
      services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/ordering-generate-proxy.json
  50. 4
      services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/EShopOnAbp.OrderingService.HttpApi.Client.csproj
  51. 61
      services/ordering/test/EShopOnAbp.OrderingService.Application.Tests/Orders/OrderApplication_Tests.cs
  52. 1
      services/ordering/test/EShopOnAbp.OrderingService.Domain.Tests/Orders/OrderManager_Tests.cs
  53. 84
      services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Orders/OrderRepository_Tests.cs
  54. 12
      services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Samples/SampleRepository_Tests.cs
  55. 33
      services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceDataSeedContributor.cs
  56. 15
      services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceTestBaseModule.cs
  57. 72
      services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceTestDataSeedContributor.cs
  58. 31
      services/ordering/test/EShopOnAbp.OrderingService.TestBase/Product.cs
  59. 23
      services/ordering/test/EShopOnAbp.OrderingService.TestBase/TestData.cs
  60. 42
      services/ordering/test/EShopOnAbp.OrderingService.TestBase/TestProducts.cs
  61. 902
      services/ordering/test/EShopOnAbp.OrderingService.TestBase/products.json
  62. 3
      services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestCreationDto.cs
  63. 2
      services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestDto.cs
  64. 2
      services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs
  65. 8
      services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestByPassAppService.cs
  66. 1
      services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestCompletedEto.cs
  67. 1
      services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestFailedEto.cs
  68. 5
      services/payment/src/EShopOnAbp.PaymentService.Domain/PaymentRequests/PaymentRequest.cs
  69. 2
      services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/EntityFrameworkCore/PaymentServiceDbContextModelCreatingExtensions.cs
  70. 140
      services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/20220107135728_Added-OrderNo.Designer.cs
  71. 26
      services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/20220107135728_Added-OrderNo.cs
  72. 3
      services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/PaymentServiceDbContextModelSnapshot.cs
  73. 1
      shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/en.json
  74. 1
      shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/tr.json

2
apps/auth-server/src/EShopOnAbp.AuthServer/appsettings.json

@ -1,7 +1,7 @@
{
"App": {
"SelfUrl": "https://localhost:44330",
"CorsOrigins": "https://*.EShopOnAbp.com,http://localhost:4200,https://localhost:44307,https://localhost:44372,https://localhost:44353",
"CorsOrigins": "https://*.EShopOnAbp.com,http://localhost:4200,https://localhost:44307,https://localhost:44372,https://localhost:44353,https://localhost:44356",
"RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307"
},
"Logging": {

4
apps/public-web/src/EShopOnAbp.PublicWeb/Components/Basket/BasketWidgetViewComponent.cs

@ -1,6 +1,6 @@
using EShopOnAbp.PublicWeb.Basket;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using EShopOnAbp.PublicWeb.ServiceProviders;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Widgets;

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

@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using EShopOnAbp.BasketService;
using EShopOnAbp.PublicWeb.Basket;
using EShopOnAbp.PublicWeb.ServiceProviders;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Widgets;

1
apps/public-web/src/EShopOnAbp.PublicWeb/Components/Purchase/Default.cshtml

@ -55,6 +55,7 @@
<div class="row" style="padding: 25px; text-align: center">
<form method="post">
@Html.AntiForgeryToken()
<input type="hidden" name="model.TotalDiscountPercentage" class="total-discount" data-discount-total="@demoDiscountPercentage" value="@demoDiscountPercentage" />
<abp-button type="submit" size="Large" class="basket-purchase-button" text="@L[Model.ButtonDescription]" button-type="Warning"/>
</form>
</div>

4
apps/public-web/src/EShopOnAbp.PublicWeb/Components/Toolbar/Cart/CartWidgetViewComponent.cs

@ -1,6 +1,6 @@
using EShopOnAbp.PublicWeb.Basket;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using EShopOnAbp.PublicWeb.ServiceProviders;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Widgets;

76
apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/Default.cshtml

@ -0,0 +1,76 @@
@using System.Globalization
@using EShopOnAbp.Localization
@using Microsoft.Extensions.Localization
@model EShopOnAbp.PublicWeb.Components.UserOrders.UserOrderWidgetViewComponent.UserOrderViewModel
@inject IStringLocalizer<EShopOnAbpResource> L
@if (Model.ServiceError)
{
<div>SERVICE ERROR</div>
}
<abp-row class="m-2 p-2" style="text-align: center">
<span class="order-title"><strong>@Model.UserOrders.Count sipariş</strong> verildi.</span>
</abp-row>
@foreach (var order in Model.UserOrders)
{
var orderTotalString = order.Items.Sum(q => q.UnitPrice).ToString("C", new CultureInfo("en-US"));
string addressString = $"{order.Address.Street} {order.Address.ZipCode} \n {order.Address.City}/{order.Address.Country}";
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<div class="o-header">Sipariş Tarihi</div>
<div class="o-description">@order.OrderDate.ToString("dd MMMM yyyy")</div>
</div>
<div class="col">
<div class="o-header">Toplam</div>
<div class="o-description">@orderTotalString</div>
</div>
<div class="col">
<div class="o-header">Teslimat Adresi</div>
<div>
<abp-button abp-tooltip-bottom="@addressString">@order.Address.Description</abp-button>
</div>
</div>
<div class="col">
<div>
<span class="o-header">Sipariş No</span> <span class="o-order-no">@order.OrderNo.ToString("N0", new NumberFormatInfo() {NumberGroupSeparator = " "})</span>
</div>
</div>
</div>
</div>
<div class="card-body">
@foreach (var item in order.Items)
{
<abp-card class="order-item m-3">
<abp-card-body>
<div class="row m-3">
<h3>@order.OrderStatus</h3>
</div>
<abp-row>
<abp-column size="_2">
<img class="img-size" src="/product-images/@item.PictureUrl"/>
</abp-column>
<abp-column size-lg="_4">
<div>@item.ProductName</div>
<div>Ürünü iade edebileceğiniz son tarih: @order.OrderDate.AddMonths(1).ToString("dd MMMM yyyy")</div>
<div class="mt-3">
<abp-button icon="fas fa-cart-plus" class="btn btn-warning buy-again" text="Tekrar Satın Alın" data-product-id="@item.ProductId"></abp-button>
</div>
</abp-column>
<abp-column offset="_3" size="_2">
<abp-row class="pb-3">
<abp-button class="btn btn-light shadow" disabled="true" abp-tooltip-right="Not available yet">Ürünleri iade et</abp-button>
</abp-row>
<abp-row>
<abp-button class="btn btn-light shadow" disabled="true" abp-tooltip-right="Not available yet">Ürün yorumu yazın</abp-button>
</abp-row>
</abp-column>
</abp-row>
</abp-card-body>
</abp-card>
}
</div>
</div>
<hr/>
}

12
apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/UserOrderWidgetScriptContributor.cs

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

12
apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/UserOrderWidgetStyleContributor.cs

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

48
apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/UserOrderWidgetViewComponent.cs

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Orders;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
namespace EShopOnAbp.PublicWeb.Components.UserOrders;
[Widget(
AutoInitialize = true,
RefreshUrl = "/Widgets/MyOrders",
StyleTypes = new[] {typeof(UserOrderWidgetStyleContributor)},
ScriptTypes = new[] {typeof(UserOrderWidgetScriptContributor)}
)]
public class UserOrderWidgetViewComponent : AbpViewComponent
{
private readonly IOrderAppService _orderAppService;
public UserOrderViewModel ViewModel { get; set; } = new();
public UserOrderWidgetViewComponent(IOrderAppService orderAppService)
{
_orderAppService = orderAppService;
}
public async Task<IViewComponentResult> InvokeAsync(string filter)
{
try
{
ViewModel.UserOrders = await _orderAppService.GetMyOrdersAsync(new GetMyOrdersInput {Filter = filter});
}
catch (Exception e)
{
ViewModel.ServiceError = true;
ViewModel.UserOrders = new List<OrderDto>();
Console.WriteLine(e);
}
return View("~/Components/UserOrders/Default.cshtml", ViewModel);
}
public class UserOrderViewModel
{
public List<OrderDto> UserOrders { get; set; }
public bool ServiceError { get; set; }
}
}

2
apps/public-web/src/EShopOnAbp.PublicWeb/Menus/EShopOnAbpPublicWebMenuContributor.cs

@ -53,8 +53,10 @@ namespace EShopOnAbp.PublicWeb.Menus
var identityServerUrl = _configuration["AuthServer:Authority"] ?? "~";
var uiResource = context.GetLocalizer<AbpUiResource>();
var accountResource = context.GetLocalizer<AccountResource>();
var eShopResource = context.GetLocalizer<EShopOnAbpResource>();
context.Menu.AddItem(new ApplicationMenuItem("Account.Manage", accountResource["MyAccount"], $"{identityServerUrl.EnsureEndsWith('/')}Account/Manage", icon: "fa fa-cog", order: 1000, null, "_blank").RequireAuthenticated());
context.Menu.AddItem(new ApplicationMenuItem("MyOrders", eShopResource["Menu:MyOrders"], $"/MyOrders", icon: "fa fa-shopping-cart", order: 2, null).RequireAuthenticated());
context.Menu.AddItem(new ApplicationMenuItem("Account.Logout", uiResource["Logout"], url: "~/Account/Logout", icon: "fa fa-power-off", order: int.MaxValue - 1000).RequireAuthenticated());
return Task.CompletedTask;

43
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/MyOrders.cshtml

@ -0,0 +1,43 @@
@page
@using EShopOnAbp.Localization
@using Microsoft.Extensions.Localization
@using EShopOnAbp.PublicWeb.Components.UserOrders
@model EShopOnAbp.PublicWeb.Pages.MyOrdersModel
@inject IStringLocalizer<EShopOnAbpResource> L
@section scripts {
<abp-script src="/client-proxies/basket-proxy.js"/>
<abp-script src="/client-proxies/ordering-proxy.js"/>
<abp-script src="/Pages/myOrders.js"/>
}
@section styles{
<abp-style src="/Pages/myOrders.css"/>
}
@{
string lastYearString = $"y{DateTime.Today.Year - 1}";
string filter = "";
var selectList = new List<SelectListItem>
{
new(@L["Last30Days"], "last30", selected: true),
new(@L["LastMonth"], "m1"),
new(@L["Last3Months"], "m3"),
new(@L["LastYear"], lastYearString),
new("2020", "y2020"),
new("2019", "y2019")
};
}
<div class="mt-5 col">
<abp-row>
<abp-column offset="_9" size="_3">
<abp-select suppress-label="true" asp-for="OrderFilter" asp-items="selectList"></abp-select>
</abp-column>
</abp-row>
</div>
<div id="UserOrdersArea" class="pt-5">
@await Component.InvokeAsync(typeof(UserOrderWidgetViewComponent), new {Filter = Model.OrderFilter})
</div>

14
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/MyOrders.cshtml.cs

@ -0,0 +1,14 @@
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
namespace EShopOnAbp.PublicWeb.Pages;
public class MyOrdersModel : AbpPageModel
{
public string OrderFilter { get; set; }
public async Task OnGet(string filter)
{
OrderFilter = filter;
}
}

59
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/OrderReceived.cshtml

@ -0,0 +1,59 @@
@page "{orderNo:int}"
@using System.Globalization
@model EShopOnAbp.PublicWeb.Pages.OrderReceivedModel
@{
decimal orderTotal = 0;
Model.ReceivedOrder.Items.ForEach(q => orderTotal += q.Units * q.UnitPrice);
string orderTotalString = orderTotal.ToString("C", new CultureInfo("en-US")); // We work with USD any ways
string orderNoString = Model.ReceivedOrder.OrderNo.ToString("N0", new NumberFormatInfo() {NumberGroupSeparator = " "});
}
@section styles{
<abp-style src="/Pages/orderReceived.css"/>
}
@{
var paymentIcon = Model.ReceivedOrder.PaymentType == "paypal" ? "fa-cc-paypal" : "fa-credit-card";
}
<abp-row class="justify-content-center p-5">
<abp-card class="col-lg-10 col-md-10 col-sm-12 shadow">
<abp-card-body>
<abp-row class="p-5">
<abp-column size="_1">
<i class="fa fa-3x fa-check-circle" style="color: greenyellow"></i>
</abp-column>
<abp-column>
<div>
<h4>Sipariş alındı!</h4>
<p>Siparişiniz ile ilgili detaylar <strong>@Model.ReceivedOrder.Buyer.Email</strong> adresine gönderildi. <a href="/MyOrders">Siparişlerime git</a></p>
</div>
</abp-column>
</abp-row>
<abp-row>
<abp-column>
<div class="ro-title">Sipariş Numarası</div>
<div class="ro-body ro-ono">
@orderNoString
</div>
</abp-column>
<abp-column>
<div class="ro-title">Teslimat Adresi</div>
<div class="ro-body ro-large">
@Model.ReceivedOrder.Address.Description
</div>
<div>@Model.ReceivedOrder.Address.Street - @Model.ReceivedOrder.Address.ZipCode</div>
<div>@Model.ReceivedOrder.Address.City / @Model.ReceivedOrder.Address.Country</div>
</abp-column>
<abp-column>
<div class="ro-title">Ödenen Tutar</div>
<div class="ro-body ro-large">@orderTotalString</div>
<div class="pt-2">
<i class="fa fa-5x @paymentIcon" style="color:indigo"></i>
</div>
</abp-column>
</abp-row>
<abp-row class="p-5"></abp-row>
</abp-card-body>
</abp-card>
</abp-row>

23
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/OrderReceived.cshtml.cs

@ -0,0 +1,23 @@
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Orders;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
namespace EShopOnAbp.PublicWeb.Pages;
public class OrderReceivedModel : AbpPageModel
{
private readonly IOrderAppService _orderAppService;
[BindProperty(SupportsGet = true)] public int OrderNo { get; set; }
public OrderDto ReceivedOrder { get; set; }
public OrderReceivedModel(IOrderAppService orderAppService)
{
_orderAppService = orderAppService;
}
public async Task OnGet(int orderNo)
{
ReceivedOrder = await _orderAppService.GetByOrderNoAsync(orderNo);
}
}

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

@ -1,6 +1,6 @@
using EShopOnAbp.BasketService;
using System;
using EShopOnAbp.BasketService;
using EShopOnAbp.PaymentService.PaymentRequests;
using EShopOnAbp.PublicWeb.Basket;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Orders;
using EShopOnAbp.PublicWeb.ServiceProviders;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Volo.Abp.Users;
@ -46,18 +47,27 @@ public class PaymentModel : AbpPageModel
Logger.LogInformation("Payment Proceeded...");
Logger.LogInformation($"AddressId: {model.SelectedAddressId}");
Logger.LogInformation($"PaymentId: {model.SelectedPaymentId}");
Logger.LogInformation($"Total Discount: {model.TotalDiscountPercentage}");
var basket = await _userBasketProvider.GetBasketAsync();
var productItems = ObjectMapper.Map<List<BasketItemDto>, List<OrderItemCreateDto>>(basket.Items);
if (model.TotalDiscountPercentage != 0)
{
ApplyDiscountPercentageToBasketItems(productItems, model.TotalDiscountPercentage);
}
var placedOrder = await _orderAppService.CreateAsync(new OrderCreateDto()
{
PaymentTypeId = 1, // Paypal
Address = GetUserAddress(model.SelectedAddressId),
Products = ObjectMapper.Map<List<BasketItemDto>, List<OrderItemCreateDto>>(basket.Items)
Products = productItems
});
var paymentRequest = await _paymentRequestAppService.CreateAsync(new PaymentRequestCreationDto
{
OrderId = placedOrder.Id.ToString(),
OrderNo = placedOrder.OrderNo,
BuyerId = CurrentUser.GetId().ToString(),
Currency = EShopOnAbpPaymentConsts.Currency,
Products = ObjectMapper.Map<List<BasketItemDto>, List<PaymentRequestProductCreationDto>>(basket.Items)
@ -73,22 +83,31 @@ public class PaymentModel : AbpPageModel
return Redirect(response.CheckoutLink);
}
public class PaymentPageViewModel
{
public int SelectedAddressId { get; set; }
public int SelectedPaymentId { get; set; }
public decimal TotalDiscountPercentage { get; set; }
}
private void ApplyDiscountPercentageToBasketItems(List<OrderItemCreateDto> productItems, decimal discount)
{
for (int i = 0; i < productItems.Count; i++)
{
productItems[i].Discount = discount;
}
}
private OrderAddressDto GetUserAddress(int selectedAddressId)
{
var address = _userAddressProvider.GetDemoAddresses().First(q => q.Id == selectedAddressId);
return new OrderAddressDto
{
Description = address.Type,
City = address.City,
Country = address.Country,
Description = address.Description,
Street = address.Street,
ZipCode = address.ZipCode
};
}
public class PaymentPageViewModel
{
public int SelectedAddressId { get; set; }
public int SelectedPaymentId { get; set; }
}
}

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

@ -1,16 +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 class="container">
<abp-row class="justify-content-center p-5">
<abp-card class="col-lg-6 col-md-6 col-sm-8 shadow" style="text-align: center; line-height: 3rem">
@* <img class="card-img-top" src="..." alt="Card image cap"> *@
<abp-card-body>
<h4 class="card-title" style="text-align: center">Order Failed!</h4>
<p class="card-text">It seems there is a problem with your payment </p>
<p class="card-text">Please check your payment method!</p>
<a href="/" class="btn btn-primary">Continue Shopping</a>
</abp-card-body>
</abp-card>
</abp-row>
</div>

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

@ -16,17 +16,22 @@ public class PaymentCompletedModel : AbpPageModel
_paymentRequestAppService = paymentRequestAppService;
}
[BindProperty(SupportsGet = true)]
public string Token { get; set; }
[BindProperty(SupportsGet = true)] public string Token { get; set; }
public PaymentRequestDto PaymentRequest { get; private set; }
public bool IsSuccessful { get; private set; }
public async Task OnGetAsync()
public async Task<IActionResult> OnGetAsync()
{
PaymentRequest = await _paymentRequestAppService.CompleteAsync(Token);
IsSuccessful = PaymentRequest.State == PaymentRequestState.Completed;
if (IsSuccessful)
{
return RedirectToPage("OrderReceived", new { orderNo = PaymentRequest.OrderNo });
}
return Page();
}
}

2
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/index.js

@ -6,7 +6,6 @@
}
$(function () {
$('.product-list-item').click(function () {
var $this = $(this);
var productId = $this.attr('data-product-id');
@ -14,7 +13,6 @@
productId: productId,
anonymousId: anonymousId,
}).then(function () {
$('.abp-widget-wrapper[data-widget-name="CartWidget"]')
.data('abp-widget-manager')
.refresh();

33
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/myOrders.css

@ -0,0 +1,33 @@
.img-size {
width: 80%;
}
.order-item {
width: -webkit-fill-available;
background-color: #fff;
border: 1px solid #eee;
border-radius: 3px;
box-shadow: 0 0 10px rgba(0, 0, 0, .05);
transition: all .2s;
cursor: default;
}
.order-item:hover {
box-shadow: 0 0 20px rgba(0, 0, 0, .1);
}
.o-header {
text-transform: uppercase;
font-weight: 500;
}
.o-description {
font-weight: 500;
font-size: larger;
}
.o-order-no{
font-size:larger;
}
.order-title{
font-size: x-large;
}

26
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/myOrders.js

@ -0,0 +1,26 @@
(function () {
const anonymousId = abp.utils.getCookieValue("anonymous_id");
$(function () {
$('.buy-again').click(function () {
const $this = $(this);
const productId = $this.attr('data-product-id');
eShopOnAbp.basketService.basket.addProduct({
productId: productId,
anonymousId: anonymousId,
}).then(function () {
$('.abp-widget-wrapper[data-widget-name="CartWidget"]')
.data('abp-widget-manager')
.refresh();
abp.notify.success("Added product to your basket.", "Successfully added");
});
});
$('#OrderFilter').on("change", el => {
const filter = el.target.value;
location.href=`?filter=${filter}`
});
$('#total-orders').val($('#total-order-count').val());
});
})();

19
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/orderReceived.css

@ -0,0 +1,19 @@
.ro-title {
text-transform: uppercase;
font-weight: 500;
color: crimson;
padding-bottom: .5em;
}
.ro-body {
font-weight: bold;
}
.ro-ono {
font-size: x-large;
}
.ro-large {
font-size: larger;
padding-bottom: .5rem;
}

2
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/payment.js

@ -12,6 +12,6 @@
paymentInput.setAttribute('name', "model.SelectedPaymentId");
paymentInput.setAttribute('value', document.querySelector(".payment-list .card.is-selected").getAttribute("data-payment-id"));
paymentInput.setAttribute('type', "hidden");
form.appendChild(paymentInput);
form.appendChild(paymentInput);
};
})();

9
apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/DiscountProvider.cs

@ -0,0 +1,9 @@

using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.PublicWeb.ServiceProviders;
public class DiscountProvider : ITransientDependency
{
// TODO: Configure or remove discount logic
}

2
apps/public-web/src/EShopOnAbp.PublicWeb/Basket/UserAddressProvider.cs → apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserAddressProvider.cs

@ -1,7 +1,7 @@
using System.Collections.Generic;
using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.PublicWeb.Basket;
namespace EShopOnAbp.PublicWeb.ServiceProviders;
public class UserAddressProvider : ITransientDependency
{

10
apps/public-web/src/EShopOnAbp.PublicWeb/Basket/UserBasketProvider.cs → apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserBasketProvider.cs

@ -1,13 +1,13 @@
using EShopOnAbp.BasketService;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System;
using System.Threading.Tasks;
using EShopOnAbp.BasketService;
using EShopOnAbp.Shared.Hosting.AspNetCore;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Users;
namespace EShopOnAbp.PublicWeb.Basket
namespace EShopOnAbp.PublicWeb.ServiceProviders
{
public class UserBasketProvider : ITransientDependency
{

47
apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/client-proxies/ordering-proxy.js

@ -0,0 +1,47 @@
/* This file is automatically generated by ABP framework to use MVC Controllers from javascript. */
// module ordering
(function(){
// controller eShopOnAbp.orderingService.orders.order
(function(){
abp.utils.createNamespace(window, 'eShopOnAbp.orderingService.orders.order');
eShopOnAbp.orderingService.orders.order.get = function(id, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/ordering/order/' + id + '',
type: 'GET'
}, ajaxParams));
};
eShopOnAbp.orderingService.orders.order.getMyOrders = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/ordering/order/my-orders' + abp.utils.buildQueryString([{ name: 'filter', value: input.filter }]) + '',
type: 'GET'
}, ajaxParams));
};
eShopOnAbp.orderingService.orders.order.getByOrderNo = function(orderNo, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/ordering/order/by-order-no' + abp.utils.buildQueryString([{ name: 'orderNo', value: orderNo }]) + '',
type: 'GET'
}, ajaxParams));
};
eShopOnAbp.orderingService.orders.order.create = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/ordering/order',
type: 'POST',
data: JSON.stringify(input)
}, ajaxParams));
};
})();
})();

19
apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/basket/basket-widget.css

@ -3,7 +3,7 @@
}
.basket-list-item {
width:-webkit-fill-available;
width: -webkit-fill-available;
background-color: #fff;
border: 1px solid #eee;
border-radius: 3px;
@ -87,15 +87,21 @@
line-height: 20px;
vertical-align: top;
}
.description-cargo{
.description-cargo {
color: #189c38;
text-align: center;
font-size: 1rem;
}
.description-cargo> span {
line-height: 20px;
vertical-align: top;
}
.description-cargo > span {
line-height: 20px;
vertical-align: top;
}
.basket-item-remove {
cursor: pointer;
}
.remove-container {
color: #bb2d3b;
@ -124,6 +130,7 @@
.basket-list-item:hover .hide {
opacity: 1.0;
}
.sticky {
position: -webkit-sticky; /* for Safari */
position: sticky;

0
apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/user-orders/user-order-widget.css

0
apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/user-orders/user-order-widget.js

6
services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/GetMyOrdersInput.cs

@ -0,0 +1,6 @@
namespace EShopOnAbp.OrderingService.Orders;
public class GetMyOrdersInput
{
public string Filter { get; set; }
}

2
services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/IOrderAppService.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
@ -8,5 +9,6 @@ public interface IOrderAppService : IApplicationService
{
Task<OrderDto> CreateAsync(OrderCreateDto input);
Task<OrderDto> GetAsync(Guid id);
Task<List<OrderDto>> GetMyOrdersAsync(GetMyOrdersInput input);
Task<OrderDto> GetByOrderNoAsync(int orderNo);
}

1
services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/OrderDto.cs

@ -7,6 +7,7 @@ namespace EShopOnAbp.OrderingService.Orders;
public class OrderDto : EntityDto<Guid>
{
public DateTime OrderDate { get; set; }
public int OrderNo {get;set;}
public int OrderStatusId { get; set; }
public string OrderStatus { get; set; }
public int PaymentTypeId { get; set; }

1
services/ordering/src/EShopOnAbp.OrderingService.Application/OrderingServiceApplicationAutoMapperProfile.cs

@ -1,5 +1,4 @@
using AutoMapper;
using EShopOnAbp.OrderingService.Buyers;
using EShopOnAbp.OrderingService.Orders;
using Volo.Abp.AutoMapper;

57
services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs

@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Buyers;
using EShopOnAbp.OrderingService.Localization;
using EShopOnAbp.OrderingService.Orders.Specifications;
using Microsoft.Extensions.Logging;
using Volo.Abp.Application.Services;
using Volo.Abp.Specifications;
using Volo.Abp.Users;
namespace EShopOnAbp.OrderingService.Orders;
@ -15,7 +17,7 @@ public class OrderAppService : ApplicationService, IOrderAppService
public OrderAppService(OrderManager orderManager,
IOrderRepository orderRepository
)
)
{
_orderManager = orderManager;
_orderRepository = orderRepository;
@ -26,12 +28,23 @@ public class OrderAppService : ApplicationService, IOrderAppService
public async Task<OrderDto> GetAsync(Guid id)
{
var order = await _orderRepository.GetAsync(id);
return await CreateOrderDtoMappingAsync(order);
return CreateOrderDtoMapping(order);
}
public Task<OrderDto> GetByOrderNoAsync(int orderNo)
public async Task<List<OrderDto>> GetMyOrdersAsync(GetMyOrdersInput input)
{
var order = await _orderRepository.get
ISpecification<Order> specification = SpecificationFactory.Create(input.Filter);
var orders = await _orderRepository.GetOrdersByUserId(CurrentUser.GetId(), specification, true);
return CreateOrderDtoMapping(orders);
}
public async Task<OrderDto> GetByOrderNoAsync(int orderNo)
{
var order = await _orderRepository.GetByOrderNoAsync(orderNo);
Logger.LogInformation($" Order recieved with order no:{orderNo}");
return CreateOrderDtoMapping(order);
}
public async Task<OrderDto> CreateAsync(OrderCreateDto input)
@ -52,7 +65,7 @@ public class OrderAppService : ApplicationService, IOrderAppService
addressDescription: input.Address.Description
);
return await CreateOrderDtoMappingAsync(placedOrder);
return CreateOrderDtoMapping(placedOrder);
}
private List<(Guid productId, string productName, string productCode, decimal unitPrice, decimal discount, string
@ -72,19 +85,31 @@ public class OrderAppService : ApplicationService, IOrderAppService
return orderItems;
}
private async Task<OrderDto> CreateOrderDtoMappingAsync(Order placedOrder)
private List<OrderDto> CreateOrderDtoMapping(List<Order> orders)
{
List<OrderDto> dtoList = new List<OrderDto>();
foreach (var order in orders)
{
dtoList.Add(CreateOrderDtoMapping(order));
}
return dtoList;
}
private OrderDto CreateOrderDtoMapping(Order order)
{
return new OrderDto()
{
Address = ObjectMapper.Map<Address, OrderAddressDto>(placedOrder.Address),
Items = ObjectMapper.Map<List<OrderItem>, List<OrderItemDto>>(placedOrder.OrderItems),
Buyer = ObjectMapper.Map<Buyer, BuyerDto>(placedOrder.Buyer),
Id = placedOrder.Id,
OrderDate = placedOrder.OrderDate,
OrderStatus = placedOrder.OrderStatus.Name,
OrderStatusId = placedOrder.OrderStatus.Id,
PaymentType = placedOrder.PaymentType.Name,
PaymentTypeId = placedOrder.PaymentType.Id
Address = ObjectMapper.Map<Address, OrderAddressDto>(order.Address),
Items = ObjectMapper.Map<List<OrderItem>, List<OrderItemDto>>(order.OrderItems),
Buyer = ObjectMapper.Map<Buyer, BuyerDto>(order.Buyer),
Id = order.Id,
OrderNo = order.OrderNo,
OrderDate = order.OrderDate,
OrderStatus = order.OrderStatus.Name,
OrderStatusId = order.OrderStatus.Id,
PaymentType = order.PaymentType.Name,
PaymentTypeId = order.PaymentType.Id
};
}
}

1
services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderPlacedEto.cs

@ -9,6 +9,7 @@ namespace EShopOnAbp.OrderingService.Orders;
public class OrderPlacedEto : EtoBase
{
public Guid OrderId { get; set; }
public int OrderNo { get; set; }
public DateTime OrderDate { get; set; }
public BuyerEto Buyer { get; set; }
public List<OrderItemEto> Items { get; set; } = new();

8
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/IOrderRepository.cs

@ -1,12 +1,20 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Specifications;
namespace EShopOnAbp.OrderingService.Orders;
public interface IOrderRepository : IRepository<Order, Guid>
{
Task<List<Order>> GetOrdersByUserId(
Guid userId,
ISpecification<Order> spec,
bool includeDetails = true,
CancellationToken cancellationToken = default);
Task<Order> GetByOrderNoAsync(int orderNo,
bool includeDetails = true,
CancellationToken cancellationToken = default);

18
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using EShopOnAbp.OrderingService.Buyers;
using Volo.Abp.Domain.Entities;
namespace EShopOnAbp.OrderingService.Orders;
@ -24,12 +23,13 @@ public class Order : AggregateRoot<Guid>
{
}
internal Order(Guid id, Buyer buyer, Address address, PaymentType paymentType, Guid? paymentRequestId = null) : base(id)
internal Order(Guid id, Buyer buyer, Address address, PaymentType paymentType,
Guid? paymentRequestId = null) : base(id)
{
_orderStatusId = OrderStatus.Placed.Id;
_paymentTypeId = paymentType.Id;
OrderDate = DateTime.UtcNow;
OrderNo = id.GetHashCode();
OrderNo = GenerateOrderNo(id);
Buyer = buyer;
Address = address;
PaymentRequestId = paymentRequestId;
@ -37,6 +37,18 @@ public class Order : AggregateRoot<Guid>
OrderItems = new List<OrderItem>();
}
private int GenerateOrderNo(Guid id)
{
// Simple order no generation. Should be improved for uniqueness.
var code = Id.GetHashCode();
if (code < 0) // Should be negative
{
code *= -1;
}
return code;
}
internal Order SetOrderAccepted(Guid paymentRequestId, string paymentRequestStatus)
{
PaymentRequestId = paymentRequestId;

2
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/OrderManager.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Buyers;
using Volo.Abp;
using Volo.Abp.Domain.Services;
using Volo.Abp.EventBus.Distributed;
@ -71,6 +70,7 @@ public class OrderManager : DomainService
{
OrderId = placedOrder.Id,
OrderDate = placedOrder.OrderDate,
OrderNo = placedOrder.OrderNo,
Buyer = GetBuyerEto(order.Buyer),
Items = GetProductItemEtoList(order.OrderItems)
});

2
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/PaymentType.cs

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Volo.Abp;
namespace EShopOnAbp.OrderingService.Buyers;
namespace EShopOnAbp.OrderingService.Orders;
public class PaymentType : Enumeration
{

16
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/Last30DaysSpecification.cs

@ -0,0 +1,16 @@
using System;
using System.Linq.Expressions;
using Volo.Abp.Specifications;
namespace EShopOnAbp.OrderingService.Orders.Specifications;
public class Last30DaysSpecification : Specification<Order>
{
public override Expression<Func<Order, bool>> ToExpression()
{
var daysAgo30 = DateTime.UtcNow.Subtract(TimeSpan.FromDays(30));
return query => query.OrderDate >= daysAgo30
;
// && query.OrderDate <= DateTime.UtcNow;
}
}

21
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/MonthsAgoSpecification.cs

@ -0,0 +1,21 @@
using System;
using System.Linq.Expressions;
using Volo.Abp.Specifications;
namespace EShopOnAbp.OrderingService.Orders.Specifications;
public class MonthsAgoSpecification : Specification<Order>
{
protected int NumberOfMonths { get; set; }
public MonthsAgoSpecification(int months)
{
NumberOfMonths = months;
}
public override Expression<Func<Order, bool>> ToExpression()
{
var monthsAgo = DateTime.UtcNow.AddMonths(-NumberOfMonths);
return query => query.OrderDate >= monthsAgo;
}
}

29
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/SpecificationFactory.cs

@ -0,0 +1,29 @@
using System;
using Volo.Abp.Specifications;
namespace EShopOnAbp.OrderingService.Orders.Specifications;
public static class SpecificationFactory
{
public static ISpecification<Order> Create(string filter)
{
if (filter.IsNullOrEmpty())
{
return new Last30DaysSpecification();
}
if (filter.StartsWith("y"))
{
var year = int.Parse(filter.Split('y')[1]);
return new YearSpecification(year);
}
if (filter.StartsWith("m"))
{
var months = int.Parse(filter.Split('m')[1]);
return new MonthsAgoSpecification(months);
}
return new Last30DaysSpecification();
}
}

20
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/YearSpecification.cs

@ -0,0 +1,20 @@
using System;
using System.Linq.Expressions;
using Volo.Abp.Specifications;
namespace EShopOnAbp.OrderingService.Orders.Specifications;
public class YearSpecification : Specification<Order>
{
protected int Year { get; set; }
public YearSpecification(int year)
{
Year = year;
}
public override Expression<Func<Order, bool>> ToExpression()
{
return query => query.OrderDate.Year == Year;
}
}

1
services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderServiceDataSeedContributor.cs

@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Buyers;
using EShopOnAbp.OrderingService.Orders;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;

1
services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderingServiceDbContext.cs

@ -1,5 +1,4 @@
using System;
using EShopOnAbp.OrderingService.Buyers;
using EShopOnAbp.OrderingService.Orders;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;

24
services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs

@ -1,11 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Specifications;
namespace EShopOnAbp.OrderingService.Orders;
@ -25,14 +29,30 @@ public class EfCoreOrderRepository : EfCoreRepository<OrderingServiceDbContext,
return newEntity;
}
public async Task<List<Order>> GetOrdersByUserId(
Guid userId,
ISpecification<Order> spec,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.IncludeDetails(includeDetails)
.Where(q => q.Buyer.Id == userId)
.Where(spec.ToExpression())
.OrderByDescending(o => o.OrderDate)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task<Order> GetByOrderNoAsync(
int orderNo,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return await (await GetQueryableAsync())
.IncludeDetails(includeDetails)
.FirstOrDefaultAsync(q => q.OrderNo == orderNo, cancellationToken: GetCancellationToken(cancellationToken));
.IncludeDetails(includeDetails)
.FirstOrDefaultAsync(q => q.OrderNo == orderNo,
cancellationToken: GetCancellationToken(cancellationToken))
?? throw new EntityNotFoundException(typeof(Order)); //TODO: Maybe create new exception with property extending this
}
public override async Task<IQueryable<Order>> WithDetailsAsync()

22
services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/OrderEfCoreQueryableExtensions.cs

@ -0,0 +1,22 @@
using System.Linq;
using Microsoft.EntityFrameworkCore;
namespace EShopOnAbp.OrderingService.Orders;
public static class OrderEfCoreQueryableExtensions
{
public static IQueryable<Order> IncludeDetails(this IQueryable<Order> queryable, bool include = true)
{
if (!include)
{
return queryable;
}
return queryable
.Include(x => x.Address)
.Include(x => x.Buyer)
.Include(x => x.OrderItems)
.Include(x => x.PaymentType)
.Include(x => x.OrderStatus);
}
}

17
services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/OrderClientProxy.Generated.cs

@ -7,6 +7,7 @@ using Volo.Abp.Http.Modeling;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using EShopOnAbp.OrderingService.Orders;
using System.Collections.Generic;
// ReSharper disable once CheckNamespace
namespace EShopOnAbp.OrderingService.Orders.ClientProxies
@ -23,6 +24,22 @@ namespace EShopOnAbp.OrderingService.Orders.ClientProxies
});
}
public virtual async Task<List<OrderDto>> GetMyOrdersAsync(GetMyOrdersInput input)
{
return await RequestAsync<List<OrderDto>>(nameof(GetMyOrdersAsync), new ClientProxyRequestTypeValue
{
{ typeof(GetMyOrdersInput), input }
});
}
public virtual async Task<OrderDto> GetByOrderNoAsync(int orderNo)
{
return await RequestAsync<OrderDto>(nameof(GetByOrderNoAsync), new ClientProxyRequestTypeValue
{
{ typeof(int), orderNo }
});
}
public virtual async Task<OrderDto> CreateAsync(OrderCreateDto input)
{
return await RequestAsync<OrderDto>(nameof(CreateAsync), new ClientProxyRequestTypeValue

74
services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/Ordering-generate-proxy.json → services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/ordering-generate-proxy.json

@ -60,6 +60,80 @@
"allowAnonymous": null,
"implementFrom": "EShopOnAbp.OrderingService.Orders.IOrderAppService"
},
"GetMyOrdersAsyncByInput": {
"uniqueName": "GetMyOrdersAsyncByInput",
"name": "GetMyOrdersAsync",
"httpMethod": "GET",
"url": "api/ordering/order/my-orders",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "input",
"typeAsString": "EShopOnAbp.OrderingService.Orders.GetMyOrdersInput, EShopOnAbp.OrderingService.Application.Contracts",
"type": "EShopOnAbp.OrderingService.Orders.GetMyOrdersInput",
"typeSimple": "EShopOnAbp.OrderingService.Orders.GetMyOrdersInput",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "input",
"name": "Filter",
"jsonName": null,
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
}
],
"returnValue": {
"type": "System.Collections.Generic.List<EShopOnAbp.OrderingService.Orders.OrderDto>",
"typeSimple": "[EShopOnAbp.OrderingService.Orders.OrderDto]"
},
"allowAnonymous": null,
"implementFrom": "EShopOnAbp.OrderingService.Orders.IOrderAppService"
},
"GetByOrderNoAsyncByOrderNo": {
"uniqueName": "GetByOrderNoAsyncByOrderNo",
"name": "GetByOrderNoAsync",
"httpMethod": "GET",
"url": "api/ordering/order/by-order-no",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "orderNo",
"typeAsString": "System.Int32, System.Private.CoreLib",
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "orderNo",
"name": "orderNo",
"jsonName": null,
"type": "System.Int32",
"typeSimple": "number",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": ""
}
],
"returnValue": {
"type": "EShopOnAbp.OrderingService.Orders.OrderDto",
"typeSimple": "EShopOnAbp.OrderingService.Orders.OrderDto"
},
"allowAnonymous": null,
"implementFrom": "EShopOnAbp.OrderingService.Orders.IOrderAppService"
},
"CreateAsyncByInput": {
"uniqueName": "CreateAsyncByInput",
"name": "CreateAsync",

4
services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/EShopOnAbp.OrderingService.HttpApi.Client.csproj

@ -17,4 +17,8 @@
<Content Remove="**\*generate-proxy.json" />
</ItemGroup>
<ItemGroup>
<Folder Include="ClientProxies" />
</ItemGroup>
</Project>

61
services/ordering/test/EShopOnAbp.OrderingService.Application.Tests/Orders/OrderApplication_Tests.cs

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using NSubstitute;
using Shouldly;
using Volo.Abp.Users;
using Xunit;
namespace EShopOnAbp.OrderingService.Orders;
public class OrderApplication_Tests:OrderingServiceApplicationTestBase
{
private readonly IOrderAppService _orderAppService;
private readonly TestData _testData;
private ICurrentUser _currentUser;
public OrderApplication_Tests()
{
_testData = GetRequiredService<TestData>();
_currentUser = GetRequiredService<ICurrentUser>();
_orderAppService = GetRequiredService<IOrderAppService>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
_currentUser = Substitute.For<ICurrentUser>();
services.AddSingleton(_currentUser);
}
[Fact]
public async Task Should_Create_Order()
{
_currentUser.Id.Returns(_testData.CurrentUserId);
_currentUser.Email.Returns(_testData.CurrentUserEmail);
_currentUser.Name.Returns(_testData.TestUserName);
// Create Order
var orderItems = new List<OrderItemCreateDto>()
{
new OrderItemCreateDto()
{
Discount = 0, Units = 2, PictureUrl = "", ProductCode = "Test-001", ProductId = Guid.NewGuid(),
ProductName = "Test product", UnitPrice = 150
}
};
var placedOrder = await _orderAppService.CreateAsync(new OrderCreateDto()
{
PaymentTypeId = 1,
Address = new OrderAddressDto()
{
City = "Test City", Country = "Test Country", Description = "No Description", Street = "Test Street",
ZipCode = "Test ZipCode"
},
Products = orderItems
});
// Get Order by OrderNo;
var myOrder = await _orderAppService.GetByOrderNoAsync(placedOrder.OrderNo);
myOrder.ShouldNotBeNull();
}
}

1
services/ordering/test/EShopOnAbp.OrderingService.Domain.Tests/Orders/OrderManager_Tests.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Buyers;
using Shouldly;
using Xunit;

84
services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Orders/OrderRepository_Tests.cs

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Orders;
using EShopOnAbp.OrderingService.Orders.Specifications;
using EShopOnAbp.OrderingService.Samples;
using Microsoft.EntityFrameworkCore;
using Shouldly;
using Xunit;
namespace EShopOnAbp.OrderingService.EntityFrameworkCore.Orders;
public class OrderRepository_Tests : SampleRepository_Tests<OrderingServiceEntityFrameworkCoreTestModule>
{
private readonly TestData _testData;
private readonly IOrderRepository _orderRepository;
private readonly IOrderingServiceDbContext _dbContext;
private readonly OrderManager _orderManager;
public OrderRepository_Tests()
{
_orderManager = GetRequiredService<OrderManager>();
_dbContext = GetRequiredService<IOrderingServiceDbContext>();
_orderRepository = GetRequiredService<IOrderRepository>();
_testData = GetRequiredService<TestData>();
}
[Fact]
public async Task Should_Get_OrderStatus()
{
var dbSet = _dbContext.Set<OrderStatus>();
var statusList = await dbSet.ToListAsync();
statusList.Count.ShouldNotBe(0);
}
[Fact]
public async Task Should_Get_User_Orders()
{
var orders =
await _orderRepository.GetOrdersByUserId(_testData.CurrentUserId, new Last30DaysSpecification(), true);
orders.Count.ShouldBe(3);
var firstOrder = orders.First();
firstOrder.OrderItems.Count.ShouldBe(5);
}
[Fact]
public async Task Should_Get_Order_By_OrderNo()
{
// Create new order
var orderItems =
new List<(Guid productId, string productName, string productCode, decimal unitPrice, decimal discount,
string pictureUrl, int
units)>();
orderItems.Add((Guid.NewGuid(), "Test product", "Code:001", 15, 0, "", 1));
var createdOrder = await _orderManager.CreateOrderAsync(
1,
Guid.Parse("11CA0F6D-208E-441A-9F9B-3611C96E4383"),
"gterdem",
"gterdem@volosoft.com",
orderItems,
"Test Street",
"Test City",
"Test Country",
"Test zipCode");
createdOrder.ShouldNotBeNull();
// Get order
var order = await _orderRepository.GetByOrderNoAsync(createdOrder.OrderNo);
order.OrderNo.ShouldBe(createdOrder.OrderNo);
order.OrderItems.Count.ShouldBe(1);
order.OrderStatus.ShouldBe(OrderStatus.Placed);
order.PaymentStatus.ShouldBe("Waiting");
}
[Fact]
public async Task Should_Get_Users_Last_Year_Orders()
{
var orders =
await _orderRepository.GetOrdersByUserId(_testData.CurrentUserId, new YearSpecification(2020), true);
orders.Count.ShouldBe(0);
}
}

12
services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Samples/SampleRepository_Tests.cs

@ -1,12 +0,0 @@
using EShopOnAbp.OrderingService.Samples;
namespace EShopOnAbp.OrderingService.EntityFrameworkCore.Samples
{
public class SampleRepository_Tests : SampleRepository_Tests<OrderingServiceEntityFrameworkCoreTestModule>
{
/* Don't write custom repository tests here, instead write to
* the base class.
* One exception can be some specific tests related to EF core.
*/
}
}

33
services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceDataSeedContributor.cs

@ -1,33 +0,0 @@
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
namespace EShopOnAbp.OrderingService
{
public class OrderingServiceDataSeedContributor : IDataSeedContributor, ITransientDependency
{
private readonly IGuidGenerator _guidGenerator;
private readonly ICurrentTenant _currentTenant;
public OrderingServiceDataSeedContributor(
IGuidGenerator guidGenerator, ICurrentTenant currentTenant)
{
_guidGenerator = guidGenerator;
_currentTenant = currentTenant;
}
public Task SeedAsync(DataSeedContext context)
{
/* Instead of returning the Task.CompletedTask, you can insert your test data
* at this point!
*/
using (_currentTenant.Change(context?.TenantId))
{
return Task.CompletedTask;
}
}
}
}

15
services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceTestBaseModule.cs

@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.Authorization;
using Volo.Abp.Autofac;
@ -13,12 +14,20 @@ namespace EShopOnAbp.OrderingService
typeof(AbpTestBaseModule),
typeof(AbpAuthorizationModule),
typeof(OrderingServiceDomainModule)
)]
)]
public class OrderingServiceTestBaseModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAlwaysAllowAuthorization();
// Add TestDataSeedContributor to the end of the list so that Domain DataSeedContributor
// (which is located under EfCore layer because of dbContext seeding) can run first
Configure<AbpDataSeedOptions>(options =>
{
options.Contributors.Remove<OrderingServiceTestDataSeedContributor>();
options.Contributors.AddLast(typeof(OrderingServiceTestDataSeedContributor));
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
@ -39,4 +48,4 @@ namespace EShopOnAbp.OrderingService
});
}
}
}
}

72
services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceTestDataSeedContributor.cs

@ -0,0 +1,72 @@
using System;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Orders;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.OrderingService
{
public class OrderingServiceTestDataSeedContributor : IDataSeedContributor, ITransientDependency
{
private readonly OrderManager _orderManager;
private readonly TestData _testData;
private readonly TestProducts _testProducts;
public OrderingServiceTestDataSeedContributor(
OrderManager orderManager,
TestData testData,
TestProducts testProducts)
{
_orderManager = orderManager;
_testData = testData;
_testProducts = testProducts;
}
public async Task SeedAsync(DataSeedContext context)
{
await SeedTestOrdersAsync();
}
private async Task SeedTestOrdersAsync()
{
await _orderManager.CreateOrderAsync(
1,
_testData.CurrentUserId,
_testData.CurrentUserName,
_testData.CurrentUserEmail,
_testProducts.GetRandomProducts(5),
_testData.Address.Street,
_testData.Address.City,
_testData.Address.Country,
_testData.Address.ZipCode
);
await _orderManager.CreateOrderAsync(
1, _testData.CurrentUserId, _testData.CurrentUserName, _testData.CurrentUserEmail,
_testProducts.GetRandomProducts(10),
_testData.Address.Street,
_testData.Address.City,
_testData.Address.Country,
_testData.Address.ZipCode
);
await _orderManager.CreateOrderAsync(
1, _testData.CurrentUserId, _testData.CurrentUserName, _testData.CurrentUserEmail,
_testProducts.GetRandomProducts(2),
_testData.Address.Street,
_testData.Address.City,
_testData.Address.Country,
_testData.Address.ZipCode
);
await _orderManager.CreateOrderAsync(
1, _testData.TestUserId, _testData.TestUserName, _testData.TestUserEmail,
_testProducts.GetRandomProducts(7),
_testData.Address.Street,
_testData.Address.City,
_testData.Address.Country,
_testData.Address.ZipCode
);
}
}
}

31
services/ordering/test/EShopOnAbp.OrderingService.TestBase/Product.cs

@ -0,0 +1,31 @@
using System;
using System.Text.Json.Serialization;
namespace EShopOnAbp.OrderingService;
public class Product
{
[JsonPropertyName("id")] public int Id { get; set; }
public Guid ProductId
{
get
{
byte[] bytes = new byte[16];
BitConverter.GetBytes(Id).CopyTo(bytes, 0);
return new Guid(bytes);
}
}
[JsonPropertyName("productName")] public string ProductName { get; set; }
[JsonPropertyName("pictureUrl")] public string PictureUrl { get; set; }
[JsonPropertyName("productStock")] public int ProductStock { get; set; }
[JsonPropertyName("unitPrice")] public string UnitPrice { get; set; }
[JsonPropertyName("productSalePrice")] public string ProductSalePrice { get; set; }
[JsonPropertyName("units")] public int Units { get; set; }
}

23
services/ordering/test/EShopOnAbp.OrderingService.TestBase/TestData.cs

@ -0,0 +1,23 @@
using System;
using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.OrderingService;
public class TestData : ISingletonDependency
{
public string CurrentUserEmail { get; set; } = "galip.erdem@volosoft.com";
public Guid CurrentUserId { get; set; } = Guid.NewGuid();
public string CurrentUserName { get; set; } = "Galip T. ERDEM";
public Guid TestUserId { get; set; } = Guid.NewGuid();
public string TestUserEmail { get; set; } = "test@user.com";
public string TestUserName { get; set; } = "Test User";
public DemoAddress Address { get; set; } = new DemoAddress();
public class DemoAddress
{
public string Street { get; set; } = "Test Demo Street";
public string City { get; set; } = "DemoCity";
public string Country { get; set; } = "DemoLand";
public string ZipCode { get; set; } = "123-456-789";
}
}

42
services/ordering/test/EShopOnAbp.OrderingService.TestBase/TestProducts.cs

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.OrderingService;
public class TestProducts : ISingletonDependency
{
private readonly List<Product> _products;
private readonly Random _random = new();
public TestProducts()
{
_products = new List<Product>();
using (StreamReader r = new StreamReader("../../../../EShopOnAbp.OrderingService.TestBase/products.json"))
{
string json = r.ReadToEnd();
_products = JsonConvert.DeserializeObject<List<Product>>(json);
}
}
public List<(Guid productId, string productName, string productCode, decimal unitPrice, decimal discount,
string pictureUrl, int units)> GetRandomProducts(int quantity)
{
List<(Guid productId, string productName, string productCode, decimal unitPrice, decimal discount,
string pictureUrl, int units)> randomProducts =
new List<(Guid productId, string productName, string productCode, decimal unitPrice, decimal discount,
string pictureUrl, int units)>();
for (int i = 0; i < quantity; i++)
{
int num = _random.Next(_products.Count);
var product = _products[num];
randomProducts.Add((Guid.NewGuid(), product.ProductName, $"Code-{num}", decimal.Parse(product.UnitPrice),
0, product.PictureUrl, product.Units));
}
return randomProducts;
}
}

902
services/ordering/test/EShopOnAbp.OrderingService.TestBase/products.json

@ -0,0 +1,902 @@
[
{
"id": 1000,
"productName": "delightful chocolate Ilise",
"pictureUrl": "https://picsum.photos/400?image=659",
"productStock": 81,
"unitPrice": "23488.67",
"productSalePrice": "23488.67",
"units": 4
},
{
"id": 1001,
"productName": "civilian salmon Delinda",
"pictureUrl": "https://picsum.photos/400?image=261",
"productStock": 66,
"unitPrice": "42992.62",
"productSalePrice": "20636.46",
"units": 2
},
{
"id": 1002,
"productName": "northern chocolate Dagmar",
"pictureUrl": "https://picsum.photos/400?image=921",
"productStock": 58,
"unitPrice": "26956.67",
"productSalePrice": "26956.67",
"units": 4
},
{
"id": 1003,
"productName": "spatial plum Mattie",
"pictureUrl": "https://picsum.photos/400?image=753",
"productStock": 74,
"unitPrice": "32827.45",
"productSalePrice": "32827.45",
"units": 2
},
{
"id": 1004,
"productName": "arrogant tan Nelia",
"pictureUrl": "https://picsum.photos/400?image=924",
"productStock": 85,
"unitPrice": "27379.36",
"productSalePrice": "9308.98",
"units": 4
},
{
"id": 1005,
"productName": "following bronze Misti",
"pictureUrl": "https://picsum.photos/400?image=340",
"productStock": 24,
"unitPrice": "34617.96",
"productSalePrice": "34617.96",
"units": 3
},
{
"id": 1006,
"productName": "continued rose Nesta",
"pictureUrl": "https://picsum.photos/400?image=712",
"productStock": 34,
"unitPrice": "27822.85",
"productSalePrice": "27822.85",
"units": 1
},
{
"id": 1007,
"productName": "sufficient peach Georgiana",
"pictureUrl": "https://picsum.photos/400?image=860",
"productStock": 55,
"unitPrice": "15506.06",
"productSalePrice": "15506.06",
"units": 4
},
{
"id": 1008,
"productName": "frequent sapphire Petronella",
"pictureUrl": "https://picsum.photos/400?image=913",
"productStock": 36,
"unitPrice": "44132.59",
"productSalePrice": "44132.59",
"units": 5
},
{
"id": 1009,
"productName": "indirect indigo Fiona",
"pictureUrl": "https://picsum.photos/400?image=583",
"productStock": 49,
"unitPrice": "40702.21",
"productSalePrice": "4477.24",
"units": 1
},
{
"id": 1010,
"productName": "gross plum Veriee",
"pictureUrl": "https://picsum.photos/400?image=306",
"productStock": 12,
"unitPrice": "42194.21",
"productSalePrice": "42194.21",
"units": 4
},
{
"id": 1011,
"productName": "gigantic red Lissy",
"pictureUrl": "https://picsum.photos/400?image=184",
"productStock": 45,
"unitPrice": "18745.19",
"productSalePrice": "8810.24",
"units": 2
},
{
"id": 1012,
"productName": "blind copper Dionne",
"pictureUrl": "https://picsum.photos/400?image=308",
"productStock": 27,
"unitPrice": "2038.28",
"productSalePrice": "448.42",
"units": 3
},
{
"id": 1013,
"productName": "varied indigo Lizzie",
"pictureUrl": "https://picsum.photos/400?image=453",
"productStock": 97,
"unitPrice": "28245.22",
"productSalePrice": "9603.37",
"units": 4
},
{
"id": 1014,
"productName": "single amaranth Doris",
"pictureUrl": "https://picsum.photos/400?image=325",
"productStock": 21,
"unitPrice": "4200.08",
"productSalePrice": "4200.08",
"units": 2
},
{
"id": 1015,
"productName": "keen maroon Lenette",
"pictureUrl": "https://picsum.photos/400?image=92",
"productStock": 88,
"unitPrice": "2282.88",
"productSalePrice": "2282.88",
"units": 3
},
{
"id": 1016,
"productName": "conservation peach Nari",
"pictureUrl": "https://picsum.photos/400?image=798",
"productStock": 31,
"unitPrice": "45707.28",
"productSalePrice": "45707.28",
"units": 5
},
{
"id": 1017,
"productName": "loyal blush Happy",
"pictureUrl": "https://picsum.photos/400?image=163",
"productStock": 58,
"unitPrice": "40390.62",
"productSalePrice": "16560.15",
"units": 5
},
{
"id": 1018,
"productName": "awkward jade Wini",
"pictureUrl": "https://picsum.photos/400?image=475",
"productStock": 46,
"unitPrice": "4221.73",
"productSalePrice": "4221.73",
"units": 5
},
{
"id": 1019,
"productName": "uncertain cyan Tawsha",
"pictureUrl": "https://picsum.photos/400?image=18",
"productStock": 24,
"unitPrice": "6790.39",
"productSalePrice": "6790.39",
"units": 2
},
{
"id": 1020,
"productName": "partial harlequin Katlin",
"pictureUrl": "https://picsum.photos/400?image=466",
"productStock": 15,
"unitPrice": "9001.19",
"productSalePrice": "3510.47",
"units": 2
},
{
"id": 1021,
"productName": "redundant emerald Allyson",
"pictureUrl": "https://picsum.photos/400?image=110",
"productStock": 59,
"unitPrice": "25272.78",
"productSalePrice": "3032.73",
"units": 4
},
{
"id": 1022,
"productName": "far beige Megan",
"pictureUrl": "https://picsum.photos/400?image=264",
"productStock": 95,
"unitPrice": "33122.53",
"productSalePrice": "33122.53",
"units": 5
},
{
"id": 1023,
"productName": "select tomato Berty",
"pictureUrl": "https://picsum.photos/400?image=316",
"productStock": 57,
"unitPrice": "6265.37",
"productSalePrice": "2819.42",
"units": 5
},
{
"id": 1024,
"productName": "recent harlequin Kally",
"pictureUrl": "https://picsum.photos/400?image=896",
"productStock": 12,
"unitPrice": "30807.26",
"productSalePrice": "9550.25",
"units": 2
},
{
"id": 1025,
"productName": "limited emerald Alethea",
"pictureUrl": "https://picsum.photos/400?image=671",
"productStock": 85,
"unitPrice": "5782.65",
"productSalePrice": "2370.89",
"units": 2
},
{
"id": 1026,
"productName": "initial pink Riane",
"pictureUrl": "https://picsum.photos/400?image=917",
"productStock": 70,
"unitPrice": "34095.19",
"productSalePrice": "34095.19",
"units": 5
},
{
"id": 1027,
"productName": "long yellow Dorey",
"pictureUrl": "https://picsum.photos/400?image=419",
"productStock": 77,
"unitPrice": "24712.30",
"productSalePrice": "24712.30",
"units": 3
},
{
"id": 1028,
"productName": "acute brown Phaidra",
"pictureUrl": "https://picsum.photos/400?image=889",
"productStock": 15,
"unitPrice": "6488.51",
"productSalePrice": "6488.51",
"units": 4
},
{
"id": 1029,
"productName": "accepted orange Harriett",
"pictureUrl": "https://picsum.photos/400?image=719",
"productStock": 41,
"unitPrice": "19609.46",
"productSalePrice": "19609.46",
"units": 2
},
{
"id": 1030,
"productName": "creative amethyst Kali",
"pictureUrl": "https://picsum.photos/400?image=888",
"productStock": 22,
"unitPrice": "26368.88",
"productSalePrice": "12393.37",
"units": 2
},
{
"id": 1031,
"productName": "crooked indigo Karen",
"pictureUrl": "https://picsum.photos/400?image=443",
"productStock": 60,
"unitPrice": "49558.08",
"productSalePrice": "8424.87",
"units": 1
},
{
"id": 1032,
"productName": "operational orange Myrtia",
"pictureUrl": "https://picsum.photos/400?image=649",
"productStock": 61,
"unitPrice": "14925.93",
"productSalePrice": "2238.89",
"units": 3
},
{
"id": 1033,
"productName": "disturbing aqua Natalya",
"pictureUrl": "https://picsum.photos/400?image=554",
"productStock": 78,
"unitPrice": "27159.30",
"productSalePrice": "11950.09",
"units": 5
},
{
"id": 1034,
"productName": "forward green Alis",
"pictureUrl": "https://picsum.photos/400?image=746",
"productStock": 23,
"unitPrice": "27608.78",
"productSalePrice": "27608.78",
"units": 5
},
{
"id": 1035,
"productName": "complicated maroon Esmaria",
"pictureUrl": "https://picsum.photos/400?image=648",
"productStock": 69,
"unitPrice": "3128.23",
"productSalePrice": "938.47",
"units": 4
},
{
"id": 1036,
"productName": "frequent chocolate Michell",
"pictureUrl": "https://picsum.photos/400?image=439",
"productStock": 64,
"unitPrice": "39521.86",
"productSalePrice": "39521.86",
"units": 4
},
{
"id": 1037,
"productName": "inquisitive cyan Janette",
"pictureUrl": "https://picsum.photos/400?image=857",
"productStock": 35,
"unitPrice": "9689.55",
"productSalePrice": "9689.55",
"units": 4
},
{
"id": 1038,
"productName": "regional tomato Melamie",
"pictureUrl": "https://picsum.photos/400?image=48",
"productStock": 20,
"unitPrice": "5948.06",
"productSalePrice": "1605.98",
"units": 4
},
{
"id": 1039,
"productName": "notable maroon Anthe",
"pictureUrl": "https://picsum.photos/400?image=802",
"productStock": 34,
"unitPrice": "49448.68",
"productSalePrice": "49448.68",
"units": 3
},
{
"id": 1040,
"productName": "unfortunate maroon Aileen",
"pictureUrl": "https://picsum.photos/400?image=38",
"productStock": 65,
"unitPrice": "24131.28",
"productSalePrice": "24131.28",
"units": 1
},
{
"id": 1041,
"productName": "illegal black Karylin",
"pictureUrl": "https://picsum.photos/400?image=859",
"productStock": 57,
"unitPrice": "36521.61",
"productSalePrice": "16799.94",
"units": 5
},
{
"id": 1042,
"productName": "diverse crimson Chiquia",
"pictureUrl": "https://picsum.photos/400?image=928",
"productStock": 63,
"unitPrice": "30920.27",
"productSalePrice": "30920.27",
"units": 4
},
{
"id": 1043,
"productName": "coming magenta Siana",
"pictureUrl": "https://picsum.photos/400?image=54",
"productStock": 66,
"unitPrice": "41255.15",
"productSalePrice": "41255.15",
"units": 3
},
{
"id": 1044,
"productName": "psychological maroon Cesya",
"pictureUrl": "https://picsum.photos/400?image=596",
"productStock": 25,
"unitPrice": "20085.00",
"productSalePrice": "7230.60",
"units": 2
},
{
"id": 1045,
"productName": "stingy moccasin Conny",
"pictureUrl": "https://picsum.photos/400?image=399",
"productStock": 95,
"unitPrice": "30494.11",
"productSalePrice": "30494.11",
"units": 4
},
{
"id": 1046,
"productName": "voiceless emerald Sarita",
"pictureUrl": "https://picsum.photos/400?image=695",
"productStock": 48,
"unitPrice": "21625.98",
"productSalePrice": "8001.61",
"units": 3
},
{
"id": 1047,
"productName": "old lime Elvera",
"pictureUrl": "https://picsum.photos/400?image=761",
"productStock": 4,
"unitPrice": "30869.36",
"productSalePrice": "30869.36",
"units": 5
},
{
"id": 1048,
"productName": "grumpy plum Jessica",
"pictureUrl": "https://picsum.photos/400?image=570",
"productStock": 73,
"unitPrice": "35395.72",
"productSalePrice": "11326.63",
"units": 3
},
{
"id": 1049,
"productName": "unknown beige Maddalena",
"pictureUrl": "https://picsum.photos/400?image=784",
"productStock": 11,
"unitPrice": "24573.75",
"productSalePrice": "2457.37",
"units": 4
},
{
"id": 1050,
"productName": "clever rose Karoly",
"pictureUrl": "https://picsum.photos/400?image=500",
"productStock": 81,
"unitPrice": "12289.15",
"productSalePrice": "12289.15",
"units": 4
},
{
"id": 1051,
"productName": "unfortunate tan Maris",
"pictureUrl": "https://picsum.photos/400?image=622",
"productStock": 63,
"unitPrice": "39042.14",
"productSalePrice": "11322.22",
"units": 2
},
{
"id": 1052,
"productName": "statutory emerald Arlyn",
"pictureUrl": "https://picsum.photos/400?image=472",
"productStock": 50,
"unitPrice": "35325.05",
"productSalePrice": "35325.05",
"units": 1
},
{
"id": 1053,
"productName": "dynamic gold Gratiana",
"pictureUrl": "https://picsum.photos/400?image=71",
"productStock": 59,
"unitPrice": "21332.58",
"productSalePrice": "21332.58",
"units": 5
},
{
"id": 1054,
"productName": "spotty cyan Micky",
"pictureUrl": "https://picsum.photos/400?image=471",
"productStock": 78,
"unitPrice": "49952.94",
"productSalePrice": "10490.12",
"units": 2
},
{
"id": 1055,
"productName": "creative peach Loria",
"pictureUrl": "https://picsum.photos/400?image=619",
"productStock": 6,
"unitPrice": "20547.31",
"productSalePrice": "8424.40",
"units": 2
},
{
"id": 1056,
"productName": "dutch peach Em",
"pictureUrl": "https://picsum.photos/400?image=236",
"productStock": 98,
"unitPrice": "42634.53",
"productSalePrice": "19611.88",
"units": 3
},
{
"id": 1057,
"productName": "civilian fuchsia Jackelyn",
"pictureUrl": "https://picsum.photos/400?image=409",
"productStock": 62,
"unitPrice": "21268.92",
"productSalePrice": "21268.92",
"units": 1
},
{
"id": 1058,
"productName": "elderly turquoise Storm",
"pictureUrl": "https://picsum.photos/400?image=270",
"productStock": 68,
"unitPrice": "45826.03",
"productSalePrice": "9623.47",
"units": 4
},
{
"id": 1059,
"productName": "charming jade Emelia",
"pictureUrl": "https://picsum.photos/400?image=696",
"productStock": 36,
"unitPrice": "23535.56",
"productSalePrice": "23535.56",
"units": 4
},
{
"id": 1060,
"productName": "uninterested violet Lind",
"pictureUrl": "https://picsum.photos/400?image=732",
"productStock": 51,
"unitPrice": "18257.20",
"productSalePrice": "18257.20",
"units": 2
},
{
"id": 1061,
"productName": "assistant gray Regine",
"pictureUrl": "https://picsum.photos/400?image=129",
"productStock": 6,
"unitPrice": "31745.83",
"productSalePrice": "31745.83",
"units": 2
},
{
"id": 1062,
"productName": "thick blush Pennie",
"pictureUrl": "https://picsum.photos/400?image=605",
"productStock": 3,
"unitPrice": "3405.51",
"productSalePrice": "3405.51",
"units": 4
},
{
"id": 1063,
"productName": "lovely brown Theressa",
"pictureUrl": "https://picsum.photos/400?image=891",
"productStock": 31,
"unitPrice": "40426.73",
"productSalePrice": "12936.55",
"units": 4
},
{
"id": 1064,
"productName": "smooth plum Robbi",
"pictureUrl": "https://picsum.photos/400?image=690",
"productStock": 18,
"unitPrice": "32980.16",
"productSalePrice": "10883.45",
"units": 2
},
{
"id": 1065,
"productName": "crude cyan Aloysia",
"pictureUrl": "https://picsum.photos/400?image=896",
"productStock": 56,
"unitPrice": "3933.53",
"productSalePrice": "3933.53",
"units": 5
},
{
"id": 1066,
"productName": "prominent turquoise Pattie",
"pictureUrl": "https://picsum.photos/400?image=855",
"productStock": 45,
"unitPrice": "30615.94",
"productSalePrice": "30615.94",
"units": 2
},
{
"id": 1067,
"productName": "daily tan Wenda",
"pictureUrl": "https://picsum.photos/400?image=869",
"productStock": 41,
"unitPrice": "36740.69",
"productSalePrice": "13226.65",
"units": 2
},
{
"id": 1068,
"productName": "primary gold Tera",
"pictureUrl": "https://picsum.photos/400?image=463",
"productStock": 88,
"unitPrice": "25121.63",
"productSalePrice": "25121.63",
"units": 4
},
{
"id": 1069,
"productName": "geographical amethyst Tania",
"pictureUrl": "https://picsum.photos/400?image=14",
"productStock": 79,
"unitPrice": "24384.38",
"productSalePrice": "24384.38",
"units": 2
},
{
"id": 1070,
"productName": "historic salmon Laraine",
"pictureUrl": "https://picsum.photos/400?image=275",
"productStock": 33,
"unitPrice": "46883.08",
"productSalePrice": "46883.08",
"units": 3
},
{
"id": 1071,
"productName": "bare jade Mabelle",
"pictureUrl": "https://picsum.photos/400?image=177",
"productStock": 79,
"unitPrice": "46760.90",
"productSalePrice": "16833.92",
"units": 3
},
{
"id": 1072,
"productName": "tame crimson Natalie",
"pictureUrl": "https://picsum.photos/400?image=152",
"productStock": 48,
"unitPrice": "22356.48",
"productSalePrice": "22356.48",
"units": 2
},
{
"id": 1073,
"productName": "regular harlequin Aigneis",
"pictureUrl": "https://picsum.photos/400?image=523",
"productStock": 8,
"unitPrice": "45933.08",
"productSalePrice": "45933.08",
"units": 5
},
{
"id": 1074,
"productName": "tight red Bernice",
"pictureUrl": "https://picsum.photos/400?image=417",
"productStock": 2,
"unitPrice": "3766.15",
"productSalePrice": "1732.43",
"units": 4
},
{
"id": 1075,
"productName": "ready chocolate Mirelle",
"pictureUrl": "https://picsum.photos/400?image=843",
"productStock": 38,
"unitPrice": "24113.38",
"productSalePrice": "24113.38",
"units": 3
},
{
"id": 1076,
"productName": "secondary red Blythe",
"pictureUrl": "https://picsum.photos/400?image=350",
"productStock": 97,
"unitPrice": "47086.10",
"productSalePrice": "9888.08",
"units": 2
},
{
"id": 1077,
"productName": "known orange Nollie",
"pictureUrl": "https://picsum.photos/400?image=578",
"productStock": 18,
"unitPrice": "30645.75",
"productSalePrice": "30645.75",
"units": 3
},
{
"id": 1078,
"productName": "very indigo Beverie",
"pictureUrl": "https://picsum.photos/400?image=304",
"productStock": 6,
"unitPrice": "36357.98",
"productSalePrice": "36357.98",
"units": 2
},
{
"id": 1079,
"productName": "legislative tan Gracie",
"pictureUrl": "https://picsum.photos/400?image=419",
"productStock": 50,
"unitPrice": "14884.72",
"productSalePrice": "2976.94",
"units": 3
},
{
"id": 1080,
"productName": "husky pink Nicola",
"pictureUrl": "https://picsum.photos/400?image=330",
"productStock": 64,
"unitPrice": "17199.38",
"productSalePrice": "17199.38",
"units": 2
},
{
"id": 1081,
"productName": "hot bronze Bertha",
"pictureUrl": "https://picsum.photos/400?image=571",
"productStock": 8,
"unitPrice": "23919.62",
"productSalePrice": "23919.62",
"units": 2
},
{
"id": 1082,
"productName": "conscious magenta Jessie",
"pictureUrl": "https://picsum.photos/400?image=707",
"productStock": 36,
"unitPrice": "1355.81",
"productSalePrice": "1355.81",
"units": 3
},
{
"id": 1083,
"productName": "shiny silver Tammie",
"pictureUrl": "https://picsum.photos/400?image=531",
"productStock": 55,
"unitPrice": "35674.84",
"productSalePrice": "10702.45",
"units": 4
},
{
"id": 1084,
"productName": "wasteful orange Stephana",
"pictureUrl": "https://picsum.photos/400?image=540",
"productStock": 26,
"unitPrice": "9266.72",
"productSalePrice": "9266.72",
"units": 4
},
{
"id": 1085,
"productName": "accepted coffee Karoly",
"pictureUrl": "https://picsum.photos/400?image=77",
"productStock": 9,
"unitPrice": "40394.96",
"productSalePrice": "8886.89",
"units": 4
},
{
"id": 1086,
"productName": "biological yellow Corene",
"pictureUrl": "https://picsum.photos/400?image=220",
"productStock": 99,
"unitPrice": "40799.67",
"productSalePrice": "12647.90",
"units": 1
},
{
"id": 1087,
"productName": "ugly white Jeanine",
"pictureUrl": "https://picsum.photos/400?image=607",
"productStock": 70,
"unitPrice": "20261.08",
"productSalePrice": "20261.08",
"units": 2
},
{
"id": 1088,
"productName": "above cyan Dredi",
"pictureUrl": "https://picsum.photos/400?image=946",
"productStock": 94,
"unitPrice": "40979.58",
"productSalePrice": "40979.58",
"units": 4
},
{
"id": 1089,
"productName": "stable plum Barbabra",
"pictureUrl": "https://picsum.photos/400?image=994",
"productStock": 30,
"unitPrice": "31625.74",
"productSalePrice": "31625.74",
"units": 5
},
{
"id": 1090,
"productName": "ambitious amber Alayne",
"pictureUrl": "https://picsum.photos/400?image=592",
"productStock": 83,
"unitPrice": "23998.74",
"productSalePrice": "9359.51",
"units": 4
},
{
"id": 1091,
"productName": "nice indigo Steffie",
"pictureUrl": "https://picsum.photos/400?image=644",
"productStock": 3,
"unitPrice": "18201.33",
"productSalePrice": "18201.33",
"units": 4
},
{
"id": 1092,
"productName": "cute ivory Ofilia",
"pictureUrl": "https://picsum.photos/400?image=832",
"productStock": 74,
"unitPrice": "49212.53",
"productSalePrice": "13287.38",
"units": 4
},
{
"id": 1093,
"productName": "fun lime Mallorie",
"pictureUrl": "https://picsum.photos/400?image=614",
"productStock": 65,
"unitPrice": "22883.28",
"productSalePrice": "22883.28",
"units": 2
},
{
"id": 1094,
"productName": "united indigo Silva",
"pictureUrl": "https://picsum.photos/400?image=404",
"productStock": 9,
"unitPrice": "40058.13",
"productSalePrice": "40058.13",
"units": 5
},
{
"id": 1095,
"productName": "pale gold Gwyn",
"pictureUrl": "https://picsum.photos/400?image=250",
"productStock": 74,
"unitPrice": "25333.23",
"productSalePrice": "11653.29",
"units": 2
},
{
"id": 1096,
"productName": "valid amaranth Constanta",
"pictureUrl": "https://picsum.photos/400?image=466",
"productStock": 19,
"unitPrice": "40992.99",
"productSalePrice": "40992.99",
"units": 2
},
{
"id": 1097,
"productName": "symbolic orange Courtney",
"pictureUrl": "https://picsum.photos/400?image=36",
"productStock": 63,
"unitPrice": "32930.92",
"productSalePrice": "32930.92",
"units": 4
},
{
"id": 1098,
"productName": "existing fuchsia Maggy",
"pictureUrl": "https://picsum.photos/400?image=991",
"productStock": 87,
"unitPrice": "29786.00",
"productSalePrice": "14595.14",
"units": 2
},
{
"id": 1099,
"productName": "surprising cyan Gene",
"pictureUrl": "https://picsum.photos/400?image=634",
"productStock": 61,
"unitPrice": "8908.76",
"productSalePrice": "8908.76",
"units": 3
}
]

3
services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestCreationDto.cs

@ -16,6 +16,9 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
[MaxLength(PaymentRequestConsts.MaxOrderIdLength)]
public string OrderId { get; set; }
[Required]
public int OrderNo { get; set; }
public string BuyerId { get; set; }
public List<PaymentRequestProductCreationDto> Products { get; set; }
}

2
services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestDto.cs

@ -14,6 +14,8 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
public string OrderId { get; set; }
public int OrderNo {get;set;}
public string BuyerId { get; set; }
public bool IsDeleted { get; set; }

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

@ -27,7 +27,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
public virtual async Task<PaymentRequestDto> CreateAsync(PaymentRequestCreationDto input)
{
var paymentRequest = new PaymentRequest(id: GuidGenerator.Create(), orderId: input.OrderId, currency: input.Currency, buyerId: input.BuyerId);
var paymentRequest = new PaymentRequest(id: GuidGenerator.Create(), orderId: input.OrderId, orderNo:input.OrderNo, currency: input.Currency, buyerId: input.BuyerId);
foreach (var paymentRequestProduct in input.Products
.Select(s => new PaymentRequestProduct(

8
services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestByPassAppService.cs

@ -8,7 +8,11 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
[ExposeServices(typeof(PaymentRequestByPassAppService))]
public class PaymentRequestByPassAppService : PaymentRequestAppService
{
public PaymentRequestByPassAppService(IPaymentRequestRepository paymentRequestRepository, PayPalHttpClient payPalHttpClient) : base(paymentRequestRepository, payPalHttpClient)
public PaymentRequestByPassAppService(
IPaymentRequestRepository paymentRequestRepository,
PayPalHttpClient payPalHttpClient)
: base(paymentRequestRepository,
payPalHttpClient)
{
}
@ -31,4 +35,4 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
return ObjectMapper.Map<PaymentRequest, PaymentRequestDto>(paymentRequest);
}
}
}
}

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

@ -11,6 +11,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
{
public Guid PaymentRequestId { get; set; }
public string OrderId { get; set; }
public int OrderNo { get; set; }
public string Currency { get; set; }
public string BuyerId { get; set; }
public PaymentRequestState State { get; set; }

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

@ -11,6 +11,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
public Guid PaymentRequestId { get; set; }
public string OrderId { get; set; }
public int OrderNo { get; set; }
public string FailReason { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; set; }
}

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

@ -11,6 +11,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
{
[NotNull] public string Currency { get; protected set; }
[NotNull] public string OrderId { get; protected set; }
public int OrderNo { get; protected set; }
[CanBeNull] public string BuyerId { get; protected set; }
public PaymentRequestState State { get; protected set; }
[CanBeNull] public string FailReason { get; protected set; }
@ -22,12 +23,14 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
public PaymentRequest(Guid id,
[NotNull] string orderId,
int orderNo,
[NotNull] string currency,
[CanBeNull] string buyerId = null) : base(id)
{
OrderId = Check.NotNullOrWhiteSpace(orderId, nameof(orderId), minLength: PaymentRequestConsts.MinOrderIdLength, maxLength: PaymentRequestConsts.MaxOrderIdLength);
Currency = Check.NotNullOrWhiteSpace(currency, nameof(currency), maxLength: PaymentRequestConsts.MaxCurrencyLength);
BuyerId = buyerId;
OrderNo = orderNo;
}
public virtual void SetAsCompleted()
@ -44,6 +47,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
{
PaymentRequestId = Id,
OrderId = OrderId,
OrderNo = OrderNo,
BuyerId = BuyerId,
Currency = Currency,
State = State,
@ -66,6 +70,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests
{
PaymentRequestId = Id,
OrderId = OrderId,
OrderNo = OrderNo,
FailReason = failReason,
ExtraProperties = ExtraProperties
});

2
services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/EntityFrameworkCore/PaymentServiceDbContextModelCreatingExtensions.cs

@ -25,6 +25,8 @@ namespace EShopOnAbp.PaymentService.EntityFrameworkCore
.Property(p => p.OrderId)
.IsRequired()
.HasMaxLength(PaymentRequestConsts.MaxOrderIdLength);
entity.Property(q => q.OrderNo).IsRequired();
entity.HasIndex(o => o.OrderId);
});

140
services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/20220107135728_Added-OrderNo.Designer.cs

@ -0,0 +1,140 @@
// <auto-generated />
using System;
using EShopOnAbp.PaymentService.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Volo.Abp.EntityFrameworkCore;
#nullable disable
namespace EShopOnAbp.PaymentService.Migrations
{
[DbContext(typeof(PaymentServiceDbContext))]
[Migration("20220107135728_Added-OrderNo")]
partial class AddedOrderNo
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql)
.HasAnnotation("ProductVersion", "6.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("EShopOnAbp.PaymentService.PaymentRequests.PaymentRequest", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("BuyerId")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("Currency")
.IsRequired()
.HasMaxLength(3)
.HasColumnType("character varying(3)");
b.Property<string>("ExtraProperties")
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<string>("FailReason")
.HasColumnType("text");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<string>("OrderId")
.IsRequired()
.HasMaxLength(36)
.HasColumnType("character varying(36)");
b.Property<int>("OrderNo")
.HasColumnType("integer");
b.Property<int>("State")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("OrderId");
b.ToTable("PaymentRequests");
});
modelBuilder.Entity("EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestProduct", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("Code")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<Guid>("PaymentRequestId")
.HasColumnType("uuid");
b.Property<int>("Quantity")
.HasColumnType("integer");
b.Property<string>("ReferenceId")
.HasColumnType("text");
b.Property<decimal>("TotalPrice")
.HasColumnType("numeric");
b.Property<decimal>("UnitPrice")
.HasColumnType("numeric");
b.HasKey("Id");
b.HasIndex("PaymentRequestId");
b.ToTable("PaymentRequestProduct");
});
modelBuilder.Entity("EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestProduct", b =>
{
b.HasOne("EShopOnAbp.PaymentService.PaymentRequests.PaymentRequest", null)
.WithMany("Products")
.HasForeignKey("PaymentRequestId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("EShopOnAbp.PaymentService.PaymentRequests.PaymentRequest", b =>
{
b.Navigation("Products");
});
#pragma warning restore 612, 618
}
}
}

26
services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/20220107135728_Added-OrderNo.cs

@ -0,0 +1,26 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace EShopOnAbp.PaymentService.Migrations
{
public partial class AddedOrderNo : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "OrderNo",
table: "PaymentRequests",
type: "integer",
nullable: false,
defaultValue: 0);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "OrderNo",
table: "PaymentRequests");
}
}
}

3
services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/PaymentServiceDbContextModelSnapshot.cs

@ -69,6 +69,9 @@ namespace EShopOnAbp.PaymentService.Migrations
.HasMaxLength(36)
.HasColumnType("character varying(36)");
b.Property<int>("OrderNo")
.HasColumnType("integer");
b.Property<int>("State")
.HasColumnType("integer");

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

@ -2,6 +2,7 @@
"culture": "en",
"texts": {
"Menu:Home": "Home",
"Menu:MyOrders": "My Orders",
"Login": "Login",
"YourBasket": "Your Basket",
"EmptyBasket": "Empyt basket",

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

@ -2,6 +2,7 @@
"culture": "tr",
"texts": {
"Menu:Home": "Ana Sayfa",
"Menu:MyOrders": "Siparişlerim",
"Login": "Giriş",
"YourBasket": "Sepetiniz",
"EmptyBasket": "Sepetiniz boş",

Loading…
Cancel
Save