This commit is contained in:
Adam 2024-12-18 20:54:25 +01:00
commit 1b6ad7e33d
20 changed files with 625 additions and 249 deletions

View File

@ -28,52 +28,52 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Components
var currency = await workContext.GetWorkingCurrencyAsync();
await logger.InformationAsync($"LiveAnnouncementViewComponent.InvokeAsync(); Before lock; widgetZone: {widgetZone}", null, customer);
using (await lockService.SemaphoreSlim.UseWaitAsync())
{
await logger.InformationAsync($"LiveAnnouncementViewComponent.InvokeAsync(); Enter lock; widgetZone: {widgetZone}", null, customer);
//using (await lockService.SemaphoreSlim.UseWaitAsync())
//{
// await logger.InformationAsync($"LiveAnnouncementViewComponent.InvokeAsync(); Enter lock; widgetZone: {widgetZone}", null, customer);
await Task.Delay(1000);
// await Task.Delay(1000);
var auctions = await auctionService.GetAllCurrentAutoOpenAndClosedAuctionsAsync();
if (auctions.Count > 0)
{
await logger.InformationAsync($"LiveAnnouncementViewComponent.InvokeAsync(); auctions.Count > 0; count: {auctions.Count}; names: {string.Join("; ", auctions.Select(x => x.AuctionName))}");
// var auctions = await auctionService.GetAllCurrentAutoOpenAndClosedAuctionsAsync();
// if (auctions.Count > 0)
// {
// await logger.InformationAsync($"LiveAnnouncementViewComponent.InvokeAsync(); auctions.Count > 0; count: {auctions.Count}; names: {string.Join("; ", auctions.Select(x => x.AuctionName))}");
var statusChangedMessageWrapper = new MessageWrapper
{
MessageType = nameof(ProductToAuctionStatusNotification),
SenderId = 0,
ResponseType = ResponseType.ToAllClients
};
// var statusChangedMessageWrapper = new MessageWrapper
// {
// MessageType = nameof(ProductToAuctionStatusNotification),
// SenderId = 0,
// ResponseType = ResponseType.ToAllClients
// };
foreach (var auction in auctions)
{
auction.Closed = false;
await auctionService.UpdateAuctionAsync(auction);
// foreach (var auction in auctions)
// {
// auction.Closed = false;
// await auctionService.UpdateAuctionAsync(auction);
var auctionDto = new AuctionDto(auction);
var productToAuctions = (await auctionService.GetProductToAuctionsByAuctionIdAsync(auction.Id, false)).Where(x => x.AuctionStatus == AuctionStatus.None).ToList();
// var auctionDto = new AuctionDto(auction);
// var productToAuctions = (await auctionService.GetProductToAuctionsByAuctionIdAsync(auction.Id, false)).Where(x => x.AuctionStatus == AuctionStatus.None).ToList();
foreach (var productToAuction in productToAuctions)
{
productToAuction.AuctionStatus = AuctionStatus.Active;
auctionDto.ProductToAuctionDtos.Add(new ProductToAuctionDto(productToAuction));
// foreach (var productToAuction in productToAuctions)
// {
// productToAuction.AuctionStatus = AuctionStatus.Active;
// auctionDto.ProductToAuctionDtos.Add(new ProductToAuctionDto(productToAuction));
////TEMPOPRARY - J.
//statusChangedMessageWrapper.Data = new ProductToAuctionStatusNotification(auctionDto, 0, $"Az aukciót megnyitottuk: {auction.AuctionName}").ToJson();
//await _auctionHubContext.Clients.All.SendAsync("send", statusChangedMessageWrapper.ToJson());
////TEMPOPRARY - J.
}
// ////TEMPOPRARY - J.
// //statusChangedMessageWrapper.Data = new ProductToAuctionStatusNotification(auctionDto, 0, $"Az aukciót megnyitottuk: {auction.AuctionName}").ToJson();
// //await _auctionHubContext.Clients.All.SendAsync("send", statusChangedMessageWrapper.ToJson());
// ////TEMPOPRARY - J.
// }
await auctionService.UpdateProductToAuctionMappingAsync(productToAuctions);
// await auctionService.UpdateProductToAuctionMappingAsync(productToAuctions);
statusChangedMessageWrapper.Data = new ProductToAuctionStatusNotification(auctionDto, 0, $"Az aukciót megnyitottuk: {auction.AuctionName}").ToJson();
await auctionHubContext.Clients.All.SendAsync("send", statusChangedMessageWrapper.ToJson());
}
}
// statusChangedMessageWrapper.Data = new ProductToAuctionStatusNotification(auctionDto, 0, $"Az aukciót megnyitottuk: {auction.AuctionName}").ToJson();
// await auctionHubContext.Clients.All.SendAsync("send", statusChangedMessageWrapper.ToJson());
// }
// }
await logger.InformationAsync($"LiveAnnouncementViewComponent.InvokeAsync(); Exit lock; widgetZone: {widgetZone}", null, customer);
}
// await logger.InformationAsync($"LiveAnnouncementViewComponent.InvokeAsync(); Exit lock; widgetZone: {widgetZone}", null, customer);
//}
await logger.InformationAsync($"SignalR Widget called customer: {customer.Email}");

View File

