From 1468aa651c882d257fdd1d56403b99e409ceb667 Mon Sep 17 00:00:00 2001 From: Loretta Date: Sat, 30 May 2026 16:26:51 +0200 Subject: [PATCH] Rename Preorder domain to PreOrder across codebase Comprehensively renamed all "Preorder" domain types, services, controllers, models, enums, database contexts, routes, views, JS, localization resources, and documentation to "PreOrder" (PascalCase, capital "O"). Updated all references in backend, frontend, localization, and schema docs for consistency. No business logic changes; this is a naming and normalization refactor. --- .../Components/_FruitBankDashboard.cshtml | 12 +- .../Controllers/CustomDashboardController.cs | 48 ++--- .../Controllers/CustomOrderController.cs | 6 +- .../Controllers/FileManagerController.cs | 8 +- .../Controllers/PreorderAdminController.cs | 134 ++++++------- .../PreorderAvailabilityController.cs | 34 ++-- .../Areas/Admin/Models/PreorderAdminModels.cs | 22 +-- .../Admin/Models/PreorderAvailabilityRow.cs | 2 +- .../Areas/Admin/Views/Preorder/Detail.cshtml | 44 ++--- .../Areas/Admin/Views/Preorder/List.cshtml | 22 +-- .../Views/PreorderAvailability/Index.cshtml | 8 +- .../CustomerPreorderNavViewComponent.cs | 4 +- .../Controllers/CustomerPreorderController.cs | 49 ++--- .../Controllers/FruitBankDataController.cs | 17 +- .../Controllers/OrderController.cs | 42 ++-- .../Controllers/PreorderController.cs | 41 ++-- .../Domains/DataLayer/CargoTruckDbTable.cs | 5 +- .../DataLayer/Interfaces/IPreorderDbSet.cs | 4 +- .../Interfaces/IPreorderItemDbSet.cs | 4 +- .../Domains/DataLayer/PreorderDbContext.cs | 92 ++++----- .../Domains/DataLayer/PreorderDbTable.cs | 16 +- .../Domains/DataLayer/PreorderItemDbTable.cs | 16 +- .../EventConsumers/FruitBankEventConsumer.cs | 16 +- Nop.Plugin.Misc.AIPlugin/FruitBankConst.cs | 4 +- Nop.Plugin.Misc.AIPlugin/FruitBankPlugin.cs | 164 ++++++++-------- .../Infrastructure/PluginNopStartup.cs | 8 +- .../Infrastructure/RouteProvider.cs | 98 +++++----- .../Localization/preorder.en.xml | 94 ++++----- .../Localization/preorder.hu.xml | 82 ++++---- .../Mapping/NameCompatibility.cs | 4 +- .../Nop.Plugin.Misc.FruitBankPlugin.csproj | 12 +- .../Services/EventConsumer.cs | 10 +- .../Services/FruitBankOrderItemService.cs | 2 +- .../PreorderConversionService.Replace.cs | 20 +- .../Services/PreorderConversionService.cs | 168 ++++++++-------- .../Views/CustomerPreorder/List.cshtml | 30 +-- .../Views/CustomerPreorder/NavItem.cshtml | 2 +- .../Views/Help/Index.cshtml | 2 +- .../Views/Order/Index.cshtml | 36 ++-- .../Views/Preorder/Index.cshtml | 90 ++++----- Nop.Plugin.Misc.AIPlugin/css/preorder.css | 2 +- Nop.Plugin.Misc.AIPlugin/docs/SCHEMA.md | 182 ++++++++++++++++-- 42 files changed, 910 insertions(+), 746 deletions(-) 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) {