diff --git a/apps/auth-server/src/EShopOnAbp.AuthServer/appsettings.json b/apps/auth-server/src/EShopOnAbp.AuthServer/appsettings.json index 42d2325f..194f3358 100644 --- a/apps/auth-server/src/EShopOnAbp.AuthServer/appsettings.json +++ b/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": { diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Basket/BasketWidgetViewComponent.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Basket/BasketWidgetViewComponent.cs index 05ebab88..308e0dc6 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Basket/BasketWidgetViewComponent.cs +++ b/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; diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Payment/PaymentWidgetViewComponent.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Payment/PaymentWidgetViewComponent.cs index 92b281fa..e0335a7a 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Payment/PaymentWidgetViewComponent.cs +++ b/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; diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Purchase/Default.cshtml b/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Purchase/Default.cshtml index 1722a34c..09bf2ff9 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Purchase/Default.cshtml +++ b/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Purchase/Default.cshtml @@ -55,6 +55,7 @@
@Html.AntiForgeryToken() +
diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Toolbar/Cart/CartWidgetViewComponent.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Toolbar/Cart/CartWidgetViewComponent.cs index ce214c76..04ca8d5b 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/Components/Toolbar/Cart/CartWidgetViewComponent.cs +++ b/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; diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/Default.cshtml b/apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/Default.cshtml new file mode 100644 index 00000000..cad59f57 --- /dev/null +++ b/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 L + +@if (Model.ServiceError) +{ +
SERVICE ERROR
+} + + @Model.UserOrders.Count sipariş verildi. + +@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}"; +
+
+
+
+
Sipariş Tarihi
+
@order.OrderDate.ToString("dd MMMM yyyy")
+
+
+
Toplam
+
@orderTotalString
+
+
+
Teslimat Adresi
+
+ @order.Address.Description +
+
+
+
+ Sipariş No @order.OrderNo.ToString("N0", new NumberFormatInfo() {NumberGroupSeparator = " "}) +
+
+
+
+
+ @foreach (var item in order.Items) + { + + +
+

@order.OrderStatus

+
+ + + + + +
@item.ProductName
+
Ürünü iade edebileceğiniz son tarih: @order.OrderDate.AddMonths(1).ToString("dd MMMM yyyy")
+
+ +
+
+ + + Ürünleri iade et + + + Ürün yorumu yazın + + +
+
+
+ } +
+
+
+} \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/UserOrderWidgetScriptContributor.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/UserOrderWidgetScriptContributor.cs new file mode 100644 index 00000000..c04eb3da --- /dev/null +++ b/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"); + } +} \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/UserOrderWidgetStyleContributor.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/UserOrderWidgetStyleContributor.cs new file mode 100644 index 00000000..bd98d748 --- /dev/null +++ b/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"); + } +} \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/UserOrderWidgetViewComponent.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Components/UserOrders/UserOrderWidgetViewComponent.cs new file mode 100644 index 00000000..31627b0f --- /dev/null +++ b/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 InvokeAsync(string filter) + { + try + { + ViewModel.UserOrders = await _orderAppService.GetMyOrdersAsync(new GetMyOrdersInput {Filter = filter}); + } + catch (Exception e) + { + ViewModel.ServiceError = true; + ViewModel.UserOrders = new List(); + Console.WriteLine(e); + } + + return View("~/Components/UserOrders/Default.cshtml", ViewModel); + } + + public class UserOrderViewModel + { + public List UserOrders { get; set; } + public bool ServiceError { get; set; } + } +} \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Menus/EShopOnAbpPublicWebMenuContributor.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Menus/EShopOnAbpPublicWebMenuContributor.cs index f2ea9b52..2e65e8b8 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/Menus/EShopOnAbpPublicWebMenuContributor.cs +++ b/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(); var accountResource = context.GetLocalizer(); + var eShopResource = context.GetLocalizer(); 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; diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/MyOrders.cshtml b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/MyOrders.cshtml new file mode 100644 index 00000000..eaf32853 --- /dev/null +++ b/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 L + +@section scripts { + + + +} + +@section styles{ + +} + +@{ + string lastYearString = $"y{DateTime.Today.Year - 1}"; + string filter = ""; + var selectList = new List + { + new(@L["Last30Days"], "last30", selected: true), + new(@L["LastMonth"], "m1"), + new(@L["Last3Months"], "m3"), + new(@L["LastYear"], lastYearString), + new("2020", "y2020"), + new("2019", "y2019") + }; +} + +
+ + + + + +
+ +
+ @await Component.InvokeAsync(typeof(UserOrderWidgetViewComponent), new {Filter = Model.OrderFilter}) +
\ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/MyOrders.cshtml.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/MyOrders.cshtml.cs new file mode 100644 index 00000000..c7dccf65 --- /dev/null +++ b/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; + } +} \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/OrderReceived.cshtml b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/OrderReceived.cshtml new file mode 100644 index 00000000..94c08676 --- /dev/null +++ b/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{ + +} + +@{ + var paymentIcon = Model.ReceivedOrder.PaymentType == "paypal" ? "fa-cc-paypal" : "fa-credit-card"; +} + + + + + + + + +
+

