diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Components/_FruitBankDashboard.cshtml b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Components/_FruitBankDashboard.cshtml index 6de8dc6..6caaa77 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Components/_FruitBankDashboard.cshtml +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Components/_FruitBankDashboard.cshtml @@ -176,7 +176,7 @@ @@ -277,7 +277,7 @@ if (alert.type === 'credit_exceeded') return 'Hitelkeret'; if (alert.type === 'old_preorder') - return 'Előrendelések'; + return 'Előrendelések'; return ''; } @@ -374,10 +374,10 @@ } // ── Pending preorders ──────────────────────────────────────────── - if (data.pendingPreorders && data.pendingPreorders.length > 0) { - $('#fb-preorders-count').text(data.pendingPreorders.length); + if (data.pendingPreOrders && data.pendingPreOrders.length > 0) { + $('#fb-preorders-count').text(data.pendingPreOrders.length); var $pb = $('#fb-preorders-body').empty(); - data.pendingPreorders.forEach(function (p) { + data.pendingPreOrders.forEach(function (p) { $pb.append( '' + '' + p.company + '' + @@ -385,7 +385,7 @@ '' + p.itemCount + '' + '' + p.fulfilledCount + ' / ' + p.itemCount + '' + '' + preorderStatusBadge(p.status) + '' + - 'Részletek' + + 'Részletek' + '' ); }); diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomDashboardController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomDashboardController.cs index 0e7f3c3..8bcc546 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomDashboardController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomDashboardController.cs @@ -37,7 +37,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers protected readonly IWorkContext _workContext; protected readonly AICalculationService _aiCalculationService; protected readonly FruitBankDbContext _fruitBankDbContext; - protected readonly PreorderDbContext _preorderDbContext; + protected readonly PreOrderDbContext _preorderDbContext; #endregion @@ -55,7 +55,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers IWorkContext workContext, AICalculationService aiCalculationService, FruitBankDbContext fruitBankDbContext, - PreorderDbContext preorderDbContext) + PreOrderDbContext preorderDbContext) { _adminAreaSettings = adminAreaSettings; _commonModelFactory = commonModelFactory; @@ -186,32 +186,32 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers var today = DateTime.Now.Date; // ── Batch 1: parallel queries ───────────────────────────────────── - // NOTE: PreorderItems is not a LinqToDB [Association] — never use LoadWith on it. - // Preorders and items are loaded separately and joined in memory below. + // NOTE: PreOrderItems is not a LinqToDB [Association] — never use LoadWith on it. + // PreOrders and items are loaded separately and joined in memory below. var allOrdersTask = _fruitBankDbContext.OrderDtos.GetAll(true).ToListAsync(); var allCreditsTask = _fruitBankDbContext.CustomerCredits.GetAll().ToListAsync(); - var allPreordersTask = _preorderDbContext.Preorders.GetAll().ToListAsync(); + var allPreOrdersTask = _preorderDbContext.PreOrders.GetAll().ToListAsync(); var unprocessedDocsTask = _fruitBankDbContext.ShippingDocuments.GetAllNotMeasured(true).ToListAsync(); - await Task.WhenAll(allOrdersTask, allCreditsTask, allPreordersTask, unprocessedDocsTask); + await Task.WhenAll(allOrdersTask, allCreditsTask, allPreOrdersTask, unprocessedDocsTask); var allOrders = await allOrdersTask; var credits = await allCreditsTask; var unprocessedDocs = await unprocessedDocsTask; // Filter pending preorders in memory — LinqToDB cannot translate enum comparisons to SQL - var pendingStatuses = new[] { PreorderStatus.Pending, PreorderStatus.PartiallyFulfilled }; - var pendingPreorders = (await allPreordersTask) + var pendingStatuses = new[] { PreOrderStatus.Pending, PreOrderStatus.PartiallyFulfilled }; + var pendingPreOrders = (await allPreOrdersTask) .Where(p => pendingStatuses.Contains(p.Status)) .ToList(); // ── Batch 1b: preorder items for pending preorders only ──────────── - var pendingPreorderIds = pendingPreorders.Select(p => p.Id).ToList(); - var pendingItems = pendingPreorderIds.Any() - ? await _preorderDbContext.PreorderItems.GetAll() - .Where(i => pendingPreorderIds.Contains(i.PreorderId)) + var pendingPreOrderIds = pendingPreOrders.Select(p => p.Id).ToList(); + var pendingItems = pendingPreOrderIds.Any() + ? await _preorderDbContext.PreOrderItems.GetAll() + .Where(i => pendingPreOrderIds.Contains(i.PreOrderId)) .ToListAsync() - : new List(); + : new List(); // ── Today's orders (in-memory filter, same pattern as AICalculationService) var todaysOrders = allOrders @@ -249,8 +249,8 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers return $"#{customerId}"; } - // ── Preorder customer names (may not appear in allOrders) ────────── - var preorderCustomerIds = pendingPreorders + // ── PreOrder customer names (may not appear in allOrders) ────────── + var preorderCustomerIds = pendingPreOrders .Select(p => p.CustomerId).Distinct() .Where(id => allOrders.All(o => o.CustomerId != id)) .ToList(); @@ -267,7 +267,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers preorderCustomerLookup[c.Id] = !string.IsNullOrEmpty(c.Company) ? c.Company : c.Email; } - string PreorderCustomerName(int customerId) + string PreOrderCustomerName(int customerId) => preorderCustomerLookup.TryGetValue(customerId, out var name) ? name : CustomerName(customerId); @@ -361,15 +361,15 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers // Pending preorders older than 7 days var sevenDaysAgo = DateTime.UtcNow.AddDays(-7); - foreach (var p in pendingPreorders.Where(p => - p.Status == PreorderStatus.Pending && + foreach (var p in pendingPreOrders.Where(p => + p.Status == PreOrderStatus.Pending && p.CreatedOnUtc < sevenDaysAgo)) { alerts.Add(new { type = "old_preorder", preorderId = p.Id, - company = PreorderCustomerName(p.CustomerId), + company = PreOrderCustomerName(p.CustomerId), createdAt = p.CreatedOnUtc.ToLocalTime().ToString("yyyy.MM.dd"), message = "Régi, nyitott előrendelés" }); @@ -404,20 +404,20 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers // ───────────────────────────────────────────────────────────────── // Section 4: Pending preorders (items joined in memory) // ───────────────────────────────────────────────────────────────── - var preorderRows = pendingPreorders + var preorderRows = pendingPreOrders .OrderBy(p => p.CreatedOnUtc) .Select(p => { - var items = pendingItems.Where(i => i.PreorderId == p.Id).ToList(); + var items = pendingItems.Where(i => i.PreOrderId == p.Id).ToList(); return new { id = p.Id, customerId = p.CustomerId, - company = PreorderCustomerName(p.CustomerId), + company = PreOrderCustomerName(p.CustomerId), status = p.Status.ToString(), createdAt = p.CreatedOnUtc.ToLocalTime().ToString("yyyy.MM.dd"), itemCount = items.Count, - fulfilledCount = items.Count(i => i.Status == PreorderItemStatus.Fulfilled) + fulfilledCount = items.Count(i => i.Status == PreOrderItemStatus.Fulfilled) }; }) .ToList(); @@ -443,7 +443,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers pipeline, alerts, creditStatus = creditRows, - pendingPreorders = preorderRows, + pendingPreOrders = preorderRows, unprocessedDocs = docRows }); } diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs index 9afa861..131e2ab 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs @@ -1076,7 +1076,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers [HttpGet] [CheckPermission(StandardPermission.Catalog.PRODUCTS_VIEW)] - public virtual async Task PreorderProductSearchAutoComplete(string term) + public virtual async Task PreOrderProductSearchAutoComplete(string term) { if (string.IsNullOrWhiteSpace(term) || term.Length < 2) return Json(new List()); @@ -1088,13 +1088,13 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers // Load preorder window attributes in two batch queries var gaStart = await _dbContext.GenericAttributes.Table .Where(ga => ga.KeyGroup == nameof(Product) - && ga.Key == FruitBankConst.PreorderWindowStart + && ga.Key == FruitBankConst.PreOrderWindowStart && ga.StoreId == store.Id) .ToListAsync(); var gaEnd = await _dbContext.GenericAttributes.Table .Where(ga => ga.KeyGroup == nameof(Product) - && ga.Key == FruitBankConst.PreorderWindowEnd + && ga.Key == FruitBankConst.PreOrderWindowEnd && ga.StoreId == store.Id) .ToListAsync(); diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/FileManagerController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/FileManagerController.cs index cfeb78a..78accd1 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/FileManagerController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/FileManagerController.cs @@ -41,7 +41,7 @@ namespace Nop.Plugin.Misc.FruitBank.Controllers private readonly FileStorageService _fileStorageService; private readonly FruitBankAttributeService _fruitBankAttributeService; private readonly IStoreContext _storeContext; - private readonly PreorderConversionService _preorderConversionService; + private readonly PreOrderConversionService _preorderConversionService; public FileManagerController( IPermissionService permissionService, @@ -55,7 +55,7 @@ namespace Nop.Plugin.Misc.FruitBank.Controllers FileStorageService fileStorageService, FruitBankAttributeService fruitBankAttributeService, IStoreContext storeContext, - PreorderConversionService preorderConversionService) + PreOrderConversionService preorderConversionService) { _permissionService = permissionService; _aiApiService = aiApiService; @@ -1140,12 +1140,12 @@ namespace Nop.Plugin.Misc.FruitBank.Controllers try { await _preorderConversionService - .ConvertPreordersForProductsAsync(productIdsWithIncoming, shippingDocument.Id); + .ConvertPreOrdersForProductsAsync(productIdsWithIncoming, shippingDocument.Id); } catch (Exception convEx) { Console.Error.WriteLine( - $"[PreorderConversion] Error during conversion for document #{shippingDocument.Id}: {convEx.Message}"); + $"[PreOrderConversion] Error during conversion for document #{shippingDocument.Id}: {convEx.Message}"); } }); } diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/PreorderAdminController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/PreorderAdminController.cs index d400687..3f28a2f 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/PreorderAdminController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/PreorderAdminController.cs @@ -16,36 +16,36 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers; [AuthorizeAdmin] [Area(AreaNames.ADMIN)] [AutoValidateAntiforgeryToken] -public class PreorderAdminController : BasePluginController +public class PreOrderAdminController : BasePluginController { private readonly IPermissionService _permissionService; - private readonly PreorderDbContext _preorderDbContext; + private readonly PreOrderDbContext _preorderDbContext; private readonly FruitBankDbContext _dbContext; private readonly ICustomerService _customerService; - private readonly PreorderConversionService _preorderConversionService; + private readonly PreOrderConversionService _preorderConversionService; - private static readonly Dictionary StatusLabels = new() + private static readonly Dictionary StatusLabels = new() { - { PreorderStatus.Pending, "Függőben" }, - { PreorderStatus.Confirmed, "Megerősítve" }, - { PreorderStatus.PartiallyFulfilled, "Részben teljesítve" }, - { PreorderStatus.Cancelled, "Törölve" } + { PreOrderStatus.Pending, "Függőben" }, + { PreOrderStatus.Confirmed, "Megerősítve" }, + { PreOrderStatus.PartiallyFulfilled, "Részben teljesítve" }, + { PreOrderStatus.Cancelled, "Törölve" } }; - private static readonly Dictionary ItemStatusLabels = new() + private static readonly Dictionary ItemStatusLabels = new() { - { PreorderItemStatus.Pending, "Függőben" }, - { PreorderItemStatus.Fulfilled, "Teljesítve" }, - { PreorderItemStatus.PartiallyFulfilled, "Részben" }, - { PreorderItemStatus.Dropped, "Ejtve" } + { PreOrderItemStatus.Pending, "Függőben" }, + { PreOrderItemStatus.Fulfilled, "Teljesítve" }, + { PreOrderItemStatus.PartiallyFulfilled, "Részben" }, + { PreOrderItemStatus.Dropped, "Ejtve" } }; - public PreorderAdminController( + public PreOrderAdminController( IPermissionService permissionService, - PreorderDbContext preorderDbContext, + PreOrderDbContext preorderDbContext, FruitBankDbContext dbContext, ICustomerService customerService, - PreorderConversionService preorderConversionService) + PreOrderConversionService preorderConversionService) { _permissionService = permissionService; _preorderDbContext = preorderDbContext; @@ -57,20 +57,20 @@ public class PreorderAdminController : BasePluginController // ── LIST PAGE ───────────────────────────────────────────────────────────── [HttpGet] - [Route("Admin/Preorders")] + [Route("Admin/PreOrders")] public async Task List() { if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) return AccessDeniedView(); - return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Preorder/List.cshtml"); + return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/PreOrder/List.cshtml"); } // ── DATATABLES SERVER-SIDE ──────────────────────────────────────────────── [HttpPost] - [Route("Admin/Preorders/PreorderList")] - public async Task PreorderList() + [Route("Admin/PreOrders/PreOrderList")] + public async Task PreOrderList() { if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) return Forbid(); @@ -87,11 +87,11 @@ public class PreorderAdminController : BasePluginController var statusFilter = Request.Form["statusFilter"].FirstOrDefault()?.Trim() ?? ""; // 1. All preorders with items — two queries - var preorders = await _preorderDbContext.Preorders.GetAll(false).ToListAsync(); - var allItems = await _preorderDbContext.PreorderItems.GetAll().ToListAsync(); + var preorders = await _preorderDbContext.PreOrders.GetAll(false).ToListAsync(); + var allItems = await _preorderDbContext.PreOrderItems.GetAll().ToListAsync(); - var itemsByPreorder = allItems - .GroupBy(i => i.PreorderId) + var itemsByPreOrder = allItems + .GroupBy(i => i.PreOrderId) .ToDictionary(g => g.Key, g => g.ToList()); // 2. Customers — batch @@ -111,7 +111,7 @@ public class PreorderAdminController : BasePluginController var rows = preorders.Select(p => { customerById.TryGetValue(p.CustomerId, out var c); - var items = itemsByPreorder.TryGetValue(p.Id, out var its) ? its : new(); + var items = itemsByPreOrder.TryGetValue(p.Id, out var its) ? its : new(); // Derive status from quantities rather than relying on the enum read var fulfilledCount = items.Count(i => i.FulfilledQuantity > 0); @@ -123,13 +123,13 @@ public class PreorderAdminController : BasePluginController // otherwise infer from quantities var effectiveStatus = (int)p.Status != 0 ? p.Status - : allFulfilled ? PreorderStatus.Confirmed - : anyFulfilled ? PreorderStatus.PartiallyFulfilled - : PreorderStatus.Pending; + : allFulfilled ? PreOrderStatus.Confirmed + : anyFulfilled ? PreOrderStatus.PartiallyFulfilled + : PreOrderStatus.Pending; - return new PreorderListRow + return new PreOrderListRow { - PreorderId = p.Id, + PreOrderId = p.Id, CustomerId = p.CustomerId, CustomerName = c != null ? $"{c.FirstName} {c.LastName}".Trim() : $"#{p.CustomerId}", CustomerEmail = c?.Email ?? string.Empty, @@ -146,7 +146,7 @@ public class PreorderAdminController : BasePluginController int recordsTotal = rows.Count; // 5. Filter by status - if (!string.IsNullOrWhiteSpace(statusFilter) && Enum.TryParse(statusFilter, out var statusEnum)) + if (!string.IsNullOrWhiteSpace(statusFilter) && Enum.TryParse(statusFilter, out var statusEnum)) rows = rows.Where(r => r.Status == statusEnum).ToList(); // 6. Global search @@ -154,7 +154,7 @@ public class PreorderAdminController : BasePluginController rows = rows.Where(r => r.CustomerName.Contains(globalSearch, StringComparison.OrdinalIgnoreCase) || r.CustomerEmail.Contains(globalSearch, StringComparison.OrdinalIgnoreCase) || - r.PreorderId.ToString().Contains(globalSearch) + r.PreOrderId.ToString().Contains(globalSearch) ).ToList(); int recordsFiltered = rows.Count; @@ -178,17 +178,17 @@ public class PreorderAdminController : BasePluginController // ── DETAIL PAGE ─────────────────────────────────────────────────────────── [HttpGet] - [Route("Admin/Preorders/Detail/{id:int}")] + [Route("Admin/PreOrders/Detail/{id:int}")] public async Task Detail(int id) { if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) return AccessDeniedView(); - var preorder = await _preorderDbContext.Preorders.GetByIdAsync(id, loadRelations: false); + var preorder = await _preorderDbContext.PreOrders.GetByIdAsync(id, loadRelations: false); if (preorder == null) return NotFound(); - var items = await _preorderDbContext.PreorderItems - .GetAllByPreorderIdAsync(id) + var items = await _preorderDbContext.PreOrderItems + .GetAllByPreOrderIdAsync(id) .ToListAsync(); var customer = await _customerService.GetCustomerByIdAsync(preorder.CustomerId); @@ -204,9 +204,9 @@ public class PreorderAdminController : BasePluginController // Use preorder.OrderId directly — stored on the entity at conversion time int? linkedOrderId = preorder.OrderId; - var model = new PreorderDetailModel + var model = new PreOrderDetailModel { - PreorderId = preorder.Id, + PreOrderId = preorder.Id, CustomerId = preorder.CustomerId, CustomerName = customer != null ? $"{customer.FirstName} {customer.LastName}".Trim() : $"#{preorder.CustomerId}", CustomerEmail = customer?.Email ?? string.Empty, @@ -222,15 +222,15 @@ public class PreorderAdminController : BasePluginController // Derive item status from quantities — enum reads unreliable in LinqToDB var derivedStatus = i.FulfilledQuantity == 0 - ? PreorderItemStatus.Pending + ? PreOrderItemStatus.Pending : i.FulfilledQuantity >= i.RequestedQuantity - ? PreorderItemStatus.Fulfilled - : PreorderItemStatus.PartiallyFulfilled; + ? PreOrderItemStatus.Fulfilled + : PreOrderItemStatus.PartiallyFulfilled; // If DB enum read as non-zero, prefer it; otherwise use derived var effectiveItemStatus = (int)i.Status != 0 ? i.Status : derivedStatus; - return new PreorderDetailItemRow + return new PreOrderDetailItemRow { ItemId = i.Id, ProductId = i.ProductId, @@ -245,14 +245,14 @@ public class PreorderAdminController : BasePluginController }).ToList() }; - return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Preorder/Detail.cshtml", model); + return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/PreOrder/Detail.cshtml", model); } // ── CREATE (admin phone order) ─────────────────────────────────────────── [HttpPost] - [Route("Admin/Preorders/CreatePreorder")] - public async Task CreatePreorder( + [Route("Admin/PreOrders/CreatePreOrder")] + public async Task CreatePreOrder( int customerId, string deliveryDateTime, string? customerNote, @@ -288,7 +288,7 @@ public class PreorderAdminController : BasePluginController .Select(g => g.StoreId).FirstOrDefaultAsync(); storeId = gaStore > 0 ? gaStore : 1; - var preorder = new Preorder + var preorder = new PreOrder { CustomerId = customerId, StoreId = storeId, @@ -296,13 +296,13 @@ public class PreorderAdminController : BasePluginController CustomerNote = customerNote?.Trim() }; - var items = new List(); + var items = new List(); foreach (var pi in productItems.Where(p => p.quantity > 0)) { var product = await _dbContext.Products.GetByIdAsync(pi.id); if (product == null || product.Deleted || !product.Published) continue; - items.Add(new PreorderItem + items.Add(new PreOrderItem { ProductId = pi.id, RequestedQuantity = pi.quantity, @@ -313,18 +313,18 @@ public class PreorderAdminController : BasePluginController if (!items.Any()) return Json(new { success = false, error = "Nincs érvényes termék az előrendelésben" }); - var saved = await _preorderDbContext.InsertPreorderAsync(preorder, items); + var saved = await _preorderDbContext.InsertPreOrderAsync(preorder, items); Console.WriteLine($"[Admin] Created preorder #{saved.Id} for customer #{customerId} " + $"by admin, {items.Count} items, delivery {deliveryDate:u}"); // Immediately check if any items can be fulfilled from current stock — - // same inline conversion as the customer-facing PlacePreorder endpoint. + // same inline conversion as the customer-facing PlacePreOrder endpoint. var productIds = items.Select(i => i.ProductId).Distinct().ToList(); - await _preorderConversionService.ConvertPreordersForProductsAsync(productIds, 0); + await _preorderConversionService.ConvertPreOrdersForProductsAsync(productIds, 0); // Re-read to pick up OrderId if conversion created a real order - var refreshed = await _preorderDbContext.Preorders.GetByIdAsync(saved.Id); + var refreshed = await _preorderDbContext.PreOrders.GetByIdAsync(saved.Id); return Json(new { success = true, preorderId = saved.Id, orderId = refreshed?.OrderId }); } @@ -347,27 +347,27 @@ public class PreorderAdminController : BasePluginController // ── CANCEL ─────────────────────────────────────────────────────────── [HttpPost] - [Route("Admin/Preorders/Cancel/{id:int}")] + [Route("Admin/PreOrders/Cancel/{id:int}")] public async Task Cancel(int id) { if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) return Json(new { success = false, error = "Access denied" }); - var preorder = await _preorderDbContext.Preorders.GetByIdAsync(id); + var preorder = await _preorderDbContext.PreOrders.GetByIdAsync(id); if (preorder == null) - return Json(new { success = false, error = "Preorder not found" }); + return Json(new { success = false, error = "PreOrder not found" }); - if (preorder.Status != PreorderStatus.Pending) + if (preorder.Status != PreOrderStatus.Pending) return Json(new { success = false, error = "Only pending preorders can be cancelled" }); - await _preorderDbContext.CancelPreorderAsync(id); + await _preorderDbContext.CancelPreOrderAsync(id); return Json(new { success = true }); } // ── DEMAND LIST ─────────────────────────────────────────────────────────── [HttpPost] - [Route("Admin/Preorders/DemandList")] + [Route("Admin/PreOrders/DemandList")] public async Task DemandList(bool openOnly = true) { if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) @@ -380,24 +380,24 @@ public class PreorderAdminController : BasePluginController openOnly = openOnlyParam != "false"; // Fetch all preorder items + preorders in two queries - var allItems = await _preorderDbContext.PreorderItems.GetAll().ToListAsync(); - var allPreorders = await _preorderDbContext.Preorders.GetAll(false).ToListAsync(); + var allItems = await _preorderDbContext.PreOrderItems.GetAll().ToListAsync(); + var allPreOrders = await _preorderDbContext.PreOrders.GetAll(false).ToListAsync(); // For "open only": include only items from preorders that still have // unfulfilled demand (FulfilledQuantity < RequestedQuantity). // We use quantities rather than Status enum (enum reads unreliable). - IEnumerable items = allItems; + IEnumerable items = allItems; if (openOnly) { // Open preorders: those where at least one item still needs fulfillment - var openPreorderIds = allPreorders + var openPreOrderIds = allPreOrders .Where(p => allItems - .Where(i => i.PreorderId == p.Id) + .Where(i => i.PreOrderId == p.Id) .Any(i => i.FulfilledQuantity < i.RequestedQuantity)) .Select(p => p.Id) .ToHashSet(); - items = allItems.Where(i => openPreorderIds.Contains(i.PreorderId)); + items = allItems.Where(i => openPreOrderIds.Contains(i.PreOrderId)); } // Group by product @@ -409,7 +409,7 @@ public class PreorderAdminController : BasePluginController TotalRequested = g.Sum(i => i.RequestedQuantity), TotalFulfilled = g.Sum(i => i.FulfilledQuantity), TotalUnfulfilled = g.Sum(i => i.RequestedQuantity - i.FulfilledQuantity), - PreorderCount = g.Select(i => i.PreorderId).Distinct().Count(), + PreOrderCount = g.Select(i => i.PreOrderId).Distinct().Count(), AvgUnitPrice = g.Where(i => i.UnitPriceInclTax > 0).Any() ? g.Where(i => i.UnitPriceInclTax > 0).Average(i => i.UnitPriceInclTax) : 0m @@ -429,7 +429,7 @@ public class PreorderAdminController : BasePluginController var rows = grouped.Select(g => { productById.TryGetValue(g.ProductId, out var dto); - return new PreorderDemandRow + return new PreOrderDemandRow { ProductId = g.ProductId, ProductName = dto?.Name ?? $"Product #{g.ProductId}", @@ -438,7 +438,7 @@ public class PreorderAdminController : BasePluginController TotalRequested = g.TotalRequested, TotalFulfilled = g.TotalFulfilled, TotalUnfulfilled = g.TotalUnfulfilled, - PreorderCount = g.PreorderCount, + PreOrderCount = g.PreOrderCount, AvgUnitPrice = Math.Round(g.AvgUnitPrice, 0) }; }).ToList(); diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/PreorderAvailabilityController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/PreorderAvailabilityController.cs index bb7c412..58d5428 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/PreorderAvailabilityController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/PreorderAvailabilityController.cs @@ -16,14 +16,14 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers; [AuthorizeAdmin] [Area(AreaNames.ADMIN)] [AutoValidateAntiforgeryToken] -public class PreorderAvailabilityController : BasePluginController +public class PreOrderAvailabilityController : BasePluginController { private readonly IPermissionService _permissionService; private readonly FruitBankDbContext _dbContext; private readonly FruitBankAttributeService _fruitBankAttributeService; private readonly IStoreContext _storeContext; - public PreorderAvailabilityController( + public PreOrderAvailabilityController( IPermissionService permissionService, FruitBankDbContext dbContext, FruitBankAttributeService fruitBankAttributeService, @@ -38,19 +38,19 @@ public class PreorderAvailabilityController : BasePluginController // ── INDEX ───────────────────────────────────────────────────────────────── [HttpGet] - [Route("Admin/PreorderAvailability")] + [Route("Admin/PreOrderAvailability")] public async Task Index() { if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) return AccessDeniedView(); - return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/PreorderAvailability/Index.cshtml"); + return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/PreOrderAvailability/Index.cshtml"); } // ── ALL PRODUCTS — DataTables server-side ───────────────────────────────── [HttpPost] - [Route("Admin/PreorderAvailability/ProductList")] + [Route("Admin/PreOrderAvailability/ProductList")] public async Task ProductList() { if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) @@ -74,13 +74,13 @@ public class PreorderAvailabilityController : BasePluginController // 2. All preorder window generic attributes — two queries, no N+1 var gaStart = await _dbContext.GenericAttributes.Table .Where(ga => ga.KeyGroup == nameof(Product) - && ga.Key == FruitBankConst.PreorderWindowStart + && ga.Key == FruitBankConst.PreOrderWindowStart && ga.StoreId == storeId) .ToListAsync(); var gaEnd = await _dbContext.GenericAttributes.Table .Where(ga => ga.KeyGroup == nameof(Product) - && ga.Key == FruitBankConst.PreorderWindowEnd + && ga.Key == FruitBankConst.PreOrderWindowEnd && ga.StoreId == storeId) .ToListAsync(); @@ -98,7 +98,7 @@ public class PreorderAvailabilityController : BasePluginController var hasStart = startByProduct.ContainsKey(p.Id); var hasEnd = endByProduct.ContainsKey(p.Id); - return new PreorderAvailabilityRow + return new PreOrderAvailabilityRow { ProductId = p.Id, ProductName = p.Name, @@ -131,7 +131,7 @@ public class PreorderAvailabilityController : BasePluginController // ── AVAILABLE TODAY — DataTables server-side ────────────────────────────── [HttpPost] - [Route("Admin/PreorderAvailability/AvailableTodayList")] + [Route("Admin/PreOrderAvailability/AvailableTodayList")] public async Task AvailableTodayList() { if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) @@ -153,13 +153,13 @@ public class PreorderAvailabilityController : BasePluginController var gaStart = await _dbContext.GenericAttributes.Table .Where(ga => ga.KeyGroup == nameof(Product) - && ga.Key == FruitBankConst.PreorderWindowStart + && ga.Key == FruitBankConst.PreOrderWindowStart && ga.StoreId == storeId) .ToListAsync(); var gaEnd = await _dbContext.GenericAttributes.Table .Where(ga => ga.KeyGroup == nameof(Product) - && ga.Key == FruitBankConst.PreorderWindowEnd + && ga.Key == FruitBankConst.PreOrderWindowEnd && ga.StoreId == storeId) .ToListAsync(); @@ -179,7 +179,7 @@ public class PreorderAvailabilityController : BasePluginController { DateTime.TryParse(startByProduct[p.Id], out var ws); DateTime.TryParse(endByProduct[p.Id], out var we); - return new PreorderAvailabilityRow + return new PreOrderAvailabilityRow { ProductId = p.Id, ProductName = p.Name, @@ -201,7 +201,7 @@ public class PreorderAvailabilityController : BasePluginController // ── SAVE WINDOW DATES for a product ─────────────────────────────────────── [HttpPost] - [Route("Admin/PreorderAvailability/SaveWindow")] + [Route("Admin/PreOrderAvailability/SaveWindow")] public async Task SaveWindow(int productId, string? windowStart, string? windowEnd) { if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) @@ -215,13 +215,13 @@ public class PreorderAvailabilityController : BasePluginController if (string.IsNullOrWhiteSpace(windowStart)) { await _fruitBankAttributeService - .DeleteGenericAttributeAsync(productId, FruitBankConst.PreorderWindowStart, storeId); + .DeleteGenericAttributeAsync(productId, FruitBankConst.PreOrderWindowStart, storeId); } else if (DateTime.TryParse(windowStart, out var ws)) { await _fruitBankAttributeService .InsertOrUpdateGenericAttributeAsync( - productId, FruitBankConst.PreorderWindowStart, ws.Date, storeId); + productId, FruitBankConst.PreOrderWindowStart, ws.Date, storeId); } else return Json(new { success = false, error = $"Invalid start date: {windowStart}" }); @@ -229,13 +229,13 @@ public class PreorderAvailabilityController : BasePluginController if (string.IsNullOrWhiteSpace(windowEnd)) { await _fruitBankAttributeService - .DeleteGenericAttributeAsync(productId, FruitBankConst.PreorderWindowEnd, storeId); + .DeleteGenericAttributeAsync(productId, FruitBankConst.PreOrderWindowEnd, storeId); } else if (DateTime.TryParse(windowEnd, out var we)) { await _fruitBankAttributeService .InsertOrUpdateGenericAttributeAsync( - productId, FruitBankConst.PreorderWindowEnd, we.Date, storeId); + productId, FruitBankConst.PreOrderWindowEnd, we.Date, storeId); } else return Json(new { success = false, error = $"Invalid end date: {windowEnd}" }); diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Models/PreorderAdminModels.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Models/PreorderAdminModels.cs index 71a8ffa..2f5f0a8 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Models/PreorderAdminModels.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Models/PreorderAdminModels.cs @@ -2,37 +2,37 @@ using FruitBank.Common.Enums; namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models; -public class PreorderListRow +public class PreOrderListRow { - public int PreorderId { get; set; } + public int PreOrderId { get; set; } public int CustomerId { get; set; } public string CustomerName { get; set; } = string.Empty; public string CustomerEmail { get; set; } = string.Empty; public string DateOfReceipt { get; set; } = string.Empty; // formatted public string CreatedOnUtc { get; set; } = string.Empty; // formatted - public PreorderStatus Status { get; set; } + public PreOrderStatus Status { get; set; } public string StatusLabel { get; set; } = string.Empty; public int ItemCount { get; set; } public int FulfilledCount { get; set; } public int? OrderId { get; set; } // linked real order, if created } -public class PreorderDetailModel +public class PreOrderDetailModel { - public int PreorderId { get; set; } + public int PreOrderId { get; set; } public int CustomerId { get; set; } public string CustomerName { get; set; } = string.Empty; public string CustomerEmail { get; set; } = string.Empty; public string DateOfReceipt { get; set; } = string.Empty; public string CreatedOnUtc { get; set; } = string.Empty; public string UpdatedOnUtc { get; set; } = string.Empty; - public PreorderStatus Status { get; set; } + public PreOrderStatus Status { get; set; } public string? CustomerNote { get; set; } public int? OrderId { get; set; } - public List Items { get; set; } = new(); + public List Items { get; set; } = new(); } -public class PreorderDetailItemRow +public class PreOrderDetailItemRow { public int ItemId { get; set; } public int ProductId { get; set; } @@ -41,11 +41,11 @@ public class PreorderDetailItemRow public int RequestedQuantity { get; set; } public int FulfilledQuantity { get; set; } public decimal UnitPriceInclTax { get; set; } - public PreorderItemStatus Status { get; set; } + public PreOrderItemStatus Status { get; set; } public string StatusLabel { get; set; } = string.Empty; } -public class PreorderDemandRow +public class PreOrderDemandRow { public int ProductId { get; set; } public string ProductName { get; set; } = string.Empty; @@ -54,6 +54,6 @@ public class PreorderDemandRow public int TotalRequested { get; set; } // sum of RequestedQuantity public int TotalFulfilled { get; set; } // sum of FulfilledQuantity public int TotalUnfulfilled { get; set; } // TotalRequested - TotalFulfilled - public int PreorderCount { get; set; } // distinct preorders containing this product + public int PreOrderCount { get; set; } // distinct preorders containing this product public decimal AvgUnitPrice { get; set; } // average snapshot price } diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Models/PreorderAvailabilityRow.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Models/PreorderAvailabilityRow.cs index baf8d6f..66f9e66 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Models/PreorderAvailabilityRow.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Models/PreorderAvailabilityRow.cs @@ -1,6 +1,6 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models; -public class PreorderAvailabilityRow +public class PreOrderAvailabilityRow { public int ProductId { get; set; } public string ProductName { get; set; } = string.Empty; diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Preorder/Detail.cshtml b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Preorder/Detail.cshtml index d01e43e..a41426c 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Preorder/Detail.cshtml +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Preorder/Detail.cshtml @@ -1,23 +1,23 @@ -@model Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.PreorderDetailModel +@model Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.PreOrderDetailModel @using FruitBank.Common.Enums @{ - ViewBag.PageTitle = $"Előrendelés #{Model.PreorderId}"; + ViewBag.PageTitle = $"Előrendelés #{Model.PreOrderId}"; Layout = "~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/_FruitBankAdminLayout.cshtml"; var statusClass = Model.Status switch { - PreorderStatus.Confirmed => "po-status-confirmed", - PreorderStatus.PartiallyFulfilled => "po-status-partial", - PreorderStatus.Cancelled => "po-status-cancelled", + PreOrderStatus.Confirmed => "po-status-confirmed", + PreOrderStatus.PartiallyFulfilled => "po-status-partial", + PreOrderStatus.Cancelled => "po-status-cancelled", _ => "po-status-pending" }; var statusLabel = Model.Status switch { - PreorderStatus.Confirmed => "Megerősítve", - PreorderStatus.PartiallyFulfilled => "Részben teljesítve", - PreorderStatus.Cancelled => "Törölve", + PreOrderStatus.Confirmed => "Megerősítve", + PreOrderStatus.PartiallyFulfilled => "Részben teljesítve", + PreOrderStatus.Cancelled => "Törölve", _ => "Függőben" }; } @@ -46,14 +46,14 @@ - + Vissza a listához

- Előrendelés #@Model.PreorderId + Előrendelés #@Model.PreOrderId @statusLabel

@@ -63,7 +63,7 @@ Rendelés #@Model.OrderId } - @if (Model.Status == PreorderStatus.Pending) + @if (Model.Status == PreOrderStatus.Pending) {