diff --git a/README.md b/README.md index a0f00e3dd4..f1d11395f6 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -# A simple, cross platform, modularized ecommerce system built on .NET Core [![Join the chat at https://gitter.im/simplcommerce/SimplCommerce](https://badges.gitter.im/simplcommerce/SimplCommerce.svg)](https://gitter.im/simplcommerce/SimplCommerce?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +# A simple, cross platform, modulith ecommerce system built on .NET Core [![Join the chat at https://gitter.im/simplcommerce/SimplCommerce](https://badges.gitter.im/simplcommerce/SimplCommerce.svg)](https://gitter.im/simplcommerce/SimplCommerce?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fsimplcommerce%2FSimplCommerce.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fsimplcommerce%2FSimplCommerce?ref=badge_shield) ## High level architecture -![SimpleCommerce - Modular architecture](https://raw.githubusercontent.com/simplcommerce/SimplCommerce/master/modular-architecture.png) +![SimpleCommerce - Modulith architecture](https://raw.githubusercontent.com/simplcommerce/SimplCommerce/master/modular-architecture.png) ## Build Status | Build server | Platform | Status | @@ -25,11 +26,24 @@ Continuous deployment: https://ci.simplcommerce.com #### Prerequisites - SQL Server -- Visual Studio 2022 +- Visual Studio 2022 and .NET 8 #### Steps to run -- Update the connection string in appsettings.json in SimplCommerce.WebHost +- Update the connection string: Open appsettings.json in src/SimplCommerce.WebHost. + The default is configured for a local SQL Server + ```json + { + "DefaultConnection": "Server=.;Database=SimplCommerce;Trusted_Connection=True;TrustServerCertificate=true" + } + ``` + If you are using Visual Studio LocalDB, change it to + ```json + { + "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=SimplCommerce;Trusted_Connection=True;TrustServerCertificate=true;MultipleActiveResultSets=true" + } + ``` +- Ensure you have a database named `SimplCommerce` created in your SQL instance, or change the `Database` name in the connection string to match your environment. - Build the whole solution. - In Solution Explorer, make sure that SimplCommerce.WebHost is selected as the Startup Project - Open the Package Manager Console Window and make sure that SimplCommerce.WebHost is selected as the Default project. Then type "Update-Database" then press "Enter". This action will create the database schema. @@ -41,21 +55,21 @@ Continuous deployment: https://ci.simplcommerce.com #### Prerequisite - PostgreSQL -- [.NET Core SDK 6.0](https://www.microsoft.com/net/download/all) -- Entity Framework Core (`dotnet tool install --global dotnet-ef`) +- [.NET Core SDK 8.0](https://www.microsoft.com/net/download/all) +- Entity Framework Core Tools (`dotnet tool install --global dotnet-ef`) #### Steps to run - Update the connection string in appsettings.json in SimplCommerce.WebHost. - Run the simpl-build.sh file by issuing the following command: "sudo ./simpl-build.sh". For ubuntu 18: "sudo bash simpl-build.sh" - In the terminal, navigate to "src/SimplCommerce.WebHost" and type "dotnet run" and then hit "Enter". -- Open http://localhost:5000 in the browser. The back-office can be accessed via /Admin using the following built-in account: admin@simplcommerce.com, 1qazZAQ! +- Open http://localhost:49206 in the browser. The back-office can be accessed via /Admin using the following built-in account: admin@simplcommerce.com, 1qazZAQ! ## Technologies and frameworks used: -- ASP.NET MVC Core 6.0 -- Entity Framework Core 6.0 -- ASP.NET Identity Core 6.0 +- ASP.NET Core +- Entity Framework Core +- ASP.NET Identity Core - Angular 1.6.3 - MediatR 7.0.0 for domain event @@ -100,3 +114,6 @@ Become a sponsor and get your logo on our README on Github with a link to your s ## License SimplCommerce is licensed under the Apache 2.0 license. + + +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fsimplcommerce%2FSimplCommerce.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fsimplcommerce%2FSimplCommerce?ref=badge_large) \ No newline at end of file diff --git a/SimplCommerce.Module.WishList.Tests.Controllers/GlobalUsings.cs b/SimplCommerce.Module.WishList.Tests.Controllers/GlobalUsings.cs new file mode 100644 index 0000000000..9df1d42179 --- /dev/null +++ b/SimplCommerce.Module.WishList.Tests.Controllers/GlobalUsings.cs @@ -0,0 +1 @@ +global using Xunit; diff --git a/SimplCommerce.Module.WishList.Tests.Controllers/SimplCommerce.Module.WishList.Tests.Controllers.csproj b/SimplCommerce.Module.WishList.Tests.Controllers/SimplCommerce.Module.WishList.Tests.Controllers.csproj new file mode 100644 index 0000000000..d6b402a0e3 --- /dev/null +++ b/SimplCommerce.Module.WishList.Tests.Controllers/SimplCommerce.Module.WishList.Tests.Controllers.csproj @@ -0,0 +1,31 @@ + + + + net8.0 + enable + enable + false + true + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/simpl-build.sh b/simpl-build.sh old mode 100644 new mode 100755 diff --git a/src/Modules/SimplCommerce.Module.Catalog/Areas/Catalog/Views/Product/ProductDetail.cshtml b/src/Modules/SimplCommerce.Module.Catalog/Areas/Catalog/Views/Product/ProductDetail.cshtml index fcac14b389..bb339674e7 100644 --- a/src/Modules/SimplCommerce.Module.Catalog/Areas/Catalog/Views/Product/ProductDetail.cshtml +++ b/src/Modules/SimplCommerce.Module.Catalog/Areas/Catalog/Views/Product/ProductDetail.cshtml @@ -199,6 +199,31 @@
@Localizer["Out of stock"]
+ +
+
+
+ @if (User.Identity.IsAuthenticated) + { +

Subscribe and we'll notify you when the product is back in stock.

+
+ + + +
+ } + else + { +

Leave your email and we'll notify you when the product is in stock

+
+ + + +
+ } +
+
+
}
diff --git a/src/Modules/SimplCommerce.Module.Catalog/Data/CatalogCustomModelBuilder.cs b/src/Modules/SimplCommerce.Module.Catalog/Data/CatalogCustomModelBuilder.cs index f5920f6f15..567de4a802 100644 --- a/src/Modules/SimplCommerce.Module.Catalog/Data/CatalogCustomModelBuilder.cs +++ b/src/Modules/SimplCommerce.Module.Catalog/Data/CatalogCustomModelBuilder.cs @@ -37,7 +37,8 @@ public void Build(ModelBuilder modelBuilder) modelBuilder.Entity().HasData( new AppSetting("Catalog.ProductPageSize") { Module = "Catalog", IsVisibleInCommonSettingPage = true, Value = "10" }, - new AppSetting("Catalog.IsProductPriceIncludeTax") { Module = "Catalog", IsVisibleInCommonSettingPage = true, Value = "true" } + new AppSetting("Catalog.IsProductPriceIncludeTax") { Module = "Catalog", IsVisibleInCommonSettingPage = true, Value = "true" }, + new AppSetting("Catalog.MinimumProductQuantityForHighlighting") { Module = "Catalog", IsVisibleInCommonSettingPage = true, Value = "5" } ); modelBuilder.Entity().HasData( diff --git a/src/Modules/SimplCommerce.Module.Catalog/wwwroot/product-detail.js b/src/Modules/SimplCommerce.Module.Catalog/wwwroot/product-detail.js index dc4995ae96..e3f61b2db6 100644 --- a/src/Modules/SimplCommerce.Module.Catalog/wwwroot/product-detail.js +++ b/src/Modules/SimplCommerce.Module.Catalog/wwwroot/product-detail.js @@ -71,4 +71,22 @@ $(document).ready(function () { }); } }); + + $("#subscribeBackInStock").on('click', function (e) { + e.preventDefault(); + var $form = $(this).closest("form"), + productId = $(this).closest("form").find('input[name=productId]').val(), + customerEmail = $(this).closest("form").find('input[name=customerEmail]').val(); + + var that = this; + $.post($form.attr('action'), $form.serializeArray()) + .done(function (result) { + $(that).closest('.back-in-stock-subscribe').html('Thank you. We\'ll notify you.'); + }) + .fail(function (result) { + if (result.status === 409) { + $(that).closest('.back-in-stock-subscribe').html('You\'ve already subscribed.'); + } + }); + }); }); diff --git a/src/Modules/SimplCommerce.Module.Checkouts/Areas/Checkouts/ViewModels/CheckoutItemVm.cs b/src/Modules/SimplCommerce.Module.Checkouts/Areas/Checkouts/ViewModels/CheckoutItemVm.cs index ef6f02e04b..c4058bd457 100644 --- a/src/Modules/SimplCommerce.Module.Checkouts/Areas/Checkouts/ViewModels/CheckoutItemVm.cs +++ b/src/Modules/SimplCommerce.Module.Checkouts/Areas/Checkouts/ViewModels/CheckoutItemVm.cs @@ -26,6 +26,8 @@ public CheckoutItemVm(ICurrencyService currencyService) public string ProductImage { get; set; } + public CalculatedProductPrice CalculatedProductPrice { get; set; } + public decimal ProductPrice { get; set; } public string ProductPriceString => _currencyService.FormatCurrency(ProductPrice); diff --git a/src/Modules/SimplCommerce.Module.Checkouts/Services/CheckoutService.cs b/src/Modules/SimplCommerce.Module.Checkouts/Services/CheckoutService.cs index 7a9eaa278c..0a356a025a 100644 --- a/src/Modules/SimplCommerce.Module.Checkouts/Services/CheckoutService.cs +++ b/src/Modules/SimplCommerce.Module.Checkouts/Services/CheckoutService.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using SimplCommerce.Infrastructure.Data; +using SimplCommerce.Module.Catalog.Services; using SimplCommerce.Module.Checkouts.Areas.Checkouts.ViewModels; using SimplCommerce.Module.Checkouts.Models; using SimplCommerce.Module.Core.Models; @@ -26,6 +27,7 @@ public class CheckoutService : ICheckoutService private readonly IMediaService _mediaService; private readonly ICouponService _couponService; private readonly bool _isProductPriceIncludeTax; + private readonly IProductPricingService _productPriceService; public CheckoutService( IRepositoryWithTypedId checkoutRepository, @@ -36,7 +38,8 @@ public CheckoutService( ICurrencyService currencyService, IMediaService mediaService, ICouponService couponService, - IConfiguration config) + IConfiguration config, + IProductPricingService productPriceService) { _checkoutRepository = checkoutRepository; _userAddressRepository = userAddressRepository; @@ -47,6 +50,7 @@ public CheckoutService( _mediaService = mediaService; _couponService = couponService; _isProductPriceIncludeTax = config.GetValue("Catalog.IsProductPriceIncludeTax"); + _productPriceService = productPriceService; } public async Task Create(long customerId, long createdById, IList cartItems, string couponCode) @@ -182,6 +186,7 @@ public async Task GetCheckoutDetails(Guid checkoutId) Id = x.Id, ProductId = x.ProductId, ProductName = x.Product.Name, + CalculatedProductPrice = _productPriceService.CalculateProductPrice(x.Product), ProductPrice = x.Product.Price, ProductStockQuantity = x.Product.StockQuantity, ProductStockTrackingIsEnabled = x.Product.StockTrackingIsEnabled, @@ -191,7 +196,7 @@ public async Task GetCheckoutDetails(Guid checkoutId) VariationOptions = CheckoutItemVm.GetVariationOption(x.Product) }).ToList(); - checkoutVm.SubTotal = checkoutVm.Items.Sum(x => x.Quantity * x.ProductPrice); + checkoutVm.SubTotal = checkoutVm.Items.Sum(x => x.Quantity * (x.CalculatedProductPrice.OldPrice ?? x.ProductPrice)); if (!string.IsNullOrWhiteSpace(checkoutVm.CouponCode)) { var cartInfoForCoupon = new CartInfoForCoupon @@ -209,6 +214,10 @@ public async Task GetCheckoutDetails(Guid checkoutId) } } + checkoutVm.Discount += checkoutVm.Items + .Where(x => x.CalculatedProductPrice.OldPrice.HasValue) + .Sum(x => x.Quantity * (x.CalculatedProductPrice.OldPrice.Value - x.CalculatedProductPrice.Price)); + return checkoutVm; } } diff --git a/src/Modules/SimplCommerce.Module.Core/Areas/Core/Views/HomeAdmin/Index.cshtml b/src/Modules/SimplCommerce.Module.Core/Areas/Core/Views/HomeAdmin/Index.cshtml index 5d2cee37ff..3467e765d7 100644 --- a/src/Modules/SimplCommerce.Module.Core/Areas/Core/Views/HomeAdmin/Index.cshtml +++ b/src/Modules/SimplCommerce.Module.Core/Areas/Core/Views/HomeAdmin/Index.cshtml @@ -238,8 +238,8 @@
-
-
+
+