Sipariş alındı!

+

Siparişiniz ile ilgili detaylar @Model.ReceivedOrder.Buyer.Email adresine gönderildi. Siparişlerime git

+
+
+ +
+ + +
Sipariş Numarası
+
+ @orderNoString +
+
+ +
Teslimat Adresi
+
+ @Model.ReceivedOrder.Address.Description +
+
@Model.ReceivedOrder.Address.Street - @Model.ReceivedOrder.Address.ZipCode
+
@Model.ReceivedOrder.Address.City / @Model.ReceivedOrder.Address.Country
+
+ +
Ödenen Tutar
+
@orderTotalString
+
+ +
+
+
+ +
+
+
\ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/OrderReceived.cshtml.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/OrderReceived.cshtml.cs new file mode 100644 index 00000000..2e64bbb6 --- /dev/null +++ b/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); + } +} \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Payment.cshtml.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Payment.cshtml.cs index 797aac15..d4191c8c 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Payment.cshtml.cs +++ b/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>(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>(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>(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 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; } - } } \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml index 1dbd3b35..df66d0c7 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml +++ b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml @@ -1,16 +1,16 @@ @page @model EShopOnAbp.PublicWeb.Pages.PaymentCompletedModel -
- - @if (Model.IsSuccessful) - { -

Thank you for the payment!

-
-

Purchase completed!

-
-

click here to return to home page

- - } - +
+ + + @* Card image cap *@ + +

Order Failed!

+

It seems there is a problem with your payment

+

Please check your payment method!

