From 849426c1aebe20df72aca1328c5f49f2aba5db22 Mon Sep 17 00:00:00 2001 From: Loretta Date: Sat, 23 Nov 2024 18:57:44 +0100 Subject: [PATCH] improvements, fixes, etc... --- .../AuctionPluginAdminController.cs | 4 +- .../Components/AuctionPublicViewComponent.cs | 2 +- .../Components/AuctionViewComponent.cs | 2 +- .../Controllers/AuctionController.cs | 2 +- .../Domains/DataLayer/AuctionBidDbTable.cs | 16 +- .../Domains/DataLayer/AuctionDbTable.cs | 4 +- .../DataLayer/ProductToAuctionDbTable.cs | 33 +++- .../Entities/ProductToAuctionMapping.cs | 9 +- .../Domains/Enums/AuctionStatus.cs | 3 +- .../EventConsumers/AuctionEventConsumer.cs | 24 +++ .../Hubs/SignalRMessageHandler.cs | 182 ++++++++++-------- .../Infrastructure/PluginNopStartup.cs | 4 +- .../Nop.Plugin.Misc.AuctionPlugin.csproj | 1 + .../Services/AuctionService.cs | 70 +++++-- .../Services/EventConsumer.cs | 137 ------------- .../Services/IAuctionService.cs | 7 +- 16 files changed, 246 insertions(+), 254 deletions(-) create mode 100644 Nop.Plugin.Misc.AuctionPlugin/Domains/EventConsumers/AuctionEventConsumer.cs delete mode 100644 Nop.Plugin.Misc.AuctionPlugin/Services/EventConsumer.cs diff --git a/Nop.Plugin.Misc.AuctionPlugin/Areas/Admin/Controllers/AuctionPluginAdminController.cs b/Nop.Plugin.Misc.AuctionPlugin/Areas/Admin/Controllers/AuctionPluginAdminController.cs index ed978e8..63d9c0b 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Areas/Admin/Controllers/AuctionPluginAdminController.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Areas/Admin/Controllers/AuctionPluginAdminController.cs @@ -155,7 +155,7 @@ public class AuctionPluginAdminController : BasePluginController var model = new TestPageViewModel(); var auctions = await _auctionService.GetAllAuctionsAsync(); - var auctionDtoWithProducts = await _auctionService.GetAuctionDtoWithProductByIdAsync(1, 4); + var auctionDtoWithProducts = await _auctionService.GetAuctionDtoWithProductByIdAsync(1, 4, false); model.Message = $"Teszt üzenet; Auctions count: {auctions.Count}; Products count: {auctionDtoWithProducts.ProductToAuctionDtos.Count}"; @@ -167,7 +167,7 @@ public class AuctionPluginAdminController : BasePluginController { _logger.Information("AssignProductToAuction has been called"); - var result = await _auctionService.GetProductToAuctionsByAuctionIdAsync(1); + var result = await _auctionService.GetProductToAuctionsByAuctionIdAsync(1, false); return Ok(result.ToJson()); } diff --git a/Nop.Plugin.Misc.AuctionPlugin/Components/AuctionPublicViewComponent.cs b/Nop.Plugin.Misc.AuctionPlugin/Components/AuctionPublicViewComponent.cs index a773500..740caf0 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Components/AuctionPublicViewComponent.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Components/AuctionPublicViewComponent.cs @@ -111,7 +111,7 @@ public class AuctionPublicViewComponent : NopViewComponent return Content(string.Empty); } - var auctionDto = (await _auctionService.GetAuctionDtoByIdAsync(productToAuction.AuctionId)); + var auctionDto = (await _auctionService.GetAuctionDtoByIdAsync(productToAuction.AuctionId, false, false)); auctionDto.ProductToAuctionDtos.Add(productToAuction); var productBidBoxViewModel = new ProductBidBoxViewModel(auctionDto); diff --git a/Nop.Plugin.Misc.AuctionPlugin/Components/AuctionViewComponent.cs b/Nop.Plugin.Misc.AuctionPlugin/Components/AuctionViewComponent.cs index f94eba3..a2dbbd8 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Components/AuctionViewComponent.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Components/AuctionViewComponent.cs @@ -94,7 +94,7 @@ public class AuctionViewComponent : NopViewComponent return Content(string.Empty); } - var auctionDto = (await _auctionService.GetAuctionDtoByIdAsync(productToAuctionDtoMappings.FirstOrDefault()!.AuctionId)); + var auctionDto = (await _auctionService.GetAuctionDtoByIdAsync(productToAuctionDtoMappings.FirstOrDefault()!.AuctionId, false, false)); auctionDto.ProductToAuctionDtos.AddRange(productToAuctionDtoMappings); var model = new AuctionPublicInfoModel(auctionDto); diff --git a/Nop.Plugin.Misc.AuctionPlugin/Controllers/AuctionController.cs b/Nop.Plugin.Misc.AuctionPlugin/Controllers/AuctionController.cs index 6007a5d..ecb2092 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Controllers/AuctionController.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Controllers/AuctionController.cs @@ -74,7 +74,7 @@ public class AuctionController : BasePluginController public async Task LiveScreen(int auctionId) { - var auctionDto = await _auctionService.GetAuctionDtoByIdAsync(auctionId); + var auctionDto = await _auctionService.GetAuctionDtoByIdAsync(auctionId, false, false); var productToAuctionDtoMappings = await _auctionService.GetProductToAuctionsByAuctionIdAsync(auctionId, false); diff --git a/Nop.Plugin.Misc.AuctionPlugin/Domains/DataLayer/AuctionBidDbTable.cs b/Nop.Plugin.Misc.AuctionPlugin/Domains/DataLayer/AuctionBidDbTable.cs index d220bfe..2a599a7 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Domains/DataLayer/AuctionBidDbTable.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Domains/DataLayer/AuctionBidDbTable.cs @@ -4,12 +4,24 @@ using Nop.Core.Configuration; using Nop.Core.Events; using Nop.Data; using Nop.Plugin.Misc.AuctionPlugin.Domains.Entities; +using Nop.Services.Logging; namespace Nop.Plugin.Misc.AuctionPlugin.Domains.DataLayer; -public class AuctionBidDbTable: MgDbTableBase +public class AuctionBidDbTable : MgDbTableBase { - public AuctionBidDbTable(IEventPublisher eventPublisher, INopDataProvider dataProvider, IShortTermCacheManager shortTermCacheManager, IStaticCacheManager staticCacheManager, AppSettings appSettings) : base(eventPublisher, dataProvider, shortTermCacheManager, staticCacheManager, appSettings) + public AuctionBidDbTable(IEventPublisher eventPublisher, INopDataProvider dataProvider, IShortTermCacheManager shortTermCacheManager, IStaticCacheManager staticCacheManager, AppSettings appSettings, ILogger logger) + : base(eventPublisher, dataProvider, shortTermCacheManager, staticCacheManager, appSettings, logger) { } + + public Task GetLastAuctionBidByProductToAuctionIdAsync(int prouctToAuctionId) + { + return Table.Where(x => x.ProductAuctionMappingId == prouctToAuctionId).OrderByDescending(x => x.Id).FirstOrDefaultAsync(); + } + + public IQueryable GetByProductToAuctionIdAsync(int prouctToAuctionId) + { + return Table.Where(x => x.ProductAuctionMappingId == prouctToAuctionId); + } } \ No newline at end of file diff --git a/Nop.Plugin.Misc.AuctionPlugin/Domains/DataLayer/AuctionDbTable.cs b/Nop.Plugin.Misc.AuctionPlugin/Domains/DataLayer/AuctionDbTable.cs index 7400e82..26041c4 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Domains/DataLayer/AuctionDbTable.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Domains/DataLayer/AuctionDbTable.cs @@ -5,12 +5,14 @@ using Nop.Core.Configuration; using Nop.Core.Events; using Nop.Data; using Nop.Plugin.Misc.AuctionPlugin.Domains.Entities; +using Nop.Services.Logging; namespace Nop.Plugin.Misc.AuctionPlugin.Domains.DataLayer; public class AuctionDbTable: MgDbTableBase { - public AuctionDbTable(IEventPublisher eventPublisher, INopDataProvider dataProvider, IShortTermCacheManager shortTermCacheManager, IStaticCacheManager staticCacheManager, AppSettings appSettings) : base(eventPublisher, dataProvider, shortTermCacheManager, staticCacheManager, appSettings) + public AuctionDbTable(IEventPublisher eventPublisher, INopDataProvider dataProvider, IShortTermCacheManager shortTermCacheManager, IStaticCacheManager staticCacheManager, AppSettings appSettings, ILogger logger) + : base(eventPublisher, dataProvider, shortTermCacheManager, staticCacheManager, appSettings, logger) { } diff --git a/Nop.Plugin.Misc.AuctionPlugin/Domains/DataLayer/ProductToAuctionDbTable.cs b/Nop.Plugin.Misc.AuctionPlugin/Domains/DataLayer/ProductToAuctionDbTable.cs index aa51e5e..fefde9b 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Domains/DataLayer/ProductToAuctionDbTable.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Domains/DataLayer/ProductToAuctionDbTable.cs @@ -1,17 +1,22 @@ using Mango.Nop.Core.Repositories; +using Microsoft.AspNetCore.Http; using Nop.Core.Caching; using Nop.Core.Configuration; +using Nop.Core.Domain.Catalog; using Nop.Core.Events; using Nop.Data; using Nop.Plugin.Misc.AuctionPlugin.Domains.Entities; using Nop.Plugin.Misc.AuctionPlugin.Domains.Enums; using Nop.Plugin.Misc.AuctionPlugin.Hubs; +using Nop.Services.Events; +using Nop.Services.Logging; namespace Nop.Plugin.Misc.AuctionPlugin.Domains.DataLayer; public class ProductToAuctionDbTable : MgDbTableBase { - public ProductToAuctionDbTable(IEventPublisher eventPublisher, INopDataProvider dataProvider, IShortTermCacheManager shortTermCacheManager, IStaticCacheManager staticCacheManager, AppSettings appSettings) : base(eventPublisher, dataProvider, shortTermCacheManager, staticCacheManager, appSettings) + public ProductToAuctionDbTable(IEventPublisher eventPublisher, INopDataProvider dataProvider, IShortTermCacheManager shortTermCacheManager, IStaticCacheManager staticCacheManager, AppSettings appSettings, ILogger logger) + : base(eventPublisher, dataProvider, shortTermCacheManager, staticCacheManager, appSettings, logger) { } @@ -29,13 +34,31 @@ public class ProductToAuctionDbTable : MgDbTableBase public IQueryable GetByProductId(int productId, bool activeProductOnly = false) { - return Table.Where(x => x.ProductId == productId && - (!activeProductOnly || x.AuctionStatus == AuctionStatus.Active || x.AuctionStatus == AuctionStatus.FirstWarning || x.AuctionStatus == AuctionStatus.SecondWarning/*HasActiveAuctionStatus(x.AuctionStatus)*/)); + return Table.Where(x => x.ProductId == productId && + (!activeProductOnly || x.AuctionStatus == AuctionStatus.Active || x.AuctionStatus == AuctionStatus.FirstWarning || x.AuctionStatus == AuctionStatus.SecondWarning /*HasActiveAuctionStatus(x.AuctionStatus)*/)); } public IQueryable GetProductToAuctionsByAuctionId(int auctionId, bool activeProductOnly = false) { - return Table.Where(x => x.AuctionId == auctionId && - (!activeProductOnly || x.AuctionStatus == AuctionStatus.Active || x.AuctionStatus == AuctionStatus.FirstWarning || x.AuctionStatus == AuctionStatus.SecondWarning/*HasActiveAuctionStatus(x.AuctionStatus)*/)); + return Table.Where(x => x.AuctionId == auctionId && + (!activeProductOnly || x.AuctionStatus == AuctionStatus.Active || x.AuctionStatus == AuctionStatus.FirstWarning || x.AuctionStatus == AuctionStatus.SecondWarning /*HasActiveAuctionStatus(x.AuctionStatus)*/)); + } + + public async Task DeactivateItemByProductId(int productId, decimal basePrice) => await DeactivateItem(await GetByProductId(productId).FirstOrDefaultAsync(), basePrice); + public async Task DeactivateItemById(int productToAuctionId, decimal basePrice) => await DeactivateItem(await GetByIdAsync(productToAuctionId), basePrice); + public async Task DeactivateItem(ProductToAuctionMapping productToAuction, decimal basePrice) + { + if (productToAuction == null) + { + Logger.Error($"ProductToAuctionDbTable.DeactivateItem(); productToAuction == null"); + return; + } + + productToAuction.StartingPrice = basePrice; + productToAuction.CurrentPrice = basePrice; + productToAuction.WinnerCustomerId = 0; + productToAuction.AuctionStatus = AuctionStatus.None; + + await UpdateAsync(productToAuction); } } \ No newline at end of file diff --git a/Nop.Plugin.Misc.AuctionPlugin/Domains/Entities/ProductToAuctionMapping.cs b/Nop.Plugin.Misc.AuctionPlugin/Domains/Entities/ProductToAuctionMapping.cs index 81cf5d4..e7f9b30 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Domains/Entities/ProductToAuctionMapping.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Domains/Entities/ProductToAuctionMapping.cs @@ -2,6 +2,7 @@ using AyCode.Interfaces.Entities; using LinqToDB.Mapping; using Mango.Nop.Core.Entities; +using Newtonsoft.Json; using Nop.Core; using Nop.Plugin.Misc.AuctionPlugin.Domains.Entities.Interfaces; using Nop.Plugin.Misc.AuctionPlugin.Domains.Enums; @@ -14,8 +15,12 @@ public partial class ProductToAuctionMapping : MgEntityBase, IProductToAuctionMa public int AuctionId { get; set; } public int WinnerCustomerId { get; set; } - //[NotMapped] - //[NotColumn] + [NotMapped] + [NotColumn] + [JsonIgnore] + [System.Text.Json.Serialization.JsonIgnore] + public bool IsActiveItem => AuctionStatus is AuctionStatus.Active or AuctionStatus.FirstWarning or AuctionStatus.SecondWarning; + public AuctionStatus AuctionStatus { get; set; } public decimal StartingPrice { get; set; } diff --git a/Nop.Plugin.Misc.AuctionPlugin/Domains/Enums/AuctionStatus.cs b/Nop.Plugin.Misc.AuctionPlugin/Domains/Enums/AuctionStatus.cs index b53dd22..0068e5c 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Domains/Enums/AuctionStatus.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Domains/Enums/AuctionStatus.cs @@ -18,5 +18,6 @@ public enum AuctionStatus : byte FirstWarning = 2, SecondWarning = 4, Sold = 8, - NotSold = 16 + NotSold = 16, + Pause = 32 } \ No newline at end of file diff --git a/Nop.Plugin.Misc.AuctionPlugin/Domains/EventConsumers/AuctionEventConsumer.cs b/Nop.Plugin.Misc.AuctionPlugin/Domains/EventConsumers/AuctionEventConsumer.cs new file mode 100644 index 0000000..4b893a5 --- /dev/null +++ b/Nop.Plugin.Misc.AuctionPlugin/Domains/EventConsumers/AuctionEventConsumer.cs @@ -0,0 +1,24 @@ +using Mango.Nop.Services; +using Microsoft.AspNetCore.Http; +using Nop.Core.Domain.Catalog; +using Nop.Core.Events; +using Nop.Plugin.Misc.AuctionPlugin.Domains.DataLayer; +using Nop.Plugin.Misc.AuctionPlugin.Domains.Enums; + +namespace Nop.Plugin.Misc.AuctionPlugin.Domains.EventConsumers; + +public class AuctionEventConsumer(IHttpContextAccessor httpContextAccessor, AuctionDbContext ctx) : MgEventConsumer(httpContextAccessor) +{ + public override async Task HandleEventAsync(EntityUpdatedEvent eventMessage) + { + //TODO: itt lehetne ciklussal az összes ProductToAuction-re! - J. + var productToAuction = await ctx.ProductToAuctions.GetByProductId(eventMessage.Entity.Id).FirstOrDefaultAsync(); + + if (productToAuction is { AuctionStatus: AuctionStatus.None }) + { + await ctx.ProductToAuctions.DeactivateItem(productToAuction, eventMessage.Entity.Price); + } + + await base.HandleEventAsync(eventMessage); + } +} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AuctionPlugin/Hubs/SignalRMessageHandler.cs b/Nop.Plugin.Misc.AuctionPlugin/Hubs/SignalRMessageHandler.cs index 436118a..5c9e9f1 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Hubs/SignalRMessageHandler.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Hubs/SignalRMessageHandler.cs @@ -1,5 +1,7 @@ using System.Globalization; using AyCode.Core.Extensions; +using AyCode.Utils.Extensions; +using AyCode.Utils.Wrappers; using Nop.Plugin.Misc.AuctionPlugin.Hubs.Messages; using Nop.Plugin.Misc.AuctionPlugin.Models; using Nop.Plugin.Misc.AuctionPlugin.Services; @@ -7,6 +9,7 @@ using Nop.Services.Catalog; using Nop.Services.Logging; using Microsoft.AspNetCore.SignalR; using Nop.Core; +using Nop.Plugin.Misc.AuctionPlugin.Domains.DataLayer.Interfaces; using Nop.Plugin.Misc.AuctionPlugin.Domains.Enums; namespace Nop.Plugin.Misc.AuctionPlugin.Hubs @@ -28,54 +31,50 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs //- DbTransaction-t vhogy megcsinánli! //- NextStepAmount - public class SignalRMessageHandler + public class SignalRMessageHandler(ILogger logger, IProductService productService, AuctionService auctionService, IHubContext hubContext, IWorkContext workContext) { - private readonly ILogger _logger; - private readonly IProductService _productService; - private readonly AuctionService _auctionService; - private readonly IHubContext _hubContext; - private readonly IWorkContext _workContext; - - public SignalRMessageHandler(ILogger logger, IProductService productService, AuctionService auctionService, IHubContext hubContext, IWorkContext workContext) - { - _logger = logger; - _productService = productService; - _auctionService = auctionService; - _hubContext = hubContext; - _workContext = workContext; - } + private readonly Mutex _handleMessageMutex = new(); public async Task HandleMessage(MessageWrapper message) { if (message?.Data == null) { - _logger.Error($"SignalRMessageHandler.HandleMessage(); message?.Data == null"); + logger.Error($"SignalRMessageHandler.HandleMessage(); message?.Data == null"); return; } - await _logger.InformationAsync($"SignalRMessageHandler.HandleMessage(); jsonData: {message.Data}"); + await logger.InformationAsync($"SignalRMessageHandler.HandleMessage(); jsonData: {message.Data}"); - if (message.SenderId <= 0 || message.SenderId != (await _workContext.GetCurrentCustomerAsync()).Id) + if (message.SenderId <= 0 || message.SenderId != (await workContext.GetCurrentCustomerAsync()).Id) { - _logger.Error($"SignalRMessageHandler.HandleMessage(); message.SenderId <= 0 || message.SenderId != (await _workContext.GetCurrentCustomerAsync()).Id; SenderId: {message.SenderId}"); + logger.Error($"SignalRMessageHandler.HandleMessage(); message.SenderId <= 0 || message.SenderId != (await _workContext.GetCurrentCustomerAsync()).Id; SenderId: {message.SenderId}"); return; } - //TODO: lock-olni! - J. - switch (message.MessageType) + using (_handleMessageMutex.UseWaitOne()) { - case "BidRequestMessage": - await HandleBidRequest(message.SenderId, message.Data.JsonTo()); - break; + try + { + switch (message.MessageType) + { + case "BidRequestMessage": + await HandleBidRequest(message.SenderId, message.Data.JsonTo()); + break; - case "AuctionProductStatusRequest": - await HandleProductToAuctionStatusChangedRequest(message.SenderId, message.Data.JsonTo()); - break; + case "AuctionProductStatusRequest": + await HandleProductToAuctionStatusChangedRequest(message.SenderId, message.Data.JsonTo()); + break; - // Add other message types here - default: - await _logger.ErrorAsync($"SignalRMessageHandler.HandleMessage(); Unknown message type; MessageType: {message.MessageType}"); - break; + // Add other message types here + default: + await logger.ErrorAsync($"SignalRMessageHandler.HandleMessage(); Unknown message type; MessageType: {message.MessageType}"); + break; + } + } + catch (Exception ex) + { + logger.Error($"SignalRMessageHandler.HandleMessage(); switch (message.MessageType); MessageType: {message.MessageType}; ex: {ex}"); + } } } @@ -83,65 +82,88 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs { if (auctionProductStatusRequest == null) { - _logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); auctionProductStatusRequest == null"); + logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); auctionProductStatusRequest == null"); return; } try { - await _logger.InformationAsync($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); ProductToAuctionMappingId: {auctionProductStatusRequest.ProductToAuctionId}; Status: {auctionProductStatusRequest.AuctionStatus}({(int)auctionProductStatusRequest.AuctionStatus})"); + await logger.InformationAsync($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); ProductToAuctionMappingId: {auctionProductStatusRequest.ProductToAuctionId}; Status: {auctionProductStatusRequest.AuctionStatus}({(int)auctionProductStatusRequest.AuctionStatus})"); //TODO: if IsAdmin.. - J. //TODO: if nincs aktív item.. - J. - var auction = await _auctionService.GetAuctionDtoByProductToAuctionIdAsync(auctionProductStatusRequest.ProductToAuctionId); + var auction = await auctionService.GetAuctionDtoByProductToAuctionIdAsync(auctionProductStatusRequest.ProductToAuctionId, false); if (auction == null || auction.Closed) { - _logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); auction == null || auction.Closed;"); + logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); (auction == null || auction.Closed); Closed: {auction?.Closed}"); return; } - var productToAuction = await _auctionService.GetProductToAuctionMappingByIdAsync(auctionProductStatusRequest.ProductToAuctionId); + var productToAuction = await auctionService.GetProductToAuctionMappingByIdAsync(auctionProductStatusRequest.ProductToAuctionId); if (productToAuction == null) { - _logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); productToAuction == null"); + logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); (productToAuction == null)"); return; } - switch (auctionProductStatusRequest.AuctionStatus) + //TODO: mi van ha már lezárt a productToAuction? - J. + if (auctionProductStatusRequest.AuctionStatus == AuctionStatus.None) { - case AuctionStatus.Sold: - productToAuction.AuctionStatus = productToAuction.CurrentPrice == productToAuction.StartingPrice ? AuctionStatus.NotSold : AuctionStatus.Sold; - break; - case AuctionStatus.NotSold: - _logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); auctionProductStatusRequest.AuctionStatus == AuctionStatus.NotSold"); - break; - case AuctionStatus.FirstWarning: - case AuctionStatus.SecondWarning: - case AuctionStatus.None: - case AuctionStatus.Active: - default: - productToAuction.AuctionStatus = auctionProductStatusRequest.AuctionStatus; - break; + //TODO: a ProductPrice-t ne változtassuk, mert emiatt nem jó a reset! - J. + productToAuction.AuctionStatus = AuctionStatus.None; + await auctionService.DeactivateProductToAuctionAsync(productToAuction); //TODO: Reset legyen és ne deactivate! - J. } + else + { + switch (auctionProductStatusRequest.AuctionStatus) + { + case AuctionStatus.Pause: + //TODO: - J. + break; - await _auctionService.UpdateProductToAuctionMappingAsync(productToAuction); + case AuctionStatus.Sold: + var lastAuctionBid = await auctionService.GetLastAuctionBidByProductToAuctionIdAsync(productToAuction.Id); + if (lastAuctionBid == null) + { + productToAuction.AuctionStatus = AuctionStatus.NotSold; + break; + } + + productToAuction.AuctionStatus = AuctionStatus.Sold; + productToAuction.WinnerCustomerId = lastAuctionBid.CustomerId; + break; + + case AuctionStatus.NotSold: + logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); (auctionProductStatusRequest.AuctionStatus == AuctionStatus.NotSold)"); + break; + + case AuctionStatus.FirstWarning: + case AuctionStatus.SecondWarning: + case AuctionStatus.Active: + default: + productToAuction.AuctionStatus = auctionProductStatusRequest.AuctionStatus; + break; + } + + await auctionService.UpdateProductToAuctionMappingAsync(productToAuction); + } var productToauctionChangedNotification = new MessageWrapper { MessageType = nameof(ProductToAuctionStatusNotification), SenderId = senderId, - Data = new ProductToAuctionStatusNotification(await _auctionService.GetAuctionDtoByProductToAuctionIdAsync(productToAuction.Id, true)) + Data = new ProductToAuctionStatusNotification(await auctionService.GetAuctionDtoByProductToAuctionIdAsync(productToAuction.Id, true)) { ToasterMessage = "string.Empty", //TODO: - J. }.ToJson() }; - await _hubContext.Clients.All.SendAsync("send", productToauctionChangedNotification.ToJson()); + await hubContext.Clients.All.SendAsync("send", productToauctionChangedNotification.ToJson()); } catch (Exception ex) { - _logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); Error {ex.Message}"); + logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); Error {ex.Message}"); } } @@ -150,63 +172,65 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs { if (bidRequestMessage == null) { - _logger.Error($"SignalRMessageHandler.HandleBidRequest(); bidRequestMessage == null"); + logger.Error($"SignalRMessageHandler.HandleBidRequest(); (bidRequestMessage == null)"); return; } try { - await _logger.InformationAsync($"SignalRMessageHandler.HandleBidRequest(); Bid received; Auction: {bidRequestMessage.AuctionId}; Product: {bidRequestMessage.ProductId}; Bid: {bidRequestMessage.BidPrice}; Customer: {bidRequestMessage.CustomerId}"); + await logger.InformationAsync($"SignalRMessageHandler.HandleBidRequest(); Bid received; Auction: {bidRequestMessage.AuctionId}; Product: {bidRequestMessage.ProductId}; Bid: {bidRequestMessage.BidPrice}; Customer: {bidRequestMessage.CustomerId}"); //CustomerService a = new CustomerService()a.IsGuestAsync() - var customer = await _workContext.GetCurrentCustomerAsync(); + var customer = await workContext.GetCurrentCustomerAsync(); if (customer == null || bidRequestMessage.CustomerId != customer.Id) //|| !customer.Active) //TODO: ??? - J. { - _logger.Error($"SignalRMessageHandler.HandleBidRequest(); customer == null || bidRequestMessage.CustomerId != customer.Id"); + logger.Error($"SignalRMessageHandler.HandleBidRequest(); (customer == null || bidRequestMessage.CustomerId != customer.Id)"); return; } - var auction = await _auctionService.GetAuctionDtoByIdAsync(bidRequestMessage.AuctionId); - if (auction.Closed) + var auction = await auctionService.GetAuctionDtoByIdAsync(bidRequestMessage.AuctionId, false, false); + if (auction == null || auction.Closed) { - _logger.Warning($"SignalRMessageHandler.HandleBidRequest(); auction.Closed"); + logger.Warning($"SignalRMessageHandler.HandleBidRequest(); (auction == null || auction.Closed); Closed: {auction?.Closed}"); return; } - var product = await _productService.GetProductByIdAsync(bidRequestMessage.ProductId); + var activeProductAuction = (await auctionService.GetProductToAuctionByAuctionIdAndProductIdAsync(bidRequestMessage.AuctionId, bidRequestMessage.ProductId, true)).FirstOrDefault(); + if (activeProductAuction is not { IsActiveItem: true } || activeProductAuction.WinnerCustomerId == customer.Id) + { + logger.Warning($"SignalRMessageHandler.HandleBidRequest(); (activeProductAuction is not {{ IsActiveItem: true }} || activeProductAuction.WinnerCustomerId == customer.Id); AuctionStatus: {activeProductAuction?.AuctionStatus}; WinnerCustomerId: {activeProductAuction?.WinnerCustomerId}"); + return; //TODO: - J. + } + + var product = await productService.GetProductByIdAsync(bidRequestMessage.ProductId); if (product == null) { - _logger.Error($"SignalRMessageHandler.HandleBidRequest(); product == null"); + logger.Error($"SignalRMessageHandler.HandleBidRequest(); (product == null)"); return; //ha nincs product vagy exception van, akkor ne broadcast-eljük ki az invalid Bid-et! - J. } - var activeProductAuction = (await _auctionService.GetProductToAuctionByAuctionIdAndProductIdAsync(bidRequestMessage.AuctionId, bidRequestMessage.ProductId, true)).FirstOrDefault(); - if (activeProductAuction == null) //|| productAuction.WinnerCustomerId == customer.Id) - { - _logger.Warning($"SignalRMessageHandler.HandleBidRequest(); activeProductAuction == null"); - return; //TODO: - J. - } - var auctionBid = bidRequestMessage.CreateMainEntity(); auctionBid.ProductAuctionMappingId = activeProductAuction.Id; //TODO: validate the bidprice amount - if (product.Price >= auctionBid.BidPrice) + if (product.Price >= auctionBid.BidPrice || activeProductAuction.CurrentPrice >= auctionBid.BidPrice) { - _logger.Warning($"SignalRMessageHandler.HandleBidRequest(); product.Price >= bidRequestMessage.BidPrice; productPrice: {product.Price}; bidRequestPrice: {auctionBid.BidPrice}"); + logger.Warning($"SignalRMessageHandler.HandleBidRequest(); (product.Price >= bidRequestMessage.BidPrice || activeProductAuction.CurrentPrice >= auctionBid.BidPrice); productPrice: {product.Price}; bidRequestPrice: {auctionBid.BidPrice}; activeProductAuctionPrice: {activeProductAuction.CurrentPrice}"); return; } //save bid - await _auctionService.InsertBidAsync(auctionBid); + await auctionService.InsertBidAsync(auctionBid); //set new price product.Price = bidRequestMessage.BidPrice; - await _productService.UpdateProductAsync(product); + await productService.UpdateProductAsync(product); activeProductAuction.StartingPrice = product.OldPrice; activeProductAuction.CurrentPrice = product.Price; - await _auctionService.UpdateProductToAuctionMappingAsync(activeProductAuction); + activeProductAuction.AuctionStatus = AuctionStatus.Active; + + await auctionService.UpdateProductToAuctionMappingAsync(activeProductAuction); var stepAmount = AuctionService.GetStepAmount(auctionBid.BidPrice); var nextBidPrice = auctionBid.BidPrice + stepAmount; @@ -216,7 +240,7 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs { MessageType = "bidNotification", SenderId = senderId, - Data = new BidNotificationMessage(await _auctionService.GetAuctionDtoByProductToAuctionIdAsync(activeProductAuction.Id, true)) + Data = new BidNotificationMessage(await auctionService.GetAuctionDtoByProductToAuctionIdAsync(activeProductAuction.Id, true)) { ProductName = auctionBid.ProductId.ToString(), CurrentPrice = auctionBid.BidPrice, @@ -226,11 +250,11 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs }.ToJson() }; - await _hubContext.Clients.All.SendAsync("send", bid.ToJson()); + await hubContext.Clients.All.SendAsync("send", bid.ToJson()); } catch (Exception ex) { - _logger.Error($"SignalRMessageHandler.HandleBidRequest(); MessageHandling error: {ex}"); + logger.Error($"SignalRMessageHandler.HandleBidRequest(); MessageHandling error: {ex}"); } } } diff --git a/Nop.Plugin.Misc.AuctionPlugin/Infrastructure/PluginNopStartup.cs b/Nop.Plugin.Misc.AuctionPlugin/Infrastructure/PluginNopStartup.cs index 415710c..69a39c5 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Infrastructure/PluginNopStartup.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Infrastructure/PluginNopStartup.cs @@ -1,4 +1,5 @@ using AyCode.Core.Extensions; +using Mango.Nop.Core; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Razor; @@ -14,6 +15,7 @@ using Nop.Core.Caching; using Nop.Core.Infrastructure; using Nop.Data; using Nop.Plugin.Misc.AuctionPlugin.Domains.DataLayer; +using Nop.Plugin.Misc.AuctionPlugin.Domains.EventConsumers; using Nop.Plugin.Misc.AuctionPlugin.Hubs; using Nop.Plugin.Misc.AuctionPlugin.Services; using Nop.Services.Catalog; @@ -51,7 +53,7 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Infrastructure services.AddScoped(); services.AddScoped(); - services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/Nop.Plugin.Misc.AuctionPlugin/Nop.Plugin.Misc.AuctionPlugin.csproj b/Nop.Plugin.Misc.AuctionPlugin/Nop.Plugin.Misc.AuctionPlugin.csproj index 9bf6545..9f36c44 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Nop.Plugin.Misc.AuctionPlugin.csproj +++ b/Nop.Plugin.Misc.AuctionPlugin/Nop.Plugin.Misc.AuctionPlugin.csproj @@ -113,6 +113,7 @@ + diff --git a/Nop.Plugin.Misc.AuctionPlugin/Services/AuctionService.cs b/Nop.Plugin.Misc.AuctionPlugin/Services/AuctionService.cs index 309ecee..bb5397f 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Services/AuctionService.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Services/AuctionService.cs @@ -1,9 +1,11 @@ using Nop.Core; using Nop.Core.Caching; +using Nop.Core.Domain.Catalog; using Nop.Plugin.Misc.AuctionPlugin.Domains.DataLayer; using Nop.Plugin.Misc.AuctionPlugin.Domains.Dtos; using Nop.Plugin.Misc.AuctionPlugin.Domains.Entities; using Nop.Plugin.Misc.AuctionPlugin.Domains.Enums; +using Nop.Services.Catalog; using Nop.Services.Logging; using Org.BouncyCastle.Crypto; @@ -30,6 +32,7 @@ public class AuctionService : IAuctionService #region Fields private readonly AuctionDbContext _ctx; + private readonly IProductService _productService; private readonly IShortTermCacheManager _shortTermCacheManager; private readonly IStaticCacheManager _staticCacheManager; private readonly IWorkContext _workContext; @@ -48,6 +51,7 @@ public class AuctionService : IAuctionService /// public AuctionService( AuctionDbContext ctx, + IProductService productService, //IRepository auctionRepository, //IRepository productToAuctionRepository, IShortTermCacheManager shortTermCacheManager, @@ -56,6 +60,7 @@ public class AuctionService : IAuctionService ILogger logger) { _ctx = ctx; + _productService = productService; //_customerBidRepository = customerBidRepository; //_auctionRepository = auctionRepository; //_productToAuctionRepository = productToAuctionRepository; @@ -119,7 +124,28 @@ public class AuctionService : IAuctionService return true; } - /// + public async Task DeactivateProductToAuctionByProductId(int productId) + => await DeactivateProductToAuctionAsync(await _ctx.ProductToAuctions.GetByProductId(productId).FirstOrDefaultAsync()); + + public async Task DeactivateProductToAuctionByIdAsync(int productToAuctionId, decimal basePrice = 0) + => await DeactivateProductToAuctionAsync(_ctx.ProductToAuctions.GetById(productToAuctionId), basePrice); + + public async Task DeactivateProductToAuctionAsync(ProductToAuctionMapping productToAuction, decimal basePrice = 0) + { + if (basePrice <= 0) + { + var product = await _productService.GetProductByIdAsync(productToAuction.ProductId); + + if (product == null) _logger.Error($"AuctionService.DeactivateProductToAuctionByIdAsync(); product == null"); + else basePrice = product.Price; + } + + await _ctx.ProductToAuctions.DeactivateItem(productToAuction, basePrice); + } + + public Task GetLastAuctionBidByProductToAuctionIdAsync(int productToAuctionId) => _ctx.AuctionBids.GetLastAuctionBidByProductToAuctionIdAsync(productToAuctionId); + + /// /// Gets all bids /// /// The store identifier; pass 0 to load all records @@ -198,36 +224,44 @@ public class AuctionService : IAuctionService return await _ctx.Auctions.GetAllAuctionsAsync(); } - public async Task> GetProductToAuctionsByAuctionIdAsync(int auctionId, bool onlyActiveItems = false) + public async Task> GetProductToAuctionsByAuctionIdAsync(int auctionId, bool onlyActiveItems) { return await _ctx.ProductToAuctions.GetProductToAuctionsByAuctionId(auctionId, onlyActiveItems).ToListAsync(); } #endregion #endregion - #region Dtots + #region Dtos - public async Task GetAuctionDtoByIdAsync(int auctionId, bool widthProducts = false) + public async Task GetAuctionDtoWithAuctionBids(int auctionId, bool activeProductOnly) { - var auction = await _ctx.Auctions.GetByIdAsync(auctionId); - if (auction == null) return null; + var auctionDto = await GetAuctionDtoByIdAsync(auctionId, true, activeProductOnly); - var auctionDto = new AuctionDto(auction); - - if (widthProducts) + foreach (var auctionDtoProductToAuctionDto in auctionDto.ProductToAuctionDtos) { - auctionDto.ProductToAuctionDtos.AddRange((await GetProductToAuctionDtosByAuctionId(auctionId))); + auctionDtoProductToAuctionDto.AuctionBidDtos.AddRange(await _ctx.AuctionBids.GetByProductToAuctionIdAsync(auctionDtoProductToAuctionDto.Id).OrderByDescending(x => x.Id).Select(x => new AuctionBidDto(x)).ToListAsync()); } return auctionDto; } - public async Task> GetProductToAuctionDtosByAuctionId(int auctionId) + public async Task GetAuctionDtoByIdAsync(int auctionId, bool widthProducts, bool activeProductOnly) { - return (await GetProductToAuctionsByAuctionIdAsync(auctionId)).Select(x => new ProductToAuctionDto(x)).ToList(); + var auction = await _ctx.Auctions.GetByIdAsync(auctionId); + if (auction == null) return null; + + var auctionDto = new AuctionDto(auction); + if (widthProducts) auctionDto.ProductToAuctionDtos.AddRange((await GetProductToAuctionDtosByAuctionId(auctionId, activeProductOnly))); + + return auctionDto; } - public async Task GetAuctionDtoWithProductByIdAsync(int auctionId, int productId, bool activeProductOnly = false) + public async Task> GetProductToAuctionDtosByAuctionId(int auctionId, bool activeProductOnly) + { + return (await GetProductToAuctionsByAuctionIdAsync(auctionId, activeProductOnly)).Select(x => new ProductToAuctionDto(x)).ToList(); + } + + public async Task GetAuctionDtoWithProductByIdAsync(int auctionId, int productId, bool activeProductOnly) { var auction = await _ctx.Auctions.GetByIdAsync(auctionId); if (auction == null) return null; @@ -244,12 +278,12 @@ public class AuctionService : IAuctionService return productToAuction == null ? null : new ProductToAuctionDto(productToAuction); } - public async Task GetAuctionDtoByProductToAuctionIdAsync(int productToAuctionId, bool includeProductToAuctionDto = true) + public async Task GetAuctionDtoByProductToAuctionIdAsync(int productToAuctionId, bool includeProductToAuctionDto) { var productTouctionDto = await GetProductToAuctionDtoByIdAsync(productToAuctionId); if (productTouctionDto == null) return null; - var auctionDto = await GetAuctionDtoByIdAsync(productTouctionDto.AuctionId); //Ez sosem lehet null! - J. + var auctionDto = await GetAuctionDtoByIdAsync(productTouctionDto.AuctionId, false, false); //Ez sosem lehet null! - J. if (includeProductToAuctionDto) auctionDto.ProductToAuctionDtos.Add(productTouctionDto); return auctionDto; @@ -272,18 +306,18 @@ public class AuctionService : IAuctionService return [..await _ctx.ProductToAuctions.GetByProductId(productId).ToListAsync()]; } - public async Task> GetProductToAuctionByAuctionIdAndProductIdAsync(int auctionId, int productId, bool activeProductOnly = false) + public async Task> GetProductToAuctionByAuctionIdAndProductIdAsync(int auctionId, int productId, bool activeProductOnly) { return [..await _ctx.ProductToAuctions.GetByAuctionAndProductId(auctionId, productId, activeProductOnly).ToListAsync()]; } public async Task AssignProductToAuctionAsync(int productId, decimal startingPrice, decimal bidPrice, int auctionId) { - var auction = await GetAuctionDtoByIdAsync(auctionId); + var auction = await GetAuctionDtoByIdAsync(auctionId, false, false); if (auction == null) return null; - var existedProductToAuction = (await GetProductToAuctionByAuctionIdAndProductIdAsync(auctionId, productId)).FirstOrDefault(); + var existedProductToAuction = (await GetProductToAuctionByAuctionIdAndProductIdAsync(auctionId, productId, false)).FirstOrDefault(); if (existedProductToAuction != null) return existedProductToAuction; var mapping = new ProductToAuctionMapping diff --git a/Nop.Plugin.Misc.AuctionPlugin/Services/EventConsumer.cs b/Nop.Plugin.Misc.AuctionPlugin/Services/EventConsumer.cs deleted file mode 100644 index b3c6a55..0000000 --- a/Nop.Plugin.Misc.AuctionPlugin/Services/EventConsumer.cs +++ /dev/null @@ -1,137 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Nop.Core.Domain.Catalog; -using Nop.Core.Events; -using Nop.Services.Events; - -namespace Nop.Plugin.Misc.AuctionPlugin.Services; - -/// -/// Represents plugin event consumer -/// -public class EventConsumer : - IConsumer> - //IConsumer, - //IConsumer>, - //IConsumer>, - //IConsumer>, - //IConsumer, - //IConsumer, - //IConsumer -{ - #region Fields - - //protected readonly FacebookPixelService _facebookPixelService; - protected readonly IHttpContextAccessor _httpContextAccessor; - - #endregion - - #region Ctor - - //public EventConsumer(FacebookPixelService facebookPixelService, - public EventConsumer(IHttpContextAccessor httpContextAccessor) - { - //_facebookPixelService = facebookPixelService; - _httpContextAccessor = httpContextAccessor; - } - - #endregion - - #region Methods - - /// - /// Handle shopping cart item inserted event - /// - /// Event message - /// A task that represents the asynchronous operation - //public async Task HandleEventAsync(EntityInsertedEvent eventMessage) - //{ - // if (eventMessage?.Entity != null) - // { - // //notify clients through SignalR - // } - - //} - - /// - /// Handle order placed event - /// - /// Event message - /// A task that represents the asynchronous operation - //public async Task HandleEventAsync(OrderPlacedEvent eventMessage) - //{ - // if (eventMessage?.Order != null) - // { - // // - // } - //} - - /// - /// Handle product details model prepared event - /// - /// Event message - /// A task that represents the asynchronous operation - //public async Task HandleEventAsync(ModelPreparedEvent eventMessage) - //{ - // if (eventMessage?.Model is ProductDetailsModel productDetailsModel) - // { - // // - // } - - //} - - /// - /// Handle page rendering event - /// - /// Event message - /// A task that represents the asynchronous operation - //public async Task HandleEventAsync(PageRenderingEvent eventMessage) - //{ - // var routeName = eventMessage.GetRouteName() ?? string.Empty; - // if (routeName == FacebookPixelDefaults.CheckoutRouteName || routeName == FacebookPixelDefaults.CheckoutOnePageRouteName) - // await _facebookPixelService.SendInitiateCheckoutEventAsync(); - - // if (_httpContextAccessor.HttpContext.GetRouteValue("area") is not string area || area != AreaNames.ADMIN) - // await _facebookPixelService.SendPageViewEventAsync(); - //} - - /// - /// Handle product search event - /// - /// Event message - /// A task that represents the asynchronous operation - //public async Task HandleEventAsync(ProductSearchEvent eventMessage) - //{ - // if (eventMessage?.SearchTerm != null) - // await _facebookPixelService.SendSearchEventAsync(eventMessage.SearchTerm); - //} - - /// - /// Handle message token added event - /// - /// Event message - /// A task that represents the asynchronous operation - //public async Task HandleEventAsync(MessageTokensAddedEvent eventMessage) - //{ - // if (eventMessage?.Message?.Name == MessageTemplateSystemNames.CONTACT_US_MESSAGE) - // await _facebookPixelService.SendContactEventAsync(); - //} - - /// - /// Handle customer registered event - /// - /// Event message - /// A task that represents the asynchronous operation - //public async Task HandleEventAsync(CustomerRegisteredEvent eventMessage) - //{ - // if (eventMessage?.Customer != null) - // await _facebookPixelService.SendCompleteRegistrationEventAsync(); - //} - - public async Task HandleEventAsync(EntityUpdatedEvent eventMessage) - { - //eventMessage. - //send notification on SignalR - } - - #endregion -} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AuctionPlugin/Services/IAuctionService.cs b/Nop.Plugin.Misc.AuctionPlugin/Services/IAuctionService.cs index 81e1ae1..49691a5 100644 --- a/Nop.Plugin.Misc.AuctionPlugin/Services/IAuctionService.cs +++ b/Nop.Plugin.Misc.AuctionPlugin/Services/IAuctionService.cs @@ -39,10 +39,11 @@ public interface IAuctionService Task> GetAllAuctionsAsync(); - Task> GetProductToAuctionsByAuctionIdAsync(int auctionId, bool onlyActiveItems = false); + Task GetAuctionDtoWithAuctionBids(int auctionId, bool activeProductOnly); + Task> GetProductToAuctionsByAuctionIdAsync(int auctionId, bool onlyActiveItems); - Task GetAuctionDtoByIdAsync(int auctionId, bool widthProducts = false); - Task> GetProductToAuctionDtosByAuctionId(int auctionId); + Task GetAuctionDtoByIdAsync(int auctionId, bool widthProducts, bool activeProductOnly); + Task> GetProductToAuctionDtosByAuctionId(int auctionId, bool activeProductOnly); Task GetAuctionDtoWithProductByIdAsync(int auctionId, int productId, bool activeProductOnly);