@ -47,6 +47,10 @@
console.log("SignalR connected! connectionId: " + window.ConnectionId);
});
connection.on("OnDateTimeReceive", dateTime => {
console.log("SignalR date received! dateTime: " + dateTime);
});
function start() {
connection.start().catch(function (err) {
setTimeout(function () {

View File

@ -15,13 +15,24 @@ public class AuctionBidDbTable : MgDbTableBase<AuctionBid>
{
}
public IQueryable<AuctionBid> GetLastAuctionBidByProductToAuctionId(int productToAuctionId)
=> GetByProductToAuctionId(productToAuctionId).OrderByDescending(x => x.Id);
public IOrderedQueryable<AuctionBid> GetAllLastBidByAuctionId(int auctionId)
{
return GetAllByAuctionId(auctionId)
.OrderByDescending(x => x.Id)
.GroupBy(x => x.AuctionId, (_, bids) => bids.FirstOrDefault())
.OrderByDescending(percentGroup => percentGroup.Id);
}
public IOrderedQueryable<AuctionBid> GetLastAuctionBidByProductToAuctionId(int productToAuctionId)
=> GetAllByProductToAuctionId(productToAuctionId).OrderByDescending(x => x.Id);
public Task<int> GetBidsCountByProductToAuctionIdAsync(int productToAuctionId)
=> Table.CountAsync(x => x.ProductAuctionMappingId == productToAuctionId);
public IQueryable<AuctionBid> GetByProductToAuctionId(int productToAuctionId)
public IQueryable<AuctionBid> GetAllByAuctionId(int auctionId)
=> Table.Where(x => x.AuctionId == auctionId);
public IQueryable<AuctionBid> GetAllByProductToAuctionId(int productToAuctionId)
=> Table.Where(x => x.ProductAuctionMappingId == productToAuctionId);
public Task<bool> HasBidByProductToAuctionIdAsync(int productToAuctionId)

View File

@ -19,7 +19,7 @@ public class AuctionDbContext : MgDbContextBase, IAuctionDbSet<AuctionDbTable>,
public AuctionDbTable Auctions { get; set; }
public ProductToAuctionDbTable ProductToAuctions { get; set; }
public AuctionBidDbTable AuctionBids { get; set; }
//public EntityRepository<Auction> Auctions2 { get; set; }
//public IRepository<AuctionBid> AuctionBids2 { get; set; }
@ -33,7 +33,7 @@ public class AuctionDbContext : MgDbContextBase, IAuctionDbSet<AuctionDbTable>,
Auctions = auctionDbTable;
ProductToAuctions = productToAuctionDbTable;
AuctionBids = auctionBidDbTable;
//Auctions.Table
//var auctions = DataProvider.GetTable<Auction>().Where(x => x.Closed);
}
@ -44,6 +44,11 @@ public class AuctionDbContext : MgDbContextBase, IAuctionDbSet<AuctionDbTable>,
// AuctionBids2 = _auctionBidRepository;
//}
public Task<List<AuctionBid>> GetAllLastBidByAuctionIdAsync(int auctionId) => AuctionBids.GetAllLastBidByAuctionId(auctionId).ToListAsync();
public Task<Dictionary<int, AuctionBid>> GetAllLastBidDictionaryByAuctionIdAsync(int auctionId)
=> AuctionBids.GetAllLastBidByAuctionId(auctionId).ToDictionaryAsync(x => x.ProductAuctionMappingId);
public async Task<List<ProductToAuctionMapping>> GetProductToAuctionsByProductIdAsync(int productId)
{
return [..await ProductToAuctions.GetByProductId(productId).ToListAsync()];
@ -61,9 +66,9 @@ public class AuctionDbContext : MgDbContextBase, IAuctionDbSet<AuctionDbTable>,
=> AuctionBids.GetLastAuctionBidByProductToAuctionId(productToAuctionId).FirstOrDefaultAsync();
public Task<int> GetBidsCountByProductToAuctionIdAsync(int productToAuctionId)
=> AuctionBids.GetBidsCountByProductToAuctionIdAsync(productToAuctionId);
=> AuctionBids.GetBidsCountByProductToAuctionIdAsync(productToAuctionId);
public Task<AuctionBid> RevertAuctionBidByProductToAuctionId(int productToAuctionId)
=> AuctionBids.RevertByProductToAuctionIdAsync(productToAuctionId);

View File

@ -10,9 +10,9 @@ using Nop.Services.Logging;
namespace Nop.Plugin.Misc.AuctionPlugin.Domains.DataLayer;
public class AuctionDbTable: MgDbTableBase<Auction>
public class AuctionDbTable : MgDbTableBase<Auction>
{
public AuctionDbTable(IEventPublisher eventPublisher, INopDataProvider dataProvider, IShortTermCacheManager shortTermCacheManager, IStaticCacheManager staticCacheManager, AppSettings appSettings, ILogger logger)
public AuctionDbTable(IEventPublisher eventPublisher, INopDataProvider dataProvider, IShortTermCacheManager shortTermCacheManager, IStaticCacheManager staticCacheManager, AppSettings appSettings, ILogger logger)
: base(eventPublisher, dataProvider, shortTermCacheManager, staticCacheManager, appSettings, logger)
{
}
@ -26,9 +26,12 @@ public class AuctionDbTable: MgDbTableBase<Auction>
/// x.StartDateUtc <= utcNow && x.EndDateUtc >= utcNow
/// </summary>
/// <returns></returns>
public IQueryable<Auction> GetAllCurrentAutoOpenAndClosedAuctions()
public IOrderedQueryable<Auction> GetAllCurrentAutoOpenAndClosedAuctions()
{
var utcNow = DateTime.UtcNow;
return Table.Where(x => x.AuctionType == AuctionType.AutomaticAll && x.Closed && x.StartDateUtc <= utcNow && x.EndDateUtc >= utcNow).OrderByDescending(x=>x.StartDateUtc);
return GetAllAuctions()
.Where(x => x.AuctionType == AuctionType.AutomaticAll && x.StartDateUtc <= utcNow && (!x.Closed || (x.Closed && x.EndDateUtc >= utcNow)))
.OrderByDescending(x => x.StartDateUtc);
}
}

View File

@ -24,7 +24,7 @@ public class ProductToAuctionDbTable : MgDbTableBase<ProductToAuctionMapping>
private static bool HasActiveAuctionStatus(AuctionStatus auctionStatus)
{
//TODO: erre a problémára kitalálni valamit! - J.
return auctionStatus == AuctionStatus.Active || auctionStatus == AuctionStatus.FirstWarning || auctionStatus == AuctionStatus.SecondWarning;
return auctionStatus == AuctionStatus.Active || auctionStatus == AuctionStatus.FirstWarning || auctionStatus == AuctionStatus.SecondWarning || auctionStatus == AuctionStatus.Pause;
//return auctionStatus.HasFlag(AuctionStatus.Active) || auctionStatus.HasFlag(AuctionStatus.FirstWarning) || auctionStatus.HasFlag(AuctionStatus.SecondWarning);
}
@ -36,13 +36,13 @@ public class ProductToAuctionDbTable : MgDbTableBase<ProductToAuctionMapping>
public IQueryable<ProductToAuctionMapping> 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)*/));
(!activeProductOnly || x.AuctionStatus == AuctionStatus.Active || x.AuctionStatus == AuctionStatus.FirstWarning || x.AuctionStatus == AuctionStatus.SecondWarning || x.AuctionStatus == AuctionStatus.Pause /*HasActiveAuctionStatus(x.AuctionStatus)*/));
}
public IQueryable<ProductToAuctionMapping> 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)*/));
(!activeProductOnly || x.AuctionStatus == AuctionStatus.Active || x.AuctionStatus == AuctionStatus.FirstWarning || x.AuctionStatus == AuctionStatus.SecondWarning || x.AuctionStatus == AuctionStatus.Pause /*HasActiveAuctionStatus(x.AuctionStatus)*/));
}
public IQueryable<ProductToAuctionMapping> GetNotClosedItemsByAuctionId(int auctionId)

View File

