357 lines
18 KiB
C#
357 lines
18 KiB
C#
using AyCode.Core.Extensions;
|
|
using AyCode.Utils.Extensions;
|
|
using Nop.Plugin.Misc.AuctionPlugin.Hubs.Messages;
|
|
using Nop.Plugin.Misc.AuctionPlugin.Models;
|
|
using Nop.Plugin.Misc.AuctionPlugin.Services;
|
|
using Nop.Services.Catalog;
|
|
using Nop.Services.Logging;
|
|
using Microsoft.AspNetCore.SignalR;
|
|
using Nop.Core;
|
|
using Nop.Core.Domain.Catalog;
|
|
using Nop.Plugin.Misc.AuctionPlugin.Domains.Enums;
|
|
using Nop.Core.Domain.Customers;
|
|
using Nop.Plugin.Misc.AuctionPlugin.Domains.Entities;
|
|
using Nop.Services.Customers;
|
|
using DocumentFormat.OpenXml.Wordprocessing;
|
|
using Mango.Nop.Core.Repositories;
|
|
using Nop.Core.Caching;
|
|
using Nop.Plugin.Misc.AuctionPlugin.Domains.Entities.Interfaces;
|
|
|
|
namespace Nop.Plugin.Misc.AuctionPlugin.Hubs
|
|
{
|
|
//- Dollár currency
|
|
//- Pipa, ha tied a licit
|
|
//- Pause, Lezárás, Revert,
|
|
|
|
//- ha saját licit a legjobb vagy lezárt, ne lehessen bid-elni
|
|
//- az előző esetben a kliensen a gombot is tiltani, már a.cshtml-ben ellenőrizni!
|
|
|
|
|
|
//- csak a watch-olt item-eknél legyen announcment
|
|
//- ha bid-elt 1x is, kerüljön a watch-ba
|
|
//- DbTransaction-t vhogy megcsinánli!
|
|
|
|
public class SignalRMessageHandler(ILogger logger, IProductService productService, AuctionService auctionService, IHubContext<AuctionHub> hubContext, IWorkContext workContext, ICustomerService customerService)
|
|
{
|
|
private readonly Mutex _handleMessageMutex = new();
|
|
|
|
public async Task HandleMessage(MessageWrapper message)
|
|
{
|
|
var customer = await workContext.GetCurrentCustomerAsync();
|
|
|
|
if (message?.Data == null)
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleMessage(); message?.Data == null", null, customer);
|
|
return;
|
|
}
|
|
|
|
await logger.InformationAsync($"SignalRMessageHandler.HandleMessage(); jsonData: {message.Data}", null, customer);
|
|
|
|
if (customer == null || message.SenderId <= 0 || message.SenderId != customer.Id || await customerService.IsGuestAsync(customer))
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleMessage(); (customer == null || message.SenderId <= 0 || message.SenderId != customer.Id || IsGuestAsync() == true)", null, customer);
|
|
return;
|
|
}
|
|
|
|
using (_handleMessageMutex.UseWaitOne())
|
|
{
|
|
try
|
|
{
|
|
if (message.MessageType == "BidRequestMessage") await HandleBidRequest(customer, message.Data.JsonTo<AuctionBidRequest>());
|
|
else
|
|
{
|
|
if (!await customerService.IsAdminAsync(customer))
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); IsAdminAsync() == false!", null, customer);
|
|
return;
|
|
}
|
|
|
|
switch (message.MessageType)
|
|
{
|
|
case nameof(AuctionProductStatusRequest):
|
|
await HandleProductToAuctionStatusChangedRequest(customer, message.Data.JsonTo<AuctionProductStatusRequest>());
|
|
break;
|
|
|
|
case nameof(RevertAuctionBidRequest):
|
|
await HandleRevertAuctionBidRequest(customer, message.Data.JsonTo<RevertAuctionBidRequest>());
|
|
break;
|
|
|
|
default:
|
|
// Add other message types here
|
|
await logger.ErrorAsync($"SignalRMessageHandler.HandleMessage(); Unknown message type; MessageType: {message.MessageType}", null, customer);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleMessage(); switch (message.MessageType); MessageType: {message.MessageType}; Exception: {ex.Message}", ex, customer);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task HandleRevertAuctionBidRequest(Customer customer, RevertAuctionBidRequest revertAuctionBidRequest)
|
|
{
|
|
if (revertAuctionBidRequest == null)
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleRevertAuctionBidRequest(); auctionProductStatusRequest == null", null, customer);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var productToAuction = (await auctionService.GetProductToAuctionMappingByIdAsync(revertAuctionBidRequest.ProductToAuctionId));
|
|
if (productToAuction is not { AuctionStatus: AuctionStatus.Pause })
|
|
{
|
|
logger.Warning($"SignalRMessageHandler.HandleRevertAuctionBidRequest(); (productToAuction is not {{ AuctionStatus: AuctionStatus.Pause }}); AuctionStatus: {productToAuction?.AuctionStatus}", null, customer);
|
|
return; //TODO: - J.
|
|
}
|
|
|
|
var product = await auctionService.GetProductById(productToAuction.ProductId);
|
|
if (product == null) return;
|
|
|
|
var revertLastBid = await auctionService.RevertAuctionBidByProductToAuctionIdAsync(productToAuction.Id);
|
|
|
|
if (revertLastBid == null) await ResetProductToAuction(productToAuction);
|
|
else await SetAuctionBidPrice(revertLastBid.BidPrice, productToAuction, product, revertLastBid.CustomerId);
|
|
|
|
await SendAuctionBidMessageAsync(productToAuction, product, customer.Id);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleRevertAuctionBidRequest(); Exception: {ex.Message}", ex, customer);
|
|
}
|
|
}
|
|
|
|
private async Task HandleProductToAuctionStatusChangedRequest(Customer customer, AuctionProductStatusRequest auctionProductStatusRequest)
|
|
{
|
|
if (auctionProductStatusRequest == null)
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); auctionProductStatusRequest == null", null, customer);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
await logger.InformationAsync($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); ProductToAuctionMappingId: {auctionProductStatusRequest.ProductToAuctionId}; Status: {auctionProductStatusRequest.AuctionStatus}({(int)auctionProductStatusRequest.AuctionStatus})", null, customer);
|
|
|
|
var auction = await auctionService.GetAuctionDtoByProductToAuctionIdAsync(auctionProductStatusRequest.ProductToAuctionId, false);
|
|
if (auction == null || auction.Closed)
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); (auction == null || auction.Closed); Closed: {auction?.Closed}", null, customer);
|
|
return;
|
|
}
|
|
|
|
var productToAuction = await auctionService.GetProductToAuctionMappingByIdAsync(auctionProductStatusRequest.ProductToAuctionId);
|
|
if (productToAuction == null)
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); (productToAuction == null)", null, customer);
|
|
return;
|
|
}
|
|
|
|
if (!IsValidRequestAuctionStatus(auctionProductStatusRequest.AuctionStatus, productToAuction.AuctionStatus))
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); RequestAuctionStatusIsValid() == false; newStatus: {auctionProductStatusRequest.AuctionStatus}; oldStatus: {productToAuction.AuctionStatus}", null, customer);
|
|
return;
|
|
}
|
|
|
|
if (auctionProductStatusRequest.AuctionStatus == AuctionStatus.None) await ResetProductToAuction(productToAuction);
|
|
else
|
|
{
|
|
switch (auctionProductStatusRequest.AuctionStatus)
|
|
{
|
|
case AuctionStatus.Pause:
|
|
productToAuction.AuctionStatus = AuctionStatus.Pause;
|
|
break;
|
|
|
|
case AuctionStatus.Sold:
|
|
var lastAuctionBid = await auctionService.GetLastAuctionBidByProductToAuctionIdAsync(productToAuction.Id);
|
|
if (lastAuctionBid == null)
|
|
{
|
|
productToAuction.AuctionStatus = AuctionStatus.NotSold;
|
|
break;
|
|
}
|
|
|
|
productToAuction.AuctionStatus = AuctionStatus.Sold;
|
|
productToAuction.CurrentPrice = lastAuctionBid.BidPrice;
|
|
productToAuction.WinnerCustomerId = lastAuctionBid.CustomerId;
|
|
|
|
//productToAuction.OrderGuid = Guid.NewGuid(); //TODO: - J.
|
|
|
|
var placeOrderResult = await auctionService.CreateOrderForWinnerAsync(productToAuction);
|
|
if (placeOrderResult is not { Success: true }) return;
|
|
|
|
//productToAuction.OrderId = placedOrder.PlacedOrder.Id; //TODO: - J.
|
|
break;
|
|
|
|
case AuctionStatus.NotSold:
|
|
logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); (auctionProductStatusRequest.AuctionStatus == AuctionStatus.NotSold)", null, customer);
|
|
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 = customer.Id,
|
|
Data = new ProductToAuctionStatusNotification(await auctionService.GetAuctionDtoByProductToAuctionIdAsync(productToAuction.Id, true))
|
|
{
|
|
ToasterMessage = "EMPTY", //TODO: - J.
|
|
}.ToJson()
|
|
};
|
|
|
|
await hubContext.Clients.All.SendAsync("send", productToauctionChangedNotification.ToJson());
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); Exception: {ex.Message}", ex, customer);
|
|
}
|
|
}
|
|
|
|
private Task ResetProductToAuction(ProductToAuctionMapping productToAuction)
|
|
{
|
|
productToAuction.AuctionStatus = AuctionStatus.None;
|
|
return auctionService.ResetProductToAuctionAsync(productToAuction, productToAuction.StartingPrice);
|
|
}
|
|
|
|
private async Task HandleBidRequest(Customer customer, AuctionBidRequest bidRequestMessage)
|
|
{
|
|
if (bidRequestMessage == null)
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleBidRequest(); (bidRequestMessage == null)", null, customer);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
await logger.InformationAsync($"SignalRMessageHandler.HandleBidRequest(); Bid received; Auction: {bidRequestMessage.AuctionId}; ProductToAuction: {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)
|
|
{
|
|
logger.Warning($"SignalRMessageHandler.HandleBidRequest(); (auction == null || auction.Closed); Closed: {auction?.Closed}", null, customer);
|
|
return;
|
|
}
|
|
|
|
var activeProductAuction = (await auctionService.GetProductToAuctionByAuctionIdAndProductIdAsync(bidRequestMessage.AuctionId, bidRequestMessage.ProductId, true)).FirstOrDefault();
|
|
if (activeProductAuction is not { IsActiveItem: true } || (activeProductAuction.WinnerCustomerId == customer.Id && !await customerService.IsAdminAsync(customer)))
|
|
{
|
|
logger.Warning($"SignalRMessageHandler.HandleBidRequest(); (activeProductAuction is not {{ IsActiveItem: true }} || activeProductAuction.WinnerCustomerId == customer.Id && !await customerService.IsAdminAsync(customer)); AuctionStatus: {activeProductAuction?.AuctionStatus}; WinnerCustomerId: {activeProductAuction?.WinnerCustomerId}", null, customer);
|
|
return; //TODO: - J.
|
|
}
|
|
|
|
var product = await auctionService.GetProductById(bidRequestMessage.ProductId);
|
|
if (product == null) return;
|
|
|
|
if (IsValidBidPrice(product.Price, activeProductAuction.CurrentPrice, bidRequestMessage.BidPrice, customer)) return;
|
|
|
|
var auctionBid = bidRequestMessage.CreateMainEntity();
|
|
auctionBid.ProductAuctionMappingId = activeProductAuction.Id;
|
|
|
|
await auctionService.InsertBidAsync(auctionBid);
|
|
|
|
activeProductAuction.AuctionStatus = AuctionStatus.Active;
|
|
if (!await SetAuctionBidPrice(auctionBid.BidPrice, activeProductAuction, product, customer.Id)) return;
|
|
|
|
await SendAuctionBidMessageAsync(activeProductAuction, product, customer.Id);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleBidRequest(); Exception: {ex.Message}", ex, customer);
|
|
}
|
|
}
|
|
|
|
private bool IsValidBidPrice(decimal productPrice, decimal productToAuctionCurrentPrice, decimal bidRequestPrice, Customer customer = null)
|
|
{
|
|
if (productPrice >= bidRequestPrice || productToAuctionCurrentPrice >= bidRequestPrice || bidRequestPrice != GetNextBidPrice(productToAuctionCurrentPrice))
|
|
{
|
|
logger.Warning($"SignalRMessageHandler.IsValidBidPrice(); (productPrice >= bidRequestPrice || productToAuctionCurrentPrice >= bidRequestPrice || bidRequestPrice != GetNextBidPrice(productToAuctionCurrentPrice)); productPrice: {productPrice}; productToAuctionCurrentPrice: {productToAuctionCurrentPrice}; bidRequestPrice: {bidRequestPrice}", null, customer);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private async Task SendAuctionBidMessageAsync(ProductToAuctionMapping productToAuction, Product product, int customerId)
|
|
{
|
|
var stepAmount = GetStepAmount(productToAuction.CurrentPrice);
|
|
var nextBidPrice = GetNextBidPrice(productToAuction.CurrentPrice, stepAmount);
|
|
|
|
var bidMessage = new MessageWrapper
|
|
{
|
|
MessageType = "bidNotification",
|
|
SenderId = customerId,
|
|
Data = new BidNotificationMessage(await auctionService.GetAuctionDtoByProductToAuctionIdAsync(productToAuction.Id, true)) //TODO: NE KÉRJÜK LE DB-BŐL!!! - j.
|
|
{
|
|
ProductName = product.Name,
|
|
CurrentPrice = productToAuction.CurrentPrice,
|
|
NextStepAmount = stepAmount,
|
|
NextBidPrice = nextBidPrice,
|
|
ToasterMessage = "EMPTY", //TODO: - J.
|
|
}.ToJson()
|
|
};
|
|
|
|
await hubContext.Clients.All.SendAsync("send", bidMessage.ToJson());
|
|
}
|
|
|
|
private async Task<bool> SetAuctionBidPrice(decimal bidPrice, ProductToAuctionMapping productToAuction, Product product, int lastBidCustomerId)
|
|
{
|
|
try
|
|
{
|
|
product.Price = bidPrice;
|
|
await productService.UpdateProductAsync(product);
|
|
|
|
//activeProductAuction.StartingPrice = product.OldPrice; //TODO: ez biztosan kezelve van mikor összerendeljük? - J.
|
|
productToAuction.CurrentPrice = product.Price;
|
|
productToAuction.WinnerCustomerId = lastBidCustomerId;
|
|
await auctionService.UpdateProductToAuctionMappingAsync(productToAuction);
|
|
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Error($"SignalRMessageHandler.HandleBidRequest(); SetAuctionBidPrice() == false", ex);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static decimal GetStepAmount(decimal currentBidPrice) => AuctionService.GetStepAmount(currentBidPrice);
|
|
private static decimal GetNextBidPrice(decimal currentBidPrice) => GetNextBidPrice(currentBidPrice, GetStepAmount(currentBidPrice));
|
|
private static decimal GetNextBidPrice(decimal currentBidPrice, decimal stepAmount)
|
|
{
|
|
return currentBidPrice + stepAmount;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|