© @DateTime.Now.Year - SimplCommerce

diff --git a/src/Modules/SimplCommerce.Module.Core/Extensions/IWorkContext.cs b/src/Modules/SimplCommerce.Module.Core/Extensions/IWorkContext.cs index b84c5b8930..6cf5cff920 100644 --- a/src/Modules/SimplCommerce.Module.Core/Extensions/IWorkContext.cs +++ b/src/Modules/SimplCommerce.Module.Core/Extensions/IWorkContext.cs @@ -5,6 +5,8 @@ namespace SimplCommerce.Module.Core.Extensions { public interface IWorkContext { + string GetCurrentHostName(); + Task GetCurrentUser(); } } diff --git a/src/Modules/SimplCommerce.Module.Core/Extensions/WorkContext.cs b/src/Modules/SimplCommerce.Module.Core/Extensions/WorkContext.cs index 4e0b463021..9829e1788e 100644 --- a/src/Modules/SimplCommerce.Module.Core/Extensions/WorkContext.cs +++ b/src/Modules/SimplCommerce.Module.Core/Extensions/WorkContext.cs @@ -33,6 +33,8 @@ public WorkContext(UserManager userManager, _configuration = configuration; } + public string GetCurrentHostName() => _httpContext.Request.Host.Value; + public async Task GetCurrentUser() { if (_currentUser != null) diff --git a/src/Modules/SimplCommerce.Module.Core/wwwroot/admin/admin-core.css b/src/Modules/SimplCommerce.Module.Core/wwwroot/admin/admin-core.css index 110d8a9bad..dd0abedb9f 100644 --- a/src/Modules/SimplCommerce.Module.Core/wwwroot/admin/admin-core.css +++ b/src/Modules/SimplCommerce.Module.Core/wwwroot/admin/admin-core.css @@ -1,5 +1,7 @@ body { - height: auto; + height: 100%; + display:flex; + flex-direction: column; } .inline { @@ -208,4 +210,15 @@ td>span.glyphicon-remove { .btn-translate { margin-right: 3px; } - \ No newline at end of file + +.body-content-custom { + width: 100% !important; + margin: 0 !important; + flex: 1; + display: flex; + flex-direction:column; +} + +.ui-view-content { + flex: 1; +} \ No newline at end of file diff --git a/src/Modules/SimplCommerce.Module.Core/wwwroot/site.css b/src/Modules/SimplCommerce.Module.Core/wwwroot/site.css index b2cf5d90c4..2ddbc03b2b 100644 --- a/src/Modules/SimplCommerce.Module.Core/wwwroot/site.css +++ b/src/Modules/SimplCommerce.Module.Core/wwwroot/site.css @@ -1,4 +1,14 @@ /* Set widths on the form inputs since otherwise they're 100% wide */ +html { + height: 100%; +} + +body { + height: 100%; + display: flex; + flex-direction: column; +} + input, select, textarea { @@ -143,6 +153,7 @@ li.nav-item-group, li.nav-item-group a { } .footer-content { + padding-top: 20px; margin-top: 30px; background-color: #eee; } diff --git a/src/Modules/SimplCommerce.Module.DinkToPdf/SimplCommerce.Module.DinkToPdf.csproj b/src/Modules/SimplCommerce.Module.DinkToPdf/SimplCommerce.Module.DinkToPdf.csproj index ae73498bbd..34bca2b313 100644 --- a/src/Modules/SimplCommerce.Module.DinkToPdf/SimplCommerce.Module.DinkToPdf.csproj +++ b/src/Modules/SimplCommerce.Module.DinkToPdf/SimplCommerce.Module.DinkToPdf.csproj @@ -6,4 +6,17 @@ + + + libwkhtmltox.dll + libwkhtmltox.so + libwkhtmltox.dylib + + 64bit + 32bit + + + + + \ No newline at end of file diff --git a/src/Modules/SimplCommerce.Module.DinkToPdf/lib/32bit/libwkhtmltox.dll b/src/Modules/SimplCommerce.Module.DinkToPdf/lib/32bit/libwkhtmltox.dll new file mode 100644 index 0000000000..c5e529e21a Binary files /dev/null and b/src/Modules/SimplCommerce.Module.DinkToPdf/lib/32bit/libwkhtmltox.dll differ diff --git a/src/Modules/SimplCommerce.Module.DinkToPdf/lib/32bit/libwkhtmltox.dylib b/src/Modules/SimplCommerce.Module.DinkToPdf/lib/32bit/libwkhtmltox.dylib new file mode 100644 index 0000000000..7ff7ac6224 Binary files /dev/null and b/src/Modules/SimplCommerce.Module.DinkToPdf/lib/32bit/libwkhtmltox.dylib differ diff --git a/src/Modules/SimplCommerce.Module.DinkToPdf/lib/32bit/libwkhtmltox.so b/src/Modules/SimplCommerce.Module.DinkToPdf/lib/32bit/libwkhtmltox.so new file mode 100644 index 0000000000..802f1dfeeb Binary files /dev/null and b/src/Modules/SimplCommerce.Module.DinkToPdf/lib/32bit/libwkhtmltox.so differ diff --git a/src/Modules/SimplCommerce.Module.DinkToPdf/lib/64bit/libwkhtmltox.dll b/src/Modules/SimplCommerce.Module.DinkToPdf/lib/64bit/libwkhtmltox.dll new file mode 100644 index 0000000000..98a007bbc7 Binary files /dev/null and b/src/Modules/SimplCommerce.Module.DinkToPdf/lib/64bit/libwkhtmltox.dll differ diff --git a/src/Modules/SimplCommerce.Module.DinkToPdf/lib/64bit/libwkhtmltox.dylib b/src/Modules/SimplCommerce.Module.DinkToPdf/lib/64bit/libwkhtmltox.dylib new file mode 100644 index 0000000000..0263cad663 Binary files /dev/null and b/src/Modules/SimplCommerce.Module.DinkToPdf/lib/64bit/libwkhtmltox.dylib differ diff --git a/src/Modules/SimplCommerce.Module.DinkToPdf/lib/64bit/libwkhtmltox.so b/src/Modules/SimplCommerce.Module.DinkToPdf/lib/64bit/libwkhtmltox.so new file mode 100644 index 0000000000..eecc8834af Binary files /dev/null and b/src/Modules/SimplCommerce.Module.DinkToPdf/lib/64bit/libwkhtmltox.so differ diff --git a/src/Modules/SimplCommerce.Module.EmailSenderSmtp/SimplCommerce.Module.EmailSenderSmtp.csproj b/src/Modules/SimplCommerce.Module.EmailSenderSmtp/SimplCommerce.Module.EmailSenderSmtp.csproj index 4eaf81e8b9..235e559f7d 100644 --- a/src/Modules/SimplCommerce.Module.EmailSenderSmtp/SimplCommerce.Module.EmailSenderSmtp.csproj +++ b/src/Modules/SimplCommerce.Module.EmailSenderSmtp/SimplCommerce.Module.EmailSenderSmtp.csproj @@ -2,7 +2,7 @@ - + diff --git a/src/Modules/SimplCommerce.Module.Inventory/Areas/Inventory/Controllers/StockApiController.cs b/src/Modules/SimplCommerce.Module.Inventory/Areas/Inventory/Controllers/StockApiController.cs index dbe2be3596..0370f9635d 100644 --- a/src/Modules/SimplCommerce.Module.Inventory/Areas/Inventory/Controllers/StockApiController.cs +++ b/src/Modules/SimplCommerce.Module.Inventory/Areas/Inventory/Controllers/StockApiController.cs @@ -20,17 +20,21 @@ public class StockApiController : Controller { private readonly IRepository _stockRepository; private readonly IStockService _stockService; + private readonly IStockSubscriptionService _stockSubscriptionService; private readonly IWorkContext _workContext; private readonly IRepository _warehouseRepository; private readonly IRepository _stockHistoryRepository; + private readonly IRepository _backInStockSubscriptionRepository; - public StockApiController(IRepository stockRepository, IStockService stockService, IWorkContext workContext, IRepository warehouseRepository, IRepository stockHistoryRepository) + public StockApiController(IRepository stockRepository, IStockService stockService, IWorkContext workContext, IRepository warehouseRepository, IRepository stockHistoryRepository, IRepository backInStockSubscriptionRepository, IStockSubscriptionService stockSubscriptionService) { _stockRepository = stockRepository; _stockService = stockService; _workContext = workContext; _warehouseRepository = warehouseRepository; _stockHistoryRepository = stockHistoryRepository; + _backInStockSubscriptionRepository = backInStockSubscriptionRepository; + _stockSubscriptionService = stockSubscriptionService; } [HttpPost("grid")] @@ -135,5 +139,20 @@ public async Task GetStockHistory(int warehouseId, int productId) return Ok(stockHistory); } + + [AllowAnonymous] + [HttpPost("back-in-stock")] + public async Task BackInStockSubscribe(long productId, string customerEmail) + { + if (await _backInStockSubscriptionRepository.Query() + .AnyAsync(o => o.ProductId == productId && o.CustomerEmail == customerEmail)) + { + return Conflict(); + } + + await _stockSubscriptionService.ProductBackInStockSubscribeAsync(productId, customerEmail); + + return Ok(); + } } } diff --git a/src/Modules/SimplCommerce.Module.Inventory/Areas/Inventory/Views/EmailTemplates/ProductBackInStockEmail.cshtml b/src/Modules/SimplCommerce.Module.Inventory/Areas/Inventory/Views/EmailTemplates/ProductBackInStockEmail.cshtml new file mode 100644 index 0000000000..4589c25ffa --- /dev/null +++ b/src/Modules/SimplCommerce.Module.Inventory/Areas/Inventory/Views/EmailTemplates/ProductBackInStockEmail.cshtml @@ -0,0 +1,30 @@ +@using SimplCommerce.Module.Catalog.Models +@using SimplCommerce.Module.Core.Extensions +@using SimplCommerce.Module.Core.Services + +@inject IWorkContext _workContext +@inject IMediaService _mediaService + +@{ + Layout = null; + + var hostName = _workContext.GetCurrentHostName(); + var thumbnailUrl = _mediaService.GetThumbnailUrl(Model.ThumbnailImage); +} + +@model SimplCommerce.Module.Catalog.Models.Product + +
+ Hi, @Model.Name in now available. + Get in now before it out of stock again. +
+
+
+ +

@Model.Name

+

$1000

+
+ + View product + +
diff --git a/src/Modules/SimplCommerce.Module.Inventory/Event/ProductBackInStock.cs b/src/Modules/SimplCommerce.Module.Inventory/Event/ProductBackInStock.cs new file mode 100644 index 0000000000..d1bd8ffafa --- /dev/null +++ b/src/Modules/SimplCommerce.Module.Inventory/Event/ProductBackInStock.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MediatR; + +namespace SimplCommerce.Module.Inventory.Event +{ + public class ProductBackInStock : INotification + { + public long ProductId { get; set; } + } +} diff --git a/src/Modules/SimplCommerce.Module.Inventory/Event/ProductBackInStockSendEmailHandler.cs b/src/Modules/SimplCommerce.Module.Inventory/Event/ProductBackInStockSendEmailHandler.cs new file mode 100644 index 0000000000..e2a9c8441b --- /dev/null +++ b/src/Modules/SimplCommerce.Module.Inventory/Event/ProductBackInStockSendEmailHandler.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using SimplCommerce.Module.Inventory.Services; + +namespace SimplCommerce.Module.Inventory.Event +{ + public class ProductBackInStockSendEmailHandler : INotificationHandler + { + public readonly IStockSubscriptionService _stockSubscriptionService; + + public ProductBackInStockSendEmailHandler(IStockSubscriptionService stockSubscriptionService) + => _stockSubscriptionService = stockSubscriptionService; + + public async Task Handle(ProductBackInStock notification, CancellationToken cancellationToken) + => await _stockSubscriptionService.ProductBackInStockSendNotificationsAsync(notification.ProductId); + } +} diff --git a/src/Modules/SimplCommerce.Module.Inventory/Models/ProductBackInStockSubscription.cs b/src/Modules/SimplCommerce.Module.Inventory/Models/ProductBackInStockSubscription.cs new file mode 100644 index 0000000000..df745367c4 --- /dev/null +++ b/src/Modules/SimplCommerce.Module.Inventory/Models/ProductBackInStockSubscription.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SimplCommerce.Infrastructure.Models; + +namespace SimplCommerce.Module.Inventory.Models +{ + public class ProductBackInStockSubscription : EntityBase + { + public long ProductId { get; set; } + + public string CustomerEmail { get; set; } + } +} diff --git a/src/Modules/SimplCommerce.Module.Inventory/ModuleInitializer.cs b/src/Modules/SimplCommerce.Module.Inventory/ModuleInitializer.cs index cc6fb11e1b..0a618743a0 100644 --- a/src/Modules/SimplCommerce.Module.Inventory/ModuleInitializer.cs +++ b/src/Modules/SimplCommerce.Module.Inventory/ModuleInitializer.cs @@ -4,6 +4,10 @@ using SimplCommerce.Infrastructure.Modules; using SimplCommerce.Module.Inventory.Services; using SimplCommerce.Infrastructure; +using MediatR; +using SimplCommerce.Module.Catalog.Events; +using SimplCommerce.Module.Core.Events; +using SimplCommerce.Module.Inventory.Event; namespace SimplCommerce.Module.Inventory { @@ -12,6 +16,8 @@ public class ModuleInitializer : IModuleInitializer public void ConfigureServices(IServiceCollection serviceCollection) { serviceCollection.AddTransient(); + serviceCollection.AddTransient(); + serviceCollection.AddTransient, ProductBackInStockSendEmailHandler>(); GlobalConfiguration.RegisterAngularModule("simplAdmin.inventory"); } diff --git a/src/Modules/SimplCommerce.Module.Inventory/Services/IStockSubscriptionService.cs b/src/Modules/SimplCommerce.Module.Inventory/Services/IStockSubscriptionService.cs new file mode 100644 index 0000000000..8abf8a7711 --- /dev/null +++ b/src/Modules/SimplCommerce.Module.Inventory/Services/IStockSubscriptionService.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimplCommerce.Module.Inventory.Services +{ + public interface IStockSubscriptionService + { + Task ProductBackInStockSubscribeAsync(long productId, string customerEmail); + + Task ProductBackInStockSendNotificationsAsync(long productId); + } +} diff --git a/src/Modules/SimplCommerce.Module.Inventory/Services/StockService.cs b/src/Modules/SimplCommerce.Module.Inventory/Services/StockService.cs index 100a7a7b15..1f2927dddc 100644 --- a/src/Modules/SimplCommerce.Module.Inventory/Services/StockService.cs +++ b/src/Modules/SimplCommerce.Module.Inventory/Services/StockService.cs @@ -1,9 +1,11 @@ using System; using System.Linq; using System.Threading.Tasks; +using MediatR; using Microsoft.EntityFrameworkCore; using SimplCommerce.Infrastructure.Data; using SimplCommerce.Module.Catalog.Models; +using SimplCommerce.Module.Inventory.Event; using SimplCommerce.Module.Inventory.Models; namespace SimplCommerce.Module.Inventory.Services @@ -13,12 +15,14 @@ public class StockService : IStockService private readonly IRepository _stockRepository; private readonly IRepository _productRepository; private readonly IRepository _stockHistoryRepository; + private readonly IMediator _mediator; - public StockService(IRepository stockRepository, IRepository productRepository, IRepository stockHistoryRepository) + public StockService(IRepository stockRepository, IRepository productRepository, IRepository stockHistoryRepository, IMediator mediator) { _stockRepository = stockRepository; _productRepository = productRepository; _stockHistoryRepository = stockHistoryRepository; + _mediator = mediator; } public async Task AddAllProduct(Warehouse warehouse) @@ -44,8 +48,15 @@ public async Task UpdateStock(StockUpdateRequest stockUpdateRequest) var product = await _productRepository.Query().FirstOrDefaultAsync(x => x.Id == stockUpdateRequest.ProductId); var stock = await _stockRepository.Query().FirstOrDefaultAsync(x => x.ProductId == stockUpdateRequest.ProductId && x.WarehouseId == stockUpdateRequest.WarehouseId); - stock.Quantity = stock.Quantity + stockUpdateRequest.AdjustedQuantity; - product.StockQuantity = product.StockQuantity + stockUpdateRequest.AdjustedQuantity; + var adjustedQuantity = stockUpdateRequest.AdjustedQuantity; + if (adjustedQuantity < 0 && Math.Abs(adjustedQuantity) > stock.Quantity) + { + adjustedQuantity = -stock.Quantity; + } + + var prevStockQuantity = product.StockQuantity; + stock.Quantity = stock.Quantity + adjustedQuantity; + product.StockQuantity = product.StockQuantity + adjustedQuantity; var stockHistory = new StockHistory { ProductId = stockUpdateRequest.ProductId, @@ -58,6 +69,11 @@ public async Task UpdateStock(StockUpdateRequest stockUpdateRequest) _stockHistoryRepository.Add(stockHistory); await _stockHistoryRepository.SaveChangesAsync(); + + if (prevStockQuantity <= 0 && product.StockQuantity > 0) + { + await _mediator.Publish(new ProductBackInStock { ProductId = product.Id }); + } } } } diff --git a/src/Modules/SimplCommerce.Module.Inventory/Services/StockSubscriptionService.cs b/src/Modules/SimplCommerce.Module.Inventory/Services/StockSubscriptionService.cs new file mode 100644 index 0000000000..46c4384fa4 --- /dev/null +++ b/src/Modules/SimplCommerce.Module.Inventory/Services/StockSubscriptionService.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.EntityFrameworkCore; +using SimplCommerce.Infrastructure.Data; +using SimplCommerce.Infrastructure.Web; +using SimplCommerce.Module.Catalog.Models; +using SimplCommerce.Module.Core.Models; +using SimplCommerce.Module.Core.Services; +using SimplCommerce.Module.Inventory.Models; + +namespace SimplCommerce.Module.Inventory.Services +{ + public class StockSubscriptionService : IStockSubscriptionService + { + private readonly IRepository _productBackInStockSubscriptionRepository; + private readonly IRepository _productRepository; + private readonly IEmailSender _emailSender; + private readonly IRazorViewRenderer _viewRender; + + public StockSubscriptionService(IRepository backInStockSubscriptionRepository, IEmailSender emailSender, IRazorViewRenderer viewRender, IRepository productRepository) + { + _productBackInStockSubscriptionRepository = backInStockSubscriptionRepository; + _emailSender = emailSender; + _viewRender = viewRender; + _productRepository = productRepository; + } + + public async Task ProductBackInStockSendNotificationsAsync(long productId) + { + var subscriptions = await _productBackInStockSubscriptionRepository + .Query() + .Where(o => o.ProductId == productId) + .ToListAsync(); + + var product = await _productRepository + .Query() + .Where(o => o.Id == productId) + .Include(o => o.ThumbnailImage) + .FirstOrDefaultAsync(); + + var emailBody = await _viewRender.RenderViewToStringAsync("/Areas/Inventory/Views/EmailTemplates/ProductBackInStockEmail.cshtml", product); + var emailSubject = $"Back in stock"; + + foreach (var subscription in subscriptions) + { + await _emailSender.SendEmailAsync(subscription.CustomerEmail, emailSubject, emailBody, true); + + _productBackInStockSubscriptionRepository.Remove(subscription); + } + + await _productBackInStockSubscriptionRepository.SaveChangesAsync(); + } + + public async Task ProductBackInStockSubscribeAsync(long productId, string customerEmail) + { + var subscription = new ProductBackInStockSubscription + { + ProductId = productId, + CustomerEmail = customerEmail + }; + + _productBackInStockSubscriptionRepository.Add(subscription); + + await _productBackInStockSubscriptionRepository.SaveChangesAsync(); + } + } +} diff --git a/src/Modules/SimplCommerce.Module.Inventory/wwwroot/admin/stock/stock-form.html b/src/Modules/SimplCommerce.Module.Inventory/wwwroot/admin/stock/stock-form.html index 6b4db26aac..3430c8f48c 100644 --- a/src/Modules/SimplCommerce.Module.Inventory/wwwroot/admin/stock/stock-form.html +++ b/src/Modules/SimplCommerce.Module.Inventory/wwwroot/admin/stock/stock-form.html @@ -47,7 +47,9 @@

{{::vm.translate.get('Stock management for warehouse')}} {{ vm.selec - + {{item.productName}} {{item.productSku}} {{item.quantity}} diff --git a/src/Modules/SimplCommerce.Module.Inventory/wwwroot/admin/stock/stock-form.js b/src/Modules/SimplCommerce.Module.Inventory/wwwroot/admin/stock/stock-form.js index 574aeada08..6a615d337f 100644 --- a/src/Modules/SimplCommerce.Module.Inventory/wwwroot/admin/stock/stock-form.js +++ b/src/Modules/SimplCommerce.Module.Inventory/wwwroot/admin/stock/stock-form.js @@ -2,9 +2,9 @@ (function () { angular .module('simplAdmin.inventory') - .controller('StockFormCtrl', ['stockService', 'translateService', StockFormCtrl]); + .controller('StockFormCtrl', ['configurationService','stockService', 'translateService', StockFormCtrl]); - function StockFormCtrl(stockService, translateService) { + function StockFormCtrl(configurationService, stockService, translateService) { var vm = this; vm.tableStateRef = {}; vm.translate = translateService; @@ -42,5 +42,11 @@ vm.selectedWarehouse = vm.warehouses[0]; } }); + + configurationService.getSettings().then(function (result) { + const minimumQuantityForHighlighting = result.data.find(o => o.key === "Catalog.MinimumProductQuantityForHighlighting"); + + vm.minimumQuantityForHighlighting = minimumQuantityForHighlighting ? minimumQuantityForHighlighting.value : 0; + }); } })(); diff --git a/src/Modules/SimplCommerce.Module.Orders/Areas/Orders/Views/Shared/Components/OrderSummary/Default.cshtml b/src/Modules/SimplCommerce.Module.Orders/Areas/Orders/Views/Shared/Components/OrderSummary/Default.cshtml index 14d2f51c8f..5bf283b60a 100644 --- a/src/Modules/SimplCommerce.Module.Orders/Areas/Orders/Views/Shared/Components/OrderSummary/Default.cshtml +++ b/src/Modules/SimplCommerce.Module.Orders/Areas/Orders/Views/Shared/Components/OrderSummary/Default.cshtml @@ -23,7 +23,16 @@ } @item.Quantity - @item.ProductPriceString + + @if(item.CalculatedProductPrice.OldPrice.HasValue) + { + @item.CalculatedProductPrice.OldPriceString + } + else + { + @item.CalculatedProductPrice.PriceString + } + } diff --git a/src/Modules/SimplCommerce.Module.Orders/Services/OrderService.cs b/src/Modules/SimplCommerce.Module.Orders/Services/OrderService.cs index 9aaf5f337e..6ed129707f 100644 --- a/src/Modules/SimplCommerce.Module.Orders/Services/OrderService.cs +++ b/src/Modules/SimplCommerce.Module.Orders/Services/OrderService.cs @@ -18,6 +18,7 @@ using SimplCommerce.Module.Checkouts.Services; using SimplCommerce.Module.Checkouts.Models; using SimplCommerce.Module.Checkouts.Areas.Checkouts.ViewModels; +using SimplCommerce.Module.Catalog.Services; namespace SimplCommerce.Module.Orders.Services { @@ -33,6 +34,7 @@ public class OrderService : IOrderService private readonly IShippingPriceService _shippingPriceService; private readonly IRepository _userAddressRepository; private readonly IMediator _mediator; + private readonly IProductPricingService _productPricingService; public OrderService(IRepository orderRepository, ICouponService couponService, @@ -43,7 +45,8 @@ public OrderService(IRepository orderRepository, IRepositoryWithTypedId checkoutRepository, IShippingPriceService shippingPriceService, IRepository userAddressRepository, - IMediator mediator) + IMediator mediator, + IProductPricingService productPricingService) { _orderRepository = orderRepository; _couponService = couponService; @@ -55,6 +58,7 @@ public OrderService(IRepository orderRepository, _shippingPriceService = shippingPriceService; _userAddressRepository = userAddressRepository; _mediator = mediator; + _productPricingService = productPricingService; } public async Task> CreateOrder(Guid checkoutId, string paymentMethod, decimal paymentFeeAmount, OrderStatus orderStatus = OrderStatus.New) @@ -206,7 +210,8 @@ public async Task> CreateOrder(Guid checkoutId, string paymentMeth PaymentMethod = paymentMethod, PaymentFeeAmount = paymentFeeAmount }; - + using (var transaction = _checkoutItemRepository.BeginTransaction()) + { foreach (var checkoutItem in checkout.CheckoutItems) { if (!checkoutItem.Product.IsAllowToOrder || !checkoutItem.Product.IsPublished || checkoutItem.Product.IsDeleted) @@ -220,7 +225,10 @@ public async Task> CreateOrder(Guid checkoutId, string paymentMeth } var taxPercent = await _taxService.GetTaxPercent(checkoutItem.Product.TaxClassId, shippingAddress.CountryId, shippingAddress.StateOrProvinceId, shippingAddress.ZipCode); - var productPrice = checkoutItem.Product.Price; + + var calculatedProductPrice = _productPricingService.CalculateProductPrice(checkoutItem.Product); + + var productPrice = calculatedProductPrice.OldPrice ?? calculatedProductPrice.Price; if (checkout.IsProductPriceIncludeTax) { productPrice = productPrice / (1 + (taxPercent / 100)); @@ -241,6 +249,11 @@ public async Task> CreateOrder(Guid checkoutId, string paymentMeth orderItem.DiscountAmount = discountedItem.DiscountAmount; } + if (calculatedProductPrice.OldPrice.HasValue) + { + orderItem.DiscountAmount += orderItem.Quantity * (calculatedProductPrice.OldPrice.Value - calculatedProductPrice.Price); + } + order.AddOrderItem(orderItem); if (checkoutItem.Product.StockTrackingIsEnabled) { @@ -248,11 +261,15 @@ public async Task> CreateOrder(Guid checkoutId, string paymentMeth } } + _checkoutItemRepository.SaveChanges(); + transaction.Commit(); + } + order.OrderStatus = orderStatus; order.OrderNote = checkout.OrderNote; order.CouponCode = checkingDiscountResult.CouponCode; order.CouponRuleName = checkout.CouponRuleName; - order.DiscountAmount = checkingDiscountResult.DiscountAmount; + order.DiscountAmount = checkingDiscountResult.DiscountAmount + order.OrderItems.Sum(x => x.DiscountAmount); order.ShippingFeeAmount = shippingMethod.Price; order.ShippingMethod = shippingMethod.Name; order.TaxAmount = order.OrderItems.Sum(x => x.TaxAmount); diff --git a/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/Components/BraintreeLandingViewComponent.cs b/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/Components/BraintreeLandingViewComponent.cs index 9610deddfb..861bed0824 100644 --- a/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/Components/BraintreeLandingViewComponent.cs +++ b/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/Components/BraintreeLandingViewComponent.cs @@ -57,7 +57,8 @@ public async Task InvokeAsync(Guid checkoutId) { ClientToken = await _braintreeConfiguration.GetClientToken(), Amount = zeroDecimalAmount, - ISOCurrencyCode = regionInfo.ISOCurrencySymbol + ISOCurrencyCode = regionInfo.ISOCurrencySymbol, + CheckoutId = checkoutId, }; return View(this.GetViewPath(), model); diff --git a/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/Controllers/BraintreeController.cs b/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/Controllers/BraintreeController.cs index 546cc63041..a1a463185d 100644 --- a/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/Controllers/BraintreeController.cs +++ b/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/Controllers/BraintreeController.cs @@ -49,18 +49,17 @@ public BraintreeController( } [HttpPost] - public async Task Charge(string nonce) + public async Task Charge(string nonce, Guid checkoutId) { var gateway = await _braintreeConfiguration.BraintreeGateway(); var curentUser = await _workContext.GetCurrentUser(); - //TODO: pass checkout Id here - var cart = await _checkoutService.GetCheckoutDetails(Guid.NewGuid()); + + var cart = await _checkoutService.GetCheckoutDetails(checkoutId); if(cart == null) { return NotFound(); } - var checkoutId = Guid.NewGuid(); var orderCreateResult = await _orderService.CreateOrder(checkoutId, PaymentProviderHelper.BraintreeProviderId, 0, OrderStatus.PendingPayment); if (!orderCreateResult.Success) diff --git a/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/ViewModels/BraintreeCheckoutForm.cs b/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/ViewModels/BraintreeCheckoutForm.cs index a5e9016f25..7baf5e6edc 100644 --- a/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/ViewModels/BraintreeCheckoutForm.cs +++ b/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/ViewModels/BraintreeCheckoutForm.cs @@ -1,4 +1,6 @@ -namespace SimplCommerce.Module.PaymentBraintree.Areas.PaymentBraintree.ViewModels +using System; + +namespace SimplCommerce.Module.PaymentBraintree.Areas.PaymentBraintree.ViewModels { public class BraintreeCheckoutForm { @@ -7,5 +9,7 @@ public class BraintreeCheckoutForm public decimal Amount { get; set; } public string ISOCurrencyCode { get; set; } + + public Guid CheckoutId { get; set; } } } diff --git a/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/Views/Shared/Components/BraintreeLanding/Default.cshtml b/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/Views/Shared/Components/BraintreeLanding/Default.cshtml index 965c24dca6..00e55a8dd8 100644 --- a/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/Views/Shared/Components/BraintreeLanding/Default.cshtml +++ b/src/Modules/SimplCommerce.Module.PaymentBraintree/Areas/PaymentBraintree/Views/Shared/Components/BraintreeLanding/Default.cshtml @@ -45,7 +45,7 @@ var request = $.ajax({ type: 'POST', url: '@Url.Action("Charge", "Braintree", new { Area = "PaymentBraintree" })', - data: { nonce: payload.nonce } + data: { nonce: payload.nonce, checkoutId: "@Model.CheckoutId" } }) .done(function (data) { window.location = "/checkout/success?orderId="+ data.orderId; diff --git a/src/Modules/SimplCommerce.Module.PaymentMomo/Areas/PaymentMomo/Components/MomoLandingViewComponent.cs b/src/Modules/SimplCommerce.Module.PaymentMomo/Areas/PaymentMomo/Components/MomoLandingViewComponent.cs index ad8d14004a..1dd5f4deaf 100644 --- a/src/Modules/SimplCommerce.Module.PaymentMomo/Areas/PaymentMomo/Components/MomoLandingViewComponent.cs +++ b/src/Modules/SimplCommerce.Module.PaymentMomo/Areas/PaymentMomo/Components/MomoLandingViewComponent.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; @@ -19,13 +20,14 @@ public MomoLandingViewComponent(IRepositoryWithTypedId _paymentProviderRepository = paymentProviderRepository; } - public async Task InvokeAsync() + public async Task InvokeAsync(Guid checkoutId) { var momoProvider = await _paymentProviderRepository.Query().FirstOrDefaultAsync(x => x.Id == PaymentProviderHelper.MomoPaymentProviderId); var momoSetting = JsonConvert.DeserializeObject(momoProvider.AdditionalSettings); var model = new MomoCheckoutForm(); model.PaymentFee = momoSetting.PaymentFee; + model.CheckoutId = checkoutId; return View(this.GetViewPath(), model); } diff --git a/src/Modules/SimplCommerce.Module.PaymentMomo/Areas/PaymentMomo/Controllers/MomoPaymentController.cs b/src/Modules/SimplCommerce.Module.PaymentMomo/Areas/PaymentMomo/Controllers/MomoPaymentController.cs index eb765343c1..75ac6fd04c 100644 --- a/src/Modules/SimplCommerce.Module.PaymentMomo/Areas/PaymentMomo/Controllers/MomoPaymentController.cs +++ b/src/Modules/SimplCommerce.Module.PaymentMomo/Areas/PaymentMomo/Controllers/MomoPaymentController.cs @@ -54,17 +54,17 @@ public MomoPaymentController( _setting = new Lazy(GetSetting()); } - public async Task MomoCheckout() + [HttpPost] + public async Task MomoCheckout(Guid checkoutId) { var currentUser = await _workContext.GetCurrentUser(); - //TODO: pass checkout Id here - var cart = await _checkoutService.GetCheckoutDetails(Guid.Empty); + + var cart = await _checkoutService.GetCheckoutDetails(checkoutId); if (cart == null) { return NotFound(); } - var checkoutId = Guid.NewGuid(); var orderCreateResult = await _orderService.CreateOrder(checkoutId, "MomoPayment", 0, OrderStatus.PendingPayment); if (!orderCreateResult.Success) diff --git a/src/Modules/SimplCommerce.Module.PaymentMomo/Areas/PaymentMomo/Views/Shared/Components/MomoLanding/Default.cshtml b/src/Modules/SimplCommerce.Module.PaymentMomo/Areas/PaymentMomo/Views/Shared/Components/MomoLanding/Default.cshtml index a7534242fe..298f81fdb6 100644 --- a/src/Modules/SimplCommerce.Module.PaymentMomo/Areas/PaymentMomo/Views/Shared/Components/MomoLanding/Default.cshtml +++ b/src/Modules/SimplCommerce.Module.PaymentMomo/Areas/PaymentMomo/Views/Shared/Components/MomoLanding/Default.cshtml @@ -1,7 +1,10 @@ - +@model SimplCommerce.Module.PaymentMomo.ViewModels.MomoCheckoutForm + +
+
diff --git a/src/Modules/SimplCommerce.Module.PaymentMomo/ViewModels/MomoCheckoutForm.cs b/src/Modules/SimplCommerce.Module.PaymentMomo/ViewModels/MomoCheckoutForm.cs index 401a655dda..32558b89ff 100644 --- a/src/Modules/SimplCommerce.Module.PaymentMomo/ViewModels/MomoCheckoutForm.cs +++ b/src/Modules/SimplCommerce.Module.PaymentMomo/ViewModels/MomoCheckoutForm.cs @@ -1,7 +1,11 @@ -namespace SimplCommerce.Module.PaymentMomo.ViewModels +using System; + +namespace SimplCommerce.Module.PaymentMomo.ViewModels { public class MomoCheckoutForm { public decimal PaymentFee { get; set; } + + public Guid CheckoutId { get; set; } } } diff --git a/src/Modules/SimplCommerce.Module.PaymentNganLuong/Areas/PaymentNganLuong/Components/NganLuongLandingViewComponent.cs b/src/Modules/SimplCommerce.Module.PaymentNganLuong/Areas/PaymentNganLuong/Components/NganLuongLandingViewComponent.cs index f14cc1c80b..5b1e390c61 100644 --- a/src/Modules/SimplCommerce.Module.PaymentNganLuong/Areas/PaymentNganLuong/Components/NganLuongLandingViewComponent.cs +++ b/src/Modules/SimplCommerce.Module.PaymentNganLuong/Areas/PaymentNganLuong/Components/NganLuongLandingViewComponent.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; @@ -19,12 +20,12 @@ public NganLuongLandingViewComponent(IRepositoryWithTypedId InvokeAsync() + public async Task InvokeAsync(Guid checkoutId) { var nganLuongProvider = await _paymentProviderRepository.Query().FirstOrDefaultAsync(x => x.Id == PaymentProviderHelper.NganLuongPaymentProviderId); var nganLuongSetting = JsonConvert.DeserializeObject(nganLuongProvider.AdditionalSettings); - return View(this.GetViewPath()); + return View(this.GetViewPath(), checkoutId); } } } diff --git a/src/Modules/SimplCommerce.Module.PaymentNganLuong/Areas/PaymentNganLuong/Controllers/NganLuongController.cs b/src/Modules/SimplCommerce.Module.PaymentNganLuong/Areas/PaymentNganLuong/Controllers/NganLuongController.cs index 8642dcf1ec..f78c55a834 100644 --- a/src/Modules/SimplCommerce.Module.PaymentNganLuong/Areas/PaymentNganLuong/Controllers/NganLuongController.cs +++ b/src/Modules/SimplCommerce.Module.PaymentNganLuong/Areas/PaymentNganLuong/Controllers/NganLuongController.cs @@ -60,17 +60,16 @@ public IActionResult PaymentMethods() } [HttpPost] - public async Task SubmitPayment(string paymentOption, string bankCode) + public async Task SubmitPayment(string paymentOption, string bankCode, Guid checkoutId) { var currentUser = await _workContext.GetCurrentUser(); - //TODO: pass checkout Id here - var cart = await _checkoutService.GetCheckoutDetails(Guid.Empty); + + var cart = await _checkoutService.GetCheckoutDetails(checkoutId); if (cart == null) { return NotFound(); } - var checkoutId = Guid.NewGuid(); var orderCreateResult = await _orderService.CreateOrder(checkoutId, "NganLuong", 0, OrderStatus.PendingPayment); if (!orderCreateResult.Success) diff --git a/src/Modules/SimplCommerce.Module.PaymentNganLuong/Areas/PaymentNganLuong/Views/NganLuong/PaymentMethods.cshtml b/src/Modules/SimplCommerce.Module.PaymentNganLuong/Areas/PaymentNganLuong/Views/NganLuong/PaymentMethods.cshtml index 4315501d71..e650ff8312 100644 --- a/src/Modules/SimplCommerce.Module.PaymentNganLuong/Areas/PaymentNganLuong/Views/NganLuong/PaymentMethods.cshtml +++ b/src/Modules/SimplCommerce.Module.PaymentNganLuong/Areas/PaymentNganLuong/Views/NganLuong/PaymentMethods.cshtml @@ -346,6 +346,7 @@

+