@ -8,8 +8,9 @@ using Nop.Plugin.Misc.AuctionPlugin.Domains.Enums;
namespace Nop.Plugin.Misc.AuctionPlugin.Domains.Entities;
public partial class Auction: MgEntityBase, IAuction
public class Auction: MgEntityBase, IAuction
{
public int StoreId { get; set; }
public string AuctionName { get; set; }
//[NotMapped]

View File

@ -8,6 +8,7 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Domains.Entities
{
public partial class AuctionBid : MgEntityBase, IAuctionBid
{
public int AuctionId { get; set; }
public int ProductAuctionMappingId { get; set; }
public int CustomerId { get; set; }

View File

@ -6,5 +6,6 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Domains.Entities.Interfaces;
public interface IAuction : IAuctionDtoBase, ITimeStampInfo //, ISoftRemoveEntityInt
{
public int StoreId { get; set; }
public int? CategoryId { get; set; }
}

View File

@ -5,6 +5,8 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Domains.Entities.Interfaces;
public interface IProductToAuctionMapping : IProductToAuctionDtoBase, ITimeStampInfo //, ISoftRemoveEntityInt
{
public decimal MinimumPrice{ get; set; }
public int OrderId { get; set; }
public int OrderItemId { get; set; }
}

View File

@ -30,6 +30,7 @@ public partial class ProductToAuctionMapping : MgEntityBase, IProductToAuctionMa
public decimal StartingPrice { get; set; }
public decimal CurrentPrice { get; set; }
public decimal MinimumPrice { get; set; }
public int ProductAmount { get; set; } = 1;
public int SortIndex { get; set; }

View File

@ -15,19 +15,17 @@ using Nop.Core.Domain.Customers;
using Nop.Services.Catalog;
using Newtonsoft.Json.Linq;
using DocumentFormat.OpenXml.Spreadsheet;
using Microsoft.IdentityModel.Tokens;
namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
{
public class AuctionHub(SessionService sessionService, ILockService lockService, ILogger logger, IProductService productService, AuctionService auctionService, IWorkContext workContext, ICustomerService customerService, ICategoryService categoryService)
public class AuctionHub(SessionService sessionService, ILockService lockService, ILogger logger, IProductService productService, AuctionService auctionService, IWorkContext workContext, ICustomerService customerService)
: Hub<IAuctionHubClient>
{
//private static readonly SemaphoreSlim _handleMessageMutex = new(1);
//private readonly Semaphore _handleMessageMutex = new(1, 1, "Nop.Plugin.Misc.AuctionPlugin.Hubs.AuctionHub");
public override async Task OnConnectedAsync()
{
var connectionId = Context.ConnectionId;
var customer = await workContext.GetCurrentCustomerAsync();
//if (sessionService.GetOrCreateSessionItem(connectionId) == null) await logger.ErrorAsync($"AuctionHub.OnConnectedAsync(); (sessionItem == null); connectionId: {connectionId}");
//await _logger.InformationAsync($"AuctionHub.OnConnectedAsync(); Caller connected with id: {connectionId}");
@ -37,34 +35,45 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
else
{
var sessionItem = sessionService.GetOrCreateSessionItem(httpContext.Session.Id);
if (sessionItem == null) await logger.ErrorAsync($"AuctionHub.OnConnectedAsync(); (sessionItem == null); connectionId: {connectionId}; sessionId: {httpContext.Session.Id}");
else sessionItem.SignaRConnectionId = connectionId;
else
{
sessionItem.CustomerId = customer.Id;
sessionItem.SignaRConnectionId = connectionId;
}
var userName = httpContext.Request.Query["ConnectionId"];
if (!string.IsNullOrEmpty(userName))
if (!userName.IsNullOrEmpty())
{
await logger.InformationAsync($"AuctionHub.OnConnectedAsync(); Caller connected with name: {userName}; connectionId: {connectionId}");
}
}
await base.OnConnectedAsync();
await Clients.Caller.OnConnected(connectionId);
}
public override Task OnDisconnectedAsync(Exception exception)
public override async Task OnDisconnectedAsync(Exception exception)
{
sessionService.TryRemoveSessionItem(Context.ConnectionId, out _);
var httpContext = Context.GetHttpContext();
return base.OnDisconnectedAsync(exception);
if (httpContext == null) await logger.ErrorAsync($"AuctionHub.OnDisconnectedAsync(); (httpContext == null); connectionId: {Context.ConnectionId}");
else sessionService.TryRemoveSessionItem(httpContext.Session.Id, out _);
await base.OnDisconnectedAsync(exception);
}
public async Task ReceiveMessageFromClient(MessageWrapper messageWrapper)
{
var sessionItem = IncrementRequestCount();
if (!TryGetCurrentSessionItem(out var sessionItem) || sessionItem == null)
{
await logger.ErrorAsync($"AuctionHub.ReceiveMessageFromClient(); (TryGetCurrentSessionItem(out var sessionItem) == false || sessionItem == null); connectionId: {Context.ConnectionId}");
return;
}
sessionItem.RequestCount++;
await HandleMessageAsync(messageWrapper, sessionItem, Context.ConnectionId);
//await SendMessageWrapperAsync(messageWrapper);
}
public async Task<ResponseType> HandleMessageAsync(MessageWrapper messageWrapper, SessionItem sessionItem, string connectionId)
@ -92,21 +101,20 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
await logger.InformationAsync($"AuctionHub.HandleMessageAsync(); Before lock; MessageType: {messageWrapper.MessageType}; connectionId: {connectionId}; jsonData: {messageWrapper.Data}", null, customer);
//TODO: az összes request-et egy base-ből származtatni és beletenni az AuctionRequestMode-ot! - J.
//using (await _handleMessageMutex.WaitOne())
using (await lockService.SemaphoreSlim.UseWaitAsync())
{
try
{
await logger.InformationAsync($"AuctionHub.HandleMessageAsync(); Enter lock; MessageType: {messageWrapper.MessageType}; connectionId: {connectionId}", null, customer);
await Task.Delay(3000);
//await Task.Delay(3000); //TODO: ez csak a teszt időszakig van itt!!! - J.
if (messageWrapper.MessageType == "BidRequestMessage") return await HandleBidRequestAsync(customer, messageWrapper);
else
{
if (!await customerService.IsAdminAsync(customer))
if (!customer.IsSystemAccount && !await customerService.IsAdminAsync(customer))
{
logger.Error($"AuctionHub.HandleProductToAuctionStatusChangedRequest(); IsAdminAsync() == false; connectionId: {connectionId}", null, customer);
logger.Error($"AuctionHub.HandleProductToAuctionStatusChangedRequest(); (!customer.IsSystemAccount && !await customerService.IsAdminAsync(customer)); connectionId: {connectionId}", null, customer);
return ResponseType.Error;
}
@ -151,11 +159,11 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
var productToAuction = (await auctionService.GetProductToAuctionMappingByIdAsync(revertAuctionBidRequest.ProductToAuctionId));
if (productToAuction == null)
{
logger.Error($"AuctionHub.HandleRevertAuctionBidRequest(); (productToAuction == null);", null, customer);
logger.Error($"AuctionHub.HandleRevertAuctionBidRequest(); (productToAuction == null); ptaId: {revertAuctionBidRequest.ProductToAuctionId}", null, customer);
return ResponseType.Error;
}
await logger.InformationAsync($"AuctionHub.HandleRevertAuctionBidRequest(); (productToAuction is not {{ AuctionStatus: AuctionStatus.Pause }}); AuctionStatus: {productToAuction.AuctionStatus}", null, customer);
await logger.InformationAsync($"AuctionHub.HandleRevertAuctionBidRequest(); (productToAuction is not {{ AuctionStatus: AuctionStatus.Pause }}); AuctionStatus: {productToAuction.AuctionStatus}; ptaId: {revertAuctionBidRequest.ProductToAuctionId}", null, customer);
var product = await auctionService.GetProductById(productToAuction.ProductId);
if (product == null)
@ -166,7 +174,7 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
if (productToAuction.AuctionStatus != AuctionStatus.Pause)
{
logger.Warning($"AuctionHub.HandleRevertAuctionBidRequest(); (productToAuction.AuctionStatus != AuctionStatus.Pause; AuctionStatus: {productToAuction.AuctionStatus}", null, customer);
logger.Warning($"AuctionHub.HandleRevertAuctionBidRequest(); (productToAuction.AuctionStatus != AuctionStatus.Pause); AuctionStatus: {productToAuction.AuctionStatus}; ptaId: {revertAuctionBidRequest.ProductToAuctionId}", null, customer);
await SendAuctionBidMessageAsync(messageWrapper, productToAuction, product, customer.Id, ResponseType.ToCaller);
return ResponseType.Error;
@ -174,7 +182,7 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
var revertLastBid = await auctionService.RevertAuctionBidByProductToAuctionIdAsync(productToAuction.Id);
if (revertLastBid == null) await ResetProductToAuction(productToAuction);
if (revertLastBid == null) await auctionService.ResetProductToAuction(productToAuction);
else
{
productToAuction.BidsCount = await auctionService.GetBidsCountByProductToAuctionIdAsync(productToAuction.Id);
@ -186,7 +194,7 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
}
catch (Exception ex)
{
logger.Error($"AuctionHub.HandleRevertAuctionBidRequest(); Exception: {ex.Message}", ex, customer);
logger.Error($"AuctionHub.HandleRevertAuctionBidRequest(); ptaId: {revertAuctionBidRequest.ProductToAuctionId}; Exception: {ex.Message}", ex, customer);
}
return ResponseType.Error;
@ -203,7 +211,7 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
try
{
await logger.InformationAsync($"AuctionHub.HandleBidRequestAsync(); Bid received; Auction: {bidRequestMessage.AuctionId}; ProductToAuction: {bidRequestMessage.ProductAuctionMappingId}; Product: {bidRequestMessage.ProductId}; Bid: {bidRequestMessage.BidPrice}; Customer: {bidRequestMessage.CustomerId}", null, customer);
await logger.InformationAsync($"AuctionHub.HandleBidRequestAsync(); Bid received; Auction: {bidRequestMessage.AuctionId}; ptaId: {bidRequestMessage.ProductAuctionMappingId}; Product: {bidRequestMessage.ProductId}; Bid: {bidRequestMessage.BidPrice}; Customer: {bidRequestMessage.CustomerId}", null, customer);
var auction = await auctionService.GetAuctionDtoByIdAsync(bidRequestMessage.AuctionId, false, false);
if (auction == null || auction.Closed)
@ -223,8 +231,8 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
var activeProductAuction = (await auctionService.GetProductToAuctionMappingByIdAsync(bidRequestMessage.ProductAuctionMappingId));
if (activeProductAuction is not { IsActiveItem: true } || (activeProductAuction.WinnerCustomerId == customer.Id && !await customerService.IsAdminAsync(customer)))
{
logger.Warning($"AuctionHub.HandleBidRequestAsync(); (activeProductAuction is not {{ IsActiveItem: true }} || activeProductAuction.WinnerCustomerId == customer.Id && !await customerService.IsAdminAsync(customer)); AuctionStatus: {activeProductAuction?.AuctionStatus}; WinnerCustomerId: {activeProductAuction?.WinnerCustomerId}", null, customer);
logger.Warning($"AuctionHub.HandleBidRequestAsync(); (activeProductAuction is not {{ IsActiveItem: true }} || activeProductAuction.WinnerCustomerId == customer.Id && !await customerService.IsAdminAsync(customer)); ptaId: {bidRequestMessage.ProductAuctionMappingId}; AuctionStatus: {activeProductAuction?.AuctionStatus}; WinnerCustomerId: {activeProductAuction?.WinnerCustomerId}", null, customer);
await SendAuctionBidMessageAsync(messageWrapper, activeProductAuction, product, customer.Id, ResponseType.ToCaller);
return ResponseType.Error;
}
@ -242,6 +250,7 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
}
var auctionBid = bidRequestMessage.CreateMainEntity();
auctionBid.AuctionId = auction.Id;
auctionBid.ProductAuctionMappingId = activeProductAuction.Id;
await auctionService.InsertBidAsync(auctionBid);
@ -260,7 +269,7 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
}
catch (Exception ex)
{
logger.Error($"AuctionHub.HandleBidRequestAsync(); Exception: {ex.Message}", ex, customer);
logger.Error($"AuctionHub.HandleBidRequestAsync(); ptaId: {bidRequestMessage.ProductAuctionMappingId}; Exception: {ex.Message}", ex, customer);
}
return ResponseType.Error;
@ -272,100 +281,113 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
if (auctionProductStatusRequest == null)
{
logger.Error($"AuctionHub.HandleProductToAuctionStatusChangedRequest(); auctionProductStatusRequest == null", null, customer);
return ResponseType.Error;
return ResponseType.None;
}
try
{
//var responseType = ResponseType.ToAllClients;
await logger.InformationAsync($"AuctionHub.HandleProductToAuctionStatusChangedRequest(); ProductToAuctionMappingId: {auctionProductStatusRequest.ProductToAuctionId}; Status: {auctionProductStatusRequest.AuctionStatus}({(int)auctionProductStatusRequest.AuctionStatus})", null, customer);
await logger.InformationAsync($"AuctionHub.HandleProductToAuctionStatusChangedRequest(); ptaId: {auctionProductStatusRequest.ProductToAuctionId}; Status: {auctionProductStatusRequest.AuctionStatus}({(int)auctionProductStatusRequest.AuctionStatus})", null, customer);
var productToAuction = await auctionService.GetProductToAuctionMappingByIdAsync(auctionProductStatusRequest.ProductToAuctionId);
if (productToAuction == null)
{
logger.Error($"AuctionHub.HandleProductToAuctionStatusChangedRequest(); (productToAuction == null)", null, customer);
return ResponseType.Error;
}
var (auction, productToAuction, responseType) = await auctionService.GetAndUpdateProductToAuctionStatusIfValidAsync(auctionProductStatusRequest.ProductToAuctionId, auctionProductStatusRequest.AuctionStatus, customer);
if (auction == null || productToAuction == null || responseType == ResponseType.None) return ResponseType.None;
var auction = await auctionService.GetAuctionByIdAsync(productToAuction.AuctionId);
if (auction == null || auction.Closed)
{
logger.Error($"AuctionHub.HandleProductToAuctionStatusChangedRequest(); (auction == null || auction.Closed); Closed: {auction?.Closed}", null, customer);
return ResponseType.Error;
}
if (!IsValidRequestAuctionStatus(auctionProductStatusRequest.AuctionStatus, productToAuction.AuctionStatus))
{
logger.Error($"AuctionHub.HandleProductToAuctionStatusChangedRequest(); RequestAuctionStatusIsValid() == false; newStatus: {auctionProductStatusRequest.AuctionStatus}; oldStatus: {productToAuction.AuctionStatus}", null, customer);
await SendStatusChangedNotificationAsync(customer, statusChangedMessageWrapper, productToAuction, ResponseType.ToCaller);
return ResponseType.Error;
}
else if (auctionProductStatusRequest.AuctionStatus == AuctionStatus.None) await ResetProductToAuction(productToAuction, auction.CategoryId);
else
{
switch (auctionProductStatusRequest.AuctionStatus)
{
case AuctionStatus.Active:
productToAuction.AuctionStatus = AuctionStatus.Active;
await UpdateProductCategoryIsFeaturedAsync(productToAuction.ProductId, auction.CategoryId, true);
break;
case AuctionStatus.FirstWarning:
case AuctionStatus.SecondWarning:
productToAuction.AuctionStatus = auctionProductStatusRequest.AuctionStatus;
break;
case AuctionStatus.Sold:
var lastAuctionBid = await auctionService.GetLastAuctionBidByProductToAuctionIdAsync(productToAuction.Id);
if (lastAuctionBid == null) productToAuction.AuctionStatus = AuctionStatus.NotSold;
else
{
productToAuction.AuctionStatus = AuctionStatus.Sold;
productToAuction.CurrentPrice = lastAuctionBid.BidPrice;
productToAuction.WinnerCustomerId = lastAuctionBid.CustomerId;
var placeOrderResult = await auctionService.CreateOrderForWinnerAsync(productToAuction);
if (placeOrderResult == null || placeOrderResult.Id == 0)
{
logger.Error($"AuctionHub.HandleProductToAuctionStatusChangedRequest(); (placeOrderResult == null || placeOrderResult.Id == 0)", null, customer);
//return; //TODO: EGYELŐRE HAGYJUK LEZÁRNI AKKOR IS, HA NEM SIKERÜLT AZ ORDERPLACE()! - J.
}
}
await UpdateProductCategoryIsFeaturedAsync(productToAuction.ProductId, auction.CategoryId, false);
break;
case AuctionStatus.Pause:
productToAuction.AuctionStatus = AuctionStatus.Pause;
break;
default:
logger.Error($"AuctionHub.HandleProductToAuctionStatusChangedRequest(); AuctionStatus not found; (auctionProductStatusRequest.AuctionStatus == {auctionProductStatusRequest.AuctionStatus})", null, customer);
await SendStatusChangedNotificationAsync(customer, statusChangedMessageWrapper, productToAuction, ResponseType.ToCaller);
return ResponseType.Error;
}
await auctionService.UpdateProductToAuctionMappingAsync(productToAuction);
}
await SendStatusChangedNotificationAsync(customer, statusChangedMessageWrapper, productToAuction, ResponseType.ToAllClients);
await SendStatusChangedNotificationAsync(customer, statusChangedMessageWrapper, productToAuction, responseType);
//TODO: gond van ha az Admin valamit módosít és újrazár egy régi ProductToAuction-t!!!! AuctionRequestMode.Normal...- J.
if (/*AuctionRequestMode.Normal &&*/ auction.AuctionType == AuctionType.AutomaticNext && productToAuction.AuctionStatus is AuctionStatus.Sold or AuctionStatus.NotSold)
if ( /*AuctionRequestMode.Normal &&*/ auction.AuctionType == AuctionType.AutomaticNext && productToAuction.AuctionStatus is AuctionStatus.Sold or AuctionStatus.NotSold)
await StepNextProductToAuctionAsync(statusChangedMessageWrapper, customer, productToAuction, auctionProductStatusRequest);
return ResponseType.ToAllClients;
}
catch (Exception ex)
{
logger.Error($"AuctionHub.HandleProductToAuctionStatusChangedRequest(); Exception: {ex.Message}", ex, customer);
logger.Error($"AuctionHub.HandleProductToAuctionStatusChangedRequest(); ptaId: {auctionProductStatusRequest.ProductToAuctionId}; Exception: {ex.Message}", ex, customer);
}
return ResponseType.Error;
}
//private async Task<ResponseType> UpdateProductToAuctionStatusIfValidAsync(AuctionStatus newProductToAuctionStatus, Auction auction, ProductToAuctionMapping productToAuction, Customer customer)
//{
// if (!IsValidRequestAuctionStatus(newProductToAuctionStatus, productToAuction.AuctionStatus))
// {
// logger.Error($"AuctionHub.UpdateProductToAuctionStatusIfValidAsync(); RequestAuctionStatusIsValid() == false; newStatus: {newProductToAuctionStatus}; oldStatus: {productToAuction.AuctionStatus}", null, customer);
// return ResponseType.ToCaller;
// }
// if (newProductToAuctionStatus == AuctionStatus.None) await ResetProductToAuction(productToAuction, auction.CategoryId);
// else
// {
// switch (newProductToAuctionStatus)
// {
// case AuctionStatus.Active:
// productToAuction.AuctionStatus = AuctionStatus.Active;
// await UpdateProductCategoryIsFeaturedAsync(productToAuction.ProductId, auction.CategoryId, true);
// break;
// case AuctionStatus.FirstWarning:
// case AuctionStatus.SecondWarning:
// productToAuction.AuctionStatus = newProductToAuctionStatus;
// break;
// case AuctionStatus.Sold:
// var lastAuctionBid = await auctionService.GetLastAuctionBidByProductToAuctionIdAsync(productToAuction.Id);
// if (lastAuctionBid == null) productToAuction.AuctionStatus = AuctionStatus.NotSold;
// else
// {
// productToAuction.AuctionStatus = AuctionStatus.Sold;
// productToAuction.CurrentPrice = lastAuctionBid.BidPrice;
// productToAuction.WinnerCustomerId = lastAuctionBid.CustomerId;
// var placeOrderResult = await auctionService.CreateOrderForWinnerAsync(productToAuction);
// if (placeOrderResult == null || placeOrderResult.Id == 0)
// {
// logger.Error($"AuctionHub.UpdateProductToAuctionStatusIfValidAsync(); (placeOrderResult == null || placeOrderResult.Id == 0)", null, customer);
// //return; //TODO: EGYELŐRE HAGYJUK LEZÁRNI AKKOR IS, HA NEM SIKERÜLT AZ ORDERPLACE()! - J.
// }
// }
// await UpdateProductCategoryIsFeaturedAsync(productToAuction.ProductId, auction.CategoryId, false);
// break;
// case AuctionStatus.Pause:
// productToAuction.AuctionStatus = AuctionStatus.Pause;
// break;
// default:
// logger.Error($"AuctionHub.UpdateProductToAuctionStatusIfValidAsync(); AuctionStatus not found; (newStatus == {newProductToAuctionStatus})", null, customer);
// return ResponseType.ToCaller;
// }
// await auctionService.UpdateProductToAuctionMappingAsync(productToAuction);
// }
// return ResponseType.ToAllClients;
//}
//private async Task<(Auction auction, ProductToAuctionMapping productToAuction, ResponseType responseType)> GetAndUpdateProductToAuctionStatusIfValidAsync(int productToAuctionId, AuctionStatus newProductToAuctionStatus, Customer customer)
//{
// var productToAuction = await auctionService.GetProductToAuctionMappingByIdAsync(productToAuctionId);
// if (productToAuction == null)
// {
// logger.Error($"AuctionHub.GetAndUpdateProductToAuctionStatusIfValidAsync(); (productToAuction == null)", null, customer);
// return (null, null, ResponseType.None);
// }
// var auction = await auctionService.GetAuctionByIdAsync(productToAuction.AuctionId);
// if (auction == null || auction.Closed)
// {
// logger.Error($"AuctionHub.GetAndUpdateProductToAuctionStatusIfValidAsync(); (auction == null || auction.Closed); Closed: {auction?.Closed}", null, customer);
// return (null, null, ResponseType.None);
// }
// var responseType = await UpdateProductToAuctionStatusIfValidAsync(newProductToAuctionStatus, auction, productToAuction, customer);
// return (auction, productToAuction, responseType);
//}
private async Task SendStatusChangedNotificationAsync(Customer customer, MessageWrapper statusChangedMessageWrapper, ProductToAuctionMapping productToAuction, ResponseType responseType)
{
await UpdateStatusChangedNotificationMessageWrapperAsync(statusChangedMessageWrapper, customer, productToAuction, responseType);
@ -402,7 +424,7 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
//activeProductAuction.StartingPrice = product.OldPrice; //TODO: ez biztosan kezelve van mikor összerendeljük? - J.
productToAuction.CurrentPrice = bidPrice;
productToAuction.WinnerCustomerId = lastBidCustomerId;
await auctionService.UpdateProductToAuctionMappingAsync(productToAuction);
await auctionService.UpdateProductToAuctionAsync(productToAuction);
return true;
}
@ -485,35 +507,35 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
}.ToJson();
}
private async Task ResetProductToAuction(ProductToAuctionMapping productToAuction, int? categoryId = null)
{
productToAuction.AuctionStatus = AuctionStatus.None;
await auctionService.ResetProductToAuctionAsync(productToAuction, productToAuction.StartingPrice);
//private async Task ResetProductToAuction(ProductToAuctionMapping productToAuction, int? categoryId = null)
//{
// productToAuction.AuctionStatus = AuctionStatus.None;
// await auctionService.ResetProductToAuctionAsync(productToAuction, productToAuction.StartingPrice);
categoryId ??= (await auctionService.GetAuctionByIdAsync(productToAuction.AuctionId))?.CategoryId;
await UpdateProductCategoryIsFeaturedAsync(productToAuction.ProductId, categoryId, false);
}
// categoryId ??= (await auctionService.GetAuctionByIdAsync(productToAuction.AuctionId))?.CategoryId;
// await UpdateProductCategoryIsFeaturedAsync(productToAuction.ProductId, categoryId, false);
//}
private async Task UpdateProductCategoryIsFeaturedAsync(int productId, int? categoryId, bool isFeatured)
{
//Leszarjuk ha elszáll, az aukció menjen tovább... - J.
try
{
if (categoryId.GetValueOrDefault(0) == 0) return;
//private async Task UpdateProductCategoryIsFeaturedAsync(int productId, int? categoryId, bool isFeatured)
//{
// //Leszarjuk ha elszáll, az aukció menjen tovább... - J.
// try
// {
// if (categoryId.GetValueOrDefault(0) == 0) return;
var productCategory = (await categoryService.GetProductCategoriesByProductIdAsync(productId)).FirstOrDefault(x => x.CategoryId == categoryId);
if (productCategory == null) return;
// var productCategory = (await categoryService.GetProductCategoriesByProductIdAsync(productId)).FirstOrDefault(x => x.CategoryId == categoryId);
// if (productCategory == null) return;
if (productCategory.IsFeaturedProduct == isFeatured) return;
// if (productCategory.IsFeaturedProduct == isFeatured) return;
productCategory.IsFeaturedProduct = isFeatured;
await categoryService.UpdateProductCategoryAsync(productCategory);
}
catch (Exception ex)
{
logger.Error($"AuctionHub.UpdateProductCategoryIsFeaturedAsync(); categoryId: {categoryId}; productId: {productId}; isFeatured: {isFeatured}", ex);
}
}
// productCategory.IsFeaturedProduct = isFeatured;
// await categoryService.UpdateProductCategoryAsync(productCategory);
// }
// catch (Exception ex)
// {
// logger.Error($"AuctionHub.UpdateProductCategoryIsFeaturedAsync(); categoryId: {categoryId}; productId: {productId}; isFeatured: {isFeatured}", ex);
// }
//}
public async Task SendAuctionBidMessageAsync(MessageWrapper messageWrapper, ProductToAuctionMapping productToAuction, Product product, int customerId, ResponseType responseType)
{
@ -538,16 +560,20 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
if (messageWrapper.HideToaster) await Clients.All.send(messageWrapperJson);
else
{
//messageWrapperJObject["senderId" /*nameof(MessageWrapper.SenderId)*/] = "-1";
await Clients.Others.send(messageWrapperJson);
var messageWrapperJObject = JObject.Parse(messageWrapperJson);
messageWrapperJObject["hideToaster" /*nameof(MessageWrapper.HideToaster)*/] = "true";
await Clients.Caller.send(messageWrapperJObject.ToString(Formatting.None));
}
break;
case ResponseType.Error:
messageWrapper.HideToaster = false;
await Clients.Caller.send(messageWrapper.ToJson());
break;
default:
throw new ArgumentOutOfRangeException();
@ -560,35 +586,33 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
// else await Clients.All.send(messageWrapper.ToJson());
//}
private static bool IsValidRequestAuctionStatus(AuctionStatus newStatus, AuctionStatus oldStatus)
{
switch (oldStatus)
{
case AuctionStatus.None:
return newStatus is AuctionStatus.Active or AuctionStatus.Pause;
case AuctionStatus.Active:
return newStatus is AuctionStatus.FirstWarning or AuctionStatus.Pause;
case AuctionStatus.FirstWarning:
return newStatus is AuctionStatus.SecondWarning or AuctionStatus.Pause;
case AuctionStatus.SecondWarning:
return newStatus is AuctionStatus.Sold or AuctionStatus.Pause;
case AuctionStatus.Pause:
return newStatus is AuctionStatus.None or AuctionStatus.Active;
case AuctionStatus.Sold:
case AuctionStatus.NotSold:
default:
return false;
}
}
//private static bool IsValidRequestAuctionStatus(AuctionStatus newStatus, AuctionStatus oldStatus)
//{
// switch (oldStatus)
// {
// case AuctionStatus.None:
// return newStatus is AuctionStatus.Active or AuctionStatus.Pause;
// case AuctionStatus.Active:
// return newStatus is AuctionStatus.FirstWarning or AuctionStatus.Pause;
// case AuctionStatus.FirstWarning:
// return newStatus is AuctionStatus.SecondWarning or AuctionStatus.Pause;
// case AuctionStatus.SecondWarning:
// return newStatus is AuctionStatus.Sold or AuctionStatus.Pause;
// case AuctionStatus.Pause:
// return newStatus is AuctionStatus.None or AuctionStatus.Active;
// case AuctionStatus.Sold:
// case AuctionStatus.NotSold:
// default:
// return false;
// }
//}
private SessionItem IncrementRequestCount()
private bool TryGetCurrentSessionItem(out SessionItem sessionItem)
{
SessionItem sessionItem = null;
sessionItem = null;
var httpContext = Context.GetHttpContext();
if (httpContext != null && sessionService.TryGetSessionItem(httpContext.Session.Id, out sessionItem)) sessionItem.RequestCount++;
return sessionItem;
return httpContext != null && sessionService.TryGetSessionItem(httpContext.Session.Id, out sessionItem);
}
}
}

View File

@ -52,11 +52,6 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Infrastructure
hubOptions.KeepAliveInterval = TimeSpan.FromMinutes(10);
});
//register services and interfaces
//IRepository<AuctionBid> _customerBidRepository;
//protected readonly IShortTermCacheManager _shortTermCacheManager;
// protected readonly IStaticCacheManager _staticCacheManager;
services.AddScoped<ILocalizationService, LocalizationService>();
services.AddScoped<ISettingService, SettingService>();
services.AddScoped<AuctionEventConsumer>();
@ -72,13 +67,15 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Infrastructure
services.AddScoped<AuctionBidDbTable>();
services.AddScoped<AuctionDbContext>();
services.AddScoped<MyProductModelFactory>();
//services.AddScoped<SignalRMessageHandler>();
services.AddScoped<MyProductModelFactory>(); //TODO: ez mi? - J.
services.AddScoped<IOrderService, OrderService>();
services.AddScoped<IOrderProcessingService, OrderProcessingService>();
services.AddScoped<IShoppingCartService, ShoppingCartService>();
services.AddScoped<IStoreContext, WebStoreContext>();
services.AddScoped<ICurrencyService, CurrencyService>();
services.AddHostedService<AuctionBackgroundService>();
}
/// <summary>

View File

@ -0,0 +1,168 @@
using AyCode.Core.Extensions;
using AyCode.Utils.Extensions;
using Mango.Nop.Services;
using Microsoft.AspNetCore.SignalR;
using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Data;
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.Plugin.Misc.AuctionPlugin.Hubs;
using Nop.Plugin.Misc.AuctionPlugin.Hubs.Messages;
using Nop.Services.Customers;
using Nop.Services.Logging;
using System.Collections.Generic;
namespace Nop.Plugin.Misc.AuctionPlugin.Services;
public class AuctionBackgroundService : MgBackgroundServiceBase
{
private const int WARNING_STATUS_INTERVAL_SECOND = 15;
private readonly ILogger _logger;
private readonly IHubContext<AuctionHub> _auctionHubContext;
private readonly ILockService _lockService;
private readonly AuctionService _auctionService;
private readonly Customer _auctionSystemCustomer;
public AuctionBackgroundService(ILogger logger, IServiceProvider service, IHubContext<AuctionHub> auctionHubContext, AuctionService auctionService, ILockService lockService, IRepository<Customer> customerService) : base(logger, service)
{
_logger = logger;
_auctionHubContext = auctionHubContext;
_lockService = lockService;
_auctionService = auctionService;
_auctionSystemCustomer = customerService.Table.FirstOrDefault(x => x.Email == "builtin@background_task_auction.com");
if (_auctionSystemCustomer == null)
_logger.Error($"AuctionBackgroundService.AuctionBackgroundService(); _auctionSystemCustomer == null;", null, null);
}
protected override async Task OnExecuteAsync()
{
await Task.Delay(WARNING_STATUS_INTERVAL_SECOND * 1000); //Az elejére kell tenni! ha exception lenne, akkor ne kezdje el darálni... - J.
if (_auctionSystemCustomer == null) return;
await _logger.InformationAsync($"AuctionBackgroundService.OnExecuteAsync(); Before lock; ", null, _auctionSystemCustomer);
using (await _lockService.SemaphoreSlim.UseWaitAsync())
{
await _logger.InformationAsync($"AuctionBackgroundService.OnExecuteAsync(); Enter lock;", null, _auctionSystemCustomer);
var currentAutomaticAuctions = await _auctionService.GetAllCurrentAutoOpenAndClosedAuctionsAsync();
if (currentAutomaticAuctions.Count > 0)
{
await _logger.InformationAsync($"AuctionBackgroundService.OnExecuteAsync(); currentAutomaticAuctions.Count > 0; count: {currentAutomaticAuctions.Count}; names: {string.Join("; ", currentAutomaticAuctions.Select(x => x.AuctionName))}", null, _auctionSystemCustomer);
var statusChangedMessageWrapper = new MessageWrapper
{
MessageType = nameof(ProductToAuctionStatusNotification),
SenderId = _auctionSystemCustomer.Id, //TODO: -1; - J.
ResponseType = ResponseType.ToAllClients
};
foreach (var automaticAuction in currentAutomaticAuctions)
{
await CheckAndUpdateProductToAuctionsStatusAsync(automaticAuction, statusChangedMessageWrapper);
await OpenOrCloseAutomaticAuctionsAsync(automaticAuction, statusChangedMessageWrapper);
}
}
//await _auctionHubContext.Clients.All.SendAsync("OnDateTimeReceive", DateTime.Now.ToString("G")); //TODO: ez csak a teszt időszakig van itt!!! - J.
await _logger.InformationAsync($"AuctionBackgroundService.OnExecuteAsync(); Exit lock;", null, _auctionSystemCustomer);
}
}
private async Task CheckAndUpdateProductToAuctionsStatusAsync(Auction automaticAuction, MessageWrapper statusChangedMessageWrapper)
{
try
{
if (automaticAuction.Closed || automaticAuction.EndDateUtc >= DateTime.UtcNow.AddSeconds(2 * WARNING_STATUS_INTERVAL_SECOND)) return;
var activeProductToAuctions = await _auctionService.GetProductToAuctionsByAuctionIdAsync(automaticAuction.Id, true);
if (activeProductToAuctions.Count == 0) return;
var auctionDto = new AuctionDto(automaticAuction);
var changedProductToAuctions = new List<ProductToAuctionMapping>(activeProductToAuctions.Count);
foreach (var activeProductToAuction in activeProductToAuctions)
{
var newPtaStatus = activeProductToAuction.AuctionStatus switch
{
AuctionStatus.Active => AuctionStatus.FirstWarning,
AuctionStatus.FirstWarning => AuctionStatus.SecondWarning,
AuctionStatus.SecondWarning => AuctionStatus.Sold,
_ => AuctionStatus.None
};
if (newPtaStatus == AuctionStatus.None) continue;
var responseType = await _auctionService.UpdateProductToAuctionStatusIfValidAsync(newPtaStatus, automaticAuction, activeProductToAuction, _auctionSystemCustomer, false);
if (responseType == ResponseType.None) continue;
changedProductToAuctions.Add(activeProductToAuction);
auctionDto.ProductToAuctionDtos.Add(new ProductToAuctionDto(activeProductToAuction));
}
if (changedProductToAuctions.Count == 0) return;
await _auctionService.UpdateProductToAuctionAsync(changedProductToAuctions);
statusChangedMessageWrapper.Data = new ProductToAuctionStatusNotification(auctionDto, 0, "EMPTY").ToJson();
await _auctionHubContext.Clients.All.SendAsync("send", statusChangedMessageWrapper.ToJson());
}
catch (Exception ex)
{
await _logger.ErrorAsync($"AuctionBackgroundService.CheckAndUpdateProductToAuctionsStatusAsync(); auctionId: {automaticAuction.Id}; auctionName: {automaticAuction.AuctionName}", ex, _auctionSystemCustomer);
}
}
private async Task OpenOrCloseAutomaticAuctionsAsync(Auction automaticAuction, MessageWrapper statusChangedMessageWrapper)
{
try
{
if (!automaticAuction.Closed)
{
var allItemsFinished = (await _auctionService.GetProductToAuctionsByAuctionIdAsync(automaticAuction.Id, false)).All(x => x.AuctionStatus is AuctionStatus.Sold or AuctionStatus.NotSold);
if (!allItemsFinished) return;
automaticAuction.Closed = true;
await _auctionService.UpdateAuctionAsync(automaticAuction);
//TODO: send message... - J.
return;
}
var productToAuctions = (await _auctionService.GetProductToAuctionsByAuctionIdAsync(automaticAuction.Id, false)).Where(x => x.AuctionStatus == AuctionStatus.None).ToList();
if (productToAuctions.Count == 0) return;
automaticAuction.Closed = false;
var auctionDto = new AuctionDto(automaticAuction);
foreach (var productToAuction in productToAuctions)
{
var responseType = await _auctionService.UpdateProductToAuctionStatusIfValidAsync(AuctionStatus.Active, automaticAuction, productToAuction, _auctionSystemCustomer, false);
if (responseType == ResponseType.None) continue;
auctionDto.ProductToAuctionDtos.Add(new ProductToAuctionDto(productToAuction));
}
await _auctionService.UpdateAuctionAsync(automaticAuction);
await _auctionService.UpdateProductToAuctionAsync(productToAuctions);
statusChangedMessageWrapper.Data = new ProductToAuctionStatusNotification(auctionDto, 0, $"Az aukciót megnyitottuk: {automaticAuction.AuctionName}").ToJson();
statusChangedMessageWrapper.HideToaster = true;
await _auctionHubContext.Clients.All.SendAsync("send", statusChangedMessageWrapper.ToJson());
}
catch (Exception ex)
{
await _logger.ErrorAsync($"AuctionBackgroundService.OpenOrCloseAutomaticAuctionsAsync(); auctionId: {automaticAuction.Id}; name: {automaticAuction.AuctionName}", ex, _auctionSystemCustomer);
}
}
}

View File

@ -22,6 +22,7 @@ using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.Shipping;
using NUglify.Helpers;
using Nop.Plugin.Misc.AuctionPlugin.Domains.Entities.Interfaces;
namespace Nop.Plugin.Misc.AuctionPlugin.Services;
@ -39,8 +40,144 @@ public class AuctionService(
IAddressService addressService,
ICustomerService customerService,
IOrderService orderService,
ILogger logger) : IAuctionService
ILogger logger,
ICategoryService categoryService) : IAuctionService
{
#region AuctionHub
public async Task<ResponseType> UpdateProductToAuctionStatusIfValidAsync(AuctionStatus newProductToAuctionStatus, Auction auction, ProductToAuctionMapping productToAuction, Customer customer, bool updateInDatabase = true)
{
if (!IsValidRequestAuctionStatus(newProductToAuctionStatus, productToAuction.AuctionStatus))
{
logger.Error($"AuctionHub.UpdateProductToAuctionStatusIfValidAsync(); RequestAuctionStatusIsValid() == false; newStatus: {newProductToAuctionStatus}; oldStatus: {productToAuction.AuctionStatus}", null, customer);
return ResponseType.ToCaller;
}
if (newProductToAuctionStatus == AuctionStatus.None) await ResetProductToAuction(productToAuction, auction.CategoryId);
else
{
switch (newProductToAuctionStatus)
{
case AuctionStatus.Active:
productToAuction.AuctionStatus = AuctionStatus.Active;
await UpdateProductCategoryIsFeaturedAsync(productToAuction.ProductId, auction.CategoryId, true);
break;
case AuctionStatus.FirstWarning:
case AuctionStatus.SecondWarning:
productToAuction.AuctionStatus = newProductToAuctionStatus;
break;
case AuctionStatus.Sold:
case AuctionStatus.NotSold:
var lastAuctionBid = await GetLastAuctionBidByProductToAuctionIdAsync(productToAuction.Id);
if (lastAuctionBid == null || lastAuctionBid.BidPrice < productToAuction.MinimumPrice) productToAuction.AuctionStatus = AuctionStatus.NotSold;
else
{
productToAuction.AuctionStatus = AuctionStatus.Sold;
productToAuction.CurrentPrice = lastAuctionBid.BidPrice;
productToAuction.WinnerCustomerId = lastAuctionBid.CustomerId;
var placeOrderResult = await CreateOrderForWinnerAsync(productToAuction);
if (placeOrderResult == null || placeOrderResult.Id == 0)
{
logger.Error($"AuctionHub.UpdateProductToAuctionStatusIfValidAsync(); (placeOrderResult == null || placeOrderResult.Id == 0)", null, customer);
//return; //TODO: EGYELŐRE HAGYJUK LEZÁRNI AKKOR IS, HA NEM SIKERÜLT AZ ORDERPLACE()! - J.
}
}
await UpdateProductCategoryIsFeaturedAsync(productToAuction.ProductId, auction.CategoryId, false);
break;
case AuctionStatus.Pause:
productToAuction.AuctionStatus = AuctionStatus.Pause;
break;
default:
logger.Error($"AuctionHub.UpdateProductToAuctionStatusIfValidAsync(); AuctionStatus not found; (newStatus == {newProductToAuctionStatus})", null, customer);
return ResponseType.ToCaller;
}
if (updateInDatabase)
await UpdateProductToAuctionAsync(productToAuction);
}
return ResponseType.ToAllClients;
}
public async Task<(Auction auction, ProductToAuctionMapping productToAuction, ResponseType responseType)> GetAndUpdateProductToAuctionStatusIfValidAsync(int productToAuctionId, AuctionStatus newProductToAuctionStatus, Customer customer)
{
var productToAuction = await GetProductToAuctionMappingByIdAsync(productToAuctionId);
if (productToAuction == null)
{
logger.Error($"AuctionHub.GetAndUpdateProductToAuctionStatusIfValidAsync(); (productToAuction == null)", null, customer);
return (null, null, ResponseType.None);
}
var auction = await GetAuctionByIdAsync(productToAuction.AuctionId);
if (auction == null || auction.Closed)
{
logger.Error($"AuctionHub.GetAndUpdateProductToAuctionStatusIfValidAsync(); (auction == null || auction.Closed); Closed: {auction?.Closed}", null, customer);
return (null, null, ResponseType.None);
}
var responseType = await UpdateProductToAuctionStatusIfValidAsync(newProductToAuctionStatus, auction, productToAuction, customer);
return (auction, productToAuction, responseType);
}
public async Task ResetProductToAuction(ProductToAuctionMapping productToAuction, int? categoryId = null)
{
productToAuction.AuctionStatus = AuctionStatus.None;
await ResetProductToAuctionAsync(productToAuction, productToAuction.StartingPrice);
categoryId ??= (await GetAuctionByIdAsync(productToAuction.AuctionId))?.CategoryId;
await UpdateProductCategoryIsFeaturedAsync(productToAuction.ProductId, categoryId, false);
}
public async Task UpdateProductCategoryIsFeaturedAsync(int productId, int? categoryId, bool isFeatured)
{
//Leszarjuk ha elszáll, az aukció menjen tovább... - J.
try
{
if (categoryId.GetValueOrDefault(0) == 0) return;
var productCategory = (await categoryService.GetProductCategoriesByProductIdAsync(productId)).FirstOrDefault(x => x.CategoryId == categoryId);
if (productCategory == null) return;
if (productCategory.IsFeaturedProduct == isFeatured) return;
productCategory.IsFeaturedProduct = isFeatured;
await categoryService.UpdateProductCategoryAsync(productCategory);
}
catch (Exception ex)
{
logger.Error($"AuctionHub.UpdateProductCategoryIsFeaturedAsync(); categoryId: {categoryId}; productId: {productId}; isFeatured: {isFeatured}", ex);
}
}
public bool IsValidRequestAuctionStatus(AuctionStatus newStatus, AuctionStatus oldStatus)
{
switch (oldStatus)
{
case AuctionStatus.None:
return newStatus is AuctionStatus.Active or AuctionStatus.Pause;
case AuctionStatus.Active:
return newStatus is AuctionStatus.FirstWarning or AuctionStatus.Pause;
case AuctionStatus.FirstWarning:
return newStatus is AuctionStatus.SecondWarning or AuctionStatus.Pause;
case AuctionStatus.SecondWarning:
return newStatus is AuctionStatus.Sold or AuctionStatus.Pause;
case AuctionStatus.Pause:
return newStatus is AuctionStatus.None or AuctionStatus.Active;
case AuctionStatus.Sold:
case AuctionStatus.NotSold:
default:
return false;
}
}
#endregion
#region Methods
public static decimal GetStepAmount(decimal currentPrice)
@ -103,29 +240,35 @@ public class AuctionService(
public Task ResetProductToAuctionAsync(ProductToAuctionMapping productToAuction, decimal basePrice = 0)
=> ctx.ResetProductToAuctionAsync(productToAuction, basePrice);
public Task<AuctionBid> GetLastAuctionBidByProductToAuctionIdAsync(int productToAuctionId)
=> ctx.GetLastAuctionBidByProductToAuctionId(productToAuctionId);
public Task<List<AuctionBid>> GetAllLastBidByAuctionIdAsync(int auctionId)
=> ctx.GetAllLastBidByAuctionIdAsync(auctionId);
public Task<int> GetBidsCountByProductToAuctionIdAsync(int productToAuctionId)
=> ctx.GetBidsCountByProductToAuctionIdAsync(productToAuctionId);
public Task<Dictionary<int, AuctionBid>> GetAllLastBidDictionaryByAuctionIdAsync(int auctionId)
=> ctx.GetAllLastBidDictionaryByAuctionIdAsync(auctionId);
public Task<bool> HasBidByProductToAuctionIdAsync(int productToAuctionId)
=> ctx.HasBidByProductToAuctionIdAsync(productToAuctionId);
public Task<AuctionBid> GetLastAuctionBidByProductToAuctionIdAsync(int productToAuctionId)
=> ctx.GetLastAuctionBidByProductToAuctionId(productToAuctionId);
public Task<AuctionBid> RevertAuctionBidByProductToAuctionIdAsync(int productToAuctionId)
=> ctx.RevertAuctionBidByProductToAuctionId(productToAuctionId);
public Task<int> GetBidsCountByProductToAuctionIdAsync(int productToAuctionId)
=> ctx.GetBidsCountByProductToAuctionIdAsync(productToAuctionId);
public async Task<Product> GetProductById(int productId)
{
var product = await productService.GetProductByIdAsync(productId);
if (product != null) return product;
public Task<bool> HasBidByProductToAuctionIdAsync(int productToAuctionId)
=> ctx.HasBidByProductToAuctionIdAsync(productToAuctionId);
logger.Error($"AuctionService.GetProductById(); (product == null)", null, await workContext.GetCurrentCustomerAsync());
return null;
public Task<AuctionBid> RevertAuctionBidByProductToAuctionIdAsync(int productToAuctionId)
=> ctx.RevertAuctionBidByProductToAuctionId(productToAuctionId);
}
public async Task<Product> GetProductById(int productId)
{
var product = await productService.GetProductByIdAsync(productId);
if (product != null) return product;
/// <summary>
logger.Error($"AuctionService.GetProductById(); (product == null)", null, await workContext.GetCurrentCustomerAsync());
return null;
}
/// <summary>
/// Gets all bids
/// </summary>
/// <param name="customerId">The store identifier; pass 0 to load all records</param>
@ -258,7 +401,7 @@ public class AuctionService(
var winnerCustomer = await customerService.GetCustomerByIdAsync(productToAuction.WinnerCustomerId);
var storeId = winnerCustomer.RegisteredInStoreId;
var billingAddress = await InsertOrUpdateBillingAddressAsync(winnerCustomer);
if (billingAddress == null)
{
@ -386,6 +529,7 @@ public class AuctionService(
}
#region auctions
public async Task InsertAuctionAsync(Auction auction)
{
await ctx.Auctions.InsertAsync(auction, false);
@ -396,19 +540,20 @@ public class AuctionService(
await ctx.Auctions.UpdateAsync(auction);
}
public Task<List<Auction>> GetAllAuctionsAsync() =>ctx.Auctions.GetAllAuctions().ToListAsync();
public Task<List<Auction>> GetAllCurrentAutoOpenAndClosedAuctionsAsync() =>ctx.Auctions.GetAllCurrentAutoOpenAndClosedAuctions().ToListAsync();
public Task<List<Auction>> GetAllAuctionsAsync() => ctx.Auctions.GetAllAuctions().ToListAsync();
public Task<List<Auction>> GetAllCurrentAutoOpenAndClosedAuctionsAsync() => ctx.Auctions.GetAllCurrentAutoOpenAndClosedAuctions().ToListAsync();
public async Task<List<ProductToAuctionMapping>> GetProductToAuctionsByAuctionIdAsync(int auctionId, bool onlyActiveItems)
=> await ctx.ProductToAuctions.GetProductToAuctionsByAuctionId(auctionId, onlyActiveItems).OrderBy(x => x.SortIndex).ToListAsync();
public Task<ProductToAuctionMapping> GetNextProductToAuctionByAuctionIdAsync(int auctionId)
public Task<ProductToAuctionMapping> GetNextProductToAuctionByAuctionIdAsync(int auctionId)
=> ctx.ProductToAuctions.GetNextItemByAuctionIdAsync(auctionId);
public Task<List<ProductToAuctionMapping>> GetNotClosedProductToAuctionsByAuctionId(int auctionId)
=> ctx.ProductToAuctions.GetNotClosedItemsByAuctionId(auctionId).OrderBy(x => x.SortIndex).ToListAsync();
#endregion
#endregion
#region Dtos
@ -420,7 +565,7 @@ public class AuctionService(
foreach (var auctionDtoProductToAuctionDto in auctionDto.ProductToAuctionDtos)
{
auctionDtoProductToAuctionDto.AuctionBidDtos.AddRange(await ctx.AuctionBids.GetByProductToAuctionId(auctionDtoProductToAuctionDto.Id).OrderByDescending(x => x.Id).Take(maxBidsCount).Select(x => new AuctionBidDto(x)).ToListAsync());
auctionDtoProductToAuctionDto.AuctionBidDtos.AddRange(await ctx.AuctionBids.GetAllByProductToAuctionId(auctionDtoProductToAuctionDto.Id).OrderByDescending(x => x.Id).Take(maxBidsCount).Select(x => new AuctionBidDto(x)).ToListAsync());
}
return auctionDto;
@ -435,7 +580,7 @@ public class AuctionService(
var auctionDto = new AuctionDto(auction);
if (widthProducts) auctionDto.ProductToAuctionDtos.AddRange((await GetProductToAuctionDtosByAuctionId(auctionId, activeProductOnly)));
return auctionDto;
}
@ -474,22 +619,22 @@ public class AuctionService(
public async Task<List<ProductToAuctionDto>> GetProductToAuctionDtosByProductIdAsync(int productId)
{
return [..await ctx.ProductToAuctions.GetByProductId(productId).Select(x=>new ProductToAuctionDto(x)).ToListAsync()];
return [..await ctx.ProductToAuctions.GetByProductId(productId).Select(x => new ProductToAuctionDto(x)).ToListAsync()];
}
public async Task<AuctionBidDto> GetAuctionBidDtoByIdAsync(int auctionBidId)
{
var auctionBid = await ctx.AuctionBids.GetByIdAsync(auctionBidId);
return auctionBid == null ? null : new AuctionBidDto(auctionBid);
}
public Task<List<ProductToAuctionMapping>> GetProductToAuctionsByProductIdAsync(int productId)
public Task<List<ProductToAuctionMapping>> GetProductToAuctionsByProductIdAsync(int productId)
=> ctx.GetProductToAuctionsByProductIdAsync(productId);
public Task<List<ProductToAuctionMapping>> GetProductToAuctionByAuctionIdAndProductIdAsync(int auctionId, int productId, bool activeProductOnly)
=> ctx.GetProductToAuctionByAuctionIdAndProductIdAsync(auctionId, productId, activeProductOnly);
public async Task<ProductToAuctionMapping> AssignProductToAuctionAsync(int productId, decimal startingPrice, decimal bidPrice, int auctionId)
{
@ -528,12 +673,12 @@ public class AuctionService(
return await ctx.ProductToAuctions.GetByIdAsync(productToAuctionMappingId);
}
public async Task UpdateProductToAuctionMappingAsync(ProductToAuctionMapping productToAuctionMapping)
public async Task UpdateProductToAuctionAsync(ProductToAuctionMapping productToAuctionMapping)
{
await ctx.ProductToAuctions.UpdateAsync(productToAuctionMapping);
}
public async Task UpdateProductToAuctionMappingAsync(IList<ProductToAuctionMapping> productToAuctionMappings)
public async Task UpdateProductToAuctionAsync(IList<ProductToAuctionMapping> productToAuctionMappings)
{
await ctx.ProductToAuctions.UpdateAsync(productToAuctionMappings);
}

View File

@ -1,9 +1,11 @@
using Microsoft.AspNetCore.Mvc;
using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Orders;
using Nop.Plugin.Misc.AuctionPlugin.Domains;
using Nop.Plugin.Misc.AuctionPlugin.Domains.Dtos;
using Nop.Plugin.Misc.AuctionPlugin.Domains.Entities;
using Nop.Plugin.Misc.AuctionPlugin.Domains.Enums;
using Nop.Services.Orders;
namespace Nop.Plugin.Misc.AuctionPlugin.Services;
@ -14,7 +16,11 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Services;
public interface IAuctionService
{
//decimal GetStepAmount(decimal currentPrice);
Task<ResponseType> UpdateProductToAuctionStatusIfValidAsync(AuctionStatus newProductToAuctionStatus, Auction auction, ProductToAuctionMapping productToAuction, Customer customer, bool updateInDatabase = true);
Task<(Auction auction, ProductToAuctionMapping productToAuction, ResponseType responseType)> GetAndUpdateProductToAuctionStatusIfValidAsync(int productToAuctionId, AuctionStatus newProductToAuctionStatus, Customer customer);
Task ResetProductToAuction(ProductToAuctionMapping productToAuction, int? categoryId = null);
Task UpdateProductCategoryIsFeaturedAsync(int productId, int? categoryId, bool isFeatured);
bool IsValidRequestAuctionStatus(AuctionStatus newStatus, AuctionStatus oldStatus);
/// <summary>
/// Gets all bids
@ -29,6 +35,8 @@ public interface IAuctionService
Task<IPagedList<AuctionBid>> GetAllBidsAsync(int customerId = 0, int pageIndex = 0, int pageSize = int.MaxValue);
Task<int> GetBidsCountByProductToAuctionIdAsync(int productToAuctionId);
Task<List<AuctionBid>> GetAllLastBidByAuctionIdAsync(int auctionId);
Task<Dictionary<int, AuctionBid>> GetAllLastBidDictionaryByAuctionIdAsync(int auctionId);
Task<bool> HasBidByProductToAuctionIdAsync(int productToAuctionId);
Task<AuctionBid> GetBidByIdAsync(int bidId);
@ -65,8 +73,8 @@ public interface IAuctionService
Task<List<ProductToAuctionMapping>> GetProductToAuctionByAuctionIdAndProductIdAsync(int auctionId, int productId, bool activeProductOnly);
Task<ProductToAuctionMapping> GetProductToAuctionMappingByIdAsync(int productToAuctionMappingId);
Task UpdateProductToAuctionMappingAsync(ProductToAuctionMapping productToAuctionMapping);
Task UpdateProductToAuctionMappingAsync(IList<ProductToAuctionMapping> productToAuctionMappings);
Task UpdateProductToAuctionAsync(ProductToAuctionMapping productToAuctionMapping);
Task UpdateProductToAuctionAsync(IList<ProductToAuctionMapping> productToAuctionMappings);
Task<Order> CreateOrderForWinnerAsync(ProductToAuctionMapping productToAuctionMapping);
}

View File

@ -4,5 +4,5 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Services;
public interface ISessionItem : IMgSessionItem
{
int CustomerId { get; set; }
}

View File

@ -4,5 +4,5 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Services;
public interface ISessionService : IMgSessionService<SessionItem>
{
bool TryGetSessionItemByCustomerId(int customerId, out SessionItem sessionItem);
}

View File

@ -4,5 +4,5 @@ namespace Nop.Plugin.Misc.AuctionPlugin.Services;
public class SessionItem(string sessionKey) : MgSessionItem(sessionKey), ISessionItem
{
public int CustomerId { get; set; }
}

View File

@ -1,8 +1,13 @@
using Mango.Nop.Services;
using Nop.Core.Domain.Customers;
namespace Nop.Plugin.Misc.AuctionPlugin.Services;
public class SessionService : MgSessionService<SessionItem>, ISessionService
{
public bool TryGetSessionItemByCustomerId(int customerId, out SessionItem sessionItem)
{
sessionItem = Sessions.Values.FirstOrDefault(x => x.CustomerId == customerId);
return sessionItem != null;
}
}