+ Continue Shopping +
+
+
\ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml.cs index fa3f87b8..e313939d 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/PaymentCompleted.cshtml.cs +++ b/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 OnGetAsync() { PaymentRequest = await _paymentRequestAppService.CompleteAsync(Token); IsSuccessful = PaymentRequest.State == PaymentRequestState.Completed; + if (IsSuccessful) + { + return RedirectToPage("OrderReceived", new { orderNo = PaymentRequest.OrderNo }); + } + + return Page(); } } \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/index.js b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/index.js index 04c54ef9..c9ed2841 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/index.js +++ b/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(); diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/myOrders.css b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/myOrders.css new file mode 100644 index 00000000..e5780259 --- /dev/null +++ b/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; +} \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/myOrders.js b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/myOrders.js new file mode 100644 index 00000000..d13b0593 --- /dev/null +++ b/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()); + + }); +})(); \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/orderReceived.css b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/orderReceived.css new file mode 100644 index 00000000..5d5e6ccb --- /dev/null +++ b/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; +} \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/payment.js b/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/payment.js index c102cea6..fd41fe8f 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/Pages/payment.js +++ b/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); }; })(); \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/DiscountProvider.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/DiscountProvider.cs new file mode 100644 index 00000000..c1d036f1 --- /dev/null +++ b/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 +} \ No newline at end of file diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Basket/UserAddressProvider.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserAddressProvider.cs similarity index 96% rename from apps/public-web/src/EShopOnAbp.PublicWeb/Basket/UserAddressProvider.cs rename to apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserAddressProvider.cs index 40b090a5..6e343752 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/Basket/UserAddressProvider.cs +++ b/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 { diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/Basket/UserBasketProvider.cs b/apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserBasketProvider.cs similarity index 95% rename from apps/public-web/src/EShopOnAbp.PublicWeb/Basket/UserBasketProvider.cs rename to apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserBasketProvider.cs index c96a21a9..fd8f5b61 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/Basket/UserBasketProvider.cs +++ b/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 { diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/client-proxies/ordering-proxy.js b/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/client-proxies/ordering-proxy.js new file mode 100644 index 00000000..cb2791a7 --- /dev/null +++ b/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)); + }; + + })(); + +})(); + + diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/basket/basket-widget.css b/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/basket/basket-widget.css index 06d922a6..c6421e2c 100644 --- a/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/basket/basket-widget.css +++ b/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; diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/user-orders/user-order-widget.css b/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/user-orders/user-order-widget.css new file mode 100644 index 00000000..e69de29b diff --git a/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/user-orders/user-order-widget.js b/apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/user-orders/user-order-widget.js new file mode 100644 index 00000000..e69de29b diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/GetMyOrdersInput.cs b/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/GetMyOrdersInput.cs new file mode 100644 index 00000000..7c5f93c2 --- /dev/null +++ b/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; } +} \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/IOrderAppService.cs b/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/IOrderAppService.cs index 4d3c7806..61282b4d 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/IOrderAppService.cs +++ b/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 CreateAsync(OrderCreateDto input); Task GetAsync(Guid id); + Task> GetMyOrdersAsync(GetMyOrdersInput input); Task GetByOrderNoAsync(int orderNo); } \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/OrderDto.cs b/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/OrderDto.cs index eb6368ef..237484b9 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/OrderDto.cs +++ b/services/ordering/src/EShopOnAbp.OrderingService.Application.Contracts/Orders/OrderDto.cs @@ -7,6 +7,7 @@ namespace EShopOnAbp.OrderingService.Orders; public class OrderDto : EntityDto { 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; } diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Application/OrderingServiceApplicationAutoMapperProfile.cs b/services/ordering/src/EShopOnAbp.OrderingService.Application/OrderingServiceApplicationAutoMapperProfile.cs index f5f73fab..2153beb2 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.Application/OrderingServiceApplicationAutoMapperProfile.cs +++ b/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; diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs b/services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs index a65219b7..7530e593 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.Application/Orders/OrderAppService.cs +++ b/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 GetAsync(Guid id) { var order = await _orderRepository.GetAsync(id); - return await CreateOrderDtoMappingAsync(order); + return CreateOrderDtoMapping(order); } - public Task GetByOrderNoAsync(int orderNo) + public async Task> GetMyOrdersAsync(GetMyOrdersInput input) { - var order = await _orderRepository.get + ISpecification specification = SpecificationFactory.Create(input.Filter); + + var orders = await _orderRepository.GetOrdersByUserId(CurrentUser.GetId(), specification, true); + + return CreateOrderDtoMapping(orders); + } + + public async Task GetByOrderNoAsync(int orderNo) + { + var order = await _orderRepository.GetByOrderNoAsync(orderNo); + Logger.LogInformation($" Order recieved with order no:{orderNo}"); + return CreateOrderDtoMapping(order); } public async Task 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 CreateOrderDtoMappingAsync(Order placedOrder) + private List CreateOrderDtoMapping(List orders) + { + List dtoList = new List(); + foreach (var order in orders) + { + dtoList.Add(CreateOrderDtoMapping(order)); + } + + return dtoList; + } + + private OrderDto CreateOrderDtoMapping(Order order) { return new OrderDto() { - Address = ObjectMapper.Map(placedOrder.Address), - Items = ObjectMapper.Map, List>(placedOrder.OrderItems), - Buyer = ObjectMapper.Map(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(order.Address), + Items = ObjectMapper.Map, List>(order.OrderItems), + Buyer = ObjectMapper.Map(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 }; } } \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderPlacedEto.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderPlacedEto.cs index 5fea3949..c74b5344 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.Domain.Shared/Orders/OrderPlacedEto.cs +++ b/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 Items { get; set; } = new(); diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/IOrderRepository.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/IOrderRepository.cs index b875886c..a9494c97 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/IOrderRepository.cs +++ b/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 { + Task> GetOrdersByUserId( + Guid userId, + ISpecification spec, + bool includeDetails = true, + CancellationToken cancellationToken = default); + Task GetByOrderNoAsync(int orderNo, bool includeDetails = true, CancellationToken cancellationToken = default); diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs index 8001fc8e..f7d44dcd 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs +++ b/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 { } - 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 OrderItems = new List(); } + 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; diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/OrderManager.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/OrderManager.cs index fac49843..5a0c5ee1 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/OrderManager.cs +++ b/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) }); diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/PaymentType.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/PaymentType.cs index 5ee66b7b..2e556acd 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/PaymentType.cs +++ b/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 { diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/Last30DaysSpecification.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/Last30DaysSpecification.cs new file mode 100644 index 00000000..6f284d44 --- /dev/null +++ b/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 +{ + public override Expression> ToExpression() + { + var daysAgo30 = DateTime.UtcNow.Subtract(TimeSpan.FromDays(30)); + return query => query.OrderDate >= daysAgo30 + ; + // && query.OrderDate <= DateTime.UtcNow; + } +} \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/MonthsAgoSpecification.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/MonthsAgoSpecification.cs new file mode 100644 index 00000000..3bcb10e7 --- /dev/null +++ b/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 +{ + protected int NumberOfMonths { get; set; } + + public MonthsAgoSpecification(int months) + { + NumberOfMonths = months; + } + + public override Expression> ToExpression() + { + var monthsAgo = DateTime.UtcNow.AddMonths(-NumberOfMonths); + return query => query.OrderDate >= monthsAgo; + } +} \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/SpecificationFactory.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/SpecificationFactory.cs new file mode 100644 index 00000000..4bb9e0fb --- /dev/null +++ b/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 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(); + } +} \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/YearSpecification.cs b/services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/YearSpecification.cs new file mode 100644 index 00000000..44c0d1ae --- /dev/null +++ b/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 +{ + protected int Year { get; set; } + + public YearSpecification(int year) + { + Year = year; + } + + public override Expression> ToExpression() + { + return query => query.OrderDate.Year == Year; + } +} \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderServiceDataSeedContributor.cs b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderServiceDataSeedContributor.cs index 468aca95..b1d2355a 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderServiceDataSeedContributor.cs +++ b/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; diff --git a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderingServiceDbContext.cs b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderingServiceDbContext.cs index 6b673f3c..3351c858 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderingServiceDbContext.cs +++ b/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; diff --git a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs index b1e95940..32414453 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs +++ b/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> GetOrdersByUserId( + Guid userId, + ISpecification 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 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> WithDetailsAsync() diff --git a/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/OrderEfCoreQueryableExtensions.cs b/services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/OrderEfCoreQueryableExtensions.cs new file mode 100644 index 00000000..7b194839 --- /dev/null +++ b/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 IncludeDetails(this IQueryable 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); + } +} \ No newline at end of file diff --git a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/OrderClientProxy.Generated.cs b/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/OrderClientProxy.Generated.cs index 41dd6783..34926156 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/OrderClientProxy.Generated.cs +++ b/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> GetMyOrdersAsync(GetMyOrdersInput input) + { + return await RequestAsync>(nameof(GetMyOrdersAsync), new ClientProxyRequestTypeValue + { + { typeof(GetMyOrdersInput), input } + }); + } + + public virtual async Task GetByOrderNoAsync(int orderNo) + { + return await RequestAsync(nameof(GetByOrderNoAsync), new ClientProxyRequestTypeValue + { + { typeof(int), orderNo } + }); + } + public virtual async Task CreateAsync(OrderCreateDto input) { return await RequestAsync(nameof(CreateAsync), new ClientProxyRequestTypeValue diff --git a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/Ordering-generate-proxy.json b/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/ordering-generate-proxy.json similarity index 55% rename from services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/Ordering-generate-proxy.json rename to services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/ordering-generate-proxy.json index 2d618d12..ecfb20cf 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/ClientProxies/Ordering-generate-proxy.json +++ b/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", + "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", diff --git a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/EShopOnAbp.OrderingService.HttpApi.Client.csproj b/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/EShopOnAbp.OrderingService.HttpApi.Client.csproj index 2732b332..e376a960 100644 --- a/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/EShopOnAbp.OrderingService.HttpApi.Client.csproj +++ b/services/ordering/src/EShopOnAbp.OrderingService.HttpApi.Client/EShopOnAbp.OrderingService.HttpApi.Client.csproj @@ -17,4 +17,8 @@ + + + + diff --git a/services/ordering/test/EShopOnAbp.OrderingService.Application.Tests/Orders/OrderApplication_Tests.cs b/services/ordering/test/EShopOnAbp.OrderingService.Application.Tests/Orders/OrderApplication_Tests.cs new file mode 100644 index 00000000..64d10435 --- /dev/null +++ b/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(); + _currentUser = GetRequiredService(); + _orderAppService = GetRequiredService(); + } + protected override void AfterAddApplication(IServiceCollection services) + { + _currentUser = Substitute.For(); + 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() + { + 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(); + } +} \ No newline at end of file diff --git a/services/ordering/test/EShopOnAbp.OrderingService.Domain.Tests/Orders/OrderManager_Tests.cs b/services/ordering/test/EShopOnAbp.OrderingService.Domain.Tests/Orders/OrderManager_Tests.cs index 78708aae..7a37be0e 100644 --- a/services/ordering/test/EShopOnAbp.OrderingService.Domain.Tests/Orders/OrderManager_Tests.cs +++ b/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; diff --git a/services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Orders/OrderRepository_Tests.cs b/services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Orders/OrderRepository_Tests.cs new file mode 100644 index 00000000..dd60c26f --- /dev/null +++ b/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 +{ + private readonly TestData _testData; + private readonly IOrderRepository _orderRepository; + private readonly IOrderingServiceDbContext _dbContext; + private readonly OrderManager _orderManager; + + public OrderRepository_Tests() + { + _orderManager = GetRequiredService(); + _dbContext = GetRequiredService(); + _orderRepository = GetRequiredService(); + _testData = GetRequiredService(); + } + + [Fact] + public async Task Should_Get_OrderStatus() + { + var dbSet = _dbContext.Set(); + 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); + } +} \ No newline at end of file diff --git a/services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Samples/SampleRepository_Tests.cs b/services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Samples/SampleRepository_Tests.cs deleted file mode 100644 index 6044bab4..00000000 --- a/services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Samples/SampleRepository_Tests.cs +++ /dev/null @@ -1,12 +0,0 @@ -using EShopOnAbp.OrderingService.Samples; - -namespace EShopOnAbp.OrderingService.EntityFrameworkCore.Samples -{ - public class SampleRepository_Tests : SampleRepository_Tests - { - /* Don't write custom repository tests here, instead write to - * the base class. - * One exception can be some specific tests related to EF core. - */ - } -} diff --git a/services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceDataSeedContributor.cs b/services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceDataSeedContributor.cs deleted file mode 100644 index c606e6fa..00000000 --- a/services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceDataSeedContributor.cs +++ /dev/null @@ -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; - } - } - } -} diff --git a/services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceTestBaseModule.cs b/services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceTestBaseModule.cs index 3080b0d0..987e47bf 100644 --- a/services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceTestBaseModule.cs +++ b/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(options => + { + options.Contributors.Remove(); + options.Contributors.AddLast(typeof(OrderingServiceTestDataSeedContributor)); + }); } public override void OnApplicationInitialization(ApplicationInitializationContext context) @@ -39,4 +48,4 @@ namespace EShopOnAbp.OrderingService }); } } -} +} \ No newline at end of file diff --git a/services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceTestDataSeedContributor.cs b/services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceTestDataSeedContributor.cs new file mode 100644 index 00000000..4b2e3aa3 --- /dev/null +++ b/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 + ); + } + } +} \ No newline at end of file diff --git a/services/ordering/test/EShopOnAbp.OrderingService.TestBase/Product.cs b/services/ordering/test/EShopOnAbp.OrderingService.TestBase/Product.cs new file mode 100644 index 00000000..39a4d6ee --- /dev/null +++ b/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; } +} \ No newline at end of file diff --git a/services/ordering/test/EShopOnAbp.OrderingService.TestBase/TestData.cs b/services/ordering/test/EShopOnAbp.OrderingService.TestBase/TestData.cs new file mode 100644 index 00000000..506dd5e7 --- /dev/null +++ b/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"; + } +} \ No newline at end of file diff --git a/services/ordering/test/EShopOnAbp.OrderingService.TestBase/TestProducts.cs b/services/ordering/test/EShopOnAbp.OrderingService.TestBase/TestProducts.cs new file mode 100644 index 00000000..357c1f08 --- /dev/null +++ b/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 _products; + private readonly Random _random = new(); + + public TestProducts() + { + _products = new List(); + using (StreamReader r = new StreamReader("../../../../EShopOnAbp.OrderingService.TestBase/products.json")) + { + string json = r.ReadToEnd(); + _products = JsonConvert.DeserializeObject>(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; + } +} \ No newline at end of file diff --git a/services/ordering/test/EShopOnAbp.OrderingService.TestBase/products.json b/services/ordering/test/EShopOnAbp.OrderingService.TestBase/products.json new file mode 100644 index 00000000..2d52a8b7 --- /dev/null +++ b/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 + } +] \ No newline at end of file diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestCreationDto.cs b/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestCreationDto.cs index 0dcce09f..5584c680 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestCreationDto.cs +++ b/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 Products { get; set; } } diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestDto.cs b/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestDto.cs index 62dbaf9d..40631e8f 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.Application.Contracts/PaymentRequests/PaymentRequestDto.cs +++ b/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; } diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs index a3266fe6..28bac790 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs +++ b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestAppService.cs @@ -27,7 +27,7 @@ namespace EShopOnAbp.PaymentService.PaymentRequests public virtual async Task 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( diff --git a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestByPassAppService.cs b/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestByPassAppService.cs index cc9488cc..1c032844 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.Application/PaymentRequests/PaymentRequestByPassAppService.cs +++ b/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); } } -} +} \ No newline at end of file diff --git a/services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestCompletedEto.cs b/services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestCompletedEto.cs index dab8dfd7..468242a7 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestCompletedEto.cs +++ b/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; } diff --git a/services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestFailedEto.cs b/services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestFailedEto.cs index 1e847b18..18d0c361 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.Domain.Shared/PaymentRequests/PaymentRequestFailedEto.cs +++ b/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; } } diff --git a/services/payment/src/EShopOnAbp.PaymentService.Domain/PaymentRequests/PaymentRequest.cs b/services/payment/src/EShopOnAbp.PaymentService.Domain/PaymentRequests/PaymentRequest.cs index 343cc1bc..e6f1528a 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.Domain/PaymentRequests/PaymentRequest.cs +++ b/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 }); diff --git a/services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/EntityFrameworkCore/PaymentServiceDbContextModelCreatingExtensions.cs b/services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/EntityFrameworkCore/PaymentServiceDbContextModelCreatingExtensions.cs index cf97fca8..73da676f 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/EntityFrameworkCore/PaymentServiceDbContextModelCreatingExtensions.cs +++ b/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); }); diff --git a/services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/20220107135728_Added-OrderNo.Designer.cs b/services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/20220107135728_Added-OrderNo.Designer.cs new file mode 100644 index 00000000..1d54e67c --- /dev/null +++ b/services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/20220107135728_Added-OrderNo.Designer.cs @@ -0,0 +1,140 @@ +// +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("Id") + .HasColumnType("uuid"); + + b.Property("BuyerId") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(3) + .HasColumnType("character varying(3)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FailReason") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("OrderId") + .IsRequired() + .HasMaxLength(36) + .HasColumnType("character varying(36)"); + + b.Property("OrderNo") + .HasColumnType("integer"); + + b.Property("State") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("PaymentRequests"); + }); + + modelBuilder.Entity("EShopOnAbp.PaymentService.PaymentRequests.PaymentRequestProduct", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PaymentRequestId") + .HasColumnType("uuid"); + + b.Property("Quantity") + .HasColumnType("integer"); + + b.Property("ReferenceId") + .HasColumnType("text"); + + b.Property("TotalPrice") + .HasColumnType("numeric"); + + b.Property("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 + } + } +} diff --git a/services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/20220107135728_Added-OrderNo.cs b/services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/20220107135728_Added-OrderNo.cs new file mode 100644 index 00000000..7430d2b1 --- /dev/null +++ b/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( + name: "OrderNo", + table: "PaymentRequests", + type: "integer", + nullable: false, + defaultValue: 0); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "OrderNo", + table: "PaymentRequests"); + } + } +} diff --git a/services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/PaymentServiceDbContextModelSnapshot.cs b/services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/PaymentServiceDbContextModelSnapshot.cs index 387b0bb8..426cd7ac 100644 --- a/services/payment/src/EShopOnAbp.PaymentService.EntityFrameworkCore/Migrations/PaymentServiceDbContextModelSnapshot.cs +++ b/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("OrderNo") + .HasColumnType("integer"); + b.Property("State") .HasColumnType("integer"); diff --git a/shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/en.json b/shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/en.json index f9a57b29..1c51d29c 100644 --- a/shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/en.json +++ b/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", diff --git a/shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/tr.json b/shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/tr.json index a010152d..238cb336 100644 --- a/shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/tr.json +++ b/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ş",