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.
This commit is contained in:
parent
2a8dfeaca9
commit
1468aa651c
|
|
@ -176,7 +176,7 @@
|
|||
</table>
|
||||
</div>
|
||||
<div class="card-footer text-muted small">
|
||||
<a href="/Admin/Preorders">Összes előrendelés →</a>
|
||||
<a href="/Admin/PreOrders">Összes előrendelés →</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -277,7 +277,7 @@
|
|||
if (alert.type === 'credit_exceeded')
|
||||
return '<a href="/Admin/CustomerCredit/Details/' + alert.customerId + '" class="btn btn-xs btn-outline-warning">Hitelkeret</a>';
|
||||
if (alert.type === 'old_preorder')
|
||||
return '<a href="/Admin/Preorders" class="btn btn-xs btn-outline-info">Előrendelések</a>';
|
||||
return '<a href="/Admin/PreOrders" class="btn btn-xs btn-outline-info">Előrendelések</a>';
|
||||
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(
|
||||
'<tr>' +
|
||||
'<td>' + p.company + '</td>' +
|
||||
|
|
@ -385,7 +385,7 @@
|
|||
'<td class="text-center">' + p.itemCount + '</td>' +
|
||||
'<td class="text-center">' + p.fulfilledCount + ' / ' + p.itemCount + '</td>' +
|
||||
'<td class="text-center">' + preorderStatusBadge(p.status) + '</td>' +
|
||||
'<td><a href="/Admin/Preorders/Details/' + p.id + '" class="btn btn-xs btn-outline-secondary">Részletek</a></td>' +
|
||||
'<td><a href="/Admin/PreOrders/Details/' + p.id + '" class="btn btn-xs btn-outline-secondary">Részletek</a></td>' +
|
||||
'</tr>'
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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<PreorderItem>();
|
||||
: new List<PreOrderItem>();
|
||||
|
||||
// ── 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
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1076,7 +1076,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
|
||||
[HttpGet]
|
||||
[CheckPermission(StandardPermission.Catalog.PRODUCTS_VIEW)]
|
||||
public virtual async Task<IActionResult> PreorderProductSearchAutoComplete(string term)
|
||||
public virtual async Task<IActionResult> PreOrderProductSearchAutoComplete(string term)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(term) || term.Length < 2)
|
||||
return Json(new List<object>());
|
||||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<PreorderStatus, string> StatusLabels = new()
|
||||
private static readonly Dictionary<PreOrderStatus, string> 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<PreorderItemStatus, string> ItemStatusLabels = new()
|
||||
private static readonly Dictionary<PreOrderItemStatus, string> 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<IActionResult> 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<IActionResult> PreorderList()
|
||||
[Route("Admin/PreOrders/PreOrderList")]
|
||||
public async Task<IActionResult> 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<PreorderStatus>(statusFilter, out var statusEnum))
|
||||
if (!string.IsNullOrWhiteSpace(statusFilter) && Enum.TryParse<PreOrderStatus>(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<IActionResult> 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<IActionResult> CreatePreorder(
|
||||
[Route("Admin/PreOrders/CreatePreOrder")]
|
||||
public async Task<IActionResult> 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<PreorderItem>();
|
||||
var items = new List<PreOrderItem>();
|
||||
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<IActionResult> 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<IActionResult> 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<PreorderItem> items = allItems;
|
||||
IEnumerable<PreOrderItem> 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();
|
||||
|
|
|
|||
|
|
@ -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<IActionResult> 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<IActionResult> 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<IActionResult> 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<IActionResult> 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<Product>(productId, FruitBankConst.PreorderWindowStart, storeId);
|
||||
.DeleteGenericAttributeAsync<Product>(productId, FruitBankConst.PreOrderWindowStart, storeId);
|
||||
}
|
||||
else if (DateTime.TryParse(windowStart, out var ws))
|
||||
{
|
||||
await _fruitBankAttributeService
|
||||
.InsertOrUpdateGenericAttributeAsync<Product, DateTime>(
|
||||
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<Product>(productId, FruitBankConst.PreorderWindowEnd, storeId);
|
||||
.DeleteGenericAttributeAsync<Product>(productId, FruitBankConst.PreOrderWindowEnd, storeId);
|
||||
}
|
||||
else if (DateTime.TryParse(windowEnd, out var we))
|
||||
{
|
||||
await _fruitBankAttributeService
|
||||
.InsertOrUpdateGenericAttributeAsync<Product, DateTime>(
|
||||
productId, FruitBankConst.PreorderWindowEnd, we.Date, storeId);
|
||||
productId, FruitBankConst.PreOrderWindowEnd, we.Date, storeId);
|
||||
}
|
||||
else return Json(new { success = false, error = $"Invalid end date: {windowEnd}" });
|
||||
|
||||
|
|
|
|||
|
|
@ -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<PreorderDetailItemRow> Items { get; set; } = new();
|
||||
public List<PreOrderDetailItemRow> 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 @@
|
|||
</style>
|
||||
|
||||
<!-- Back link -->
|
||||
<a href="/Admin/Preorders" class="btn btn-default btn-sm mb-3">
|
||||
<a href="/Admin/PreOrders" class="btn btn-default btn-sm mb-3">
|
||||
<i class="fas fa-arrow-left"></i> Vissza a listához
|
||||
</a>
|
||||
|
||||
<div class="content-header clearfix">
|
||||
<h1 class="float-left">
|
||||
<i class="fas fa-calendar-plus" style="color:#2d7a3a;"></i>
|
||||
Előrendelés <strong>#@Model.PreorderId</strong>
|
||||
Előrendelés <strong>#@Model.PreOrderId</strong>
|
||||
<span class="@statusClass ml-2">@statusLabel</span>
|
||||
</h1>
|
||||
<div class="float-right">
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
<i class="fas fa-external-link-alt"></i> Rendelés #@Model.OrderId
|
||||
</a>
|
||||
}
|
||||
@if (Model.Status == PreorderStatus.Pending)
|
||||
@if (Model.Status == PreOrderStatus.Pending)
|
||||
{
|
||||
<button id="cancelBtn" class="btn btn-danger btn-sm ml-2">
|
||||
<i class="fas fa-times"></i> Visszavonás
|
||||
|
|
@ -112,10 +112,10 @@
|
|||
<div class="card-header">
|
||||
<strong>Tételek (@Model.Items.Count)</strong>
|
||||
@{
|
||||
var fulfilled = Model.Items.Count(i => i.Status == PreorderItemStatus.Fulfilled);
|
||||
var partial = Model.Items.Count(i => i.Status == PreorderItemStatus.PartiallyFulfilled);
|
||||
var dropped = Model.Items.Count(i => i.Status == PreorderItemStatus.Dropped);
|
||||
var pending = Model.Items.Count(i => i.Status == PreorderItemStatus.Pending);
|
||||
var fulfilled = Model.Items.Count(i => i.Status == PreOrderItemStatus.Fulfilled);
|
||||
var partial = Model.Items.Count(i => i.Status == PreOrderItemStatus.PartiallyFulfilled);
|
||||
var dropped = Model.Items.Count(i => i.Status == PreOrderItemStatus.Dropped);
|
||||
var pending = Model.Items.Count(i => i.Status == PreOrderItemStatus.Pending);
|
||||
}
|
||||
<span class="ml-2 text-muted" style="font-size:13px;">
|
||||
@if (fulfilled > 0) { <span class="badge badge-success">@fulfilled teljesítve</span> }
|
||||
|
|
@ -142,9 +142,9 @@
|
|||
{
|
||||
var rowClass = item.Status switch
|
||||
{
|
||||
PreorderItemStatus.Fulfilled => "item-fulfilled",
|
||||
PreorderItemStatus.PartiallyFulfilled => "item-partial",
|
||||
PreorderItemStatus.Dropped => "item-dropped",
|
||||
PreOrderItemStatus.Fulfilled => "item-fulfilled",
|
||||
PreOrderItemStatus.PartiallyFulfilled => "item-partial",
|
||||
PreOrderItemStatus.Dropped => "item-dropped",
|
||||
_ => "item-pending"
|
||||
};
|
||||
var pct = item.RequestedQuantity > 0
|
||||
|
|
@ -188,7 +188,7 @@
|
|||
</tbody>
|
||||
@{
|
||||
var totalEstimated = Model.Items
|
||||
.Where(i => !i.IsMeasurable && (i.Status == PreorderItemStatus.Fulfilled || i.Status == PreorderItemStatus.PartiallyFulfilled))
|
||||
.Where(i => !i.IsMeasurable && (i.Status == PreOrderItemStatus.Fulfilled || i.Status == PreOrderItemStatus.PartiallyFulfilled))
|
||||
.Sum(i => i.UnitPriceInclTax * i.FulfilledQuantity);
|
||||
}
|
||||
<tfoot>
|
||||
|
|
@ -205,19 +205,19 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
@if (Model.Status == PreorderStatus.Pending)
|
||||
@if (Model.Status == PreOrderStatus.Pending)
|
||||
{
|
||||
<script>
|
||||
$(function () {
|
||||
$('#cancelBtn').click(function () {
|
||||
if (!confirm('Biztosan visszavonod ezt az előrendelést? Ez a művelet nem visszafordítható.')) return;
|
||||
$.ajax({
|
||||
url : '/Admin/Preorders/Cancel/@Model.PreorderId',
|
||||
url : '/Admin/PreOrders/Cancel/@Model.PreOrderId',
|
||||
type : 'POST',
|
||||
data : { __RequestVerificationToken: $('input[name="__RequestVerificationToken"]').val() },
|
||||
success: function (res) {
|
||||
if (res.success) {
|
||||
location.href = '/Admin/Preorders';
|
||||
location.href = '/Admin/PreOrders';
|
||||
} else {
|
||||
alert('Hiba: ' + (res.error || 'Ismeretlen hiba'));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@{
|
||||
ViewBag.PageTitle = "Előrendelések";
|
||||
NopHtml.SetActiveMenuItemSystemName("Preorders.List");
|
||||
NopHtml.SetActiveMenuItemSystemName("PreOrders.List");
|
||||
Layout = "~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/_FruitBankAdminLayout.cshtml";
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +194,7 @@ $(function () {
|
|||
return diff >= 0 && diff <= 4;
|
||||
}
|
||||
|
||||
// ── Preorder list grid ──────────────────────────────────────────────────
|
||||
// ── PreOrder list grid ──────────────────────────────────────────────────
|
||||
var poTable = $('#po-grid').DataTable({
|
||||
serverSide: true, processing: true, pageLength: 25,
|
||||
lengthMenu: [[25,50,100],[25,50,100]], order: [[3,'desc']],
|
||||
|
|
@ -202,13 +202,13 @@ $(function () {
|
|||
info:'_START_–_END_ / _TOTAL_ előrendelés', infoEmpty:'0 előrendelés',
|
||||
infoFiltered:'(szűrve _MAX_-ból)', emptyTable:'Nincs előrendelés', zeroRecords:'Nincs találat',
|
||||
paginate:{first:'««',previous:'«',next:'»',last:'»»'} },
|
||||
ajax: { url:'/Admin/Preorders/PreorderList', type:'POST',
|
||||
ajax: { url:'/Admin/PreOrders/PreOrderList', type:'POST',
|
||||
data: function(d){ d.__RequestVerificationToken=_token; d.statusFilter=activeStatus; } },
|
||||
createdRow: function(row, data) {
|
||||
if (isUrgentRow(data)) $(row).addClass('po-urgent-row');
|
||||
},
|
||||
columns: [
|
||||
{ data:'PreorderId', name:'PreorderId', render:function(d){ return '<strong>#'+d+'</strong>'; } },
|
||||
{ data:'PreOrderId', name:'PreOrderId', render:function(d){ return '<strong>#'+d+'</strong>'; } },
|
||||
{ data:'CustomerName', name:'CustomerName', render:function(d,t,row){ return '<div>'+d+'</div><small class="text-muted">'+row.CustomerEmail+'</small>'; } },
|
||||
{ data:'DateOfReceipt',name:'DateOfReceipt',render:function(d,t,row){
|
||||
var icon = '<i class="fas fa-calendar-day text-muted mr-1"></i>';
|
||||
|
|
@ -218,8 +218,8 @@ $(function () {
|
|||
{ data:'CreatedOnUtc', name:'CreatedOnUtc', render:function(d){ return '<small>'+d+'</small>'; } },
|
||||
{ data:'Status', name:'Status', orderable:false, render:function(d,t,row){ return statusBadge(row); } },
|
||||
{ data:'ItemCount', orderable:false, className:'text-center', render:function(d,t,row){ return itemProgress(row); } },
|
||||
{ data:'PreorderId', orderable:false, searchable:false, className:'text-center', width:'60px',
|
||||
render:function(d){ return '<a href="/Admin/Preorders/Detail/'+d+'" class="btn btn-xs btn-default" title="Részletek"><i class="fas fa-eye"></i></a>'; } }
|
||||
{ data:'PreOrderId', orderable:false, searchable:false, className:'text-center', width:'60px',
|
||||
render:function(d){ return '<a href="/Admin/PreOrders/Detail/'+d+'" class="btn btn-xs btn-default" title="Részletek"><i class="fas fa-eye"></i></a>'; } }
|
||||
]
|
||||
});
|
||||
$(document).on('click','.po-filter',function(){
|
||||
|
|
@ -235,7 +235,7 @@ $(function () {
|
|||
info:'_START_–_END_ / _TOTAL_ termék', infoEmpty:'Nincs adat',
|
||||
infoFiltered:'(szűrve _MAX_-ból)', emptyTable:'Nincs előrendelési igény', zeroRecords:'Nincs találat',
|
||||
paginate:{first:'««',previous:'«',next:'»',last:'»»'} },
|
||||
ajax:{ url:'/Admin/Preorders/DemandList', type:'POST',
|
||||
ajax:{ url:'/Admin/PreOrders/DemandList', type:'POST',
|
||||
data:function(d){ d.__RequestVerificationToken=_token; d.openOnly=demandOpenOnly?'true':'false'; },
|
||||
dataSrc:function(json){
|
||||
var n=(json.data||[]).filter(function(r){return r.TotalUnfulfilled>0;}).length;
|
||||
|
|
@ -253,7 +253,7 @@ $(function () {
|
|||
var cls=pct===100?'bg-success':pct>0?'bg-warning':'bg-secondary';
|
||||
return '<div>'+fmtQty(d)+'</div><div class="progress mt-1" style="height:4px;"><div class="progress-bar '+cls+'" style="width:'+pct+'%"></div></div>'; } },
|
||||
{ data:'TotalUnfulfilled',orderable:false, className:'text-center', render:function(d){ return unfulfilledCell(d); } },
|
||||
{ data:'PreorderCount', orderable:false, className:'text-center', render:function(d){ return '<span class="badge badge-secondary">'+d+'</span>'; } },
|
||||
{ data:'PreOrderCount', orderable:false, className:'text-center', render:function(d){ return '<span class="badge badge-secondary">'+d+'</span>'; } },
|
||||
{ data:'AvgUnitPrice', orderable:false, className:'text-right', render:function(d){ return fmtPrice(d); } }
|
||||
]
|
||||
});
|
||||
|
|
@ -270,7 +270,7 @@ $(function () {
|
|||
demandTable.ajax.reload();
|
||||
});
|
||||
|
||||
// ── Create Order / Preorder Modal (mode-aware) ──────────────────────────
|
||||
// ── Create Order / PreOrder Modal (mode-aware) ──────────────────────────
|
||||
var cpProducts = [];
|
||||
var cpMode = null;
|
||||
var CP_CUTOFF = 4; // ≤4 days → order, >4 days → preorder
|
||||
|
|
@ -332,7 +332,7 @@ $(function () {
|
|||
if (!cpMode){ resp([]); return; }
|
||||
$.get(cpMode==='order'
|
||||
?'/Admin/CustomOrder/ProductSearchAutoComplete'
|
||||
:'/Admin/CustomOrder/PreorderProductSearchAutoComplete',
|
||||
:'/Admin/CustomOrder/PreOrderProductSearchAutoComplete',
|
||||
{term:req.term}, resp);
|
||||
},
|
||||
select:function(e,ui){ addCpProduct(ui.item); $('#cp-product-search').val(''); return false; }
|
||||
|
|
@ -402,7 +402,7 @@ $(function () {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
$.ajax({url:'/Admin/Preorders/CreatePreorder', type:'POST',
|
||||
$.ajax({url:'/Admin/PreOrders/CreatePreOrder', type:'POST',
|
||||
data:{ customerId:$('#cp-customer-id').val(), deliveryDateTime:$('#cp-delivery').val(),
|
||||
customerNote:$('#cp-note').val().trim(), productsJson:$('#cp-products-json').val(),
|
||||
__RequestVerificationToken:_token },
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@{
|
||||
ViewBag.PageTitle = "Előrendelés — termékelérhetőség";
|
||||
NopHtml.SetActiveMenuItemSystemName("PreorderAvailability");
|
||||
NopHtml.SetActiveMenuItemSystemName("PreOrderAvailability");
|
||||
Layout = "~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/_FruitBankAdminLayout.cshtml";
|
||||
}
|
||||
|
||||
|
|
@ -149,7 +149,7 @@ $(function () {
|
|||
zeroRecords : 'Nincs találat'
|
||||
},
|
||||
ajax: {
|
||||
url : '/Admin/PreorderAvailability/ProductList',
|
||||
url : '/Admin/PreOrderAvailability/ProductList',
|
||||
type: 'POST',
|
||||
data: function (d) { d.__RequestVerificationToken = _token; }
|
||||
},
|
||||
|
|
@ -197,7 +197,7 @@ $(function () {
|
|||
else rowData.WindowEnd = newVal || null;
|
||||
|
||||
$.ajax({
|
||||
url : '/Admin/PreorderAvailability/SaveWindow',
|
||||
url : '/Admin/PreOrderAvailability/SaveWindow',
|
||||
type : 'POST',
|
||||
data : {
|
||||
__RequestVerificationToken : _token,
|
||||
|
|
@ -243,7 +243,7 @@ $(function () {
|
|||
zeroRecords : 'Nincs találat'
|
||||
},
|
||||
ajax: {
|
||||
url : '/Admin/PreorderAvailability/AvailableTodayList',
|
||||
url : '/Admin/PreOrderAvailability/AvailableTodayList',
|
||||
type: 'POST',
|
||||
data: function (d) { d.__RequestVerificationToken = _token; },
|
||||
dataSrc: function (json) {
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ using Nop.Web.Framework.Components;
|
|||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Components;
|
||||
|
||||
public class CustomerPreorderNavViewComponent : NopViewComponent
|
||||
public class CustomerPreOrderNavViewComponent : NopViewComponent
|
||||
{
|
||||
public IViewComponentResult Invoke(string widgetZone, object additionalData)
|
||||
{
|
||||
return View("~/Plugins/Misc.FruitBankPlugin/Views/CustomerPreorder/NavItem.cshtml");
|
||||
return View("~/Plugins/Misc.FruitBankPlugin/Views/CustomerPreOrder/NavItem.cshtml");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,20 +5,21 @@ using Nop.Core;
|
|||
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
|
||||
using Nop.Services.Customers;
|
||||
using Nop.Web.Framework.Controllers;
|
||||
using static Nop.Plugin.Misc.FruitBankPlugin.Controllers.CustomerPreOrderController;
|
||||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers;
|
||||
|
||||
public class CustomerPreorderController : BasePluginController
|
||||
public class CustomerPreOrderController : BasePluginController
|
||||
{
|
||||
private readonly IWorkContext _workContext;
|
||||
private readonly ICustomerService _customerService;
|
||||
private readonly PreorderDbContext _preorderDbContext;
|
||||
private readonly PreOrderDbContext _preorderDbContext;
|
||||
private readonly FruitBankDbContext _dbContext;
|
||||
|
||||
public CustomerPreorderController(
|
||||
public CustomerPreOrderController(
|
||||
IWorkContext workContext,
|
||||
ICustomerService customerService,
|
||||
PreorderDbContext preorderDbContext,
|
||||
PreOrderDbContext preorderDbContext,
|
||||
FruitBankDbContext dbContext)
|
||||
{
|
||||
_workContext = workContext;
|
||||
|
|
@ -35,13 +36,13 @@ public class CustomerPreorderController : BasePluginController
|
|||
return Challenge();
|
||||
|
||||
// Load this customer's preorders, newest first
|
||||
var preorders = await _preorderDbContext.Preorders
|
||||
var preorders = await _preorderDbContext.PreOrders
|
||||
.GetAllByCustomerIdAsync(customer.Id, false)
|
||||
.OrderByDescending(p => p.CreatedOnUtc)
|
||||
.ToListAsync();
|
||||
|
||||
var allItems = await _preorderDbContext.PreorderItems.GetAll()
|
||||
.Where(i => preorders.Select(p => p.Id).Contains(i.PreorderId))
|
||||
var allItems = await _preorderDbContext.PreOrderItems.GetAll()
|
||||
.Where(i => preorders.Select(p => p.Id).Contains(i.PreOrderId))
|
||||
.ToListAsync();
|
||||
|
||||
// Resolve product names
|
||||
|
|
@ -54,7 +55,7 @@ public class CustomerPreorderController : BasePluginController
|
|||
|
||||
var rows = preorders.Select(p =>
|
||||
{
|
||||
var items = allItems.Where(i => i.PreorderId == p.Id).ToList();
|
||||
var items = allItems.Where(i => i.PreOrderId == p.Id).ToList();
|
||||
|
||||
// Derive status from quantities (enum reads unreliable in LinqToDB)
|
||||
var allFulfilled = items.Any() && items.All(i => i.FulfilledQuantity >= i.RequestedQuantity);
|
||||
|
|
@ -63,13 +64,13 @@ public class CustomerPreorderController : BasePluginController
|
|||
i.RequestedQuantity > 0);
|
||||
|
||||
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 CustomerPreorderRow
|
||||
return new CustomerPreOrderRow
|
||||
{
|
||||
PreorderId = p.Id,
|
||||
PreOrderId = p.Id,
|
||||
OrderId = p.OrderId,
|
||||
DateOfReceipt = p.DateOfReceipt,
|
||||
CreatedOnUtc = p.CreatedOnUtc,
|
||||
|
|
@ -78,7 +79,7 @@ public class CustomerPreorderController : BasePluginController
|
|||
Items = items.Select(i =>
|
||||
{
|
||||
productById.TryGetValue(i.ProductId, out var dto);
|
||||
return new CustomerPreorderItemRow
|
||||
return new CustomerPreOrderItemRow
|
||||
{
|
||||
ProductName = dto?.Name ?? $"Termék #{i.ProductId}",
|
||||
IsMeasurable = dto?.IsMeasurable ?? false,
|
||||
|
|
@ -86,38 +87,38 @@ public class CustomerPreorderController : BasePluginController
|
|||
FulfilledQuantity = i.FulfilledQuantity,
|
||||
UnitPriceInclTax = i.UnitPriceInclTax,
|
||||
Status = i.FulfilledQuantity == 0
|
||||
? PreorderItemStatus.Pending
|
||||
? PreOrderItemStatus.Pending
|
||||
: i.FulfilledQuantity >= i.RequestedQuantity
|
||||
? PreorderItemStatus.Fulfilled
|
||||
: PreorderItemStatus.PartiallyFulfilled
|
||||
? PreOrderItemStatus.Fulfilled
|
||||
: PreOrderItemStatus.PartiallyFulfilled
|
||||
};
|
||||
}).ToList()
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
return View("~/Plugins/Misc.FruitBankPlugin/Views/CustomerPreorder/List.cshtml", rows);
|
||||
return View("~/Plugins/Misc.FruitBankPlugin/Views/CustomerPreOrder/List.cshtml", rows);
|
||||
}
|
||||
|
||||
// ── Inner models ──────────────────────────────────────────────────────────
|
||||
|
||||
public class CustomerPreorderRow
|
||||
public class CustomerPreOrderRow
|
||||
{
|
||||
public int PreorderId { get; set; }
|
||||
public int PreOrderId { get; set; }
|
||||
public int? OrderId { get; set; }
|
||||
public DateTime DateOfReceipt { get; set; }
|
||||
public DateTime CreatedOnUtc { get; set; }
|
||||
public PreorderStatus Status { get; set; }
|
||||
public PreOrderStatus Status { get; set; }
|
||||
public string? CustomerNote { get; set; }
|
||||
public List<CustomerPreorderItemRow> Items { get; set; } = new();
|
||||
public List<CustomerPreOrderItemRow> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public class CustomerPreorderItemRow
|
||||
public class CustomerPreOrderItemRow
|
||||
{
|
||||
public string ProductName { get; set; } = string.Empty;
|
||||
public bool IsMeasurable { get; set; }
|
||||
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; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
|
|||
ICustomerService customerService,
|
||||
ICustomerRegistrationService customerRegistrationService,
|
||||
ILocalizationService localizationService,
|
||||
PreorderConversionService preorderConversionService,
|
||||
PreOrderConversionService preorderConversionService,
|
||||
IEnumerable<IAcLogWriterBase> logWriters)
|
||||
: BasePluginController, IFruitBankDataControllerServer
|
||||
{
|
||||
|
|
@ -187,7 +187,14 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
|
|||
public async Task<CargoTruck> GetCargoTruckById(int id)
|
||||
{
|
||||
_logger.Detail($"GetCargoTruckById invoked; id: {id}");
|
||||
return await ctx.CargoTrucks.GetByIdAsync(id);
|
||||
return await ctx.CargoTrucks.GetByIdAsync(id, true);
|
||||
}
|
||||
|
||||
[SignalR(SignalRTags.GetCargoTrucksByCargoPartnerId)]
|
||||
public async Task<List<CargoTruck>> GetCargoTrucksByCargoPartnerId(int cargoPartnerId)
|
||||
{
|
||||
_logger.Detail($"GetCargoTrucksByCargoPartnerId invoked; cargoPartnerId: {cargoPartnerId}");
|
||||
return await ctx.CargoTrucks.GetByCargoPartnerId(cargoPartnerId, true).ToListAsync();
|
||||
}
|
||||
|
||||
[SignalR(SignalRTags.AddCargoTruck)]
|
||||
|
|
@ -198,7 +205,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
|
|||
_logger.Detail($"AddCargoTruck invoked; id: {cargoTruck.Id}");
|
||||
|
||||
await ctx.CargoTrucks.InsertAsync(cargoTruck);
|
||||
return await ctx.CargoTrucks.GetByIdAsync(cargoTruck.Id);
|
||||
return await ctx.CargoTrucks.GetByIdAsync(cargoTruck.Id, true);
|
||||
}
|
||||
|
||||
[SignalR(SignalRTags.UpdateCargoTruck)]
|
||||
|
|
@ -209,7 +216,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
|
|||
_logger.Detail($"UpdateCargoTruck invoked; id: {cargoTruck.Id}");
|
||||
|
||||
await ctx.CargoTrucks.UpdateAsync(cargoTruck);
|
||||
return await ctx.CargoTrucks.GetByIdAsync(cargoTruck.Id);
|
||||
return await ctx.CargoTrucks.GetByIdAsync(cargoTruck.Id, true);
|
||||
}
|
||||
|
||||
[SignalR(SignalRTags.GetShippings)]
|
||||
|
|
@ -360,7 +367,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
|
|||
// (EventConsumer also fires this, double-call is idempotent)
|
||||
if (shippingItem.QuantityOnDocument > oldItem.QuantityOnDocument)
|
||||
_ = Task.Run(async () => await preorderConversionService
|
||||
.ConvertPreordersForProductsAsync(
|
||||
.ConvertPreOrdersForProductsAsync(
|
||||
new List<int> { shippingItem.ProductId.Value },
|
||||
shippingItem.ShippingDocumentId));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,14 +28,14 @@ public class OrderController : BasePluginController
|
|||
private readonly ICustomerService _customerService;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly FruitBankDbContext _dbContext;
|
||||
private readonly PreorderDbContext _preorderDbContext;
|
||||
private readonly PreOrderDbContext _preorderDbContext;
|
||||
private readonly FruitBankAttributeService _fruitBankAttributeService;
|
||||
private readonly CustomPriceCalculationService _customPriceCalculationService;
|
||||
private readonly IShoppingCartService _shoppingCartService;
|
||||
private readonly IProductService _productService;
|
||||
private readonly OpenAIApiService _aiApiService;
|
||||
private readonly CerebrasAPIService _cerebrasApiService;
|
||||
private readonly PreorderConversionService _preorderConversionService;
|
||||
private readonly PreOrderConversionService _preorderConversionService;
|
||||
|
||||
private const string PendingDeliveryKey = "OrderFlowPendingDeliveryDateTime";
|
||||
|
||||
|
|
@ -45,14 +45,14 @@ public class OrderController : BasePluginController
|
|||
ICustomerService customerService,
|
||||
ILocalizationService localizationService,
|
||||
FruitBankDbContext dbContext,
|
||||
PreorderDbContext preorderDbContext,
|
||||
PreOrderDbContext preorderDbContext,
|
||||
FruitBankAttributeService fruitBankAttributeService,
|
||||
IPriceCalculationService priceCalculationService,
|
||||
IShoppingCartService shoppingCartService,
|
||||
IProductService productService,
|
||||
OpenAIApiService aiApiService,
|
||||
CerebrasAPIService cerebrasApiService,
|
||||
PreorderConversionService preorderConversionService)
|
||||
PreOrderConversionService preorderConversionService)
|
||||
{
|
||||
_workContext = workContext;
|
||||
_storeContext = storeContext;
|
||||
|
|
@ -105,7 +105,7 @@ public class OrderController : BasePluginController
|
|||
|
||||
// Quick Order: delivery needs current stock (before Thursday)
|
||||
// OR goods already arrived (Thu-Sun) and delivery still this week
|
||||
// Preorder: delivery is Thursday+ but today is still Mon/Tue/Wed (goods not yet here)
|
||||
// PreOrder: delivery is Thursday+ but today is still Mon/Tue/Wed (goods not yet here)
|
||||
return (deliveryBeforeThursday || (isLateWeek && deliveryThisWeek))
|
||||
? "quickorder"
|
||||
: "preorder";
|
||||
|
|
@ -216,10 +216,10 @@ public class OrderController : BasePluginController
|
|||
}
|
||||
}
|
||||
|
||||
// ── PRODUCTS — Preorder flow (curated window list) ────────────────────────
|
||||
// ── PRODUCTS — PreOrder flow (curated window list) ────────────────────────
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetPreorderProducts()
|
||||
public async Task<IActionResult> GetPreOrderProducts()
|
||||
{
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
if (await _customerService.IsGuestAsync(customer))
|
||||
|
|
@ -232,12 +232,12 @@ public class OrderController : BasePluginController
|
|||
|
||||
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();
|
||||
|
||||
|
|
@ -403,10 +403,10 @@ public class OrderController : BasePluginController
|
|||
return Json(new { success = true, cartItems = await GetCartItemsJson(customer, store) });
|
||||
}
|
||||
|
||||
// ── PLACE PREORDER (Preorder flow) ────────────────────────────────────────
|
||||
// ── PLACE PREORDER (PreOrder flow) ────────────────────────────────────────
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> PlacePreorder([FromBody] PlacePreorderRequest request)
|
||||
public async Task<IActionResult> PlacePreOrder([FromBody] PlacePreOrderRequest request)
|
||||
{
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
if (await _customerService.IsGuestAsync(customer))
|
||||
|
|
@ -422,7 +422,7 @@ public class OrderController : BasePluginController
|
|||
{
|
||||
var store = await _storeContext.GetCurrentStoreAsync();
|
||||
|
||||
var preorder = new Preorder
|
||||
var preorder = new PreOrder
|
||||
{
|
||||
CustomerId = customer.Id,
|
||||
StoreId = store.Id,
|
||||
|
|
@ -430,7 +430,7 @@ public class OrderController : BasePluginController
|
|||
CustomerNote = request.CustomerNote?.Trim()
|
||||
};
|
||||
|
||||
var items = new List<PreorderItem>();
|
||||
var items = new List<PreOrderItem>();
|
||||
foreach (var req in request.Items.Where(i => i.Quantity > 0))
|
||||
{
|
||||
var product = await _dbContext.Products.GetByIdAsync(req.ProductId);
|
||||
|
|
@ -444,7 +444,7 @@ public class OrderController : BasePluginController
|
|||
unitPrice = pr.finalPrice;
|
||||
}
|
||||
|
||||
items.Add(new PreorderItem
|
||||
items.Add(new PreOrderItem
|
||||
{
|
||||
ProductId = req.ProductId,
|
||||
RequestedQuantity = req.Quantity,
|
||||
|
|
@ -455,7 +455,7 @@ public class OrderController : BasePluginController
|
|||
if (!items.Any())
|
||||
return Json(new { success = false, message = "Nincs érvényes termék az előrendelésben" });
|
||||
|
||||
var saved = await _preorderDbContext.InsertPreorderAsync(preorder, items);
|
||||
var saved = await _preorderDbContext.InsertPreOrderAsync(preorder, items);
|
||||
|
||||
// Clean up the pending datetime attribute
|
||||
await _fruitBankAttributeService
|
||||
|
|
@ -466,12 +466,12 @@ public class OrderController : BasePluginController
|
|||
// Awaited inline (not fire-and-forget) so we can return the order ID if one is created.
|
||||
// shippingDocumentId = 0 signals this was triggered at preorder placement, not by a document.
|
||||
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);
|
||||
|
||||
Console.WriteLine($"[OrderFlow] PlacePreorder #{saved.Id} — orderId={refreshed?.OrderId}");
|
||||
Console.WriteLine($"[OrderFlow] PlacePreOrder #{saved.Id} — orderId={refreshed?.OrderId}");
|
||||
|
||||
return Json(new
|
||||
{
|
||||
|
|
@ -607,14 +607,14 @@ OUTPUT FORMAT: [{""product"": ""narancs"", ""quantity"": 100}]";
|
|||
|
||||
// ── Inner models ──────────────────────────────────────────────────────────
|
||||
|
||||
public class PlacePreorderRequest
|
||||
public class PlacePreOrderRequest
|
||||
{
|
||||
public string? DeliveryDateTime { get; set; }
|
||||
public string? CustomerNote { get; set; }
|
||||
public List<PreorderItemRequest> Items { get; set; } = new();
|
||||
public List<PreOrderItemRequest> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public class PreorderItemRequest
|
||||
public class PreOrderItemRequest
|
||||
{
|
||||
public int ProductId { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
|
|
|
|||
|
|
@ -10,31 +10,32 @@ using Nop.Services.Catalog;
|
|||
using Nop.Services.Customers;
|
||||
using Nop.Services.Localization;
|
||||
using Nop.Web.Framework.Controllers;
|
||||
using static Nop.Plugin.Misc.FruitBankPlugin.Controllers.OrderController;
|
||||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers;
|
||||
|
||||
[AutoValidateAntiforgeryToken]
|
||||
public class PreorderController : BasePluginController
|
||||
public class PreOrderController : BasePluginController
|
||||
{
|
||||
private readonly IWorkContext _workContext;
|
||||
private readonly IStoreContext _storeContext;
|
||||
private readonly ICustomerService _customerService;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly FruitBankDbContext _dbContext;
|
||||
private readonly PreorderDbContext _preorderDbContext;
|
||||
private readonly PreOrderDbContext _preorderDbContext;
|
||||
private readonly FruitBankAttributeService _fruitBankAttributeService;
|
||||
private readonly CustomPriceCalculationService _customPriceCalculationService;
|
||||
|
||||
private const string PendingDeliveryDateTimeKey = "PreorderPendingDeliveryDateTime";
|
||||
private const string Prefix = "Plugins.Misc.FruitBankPlugin.Preorder.";
|
||||
private const string PendingDeliveryDateTimeKey = "PreOrderPendingDeliveryDateTime";
|
||||
private const string Prefix = "Plugins.Misc.FruitBankPlugin.PreOrder.";
|
||||
|
||||
public PreorderController(
|
||||
public PreOrderController(
|
||||
IWorkContext workContext,
|
||||
IStoreContext storeContext,
|
||||
ICustomerService customerService,
|
||||
ILocalizationService localizationService,
|
||||
FruitBankDbContext dbContext,
|
||||
PreorderDbContext preorderDbContext,
|
||||
PreOrderDbContext preorderDbContext,
|
||||
FruitBankAttributeService fruitBankAttributeService,
|
||||
IPriceCalculationService priceCalculationService)
|
||||
{
|
||||
|
|
@ -60,7 +61,7 @@ public class PreorderController : BasePluginController
|
|||
if (await _customerService.IsGuestAsync(customer))
|
||||
return Challenge();
|
||||
|
||||
return View("~/Plugins/Misc.FruitBankPlugin/Views/Preorder/Index.cshtml");
|
||||
return View("~/Plugins/Misc.FruitBankPlugin/Views/PreOrder/Index.cshtml");
|
||||
}
|
||||
|
||||
// ── GET SAVED DELIVERY DATETIME (page restore) ────────────────────────────
|
||||
|
|
@ -129,13 +130,13 @@ public class PreorderController : BasePluginController
|
|||
// Load 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 == 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();
|
||||
|
||||
|
|
@ -192,7 +193,7 @@ public class PreorderController : BasePluginController
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[Preorder] GetAvailableProducts error: {ex.Message}");
|
||||
Console.WriteLine($"[PreOrder] GetAvailableProducts error: {ex.Message}");
|
||||
return Json(new { success = false, message = $"Hiba: {ex.Message}" });
|
||||
}
|
||||
}
|
||||
|
|
@ -200,7 +201,7 @@ public class PreorderController : BasePluginController
|
|||
// ── PLACE PREORDER ────────────────────────────────────────────────────────
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> PlacePreorder([FromBody] PlacePreorderRequest request)
|
||||
public async Task<IActionResult> PlacePreOrder([FromBody] PlacePreOrderRequest request)
|
||||
{
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
if (await _customerService.IsGuestAsync(customer))
|
||||
|
|
@ -216,7 +217,7 @@ public class PreorderController : BasePluginController
|
|||
{
|
||||
var store = await _storeContext.GetCurrentStoreAsync();
|
||||
|
||||
var preorder = new Preorder
|
||||
var preorder = new PreOrder
|
||||
{
|
||||
CustomerId = customer.Id,
|
||||
StoreId = store.Id,
|
||||
|
|
@ -224,7 +225,7 @@ public class PreorderController : BasePluginController
|
|||
CustomerNote = request.CustomerNote?.Trim()
|
||||
};
|
||||
|
||||
var items = new List<PreorderItem>();
|
||||
var items = new List<PreOrderItem>();
|
||||
foreach (var req in request.Items.Where(i => i.Quantity > 0))
|
||||
{
|
||||
var product = await _dbContext.Products.GetByIdAsync(req.ProductId);
|
||||
|
|
@ -239,7 +240,7 @@ public class PreorderController : BasePluginController
|
|||
unitPrice = pr.finalPrice;
|
||||
}
|
||||
|
||||
items.Add(new PreorderItem
|
||||
items.Add(new PreOrderItem
|
||||
{
|
||||
ProductId = req.ProductId,
|
||||
RequestedQuantity = req.Quantity,
|
||||
|
|
@ -250,14 +251,14 @@ public class PreorderController : BasePluginController
|
|||
if (!items.Any())
|
||||
return Json(new { success = false, message = await L("NoValidItems") });
|
||||
|
||||
var saved = await _preorderDbContext.InsertPreorderAsync(preorder, items);
|
||||
var saved = await _preorderDbContext.InsertPreOrderAsync(preorder, items);
|
||||
|
||||
// Clean up the pending delivery datetime attribute
|
||||
await _fruitBankAttributeService
|
||||
.DeleteGenericAttributeAsync<Nop.Core.Domain.Customers.Customer>(
|
||||
customer.Id, PendingDeliveryDateTimeKey, store.Id);
|
||||
|
||||
Console.WriteLine($"[Preorder] Placed #{saved.Id} — customer #{customer.Id}, {items.Count} items, delivery {deliveryDateTime:u}");
|
||||
Console.WriteLine($"[PreOrder] Placed #{saved.Id} — customer #{customer.Id}, {items.Count} items, delivery {deliveryDateTime:u}");
|
||||
|
||||
return Json(new
|
||||
{
|
||||
|
|
@ -268,21 +269,21 @@ public class PreorderController : BasePluginController
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[Preorder] PlacePreorder error: {ex.Message}");
|
||||
Console.WriteLine($"[PreOrder] PlacePreOrder error: {ex.Message}");
|
||||
return Json(new { success = false, message = $"Hiba: {ex.Message}" });
|
||||
}
|
||||
}
|
||||
|
||||
// ── INNER MODELS ──────────────────────────────────────────────────────────
|
||||
|
||||
public class PlacePreorderRequest
|
||||
public class PlacePreOrderRequest
|
||||
{
|
||||
public string? DeliveryDateTime { get; set; }
|
||||
public string? CustomerNote { get; set; }
|
||||
public List<PreorderItemRequest> Items { get; set; } = new();
|
||||
public List<PreOrderItemRequest> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public class PreorderItemRequest
|
||||
public class PreOrderItemRequest
|
||||
{
|
||||
public int ProductId { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using FruitBank.Common.Entities;
|
||||
using LinqToDB;
|
||||
using Mango.Nop.Data.Repositories;
|
||||
using Nop.Core.Caching;
|
||||
using Nop.Core.Configuration;
|
||||
|
|
@ -18,9 +19,9 @@ public class CargoTruckDbTable : MgDbTableBase<CargoTruck>
|
|||
|
||||
public IQueryable<CargoTruck> GetAll(bool loadRelations)
|
||||
{
|
||||
return GetAll();
|
||||
//return loadRelations ? GetAll().LoadWith(sd => sd.CargoTrucks) : GetAll();
|
||||
return loadRelations ? GetAll().LoadWith(sd => sd.CargoPartner) : GetAll();
|
||||
}
|
||||
|
||||
public Task<CargoTruck> GetByIdAsync(int id, bool loadRelations) => GetAll(loadRelations).FirstOrDefaultAsync(p => p.Id == id);
|
||||
public IQueryable<CargoTruck> GetByCargoPartnerId(int cargoPartnerId, bool loadRelations) => GetAll(loadRelations).Where(p => p.CargoPartnerId == cargoPartnerId);
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ using Nop.Data;
|
|||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer.Interfaces;
|
||||
|
||||
public interface IPreorderDbSet<TDbTable> : IMgDbTableBase where TDbTable : IRepository<Preorder>
|
||||
public interface IPreOrderDbSet<TDbTable> : IMgDbTableBase where TDbTable : IRepository<PreOrder>
|
||||
{
|
||||
public TDbTable Preorders { get; set; }
|
||||
public TDbTable PreOrders { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using Nop.Data;
|
|||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer.Interfaces;
|
||||
|
||||
public interface IPreorderItemDbSet<TDbTable> : IMgDbTableBase where TDbTable : IRepository<PreorderItem>
|
||||
public interface IPreOrderItemDbSet<TDbTable> : IMgDbTableBase where TDbTable : IRepository<PreOrderItem>
|
||||
{
|
||||
public TDbTable PreorderItems { get; set; }
|
||||
public TDbTable PreOrderItems { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,14 +15,14 @@ using Nop.Plugin.Misc.FruitBankPlugin.Services;
|
|||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
|
||||
|
||||
public class PreorderDbContext :
|
||||
IPreorderDbSet<PreorderDbTable>,
|
||||
IPreorderItemDbSet<PreorderItemDbTable>
|
||||
public class PreOrderDbContext :
|
||||
IPreOrderDbSet<PreOrderDbTable>,
|
||||
IPreOrderItemDbSet<PreOrderItemDbTable>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public PreorderDbTable Preorders { get; set; }
|
||||
public PreorderItemDbTable PreorderItems { get; set; }
|
||||
public PreOrderDbTable PreOrders { get; set; }
|
||||
public PreOrderItemDbTable PreOrderItems { get; set; }
|
||||
|
||||
// Read-only access to related NopCommerce repositories needed during conversion
|
||||
public IRepository<Customer> Customers { get; set; }
|
||||
|
|
@ -30,112 +30,112 @@ public class PreorderDbContext :
|
|||
public IRepository<Order> Orders { get; set; }
|
||||
public IRepository<OrderItem> OrderItems { get; set; }
|
||||
|
||||
public PreorderDbContext(
|
||||
PreorderDbTable preorderDbTable,
|
||||
PreorderItemDbTable preorderItemDbTable,
|
||||
public PreOrderDbContext(
|
||||
PreOrderDbTable preorderDbTable,
|
||||
PreOrderItemDbTable preorderItemDbTable,
|
||||
IRepository<Customer> customerRepository,
|
||||
IRepository<Product> productRepository,
|
||||
IRepository<Order> orderRepository,
|
||||
IRepository<OrderItem> orderItemRepository,
|
||||
IEnumerable<IAcLogWriterBase> logWriters)
|
||||
{
|
||||
Preorders = preorderDbTable;
|
||||
PreorderItems = preorderItemDbTable;
|
||||
PreOrders = preorderDbTable;
|
||||
PreOrderItems = preorderItemDbTable;
|
||||
Customers = customerRepository;
|
||||
Products = productRepository;
|
||||
Orders = orderRepository;
|
||||
OrderItems = orderItemRepository;
|
||||
_logger = new Logger<PreorderDbContext>(logWriters.ToArray());
|
||||
_logger = new Logger<PreOrderDbContext>(logWriters.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert a complete preorder with all its items in one operation.
|
||||
/// Returns the saved preorder (with Id populated).
|
||||
/// </summary>
|
||||
public async Task<Preorder> InsertPreorderAsync(Preorder preorder, IList<PreorderItem> items)
|
||||
public async Task<PreOrder> InsertPreOrderAsync(PreOrder preorder, IList<PreOrderItem> items)
|
||||
{
|
||||
preorder.CreatedOnUtc = DateTime.UtcNow;
|
||||
preorder.UpdatedOnUtc = DateTime.UtcNow;
|
||||
preorder.Status = PreorderStatus.Pending;
|
||||
preorder.Status = PreOrderStatus.Pending;
|
||||
|
||||
await Preorders.InsertAsync(preorder);
|
||||
await PreOrders.InsertAsync(preorder);
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
item.PreorderId = preorder.Id;
|
||||
item.PreOrderId = preorder.Id;
|
||||
item.FulfilledQuantity = 0;
|
||||
item.Status = PreorderItemStatus.Pending;
|
||||
await PreorderItems.InsertAsync(item);
|
||||
item.Status = PreOrderItemStatus.Pending;
|
||||
await PreOrderItems.InsertAsync(item);
|
||||
}
|
||||
|
||||
_logger.Info($"PreorderDbContext: inserted Preorder #{preorder.Id} with {items.Count} items for customer #{preorder.CustomerId}");
|
||||
_logger.Info($"PreOrderDbContext: inserted PreOrder #{preorder.Id} with {items.Count} items for customer #{preorder.CustomerId}");
|
||||
return preorder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all pending preorder items for a set of productIds, ordered by PreorderId (FCFS).
|
||||
/// Used by PreorderConversionService after IncomingQuantity is written.
|
||||
/// Returns all pending preorder items for a set of productIds, ordered by PreOrderId (FCFS).
|
||||
/// Used by PreOrderConversionService after IncomingQuantity is written.
|
||||
/// </summary>
|
||||
public async Task<List<PreorderItem>> GetPendingItemsForProductsAsync(IList<int> productIds)
|
||||
public async Task<List<PreOrderItem>> GetPendingItemsForProductsAsync(IList<int> productIds)
|
||||
{
|
||||
// Fetch all items for these products first, then filter by status in memory
|
||||
// LinqToDB cannot translate enum comparisons to SQL in this codebase
|
||||
var all = await PreorderItems.Table
|
||||
var all = await PreOrderItems.Table
|
||||
.Where(i => productIds.Contains(i.ProductId))
|
||||
.OrderBy(i => i.PreorderId)
|
||||
.OrderBy(i => i.PreOrderId)
|
||||
.ToListAsync();
|
||||
|
||||
return all.Where(i =>
|
||||
i.Status == PreorderItemStatus.Pending ||
|
||||
i.Status == PreorderItemStatus.PartiallyFulfilled)
|
||||
i.Status == PreOrderItemStatus.Pending ||
|
||||
i.Status == PreOrderItemStatus.PartiallyFulfilled)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// After conversion: check if all items in a preorder are resolved and update the preorder's status.
|
||||
/// </summary>
|
||||
public async Task RefreshPreorderStatusAsync(int preorderId)
|
||||
public async Task RefreshPreOrderStatusAsync(int preorderId)
|
||||
{
|
||||
var preorder = await Preorders.GetByIdAsync(preorderId);
|
||||
var preorder = await PreOrders.GetByIdAsync(preorderId);
|
||||
if (preorder == null) return;
|
||||
|
||||
var items = await PreorderItems.GetAllByPreorderIdAsync(preorderId).ToListAsync();
|
||||
var items = await PreOrderItems.GetAllByPreOrderIdAsync(preorderId).ToListAsync();
|
||||
|
||||
var hasDropped = items.Any(i => i.Status == PreorderItemStatus.Dropped);
|
||||
var hasPartial = items.Any(i => i.Status == PreorderItemStatus.PartiallyFulfilled);
|
||||
var hasPending = items.Any(i => i.Status == PreorderItemStatus.Pending);
|
||||
var allFulfilled = items.All(i => i.Status == PreorderItemStatus.Fulfilled);
|
||||
var hasDropped = items.Any(i => i.Status == PreOrderItemStatus.Dropped);
|
||||
var hasPartial = items.Any(i => i.Status == PreOrderItemStatus.PartiallyFulfilled);
|
||||
var hasPending = items.Any(i => i.Status == PreOrderItemStatus.Pending);
|
||||
var allFulfilled = items.All(i => i.Status == PreOrderItemStatus.Fulfilled);
|
||||
|
||||
preorder.Status = (hasDropped || hasPartial) && !hasPending ? PreorderStatus.PartiallyFulfilled
|
||||
: allFulfilled ? PreorderStatus.Confirmed
|
||||
: PreorderStatus.Pending;
|
||||
preorder.Status = (hasDropped || hasPartial) && !hasPending ? PreOrderStatus.PartiallyFulfilled
|
||||
: allFulfilled ? PreOrderStatus.Confirmed
|
||||
: PreOrderStatus.Pending;
|
||||
|
||||
preorder.UpdatedOnUtc = DateTime.UtcNow;
|
||||
await Preorders.UpdateAsync(preorder);
|
||||
await PreOrders.UpdateAsync(preorder);
|
||||
|
||||
_logger.Info($"PreorderDbContext: Preorder #{preorderId} status → {preorder.Status}");
|
||||
_logger.Info($"PreOrderDbContext: PreOrder #{preorderId} status → {preorder.Status}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark a preorder as cancelled (customer or admin action).
|
||||
/// </summary>
|
||||
public async Task CancelPreorderAsync(int preorderId)
|
||||
public async Task CancelPreOrderAsync(int preorderId)
|
||||
{
|
||||
var preorder = await Preorders.GetByIdAsync(preorderId);
|
||||
var preorder = await PreOrders.GetByIdAsync(preorderId);
|
||||
if (preorder == null) return;
|
||||
|
||||
preorder.Status = PreorderStatus.Cancelled;
|
||||
preorder.Status = PreOrderStatus.Cancelled;
|
||||
preorder.UpdatedOnUtc = DateTime.UtcNow;
|
||||
await Preorders.UpdateAsync(preorder);
|
||||
await PreOrders.UpdateAsync(preorder);
|
||||
|
||||
var items = await PreorderItems.GetAllByPreorderIdAsync(preorderId).ToListAsync();
|
||||
var cancellableStatuses = new[] { PreorderItemStatus.Pending, PreorderItemStatus.PartiallyFulfilled };
|
||||
var items = await PreOrderItems.GetAllByPreOrderIdAsync(preorderId).ToListAsync();
|
||||
var cancellableStatuses = new[] { PreOrderItemStatus.Pending, PreOrderItemStatus.PartiallyFulfilled };
|
||||
foreach (var item in items.Where(i => cancellableStatuses.Contains(i.Status)))
|
||||
{
|
||||
item.Status = PreorderItemStatus.Dropped;
|
||||
await PreorderItems.UpdateAsync(item);
|
||||
item.Status = PreOrderItemStatus.Dropped;
|
||||
await PreOrderItems.UpdateAsync(item);
|
||||
}
|
||||
|
||||
_logger.Info($"PreorderDbContext: Preorder #{preorderId} cancelled");
|
||||
_logger.Info($"PreOrderDbContext: PreOrder #{preorderId} cancelled");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ using Nop.Data;
|
|||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
|
||||
|
||||
public class PreorderDbTable : MgDbTableBase<Preorder>
|
||||
public class PreOrderDbTable : MgDbTableBase<PreOrder>
|
||||
{
|
||||
public PreorderDbTable(
|
||||
public PreOrderDbTable(
|
||||
IEventPublisher eventPublisher,
|
||||
INopDataProvider dataProvider,
|
||||
IShortTermCacheManager shortTermCacheManager,
|
||||
|
|
@ -22,23 +22,23 @@ public class PreorderDbTable : MgDbTableBase<Preorder>
|
|||
{
|
||||
}
|
||||
|
||||
public IQueryable<Preorder> GetAll(bool loadRelations)
|
||||
public IQueryable<PreOrder> GetAll(bool loadRelations)
|
||||
{
|
||||
return loadRelations
|
||||
? GetAll()
|
||||
.LoadWith(p => p.PreorderItems)
|
||||
.LoadWith(p => p.PreOrderItems)
|
||||
: GetAll();
|
||||
}
|
||||
|
||||
public Task<Preorder?> GetByIdAsync(int id, bool loadRelations)
|
||||
public Task<PreOrder?> GetByIdAsync(int id, bool loadRelations)
|
||||
=> GetAll(loadRelations).FirstOrDefaultAsync(p => p.Id == id);
|
||||
|
||||
public IQueryable<Preorder> GetAllByCustomerIdAsync(int customerId, bool loadRelations)
|
||||
public IQueryable<PreOrder> GetAllByCustomerIdAsync(int customerId, bool loadRelations)
|
||||
=> GetAll(loadRelations).Where(p => p.CustomerId == customerId);
|
||||
|
||||
public IQueryable<Preorder> GetAllPendingAsync(bool loadRelations)
|
||||
public IQueryable<PreOrder> GetAllPendingAsync(bool loadRelations)
|
||||
{
|
||||
var pendingStatuses = new[] { PreorderStatus.Pending, PreorderStatus.PartiallyFulfilled };
|
||||
var pendingStatuses = new[] { PreOrderStatus.Pending, PreOrderStatus.PartiallyFulfilled };
|
||||
return GetAll(loadRelations).Where(p => pendingStatuses.Contains(p.Status));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ using Nop.Data;
|
|||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
|
||||
|
||||
public class PreorderItemDbTable : MgDbTableBase<PreorderItem>
|
||||
public class PreOrderItemDbTable : MgDbTableBase<PreOrderItem>
|
||||
{
|
||||
public PreorderItemDbTable(
|
||||
public PreOrderItemDbTable(
|
||||
IEventPublisher eventPublisher,
|
||||
INopDataProvider dataProvider,
|
||||
IShortTermCacheManager shortTermCacheManager,
|
||||
|
|
@ -22,21 +22,21 @@ public class PreorderItemDbTable : MgDbTableBase<PreorderItem>
|
|||
{
|
||||
}
|
||||
|
||||
public IQueryable<PreorderItem> GetAllByPreorderIdAsync(int preorderId)
|
||||
=> GetAll().Where(i => i.PreorderId == preorderId);
|
||||
public IQueryable<PreOrderItem> GetAllByPreOrderIdAsync(int preorderId)
|
||||
=> GetAll().Where(i => i.PreOrderId == preorderId);
|
||||
|
||||
public IQueryable<PreorderItem> GetAllByProductIdAsync(int productId)
|
||||
public IQueryable<PreOrderItem> GetAllByProductIdAsync(int productId)
|
||||
=> GetAll().Where(i => i.ProductId == productId);
|
||||
|
||||
/// <summary>
|
||||
/// All pending/partially-fulfilled items for a product, ordered by their parent preorder's
|
||||
/// CreatedOnUtc for first-come-first-served allocation.
|
||||
/// </summary>
|
||||
public IQueryable<PreorderItem> GetPendingByProductIdOrderedAsync(int productId)
|
||||
public IQueryable<PreOrderItem> GetPendingByProductIdOrderedAsync(int productId)
|
||||
{
|
||||
var pendingStatuses = new[] { PreorderItemStatus.Pending, PreorderItemStatus.PartiallyFulfilled };
|
||||
var pendingStatuses = new[] { PreOrderItemStatus.Pending, PreOrderItemStatus.PartiallyFulfilled };
|
||||
return GetAll()
|
||||
.Where(i => i.ProductId == productId && pendingStatuses.Contains(i.Status))
|
||||
.OrderBy(i => i.PreorderId);
|
||||
.OrderBy(i => i.PreOrderId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,11 +38,11 @@ public class FruitBankEventConsumer :
|
|||
private readonly FruitBankDbContext _ctx;
|
||||
private readonly MeasurementService _measurementService;
|
||||
private readonly FruitBankAttributeService _fruitBankAttributeService;
|
||||
private readonly PreorderConversionService _preorderConversionService;
|
||||
private readonly PreOrderConversionService _preorderConversionService;
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
|
||||
public FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, FruitBankDbContext ctx, MeasurementService measurementService,
|
||||
FruitBankAttributeService fruitBankAttributeService, PreorderConversionService preorderConversionService,
|
||||
FruitBankAttributeService fruitBankAttributeService, PreOrderConversionService preorderConversionService,
|
||||
IServiceScopeFactory serviceScopeFactory, IEnumerable<IAcLogWriterBase> logWriters) : base(ctx, httpContextAcc, logWriters)
|
||||
{
|
||||
_ctx = ctx;
|
||||
|
|
@ -212,9 +212,9 @@ public class FruitBankEventConsumer :
|
|||
System.Transactions.TransactionScopeOption.Suppress,
|
||||
System.Transactions.TransactionScopeAsyncFlowOption.Enabled);
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var conversion = scope.ServiceProvider.GetRequiredService<PreorderConversionService>();
|
||||
try { await conversion.ConvertPreordersForProductsAsync(new List<int> { item.ProductId.Value }, item.ShippingDocumentId); }
|
||||
catch (Exception ex) { Logger.Error($"[FruitBankEventConsumer] Preorder conversion failed for ProductId={item.ProductId}: {ex.Message}", ex); }
|
||||
var conversion = scope.ServiceProvider.GetRequiredService<PreOrderConversionService>();
|
||||
try { await conversion.ConvertPreOrdersForProductsAsync(new List<int> { item.ProductId.Value }, item.ShippingDocumentId); }
|
||||
catch (Exception ex) { Logger.Error($"[FruitBankEventConsumer] PreOrder conversion failed for ProductId={item.ProductId}: {ex.Message}", ex); }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -238,9 +238,9 @@ public class FruitBankEventConsumer :
|
|||
System.Transactions.TransactionScopeOption.Suppress,
|
||||
System.Transactions.TransactionScopeAsyncFlowOption.Enabled);
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var conversion = scope.ServiceProvider.GetRequiredService<PreorderConversionService>();
|
||||
try { await conversion.ConvertPreordersForProductsAsync(new List<int> { shippingItem.ProductId.Value }, shippingItem.ShippingDocumentId); }
|
||||
catch (Exception ex) { Logger.Error($"[FruitBankEventConsumer] Preorder conversion failed for ProductId={shippingItem.ProductId}: {ex.Message}", ex); }
|
||||
var conversion = scope.ServiceProvider.GetRequiredService<PreOrderConversionService>();
|
||||
try { await conversion.ConvertPreOrdersForProductsAsync(new List<int> { shippingItem.ProductId.Value }, shippingItem.ShippingDocumentId); }
|
||||
catch (Exception ex) { Logger.Error($"[FruitBankEventConsumer] PreOrder conversion failed for ProductId={shippingItem.ProductId}: {ex.Message}", ex); }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ namespace Nop.Plugin.Misc.FruitBankPlugin
|
|||
public static class FruitBankPluginConst
|
||||
{
|
||||
/// <summary>
|
||||
/// Preorders whose DateOfReceipt is further than this many days in the future
|
||||
/// PreOrders whose DateOfReceipt is further than this many days in the future
|
||||
/// are NOT converted at the current conversion run.
|
||||
/// Based on the bi-weekly truck cycle (~3-4 days between arrivals):
|
||||
/// if delivery is more than 4 days away, the next truck will arrive before
|
||||
/// that delivery date, and its document processing will be the correct trigger.
|
||||
/// </summary>
|
||||
public const int PreorderConversionWindowDays = 4;
|
||||
public const int PreOrderConversionWindowDays = 4;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,92 +228,92 @@ namespace Nop.Plugin.Misc.FruitBankPlugin
|
|||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.QuickOrder.InvalidProductOrQuantity", "Invalid product or quantity", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.QuickOrder.InvalidProductOrQuantity", "\u00c9rv\u00e9nytelen term\u00e9k vagy mennyis\u00e9g", hu);
|
||||
|
||||
// ── Preorder page ───────────────────────────────────────────────────
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.PageTitle", "Preorder", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.PageTitle", "El\u0151rendel\u00e9s", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.MenuLabel", "Preorder", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.MenuLabel", "El\u0151rendel\u00e9s", hu);
|
||||
// ── PreOrder page ───────────────────────────────────────────────────
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.PageTitle", "PreOrder", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.PageTitle", "El\u0151rendel\u00e9s", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.MenuLabel", "PreOrder", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.MenuLabel", "El\u0151rendel\u00e9s", hu);
|
||||
// Delivery step
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Title", "When do you want to receive your preorder?", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Title", "Mikor k\u00e9red a rendel\u00e9st?", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Subtitle", "Choose a delivery day and time (we\u2019ll confirm availability)", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Subtitle", "V\u00e1lassz sz\u00e1ll\u00edt\u00e1si napot \u00e9s id\u0151pontot (az el\u00e9rhet\u0151s\u00e9get meger\u0151s\u00edtj\u00fck)", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.DayLabel", "Delivery day", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.DayLabel", "K\u00edv\u00e1nt sz\u00e1ll\u00edt\u00e1si nap", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.TimeLabel", "Delivery time", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.TimeLabel", "K\u00edv\u00e1nt id\u0151pont", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.TimeHint", "Choose an exact time", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.TimeHint", "V\u00e1lassz pontos id\u0151pontot", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ConfirmButton", "Show available products", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ConfirmButton", "El\u00e9rhet\u0151 term\u00e9kek mutat\u00e1sa", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ChangeLabel", "Delivery:", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ChangeLabel", "Sz\u00e1ll\u00edt\u00e1s:", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ChangeButton", "Change", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ChangeButton", "M\u00f3dos\u00edt\u00e1s", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Today", "Today", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Today", "Ma", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Tomorrow", "Tomorrow", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Tomorrow", "Holnap", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Saving", "Saving...", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Saving", "Ment\u00e9s...", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Title", "When do you want to receive your preorder?", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Title", "Mikor k\u00e9red a rendel\u00e9st?", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Subtitle", "Choose a delivery day and time (we\u2019ll confirm availability)", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Subtitle", "V\u00e1lassz sz\u00e1ll\u00edt\u00e1si napot \u00e9s id\u0151pontot (az el\u00e9rhet\u0151s\u00e9get meger\u0151s\u00edtj\u00fck)", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.DayLabel", "Delivery day", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.DayLabel", "K\u00edv\u00e1nt sz\u00e1ll\u00edt\u00e1si nap", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.TimeLabel", "Delivery time", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.TimeLabel", "K\u00edv\u00e1nt id\u0151pont", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.TimeHint", "Choose an exact time", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.TimeHint", "V\u00e1lassz pontos id\u0151pontot", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ConfirmButton", "Show available products", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ConfirmButton", "El\u00e9rhet\u0151 term\u00e9kek mutat\u00e1sa", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ChangeLabel", "Delivery:", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ChangeLabel", "Sz\u00e1ll\u00edt\u00e1s:", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ChangeButton", "Change", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ChangeButton", "M\u00f3dos\u00edt\u00e1s", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Today", "Today", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Today", "Ma", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Tomorrow", "Tomorrow", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Tomorrow", "Holnap", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Saving", "Saving...", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Saving", "Ment\u00e9s...", hu);
|
||||
// Products
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.InfoBanner", "Preorders are wishes \u2014 we will confirm availability when the shipment arrives and notify you of any changes.", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.InfoBanner", "Az el\u0151rendel\u00e9s egy k\u00edv\u00e1ns\u00e1glista \u2014 az áruk meger\u0151s\u00edt\u00e9se a sz\u00e1ll\u00edtm\u00e1ny be\u00e9rkez\u00e9sekor t\u00f6rt\u00e9nik, \u00e9s az esetleges v\u00e1ltoz\u00e1sokr\u00f3l \u00e9rtes\u00edt\u00fcnk.", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.LoadingProducts", "Loading available products...", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.LoadingProducts", "El\u00e9rhet\u0151 term\u00e9kek bet\u00f6lt\u00e9se...", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NoProductsAvailable", "No products are currently available for preorder. Please check back later.", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NoProductsAvailable", "Jelenleg nincs el\u0151rendelhet\u0151 term\u00e9k. K\u00e9rj\u00fck, l\u00e1togass vissza k\u00e9s\u0151bb.", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.ProductsLabel", "Available for preorder \u2014 set quantities:", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.ProductsLabel", "El\u0151rendelhet\u0151 term\u00e9kek \u2014 add meg a mennyis\u00e9geket:", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.MeasurableBadge", "Requires weighing", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.MeasurableBadge", "S\u00falym\u00e9r\u00e9st ig\u00e9nyel", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.PricePerPiece", "Ft/pcs", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.PricePerPiece", "Ft/db", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.PieceUnit", "pcs", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.PieceUnit", "db", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.StockLabel", "Incoming stock:", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.StockLabel", "V\u00e1rhat\u00f3 k\u00e9szlet:", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.InfoBanner", "PreOrders are wishes \u2014 we will confirm availability when the shipment arrives and notify you of any changes.", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.InfoBanner", "Az el\u0151rendel\u00e9s egy k\u00edv\u00e1ns\u00e1glista \u2014 az áruk meger\u0151s\u00edt\u00e9se a sz\u00e1ll\u00edtm\u00e1ny be\u00e9rkez\u00e9sekor t\u00f6rt\u00e9nik, \u00e9s az esetleges v\u00e1ltoz\u00e1sokr\u00f3l \u00e9rtes\u00edt\u00fcnk.", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.LoadingProducts", "Loading available products...", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.LoadingProducts", "El\u00e9rhet\u0151 term\u00e9kek bet\u00f6lt\u00e9se...", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NoProductsAvailable", "No products are currently available for preorder. Please check back later.", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NoProductsAvailable", "Jelenleg nincs el\u0151rendelhet\u0151 term\u00e9k. K\u00e9rj\u00fck, l\u00e1togass vissza k\u00e9s\u0151bb.", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.ProductsLabel", "Available for preorder \u2014 set quantities:", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.ProductsLabel", "El\u0151rendelhet\u0151 term\u00e9kek \u2014 add meg a mennyis\u00e9geket:", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.MeasurableBadge", "Requires weighing", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.MeasurableBadge", "S\u00falym\u00e9r\u00e9st ig\u00e9nyel", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.PricePerPiece", "Ft/pcs", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.PricePerPiece", "Ft/db", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.PieceUnit", "pcs", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.PieceUnit", "db", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.StockLabel", "Incoming stock:", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.StockLabel", "V\u00e1rhat\u00f3 k\u00e9szlet:", hu);
|
||||
// Note + submit
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NoteLabel", "Additional note (optional)", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NoteLabel", "Megjegyz\u00e9s (nem k\u00f6telez\u0151)", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NotePlaceholder", "Any special requests or notes for this preorder...", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NotePlaceholder", "Esetleges megjegyz\u00e9sek az el\u0151rendel\u00e9ssel kapcsolatban...", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SelectionNone", "No products selected yet", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SelectionNone", "M\u00e9g nincs kiv\u00e1lasztott term\u00e9k", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SelectionItems", "product(s) selected", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SelectionItems", "term\u00e9k kiv\u00e1lasztva", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SubmitButton", "Place preorder", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SubmitButton", "El\u0151rendel\u00e9s lead\u00e1sa", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.Submitting", "Placing preorder...", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.Submitting", "El\u0151rendel\u00e9s ment\u00e9se...", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NoteLabel", "Additional note (optional)", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NoteLabel", "Megjegyz\u00e9s (nem k\u00f6telez\u0151)", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NotePlaceholder", "Any special requests or notes for this preorder...", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NotePlaceholder", "Esetleges megjegyz\u00e9sek az el\u0151rendel\u00e9ssel kapcsolatban...", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SelectionNone", "No products selected yet", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SelectionNone", "M\u00e9g nincs kiv\u00e1lasztott term\u00e9k", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SelectionItems", "product(s) selected", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SelectionItems", "term\u00e9k kiv\u00e1lasztva", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SubmitButton", "Place preorder", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SubmitButton", "El\u0151rendel\u00e9s lead\u00e1sa", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.Submitting", "Placing preorder...", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.Submitting", "El\u0151rendel\u00e9s ment\u00e9se...", hu);
|
||||
// Summary panel
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SummaryTitle", "Your preorder", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SummaryTitle", "El\u0151rendel\u00e9sed", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SummaryEmpty", "Set quantities above to build your preorder.", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SummaryEmpty", "Add meg a mennyis\u00e9geket a term\u00e9kekn\u00e9l.", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SummaryNote", "Prices for weighed items will be finalised after measurement. Preorder quantities may change depending on actual shipment.", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SummaryNote", "A s\u00falym\u00e9r\u00e9st ig\u00e9nyl\u0151 t\u00e9teleikn\u00e9l az \u00e1r a m\u00e9r\u00e9s ut\u00e1n v\u00e9glegesedik. A mennyis\u00e9gek a t\u00e9nyleges sz\u00e1ll\u00edtm\u00e1nyt\u00f3l f\u00fcgg\u0151en v\u00e1ltozhatnak.", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SummaryTitle", "Your preorder", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SummaryTitle", "El\u0151rendel\u00e9sed", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SummaryEmpty", "Set quantities above to build your preorder.", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SummaryEmpty", "Add meg a mennyis\u00e9geket a term\u00e9kekn\u00e9l.", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SummaryNote", "Prices for weighed items will be finalised after measurement. PreOrder quantities may change depending on actual shipment.", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SummaryNote", "A s\u00falym\u00e9r\u00e9st ig\u00e9nyl\u0151 t\u00e9teleikn\u00e9l az \u00e1r a m\u00e9r\u00e9s ut\u00e1n v\u00e9glegesedik. A mennyis\u00e9gek a t\u00e9nyleges sz\u00e1ll\u00edtm\u00e1nyt\u00f3l f\u00fcgg\u0151en v\u00e1ltozhatnak.", hu);
|
||||
// Success + errors
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SuccessTitle", "Preorder placed!", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SuccessTitle", "El\u0151rendel\u00e9s leadva!", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SuccessMessage", "Your preorder #{0} has been received. We will notify you when the shipment arrives.", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.SuccessMessage", "#{0} sz\u00e1m\u00fa el\u0151rendel\u00e9sed be\u00e9rkezett. A sz\u00e1ll\u00edtm\u00e1ny meger\u0151s\u00edt\u00e9sekor \u00e9rtes\u00edt\u00fcnk.", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.BackToHome", "Back to home", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.BackToHome", "Vissza a f\u0151oldalra", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.ErrorPrefix", "Error: ", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.ErrorPrefix", "Hiba: ", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NotLoggedIn", "Not logged in", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NotLoggedIn", "Nincs bejelentkezve", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NoItemsSelected", "No items selected", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NoItemsSelected", "Nincs kiv\u00e1lasztott term\u00e9k", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NoValidItems", "No valid items in preorder", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NoValidItems", "Nincs \u00e9rv\u00e9nyes term\u00e9k az el\u0151rendel\u00e9sben", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NoDeliveryDateTimeProvided", "No delivery date/time provided", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.NoDeliveryDateTimeProvided", "Nincs sz\u00e1ll\u00edt\u00e1si id\u0151pont megadva", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.InvalidDeliveryDateTime", "Invalid delivery date/time format", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.InvalidDeliveryDateTime", "\u00c9rv\u00e9nytelen sz\u00e1ll\u00edt\u00e1si d\u00e1tum/id\u0151 form\u00e1tum", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.PlacedSuccessfully", "Preorder placed successfully", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Preorder.PlacedSuccessfully", "El\u0151rendel\u00e9s sikeresen leadva", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SuccessTitle", "PreOrder placed!", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SuccessTitle", "El\u0151rendel\u00e9s leadva!", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SuccessMessage", "Your preorder #{0} has been received. We will notify you when the shipment arrives.", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.SuccessMessage", "#{0} sz\u00e1m\u00fa el\u0151rendel\u00e9sed be\u00e9rkezett. A sz\u00e1ll\u00edtm\u00e1ny meger\u0151s\u00edt\u00e9sekor \u00e9rtes\u00edt\u00fcnk.", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.BackToHome", "Back to home", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.BackToHome", "Vissza a f\u0151oldalra", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.ErrorPrefix", "Error: ", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.ErrorPrefix", "Hiba: ", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NotLoggedIn", "Not logged in", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NotLoggedIn", "Nincs bejelentkezve", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NoItemsSelected", "No items selected", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NoItemsSelected", "Nincs kiv\u00e1lasztott term\u00e9k", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NoValidItems", "No valid items in preorder", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NoValidItems", "Nincs \u00e9rv\u00e9nyes term\u00e9k az el\u0151rendel\u00e9sben", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NoDeliveryDateTimeProvided", "No delivery date/time provided", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.NoDeliveryDateTimeProvided", "Nincs sz\u00e1ll\u00edt\u00e1si id\u0151pont megadva", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.InvalidDeliveryDateTime", "Invalid delivery date/time format", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.InvalidDeliveryDateTime", "\u00c9rv\u00e9nytelen sz\u00e1ll\u00edt\u00e1si d\u00e1tum/id\u0151 form\u00e1tum", hu);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.PlacedSuccessfully", "PreOrder placed successfully", en);
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.PreOrder.PlacedSuccessfully", "El\u0151rendel\u00e9s sikeresen leadva", hu);
|
||||
|
||||
// ── Customer Credit ────────────────────────────────────────────────────
|
||||
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.CustomerCredit.PageTitle", "Customer Credit Management", en);
|
||||
|
|
@ -464,7 +464,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin
|
|||
}
|
||||
else if (widgetZone == PublicWidgetZones.AccountNavigationAfter)
|
||||
{
|
||||
return typeof(CustomerPreorderNavViewComponent);
|
||||
return typeof(CustomerPreOrderNavViewComponent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,9 +94,9 @@ public class PluginNopStartup : INopStartup
|
|||
services.AddScoped<StockTakingItemDbTable>();
|
||||
services.AddScoped<StockTakingItemPalletDbTable>();
|
||||
services.AddScoped<CustomerCreditDbTable>();
|
||||
services.AddScoped<PreorderDbTable>();
|
||||
services.AddScoped<PreorderItemDbTable>();
|
||||
services.AddScoped<PreorderDbContext>();
|
||||
services.AddScoped<PreOrderDbTable>();
|
||||
services.AddScoped<PreOrderItemDbTable>();
|
||||
services.AddScoped<PreOrderDbContext>();
|
||||
|
||||
services.AddScoped<StockTakingDbContext>();
|
||||
services.AddScoped<FruitBankDbContext>();
|
||||
|
|
@ -151,7 +151,7 @@ public class PluginNopStartup : INopStartup
|
|||
services.AddScoped<PdfToImageService>();
|
||||
services.AddScoped<FruitBankNotificationService>();
|
||||
services.AddScoped<FruitBankOrderItemService>();
|
||||
services.AddScoped<PreorderConversionService>();
|
||||
services.AddScoped<PreOrderConversionService>();
|
||||
services.AddSingleton<IFileStorageProvider>(sp =>
|
||||
new LocalFileStorageProvider() // Uses default wwwroot/uploads
|
||||
// Or specify custom path:
|
||||
|
|
|
|||
|
|
@ -197,57 +197,57 @@ public class RouteProvider : IRouteProvider
|
|||
pattern: "Admin/CustomerCredit/UpdateCreditLimit",
|
||||
defaults: new { controller = "CustomerCredit", action = "UpdateCreditLimit", area = AreaNames.ADMIN });
|
||||
|
||||
// ── Admin: Preorder list ───────────────────────────────────────────
|
||||
// ── Admin: PreOrder list ───────────────────────────────────────────
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Preorders.List",
|
||||
pattern: "Admin/Preorders",
|
||||
defaults: new { controller = "PreorderAdmin", action = "List", area = AreaNames.ADMIN });
|
||||
name: "Plugin.FruitBank.PreOrders.List",
|
||||
pattern: "Admin/PreOrders",
|
||||
defaults: new { controller = "PreOrderAdmin", action = "List", area = AreaNames.ADMIN });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Preorders.PreorderList",
|
||||
pattern: "Admin/Preorders/PreorderList",
|
||||
defaults: new { controller = "PreorderAdmin", action = "PreorderList", area = AreaNames.ADMIN });
|
||||
name: "Plugin.FruitBank.PreOrders.PreOrderList",
|
||||
pattern: "Admin/PreOrders/PreOrderList",
|
||||
defaults: new { controller = "PreOrderAdmin", action = "PreOrderList", area = AreaNames.ADMIN });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Preorders.Detail",
|
||||
pattern: "Admin/Preorders/Detail/{id:int}",
|
||||
defaults: new { controller = "PreorderAdmin", action = "Detail", area = AreaNames.ADMIN });
|
||||
name: "Plugin.FruitBank.PreOrders.Detail",
|
||||
pattern: "Admin/PreOrders/Detail/{id:int}",
|
||||
defaults: new { controller = "PreOrderAdmin", action = "Detail", area = AreaNames.ADMIN });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Preorders.Cancel",
|
||||
pattern: "Admin/Preorders/Cancel/{id:int}",
|
||||
defaults: new { controller = "PreorderAdmin", action = "Cancel", area = AreaNames.ADMIN });
|
||||
name: "Plugin.FruitBank.PreOrders.Cancel",
|
||||
pattern: "Admin/PreOrders/Cancel/{id:int}",
|
||||
defaults: new { controller = "PreOrderAdmin", action = "Cancel", area = AreaNames.ADMIN });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Preorders.CreatePreorder",
|
||||
pattern: "Admin/Preorders/CreatePreorder",
|
||||
defaults: new { controller = "PreorderAdmin", action = "CreatePreorder", area = AreaNames.ADMIN });
|
||||
name: "Plugin.FruitBank.PreOrders.CreatePreOrder",
|
||||
pattern: "Admin/PreOrders/CreatePreOrder",
|
||||
defaults: new { controller = "PreOrderAdmin", action = "CreatePreOrder", area = AreaNames.ADMIN });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Preorders.DemandList",
|
||||
pattern: "Admin/Preorders/DemandList",
|
||||
defaults: new { controller = "PreorderAdmin", action = "DemandList", area = AreaNames.ADMIN });
|
||||
name: "Plugin.FruitBank.PreOrders.DemandList",
|
||||
pattern: "Admin/PreOrders/DemandList",
|
||||
defaults: new { controller = "PreOrderAdmin", action = "DemandList", area = AreaNames.ADMIN });
|
||||
|
||||
// ── Admin: Preorder availability ─────────────────────────────────
|
||||
// ── Admin: PreOrder availability ─────────────────────────────────
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.PreorderAvailability.Index",
|
||||
pattern: "Admin/PreorderAvailability",
|
||||
defaults: new { controller = "PreorderAvailability", action = "Index", area = AreaNames.ADMIN });
|
||||
name: "Plugin.FruitBank.PreOrderAvailability.Index",
|
||||
pattern: "Admin/PreOrderAvailability",
|
||||
defaults: new { controller = "PreOrderAvailability", action = "Index", area = AreaNames.ADMIN });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.PreorderAvailability.ProductList",
|
||||
pattern: "Admin/PreorderAvailability/ProductList",
|
||||
defaults: new { controller = "PreorderAvailability", action = "ProductList", area = AreaNames.ADMIN });
|
||||
name: "Plugin.FruitBank.PreOrderAvailability.ProductList",
|
||||
pattern: "Admin/PreOrderAvailability/ProductList",
|
||||
defaults: new { controller = "PreOrderAvailability", action = "ProductList", area = AreaNames.ADMIN });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.PreorderAvailability.AvailableTodayList",
|
||||
pattern: "Admin/PreorderAvailability/AvailableTodayList",
|
||||
defaults: new { controller = "PreorderAvailability", action = "AvailableTodayList", area = AreaNames.ADMIN });
|
||||
name: "Plugin.FruitBank.PreOrderAvailability.AvailableTodayList",
|
||||
pattern: "Admin/PreOrderAvailability/AvailableTodayList",
|
||||
defaults: new { controller = "PreOrderAvailability", action = "AvailableTodayList", area = AreaNames.ADMIN });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.PreorderAvailability.SaveWindow",
|
||||
pattern: "Admin/PreorderAvailability/SaveWindow",
|
||||
defaults: new { controller = "PreorderAvailability", action = "SaveWindow", area = AreaNames.ADMIN });
|
||||
name: "Plugin.FruitBank.PreOrderAvailability.SaveWindow",
|
||||
pattern: "Admin/PreOrderAvailability/SaveWindow",
|
||||
defaults: new { controller = "PreOrderAvailability", action = "SaveWindow", area = AreaNames.ADMIN });
|
||||
|
||||
// ── Public: Unified Order flow ─────────────────────────────────────────
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
|
|
@ -271,9 +271,9 @@ public class RouteProvider : IRouteProvider
|
|||
defaults: new { controller = "Order", action = "GetAllProducts" });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Order.GetPreorderProducts",
|
||||
name: "Plugin.FruitBank.Order.GetPreOrderProducts",
|
||||
pattern: "rendeles/elozetes-termekek",
|
||||
defaults: new { controller = "Order", action = "GetPreorderProducts" });
|
||||
defaults: new { controller = "Order", action = "GetPreOrderProducts" });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Order.SearchProducts",
|
||||
|
|
@ -296,9 +296,9 @@ public class RouteProvider : IRouteProvider
|
|||
defaults: new { controller = "Order", action = "GetCartItems" });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Order.PlacePreorder",
|
||||
name: "Plugin.FruitBank.Order.PlacePreOrder",
|
||||
pattern: "rendeles/elozetes-leadás",
|
||||
defaults: new { controller = "Order", action = "PlacePreorder" });
|
||||
defaults: new { controller = "Order", action = "PlacePreOrder" });
|
||||
|
||||
// ── Public: Help page ───────────────────────────────────────────────────
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
|
|
@ -308,35 +308,35 @@ public class RouteProvider : IRouteProvider
|
|||
|
||||
// ── Public: Customer preorder list ───────────────────────────────────────────
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.CustomerPreorder.List",
|
||||
name: "Plugin.FruitBank.CustomerPreOrder.List",
|
||||
pattern: "fiokom/elorerendeles-aim",
|
||||
defaults: new { controller = "CustomerPreorder", action = "List" });
|
||||
defaults: new { controller = "CustomerPreOrder", action = "List" });
|
||||
|
||||
// ── Public: Preorder (legacy, kept for backward compat) ───────────────
|
||||
// ── Public: PreOrder (legacy, kept for backward compat) ───────────────
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Preorder.Index",
|
||||
name: "Plugin.FruitBank.PreOrder.Index",
|
||||
pattern: "elozetes-rendeles",
|
||||
defaults: new { controller = "Preorder", action = "Index" });
|
||||
defaults: new { controller = "PreOrder", action = "Index" });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Preorder.GetDeliveryDateTime",
|
||||
name: "Plugin.FruitBank.PreOrder.GetDeliveryDateTime",
|
||||
pattern: "elozetes-rendeles/szallitas-idopont",
|
||||
defaults: new { controller = "Preorder", action = "GetDeliveryDateTime" });
|
||||
defaults: new { controller = "PreOrder", action = "GetDeliveryDateTime" });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Preorder.SetDeliveryDateTime",
|
||||
name: "Plugin.FruitBank.PreOrder.SetDeliveryDateTime",
|
||||
pattern: "elozetes-rendeles/szallitas-idopont-beallitas",
|
||||
defaults: new { controller = "Preorder", action = "SetDeliveryDateTime" });
|
||||
defaults: new { controller = "PreOrder", action = "SetDeliveryDateTime" });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Preorder.GetAvailableProducts",
|
||||
name: "Plugin.FruitBank.PreOrder.GetAvailableProducts",
|
||||
pattern: "elozetes-rendeles/termekek",
|
||||
defaults: new { controller = "Preorder", action = "GetAvailableProducts" });
|
||||
defaults: new { controller = "PreOrder", action = "GetAvailableProducts" });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Preorder.PlacePreorder",
|
||||
name: "Plugin.FruitBank.PreOrder.PlacePreOrder",
|
||||
pattern: "elozetes-rendeles/leadás",
|
||||
defaults: new { controller = "Preorder", action = "PlacePreorder" });
|
||||
defaults: new { controller = "PreOrder", action = "PlacePreOrder" });
|
||||
|
||||
// ── Public: Quick Order ──────────────────────────────────────────────
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
|
|
|
|||
|
|
@ -2,142 +2,142 @@
|
|||
<Language Name="English" IsDefault="false" IsRightToLeft="false">
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════
|
||||
Preorder page — Plugins.Misc.FruitBankPlugin.Preorder.*
|
||||
PreOrder page — Plugins.Misc.FruitBankPlugin.PreOrder.*
|
||||
Import: Admin > Configuration > Languages > [English] > Import resources
|
||||
═══════════════════════════════════════════════════════════ -->
|
||||
|
||||
<!-- General -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.PageTitle">
|
||||
<Value><![CDATA[Preorder]]></Value>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.PageTitle">
|
||||
<Value><![CDATA[PreOrder]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.MenuLabel">
|
||||
<Value><![CDATA[Preorder]]></Value>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.MenuLabel">
|
||||
<Value><![CDATA[PreOrder]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
<!-- Delivery step -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Title">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Title">
|
||||
<Value><![CDATA[When do you want to receive your preorder?]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Subtitle">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Subtitle">
|
||||
<Value><![CDATA[Choose a delivery day and time (we'll confirm availability)]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.DayLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.DayLabel">
|
||||
<Value><![CDATA[Delivery day]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.TimeLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.TimeLabel">
|
||||
<Value><![CDATA[Delivery time]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.TimeHint">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.TimeHint">
|
||||
<Value><![CDATA[Choose an exact time]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ConfirmButton">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ConfirmButton">
|
||||
<Value><![CDATA[Show available products]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ChangeLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ChangeLabel">
|
||||
<Value><![CDATA[Delivery:]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ChangeButton">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ChangeButton">
|
||||
<Value><![CDATA[Change]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Today">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Today">
|
||||
<Value><![CDATA[Today]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Tomorrow">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Tomorrow">
|
||||
<Value><![CDATA[Tomorrow]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Saving">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Saving">
|
||||
<Value><![CDATA[Saving...]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
<!-- Product list -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.InfoBanner">
|
||||
<Value><![CDATA[Preorders are wishes — we will confirm availability when the shipment arrives and notify you of any changes.]]></Value>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.InfoBanner">
|
||||
<Value><![CDATA[PreOrders are wishes — we will confirm availability when the shipment arrives and notify you of any changes.]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.LoadingProducts">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.LoadingProducts">
|
||||
<Value><![CDATA[Loading available products...]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NoProductsAvailable">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NoProductsAvailable">
|
||||
<Value><![CDATA[No products are currently available for preorder. Please check back later.]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.ProductsLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.ProductsLabel">
|
||||
<Value><![CDATA[Available for preorder — set quantities:]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.MeasurableBadge">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.MeasurableBadge">
|
||||
<Value><![CDATA[Requires weighing]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.PricePerPiece">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.PricePerPiece">
|
||||
<Value><![CDATA[Ft/pcs]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.PieceUnit">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.PieceUnit">
|
||||
<Value><![CDATA[pcs]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.StockLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.StockLabel">
|
||||
<Value><![CDATA[Incoming stock:]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
<!-- Note and submit -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NoteLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NoteLabel">
|
||||
<Value><![CDATA[Additional note (optional)]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NotePlaceholder">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NotePlaceholder">
|
||||
<Value><![CDATA[Any special requests or notes for this preorder...]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SelectionNone">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SelectionNone">
|
||||
<Value><![CDATA[No products selected yet]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SelectionItems">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SelectionItems">
|
||||
<Value><![CDATA[product(s) selected]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SubmitButton">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SubmitButton">
|
||||
<Value><![CDATA[Place preorder]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.Submitting">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.Submitting">
|
||||
<Value><![CDATA[Placing preorder...]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
<!-- Summary panel -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SummaryTitle">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SummaryTitle">
|
||||
<Value><![CDATA[Your preorder]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SummaryEmpty">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SummaryEmpty">
|
||||
<Value><![CDATA[Set quantities above to build your preorder.]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SummaryNote">
|
||||
<Value><![CDATA[Prices for weighed items will be finalised after measurement. Preorder quantities may change depending on actual shipment.]]></Value>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SummaryNote">
|
||||
<Value><![CDATA[Prices for weighed items will be finalised after measurement. PreOrder quantities may change depending on actual shipment.]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
<!-- Success -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SuccessTitle">
|
||||
<Value><![CDATA[Preorder placed!]]></Value>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SuccessTitle">
|
||||
<Value><![CDATA[PreOrder placed!]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SuccessMessage">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SuccessMessage">
|
||||
<Value><![CDATA[Your preorder #{0} has been received. We will notify you when the shipment arrives.]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.BackToHome">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.BackToHome">
|
||||
<Value><![CDATA[Back to home]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
<!-- Error messages -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.ErrorPrefix">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.ErrorPrefix">
|
||||
<Value><![CDATA[Error: ]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NotLoggedIn">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NotLoggedIn">
|
||||
<Value><![CDATA[Not logged in]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NoItemsSelected">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NoItemsSelected">
|
||||
<Value><![CDATA[No items selected]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NoValidItems">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NoValidItems">
|
||||
<Value><![CDATA[No valid items in preorder]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NoDeliveryDateTimeProvided">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NoDeliveryDateTimeProvided">
|
||||
<Value><![CDATA[No delivery date/time provided]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.InvalidDeliveryDateTime">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.InvalidDeliveryDateTime">
|
||||
<Value><![CDATA[Invalid delivery date/time format]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.PlacedSuccessfully">
|
||||
<Value><![CDATA[Preorder placed successfully]]></Value>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.PlacedSuccessfully">
|
||||
<Value><![CDATA[PreOrder placed successfully]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
</Language>
|
||||
|
|
|
|||
|
|
@ -2,141 +2,141 @@
|
|||
<Language Name="Hungarian" IsDefault="false" IsRightToLeft="false">
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════
|
||||
Előrendelés oldal — Plugins.Misc.FruitBankPlugin.Preorder.*
|
||||
Előrendelés oldal — Plugins.Misc.FruitBankPlugin.PreOrder.*
|
||||
Import: Admin > Konfiguráció > Nyelvek > [Magyar] > Erőforrások importálása
|
||||
═══════════════════════════════════════════════════════════ -->
|
||||
|
||||
<!-- Általános -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.PageTitle">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.PageTitle">
|
||||
<Value><![CDATA[Előrendelés]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.MenuLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.MenuLabel">
|
||||
<Value><![CDATA[Előrendelés]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
<!-- Szállítási időpont lépés -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Title">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Title">
|
||||
<Value><![CDATA[Mikor kéred a rendelést?]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Subtitle">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Subtitle">
|
||||
<Value><![CDATA[Válassz szállítási napot és időpontot (az elérhetőséget megerősítjük)]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.DayLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.DayLabel">
|
||||
<Value><![CDATA[Kívánt szállítási nap]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.TimeLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.TimeLabel">
|
||||
<Value><![CDATA[Kívánt időpont]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.TimeHint">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.TimeHint">
|
||||
<Value><![CDATA[Válassz pontos időpontot]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ConfirmButton">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ConfirmButton">
|
||||
<Value><![CDATA[Elérhető termékek mutatása]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ChangeLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ChangeLabel">
|
||||
<Value><![CDATA[Szállítás:]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ChangeButton">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ChangeButton">
|
||||
<Value><![CDATA[Módosítás]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Today">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Today">
|
||||
<Value><![CDATA[Ma]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Tomorrow">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Tomorrow">
|
||||
<Value><![CDATA[Holnap]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Saving">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Saving">
|
||||
<Value><![CDATA[Mentés...]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
<!-- Terméklista -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.InfoBanner">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.InfoBanner">
|
||||
<Value><![CDATA[Az előrendelés egy kívánságlista — az áruk megerősítése a szállítmány beérkezésekor történik, és az esetleges változásokról értesítünk.]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.LoadingProducts">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.LoadingProducts">
|
||||
<Value><![CDATA[Elérhető termékek betöltése...]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NoProductsAvailable">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NoProductsAvailable">
|
||||
<Value><![CDATA[Jelenleg nincs előrendelhető termék. Kérjük, látogass vissza később.]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.ProductsLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.ProductsLabel">
|
||||
<Value><![CDATA[Előrendelhető termékek — add meg a mennyiségeket:]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.MeasurableBadge">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.MeasurableBadge">
|
||||
<Value><![CDATA[Súlymérést igényel]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.PricePerPiece">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.PricePerPiece">
|
||||
<Value><![CDATA[Ft/db]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.PieceUnit">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.PieceUnit">
|
||||
<Value><![CDATA[db]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.StockLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.StockLabel">
|
||||
<Value><![CDATA[Várható készlet:]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
<!-- Megjegyzés és leadás -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NoteLabel">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NoteLabel">
|
||||
<Value><![CDATA[Megjegyzés (nem kötelező)]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NotePlaceholder">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NotePlaceholder">
|
||||
<Value><![CDATA[Esetleges megjegyzések az előrendeléssel kapcsolatban...]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SelectionNone">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SelectionNone">
|
||||
<Value><![CDATA[Még nincs kiválasztott termék]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SelectionItems">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SelectionItems">
|
||||
<Value><![CDATA[termék kiválasztva]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SubmitButton">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SubmitButton">
|
||||
<Value><![CDATA[Előrendelés leadása]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.Submitting">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.Submitting">
|
||||
<Value><![CDATA[Előrendelés mentése...]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
<!-- Összefoglaló panel -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SummaryTitle">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SummaryTitle">
|
||||
<Value><![CDATA[Előrendelésed]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SummaryEmpty">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SummaryEmpty">
|
||||
<Value><![CDATA[Add meg a mennyiségeket a termékeknél.]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SummaryNote">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SummaryNote">
|
||||
<Value><![CDATA[A súlymérést igénylő tételeknél az ár a mérés után véglegesedik. A mennyiségek a tényleges szállítmánytól függően változhatnak.]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
<!-- Sikeres leadás -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SuccessTitle">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SuccessTitle">
|
||||
<Value><![CDATA[Előrendelés leadva!]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.SuccessMessage">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.SuccessMessage">
|
||||
<Value><![CDATA[#{0} számú előrendelésed beérkezett. A szállítmány megerősítésekor értesítünk.]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.BackToHome">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.BackToHome">
|
||||
<Value><![CDATA[Vissza a főoldalra]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
<!-- Hibaüzenetek -->
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.ErrorPrefix">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.ErrorPrefix">
|
||||
<Value><![CDATA[Hiba: ]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NotLoggedIn">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NotLoggedIn">
|
||||
<Value><![CDATA[Nincs bejelentkezve]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NoItemsSelected">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NoItemsSelected">
|
||||
<Value><![CDATA[Nincs kiválasztott termék]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NoValidItems">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NoValidItems">
|
||||
<Value><![CDATA[Nincs érvényes termék az előrendelésben]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.NoDeliveryDateTimeProvided">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.NoDeliveryDateTimeProvided">
|
||||
<Value><![CDATA[Nincs szállítási időpont megadva]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.InvalidDeliveryDateTime">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.InvalidDeliveryDateTime">
|
||||
<Value><![CDATA[Érvénytelen szállítási dátum/idő formátum]]></Value>
|
||||
</LocaleResource>
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.Preorder.PlacedSuccessfully">
|
||||
<LocaleResource Name="Plugins.Misc.FruitBankPlugin.PreOrder.PlacedSuccessfully">
|
||||
<Value><![CDATA[Előrendelés sikeresen leadva]]></Value>
|
||||
</LocaleResource>
|
||||
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ public partial class NameCompatibility : INameCompatibility
|
|||
{ typeof(StockTakingItemPallet), FruitBankConstClient.StockTakingItemPalletDbTableName},
|
||||
|
||||
{ typeof(CustomerCredit), FruitBankConstClient.CustomerCreditDbTableName},
|
||||
{ typeof(Preorder), FruitBankConstClient.PreOrderDbTableName},
|
||||
{ typeof(PreorderItem), FruitBankConstClient.PreOrderItemDbTableName},
|
||||
{ typeof(PreOrder), FruitBankConstClient.PreOrderDbTableName},
|
||||
{ typeof(PreOrderItem), FruitBankConstClient.PreOrderItemDbTableName},
|
||||
|
||||
{ typeof(CargoPartner), FruitBankConstClient.CargoPartnerDbTableName},
|
||||
{ typeof(CargoTruck), FruitBankConstClient.CargoTruckDbTableName},
|
||||
|
|
|
|||
|
|
@ -224,13 +224,13 @@
|
|||
<None Update="Areas\Admin\Views\Order\List.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Areas\Admin\Views\PreorderAvailability\Index.cshtml">
|
||||
<None Update="Areas\Admin\Views\PreOrderAvailability\Index.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Areas\Admin\Views\Preorder\Detail.cshtml">
|
||||
<None Update="Areas\Admin\Views\PreOrder\Detail.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Areas\Admin\Views\Preorder\List.cshtml">
|
||||
<None Update="Areas\Admin\Views\PreOrder\List.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Areas\Admin\Views\Product\List.cshtml">
|
||||
|
|
@ -677,10 +677,10 @@
|
|||
<None Update="Views\CustomerCreditWidget.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Views\CustomerPreorder\List.cshtml">
|
||||
<None Update="Views\CustomerPreOrder\List.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Views\CustomerPreorder\NavItem.cshtml">
|
||||
<None Update="Views\CustomerPreOrder\NavItem.cshtml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Views\Help\Index.cshtml">
|
||||
|
|
@ -689,7 +689,7 @@
|
|||
<None Update="Views\Order\Index.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Views\Preorder\Index.cshtml">
|
||||
<None Update="Views\PreOrder\Index.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Views\ProductAIListWidget.cshtml">
|
||||
|
|
|
|||
|
|
@ -260,10 +260,10 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
var preorderAvailabilityMenuItem = new AdminMenuItem
|
||||
{
|
||||
Visible = true,
|
||||
SystemName = "PreorderAvailability",
|
||||
SystemName = "PreOrderAvailability",
|
||||
Title = "Előrendelés — elérhetőség",
|
||||
IconClass = "fas fa-calendar-check",
|
||||
Url = _adminMenu.GetMenuItemUrl("PreorderAvailability", "Index")
|
||||
Url = _adminMenu.GetMenuItemUrl("PreOrderAvailability", "Index")
|
||||
};
|
||||
|
||||
//shippingConfigurationItem.ChildNodes.Insert(4, preorderAvailabilityMenuItem);
|
||||
|
|
@ -271,10 +271,10 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
var preorderListMenuItem = new AdminMenuItem
|
||||
{
|
||||
Visible = true,
|
||||
SystemName = "Preorders.List",
|
||||
SystemName = "PreOrders.List",
|
||||
Title = "Előrendelések",
|
||||
IconClass = "fas fa-calendar-plus",
|
||||
Url = _adminMenu.GetMenuItemUrl("PreorderAdmin", "List")
|
||||
Url = _adminMenu.GetMenuItemUrl("PreOrderAdmin", "List")
|
||||
};
|
||||
|
||||
var preordersRootMenuItem = new AdminMenuItem
|
||||
|
|
@ -282,7 +282,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
Visible = true,
|
||||
SystemName = "FruitBank",
|
||||
Title = "Előrendelés",
|
||||
//Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.Preorders"), // You can localize this with await _localizationService.GetResourceAsync("...")
|
||||
//Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.PreOrders"), // You can localize this with await _localizationService.GetResourceAsync("...")
|
||||
IconClass = "fas fa-heart",
|
||||
//Url = _adminMenu.GetMenuItemUrl("Shipping", "List")
|
||||
//ChildNodes = [shippingsListMenuItem, createShippingMenuItem, editShippingMenuItem]
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services;
|
|||
/// <summary>
|
||||
/// Shared service for creating, adding and removing order items.
|
||||
/// Extracted from CustomOrderController so the same logic can be reused
|
||||
/// by PreorderConversionService without duplication.
|
||||
/// by PreOrderConversionService without duplication.
|
||||
/// </summary>
|
||||
public class FruitBankOrderItemService
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ using Nop.Services.Orders;
|
|||
namespace Nop.Plugin.Misc.FruitBankPlugin.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for product replacement logic on PreorderConversionService.
|
||||
/// Extension methods for product replacement logic on PreOrderConversionService.
|
||||
///
|
||||
/// SETUP REQUIRED: Add this as a partial class by:
|
||||
/// 1. Add `partial` keyword to PreorderConversionService class declaration
|
||||
/// 1. Add `partial` keyword to PreOrderConversionService class declaration
|
||||
/// 2. This file uses the same injected fields — no extra DI needed
|
||||
/// </summary>
|
||||
public partial class PreorderConversionService
|
||||
public partial class PreOrderConversionService
|
||||
{
|
||||
// ── Product replacement ───────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -127,32 +127,32 @@ public partial class PreorderConversionService
|
|||
// ── Swap preorder items ───────────────────────────────────────────────
|
||||
if (affectedOrderIds.Any())
|
||||
{
|
||||
var preorders = (await _preorderDbContext.Preorders.GetAll(false).ToListAsync())
|
||||
var preorders = (await _preorderDbContext.PreOrders.GetAll(false).ToListAsync())
|
||||
.Where(p => p.OrderId.HasValue && affectedOrderIds.Contains(p.OrderId.Value))
|
||||
.ToList();
|
||||
|
||||
foreach (var preorder in preorders)
|
||||
{
|
||||
var piList = await _preorderDbContext.PreorderItems
|
||||
.GetAllByPreorderIdAsync(preorder.Id)
|
||||
var piList = await _preorderDbContext.PreOrderItems
|
||||
.GetAllByPreOrderIdAsync(preorder.Id)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var pi in piList.Where(i => i.ProductId == oldProductId))
|
||||
{
|
||||
pi.ProductId = newProductId;
|
||||
await _preorderDbContext.PreorderItems.UpdateAsync(pi);
|
||||
await _preorderDbContext.PreOrderItems.UpdateAsync(pi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Trigger conversion for new product ────────────────────────────────
|
||||
// New product may now have pending preorders that can be fulfilled
|
||||
await ConvertPreordersForProductsAsync(
|
||||
await ConvertPreOrdersForProductsAsync(
|
||||
new List<int> { newProductId },
|
||||
oldItem.ShippingDocumentId);
|
||||
|
||||
// TODO: SignalR notification to admin hub
|
||||
// TODO: SendPreorderProductReplacedNotificationAsync per affected customer
|
||||
// TODO: SendPreOrderProductReplacedNotificationAsync per affected customer
|
||||
|
||||
Console.WriteLine($"[ReplaceShippingItemProduct] Complete: " +
|
||||
$"{affectedOrderIds.Count} orders swapped, budget remaining={replacementBudget}");
|
||||
|
|
@ -161,7 +161,7 @@ public partial class PreorderConversionService
|
|||
private async Task<List<OrderDto>> GetAffectedOpenOrdersAsync(int oldProductId)
|
||||
{
|
||||
// Orders that are referenced by a preorder AND contain the old product
|
||||
var preorderOrderIds = (await _preorderDbContext.Preorders.GetAll(false).ToListAsync())
|
||||
var preorderOrderIds = (await _preorderDbContext.PreOrders.GetAll(false).ToListAsync())
|
||||
.Where(p => p.OrderId.HasValue)
|
||||
.Select(p => p.OrderId!.Value)
|
||||
.ToHashSet();
|
||||
|
|
|
|||
|
|
@ -24,17 +24,17 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services;
|
|||
/// Called once per shipping document save, after all IncomingQuantity
|
||||
/// attributes have been written for that document's product set.
|
||||
///
|
||||
/// Allocation strategy: first-come-first-served by PreorderId (insertion order).
|
||||
/// Allocation strategy: first-come-first-served by PreOrderId (insertion order).
|
||||
///
|
||||
/// Multi-document design:
|
||||
/// - Preorder.OrderId tracks the linked real order once created.
|
||||
/// - First partial fulfillment → creates the order, saves OrderId on Preorder.
|
||||
/// - PreOrder.OrderId tracks the linked real order once created.
|
||||
/// - First partial fulfillment → creates the order, saves OrderId on PreOrder.
|
||||
/// - Subsequent documents → appends only newly-fulfilled items to that same order.
|
||||
/// - Dropped items are recorded in an order note but never become OrderItems.
|
||||
/// </summary>
|
||||
public partial class PreorderConversionService
|
||||
public partial class PreOrderConversionService
|
||||
{
|
||||
private readonly PreorderDbContext _preorderDbContext;
|
||||
private readonly PreOrderDbContext _preorderDbContext;
|
||||
private readonly FruitBankDbContext _dbContext;
|
||||
private readonly ICustomerService _customerService;
|
||||
private readonly IProductService _productService;
|
||||
|
|
@ -45,8 +45,8 @@ public partial class PreorderConversionService
|
|||
private readonly FruitBankOrderItemService _orderItemService;
|
||||
private readonly IStoreContext _storeContext;
|
||||
|
||||
public PreorderConversionService(
|
||||
PreorderDbContext preorderDbContext,
|
||||
public PreOrderConversionService(
|
||||
PreOrderDbContext preorderDbContext,
|
||||
FruitBankDbContext dbContext,
|
||||
ICustomerService customerService,
|
||||
IProductService productService,
|
||||
|
|
@ -71,54 +71,54 @@ public partial class PreorderConversionService
|
|||
|
||||
// ── Entry point ───────────────────────────────────────────────────────────
|
||||
|
||||
public async Task ConvertPreordersForProductsAsync(IList<int> productIds, int shippingDocumentId)
|
||||
public async Task ConvertPreOrdersForProductsAsync(IList<int> productIds, int shippingDocumentId)
|
||||
{
|
||||
Console.WriteLine($"[PreorderConversion] Starting for {productIds.Count} products, shippingDocumentId={shippingDocumentId}");
|
||||
Console.WriteLine($"[PreOrderConversion] Starting for {productIds.Count} products, shippingDocumentId={shippingDocumentId}");
|
||||
|
||||
// Always sweep expired preorders first — any preorder whose DateOfReceipt
|
||||
// is in the past is closed regardless of stock, before we allocate anything
|
||||
await SweepExpiredPreordersAsync();
|
||||
await SweepExpiredPreOrdersAsync();
|
||||
|
||||
var pendingItems = await _preorderDbContext.GetPendingItemsForProductsAsync(productIds);
|
||||
if (!pendingItems.Any())
|
||||
{
|
||||
Console.WriteLine("[PreorderConversion] No pending preorder items — done.");
|
||||
Console.WriteLine("[PreOrderConversion] No pending preorder items — done.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter out preorders whose delivery date is more than PreorderConversionWindowDays
|
||||
// Filter out preorders whose delivery date is more than PreOrderConversionWindowDays
|
||||
// (4 days) away. With bi-weekly trucks, a delivery that far out will be served
|
||||
// by the next truck's document — converting now would steal stock from
|
||||
// earlier deliveries that legitimately need it.
|
||||
var conversionCutoff = DateTime.UtcNow.Date.AddDays(FruitBankPluginConst.PreorderConversionWindowDays);
|
||||
var pendingPreorderIds = pendingItems.Select(i => i.PreorderId).Distinct().ToList();
|
||||
var parentPreorders = await _preorderDbContext.Preorders
|
||||
var conversionCutoff = DateTime.UtcNow.Date.AddDays(FruitBankPluginConst.PreOrderConversionWindowDays);
|
||||
var pendingPreOrderIds = pendingItems.Select(i => i.PreOrderId).Distinct().ToList();
|
||||
var parentPreOrders = await _preorderDbContext.PreOrders
|
||||
.GetAll(false)
|
||||
.Where(p => pendingPreorderIds.Contains(p.Id))
|
||||
.Where(p => pendingPreOrderIds.Contains(p.Id))
|
||||
.ToListAsync();
|
||||
|
||||
var eligiblePreorderIds = parentPreorders
|
||||
var eligiblePreOrderIds = parentPreOrders
|
||||
.Where(p => p.DateOfReceipt.Date <= conversionCutoff)
|
||||
.Select(p => p.Id)
|
||||
.ToHashSet();
|
||||
|
||||
pendingItems = pendingItems.Where(i => eligiblePreorderIds.Contains(i.PreorderId)).ToList();
|
||||
pendingItems = pendingItems.Where(i => eligiblePreOrderIds.Contains(i.PreOrderId)).ToList();
|
||||
|
||||
if (!pendingItems.Any())
|
||||
{
|
||||
Console.WriteLine($"[PreorderConversion] All pending preorders are beyond the " +
|
||||
$"{FruitBankPluginConst.PreorderConversionWindowDays}-day window — skipped.");
|
||||
Console.WriteLine($"[PreOrderConversion] All pending preorders are beyond the " +
|
||||
$"{FruitBankPluginConst.PreOrderConversionWindowDays}-day window — skipped.");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine($"[PreorderConversion] {pendingItems.Count} items eligible " +
|
||||
$"(within {FruitBankPluginConst.PreorderConversionWindowDays}-day window).");
|
||||
Console.WriteLine($"[PreOrderConversion] {pendingItems.Count} items eligible " +
|
||||
$"(within {FruitBankPluginConst.PreOrderConversionWindowDays}-day window).");
|
||||
|
||||
var incomingPool = await BuildIncomingQuantityPoolAsync(productIds);
|
||||
|
||||
// Track which items were newly resolved in THIS run, grouped by preorder
|
||||
// Key: preorderId Value: list of items whose status changed in this run
|
||||
var newlyResolvedByPreorder = new Dictionary<int, List<PreorderItem>>();
|
||||
var newlyResolvedByPreOrder = new Dictionary<int, List<PreOrderItem>>();
|
||||
|
||||
foreach (var item in pendingItems)
|
||||
{
|
||||
|
|
@ -138,49 +138,49 @@ public partial class PreorderConversionService
|
|||
incomingPool[item.ProductId] -= fulfill;
|
||||
|
||||
item.Status = item.FulfilledQuantity >= item.RequestedQuantity
|
||||
? PreorderItemStatus.Fulfilled
|
||||
? PreOrderItemStatus.Fulfilled
|
||||
: item.FulfilledQuantity > 0
|
||||
? PreorderItemStatus.PartiallyFulfilled
|
||||
: PreorderItemStatus.Dropped;
|
||||
? PreOrderItemStatus.PartiallyFulfilled
|
||||
: PreOrderItemStatus.Dropped;
|
||||
|
||||
await _preorderDbContext.PreorderItems.UpdateAsync(item);
|
||||
await _preorderDbContext.PreOrderItems.UpdateAsync(item);
|
||||
}
|
||||
|
||||
// Only track this item if something actually changed this run
|
||||
// (i.e. it gained fulfilled quantity or got dropped)
|
||||
var gainedQuantity = item.FulfilledQuantity - prevFulfilled;
|
||||
bool wasDropped = item.Status == PreorderItemStatus.Dropped && prevFulfilled == 0;
|
||||
bool wasDropped = item.Status == PreOrderItemStatus.Dropped && prevFulfilled == 0;
|
||||
|
||||
if (gainedQuantity > 0 || wasDropped)
|
||||
{
|
||||
if (!newlyResolvedByPreorder.ContainsKey(item.PreorderId))
|
||||
newlyResolvedByPreorder[item.PreorderId] = new List<PreorderItem>();
|
||||
newlyResolvedByPreorder[item.PreorderId].Add(item);
|
||||
if (!newlyResolvedByPreOrder.ContainsKey(item.PreOrderId))
|
||||
newlyResolvedByPreOrder[item.PreOrderId] = new List<PreOrderItem>();
|
||||
newlyResolvedByPreOrder[item.PreOrderId].Add(item);
|
||||
}
|
||||
|
||||
Console.WriteLine($"[PreorderConversion] Item #{item.Id} (product {item.ProductId}): " +
|
||||
Console.WriteLine($"[PreOrderConversion] Item #{item.Id} (product {item.ProductId}): " +
|
||||
$"requested={item.RequestedQuantity}, fulfilled={item.FulfilledQuantity}, " +
|
||||
$"gained={item.FulfilledQuantity - prevFulfilled}, status={item.Status}");
|
||||
}
|
||||
|
||||
// Process each affected preorder
|
||||
foreach (var (preorderId, changedItems) in newlyResolvedByPreorder)
|
||||
foreach (var (preorderId, changedItems) in newlyResolvedByPreOrder)
|
||||
{
|
||||
await _preorderDbContext.RefreshPreorderStatusAsync(preorderId);
|
||||
await _preorderDbContext.RefreshPreOrderStatusAsync(preorderId);
|
||||
|
||||
var preorder = await _preorderDbContext.Preorders.GetByIdAsync(preorderId);
|
||||
var preorder = await _preorderDbContext.PreOrders.GetByIdAsync(preorderId);
|
||||
if (preorder == null) continue;
|
||||
|
||||
// Items newly gaining fulfilled quantity in this run
|
||||
var newlyFulfilled = changedItems
|
||||
.Where(i => i.FulfilledQuantity - 0 > 0 &&
|
||||
(i.Status == PreorderItemStatus.Fulfilled ||
|
||||
i.Status == PreorderItemStatus.PartiallyFulfilled))
|
||||
(i.Status == PreOrderItemStatus.Fulfilled ||
|
||||
i.Status == PreOrderItemStatus.PartiallyFulfilled))
|
||||
.ToList();
|
||||
|
||||
// Items dropped in this run (no stock at all)
|
||||
var newlyDropped = changedItems
|
||||
.Where(i => i.Status == PreorderItemStatus.Dropped)
|
||||
.Where(i => i.Status == PreOrderItemStatus.Dropped)
|
||||
.ToList();
|
||||
|
||||
if (preorder.OrderId == null)
|
||||
|
|
@ -198,7 +198,7 @@ public partial class PreorderConversionService
|
|||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"[PreorderConversion] Done. {newlyResolvedByPreorder.Count} preorders affected.");
|
||||
Console.WriteLine($"[PreOrderConversion] Done. {newlyResolvedByPreOrder.Count} preorders affected.");
|
||||
}
|
||||
|
||||
// ── Expiry sweep ───────────────────────────────────────────────────────────
|
||||
|
|
@ -210,71 +210,71 @@ public partial class PreorderConversionService
|
|||
/// quantities already made it into a real order).
|
||||
/// Called at the start of every conversion run.
|
||||
/// </summary>
|
||||
private async Task SweepExpiredPreordersAsync()
|
||||
private async Task SweepExpiredPreOrdersAsync()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
var activePreorderStatuses = new[] { PreorderStatus.Pending, PreorderStatus.PartiallyFulfilled };
|
||||
var activePreOrderStatuses = new[] { PreOrderStatus.Pending, PreOrderStatus.PartiallyFulfilled };
|
||||
|
||||
// Find preorders that are past their receipt date — fetch by date only,
|
||||
// then filter by status in memory (LinqToDB can't translate enum comparisons)
|
||||
var expiredPreorders = (await _preorderDbContext.Preorders
|
||||
var expiredPreOrders = (await _preorderDbContext.PreOrders
|
||||
.GetAll(false)
|
||||
.Where(p => p.DateOfReceipt < now)
|
||||
.ToListAsync())
|
||||
.Where(p => p.Status == PreorderStatus.Pending ||
|
||||
p.Status == PreorderStatus.PartiallyFulfilled)
|
||||
.Where(p => p.Status == PreOrderStatus.Pending ||
|
||||
p.Status == PreOrderStatus.PartiallyFulfilled)
|
||||
.ToList();
|
||||
|
||||
if (!expiredPreorders.Any()) return;
|
||||
if (!expiredPreOrders.Any()) return;
|
||||
|
||||
Console.WriteLine($"[PreorderConversion] Sweeping {expiredPreorders.Count} expired preorders");
|
||||
Console.WriteLine($"[PreOrderConversion] Sweeping {expiredPreOrders.Count} expired preorders");
|
||||
|
||||
foreach (var preorder in expiredPreorders)
|
||||
foreach (var preorder in expiredPreOrders)
|
||||
{
|
||||
var items = await _preorderDbContext.PreorderItems
|
||||
.GetAllByPreorderIdAsync(preorder.Id)
|
||||
var items = await _preorderDbContext.PreOrderItems
|
||||
.GetAllByPreOrderIdAsync(preorder.Id)
|
||||
.ToListAsync();
|
||||
|
||||
// Drop only the items that were never fulfilled — already-fulfilled
|
||||
// items stay as-is since they are already on a real order
|
||||
var stillPending = items.Where(i => i.Status == PreorderItemStatus.Pending).ToList();
|
||||
var stillPending = items.Where(i => i.Status == PreOrderItemStatus.Pending).ToList();
|
||||
foreach (var item in stillPending)
|
||||
{
|
||||
item.Status = PreorderItemStatus.Dropped;
|
||||
await _preorderDbContext.PreorderItems.UpdateAsync(item);
|
||||
item.Status = PreOrderItemStatus.Dropped;
|
||||
await _preorderDbContext.PreOrderItems.UpdateAsync(item);
|
||||
}
|
||||
|
||||
// Recalculate header status
|
||||
await _preorderDbContext.RefreshPreorderStatusAsync(preorder.Id);
|
||||
await _preorderDbContext.RefreshPreOrderStatusAsync(preorder.Id);
|
||||
|
||||
var hadAnyFulfillment = items.Any(i =>
|
||||
i.Status == PreorderItemStatus.Fulfilled ||
|
||||
i.Status == PreorderItemStatus.PartiallyFulfilled);
|
||||
i.Status == PreOrderItemStatus.Fulfilled ||
|
||||
i.Status == PreOrderItemStatus.PartiallyFulfilled);
|
||||
|
||||
Console.WriteLine($"[PreorderConversion] Expired preorder #{preorder.Id}: " +
|
||||
Console.WriteLine($"[PreOrderConversion] Expired preorder #{preorder.Id}: " +
|
||||
$"{stillPending.Count} items dropped, " +
|
||||
$"hadFulfillment={hadAnyFulfillment}, orderId={preorder.OrderId}");
|
||||
|
||||
// TODO: Send expiry notification if nothing was ever fulfilled
|
||||
// (fully unfulfilled preorders — customer should be notified)
|
||||
// if (!hadAnyFulfillment)
|
||||
// await _fruitBankNotificationService.SendPreorderExpiredNotificationAsync(preorder);
|
||||
// await _fruitBankNotificationService.SendPreOrderExpiredNotificationAsync(preorder);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Create new order (first document that fulfills anything) ──────────────
|
||||
|
||||
private async Task CreateOrderAsync(
|
||||
Preorder preorder,
|
||||
List<PreorderItem> fulfilledItems,
|
||||
List<PreorderItem> droppedItems,
|
||||
PreOrder preorder,
|
||||
List<PreOrderItem> fulfilledItems,
|
||||
List<PreOrderItem> droppedItems,
|
||||
int shippingDocumentId)
|
||||
{
|
||||
var customer = await _customerService.GetCustomerByIdAsync(preorder.CustomerId);
|
||||
if (customer == null)
|
||||
{
|
||||
Console.WriteLine($"[PreorderConversion] Customer {preorder.CustomerId} not found — skipping order creation for preorder #{preorder.Id}");
|
||||
Console.WriteLine($"[PreOrderConversion] Customer {preorder.CustomerId} not found — skipping order creation for preorder #{preorder.Id}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -289,7 +289,7 @@ public partial class PreorderConversionService
|
|||
|
||||
if (billingAddressId == 0)
|
||||
{
|
||||
Console.WriteLine($"[PreorderConversion] No billing address for customer {customer.Id} — skipping for preorder #{preorder.Id}");
|
||||
Console.WriteLine($"[PreOrderConversion] No billing address for customer {customer.Id} — skipping for preorder #{preorder.Id}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -351,10 +351,10 @@ public partial class PreorderConversionService
|
|||
order.CustomOrderNumber = order.Id.ToString();
|
||||
await _dbContext.Orders.UpdateAsync(order);
|
||||
|
||||
// Save OrderId back on the Preorder so future documents can find it
|
||||
// Save OrderId back on the PreOrder so future documents can find it
|
||||
preorder.OrderId = order.Id;
|
||||
preorder.UpdatedOnUtc = DateTime.UtcNow;
|
||||
await _preorderDbContext.Preorders.UpdateAsync(preorder);
|
||||
await _preorderDbContext.PreOrders.UpdateAsync(preorder);
|
||||
|
||||
// DateOfReceipt generic attribute
|
||||
await _dbContext.GenericAttributes.InsertAsync(new Nop.Core.Domain.Common.GenericAttribute
|
||||
|
|
@ -370,26 +370,26 @@ public partial class PreorderConversionService
|
|||
// Fire event so existing handlers (EventConsumer etc.) run
|
||||
await _eventPublisher.PublishAsync(new OrderPlacedEvent(order));
|
||||
|
||||
// TODO: Send "FruitBank.PreorderConverted.CustomerNotification" email
|
||||
// TODO: Send "FruitBank.PreOrderConverted.CustomerNotification" email
|
||||
// summarising fulfilled items, dropped items, order ID, DateOfReceipt
|
||||
// await _fruitBankNotificationService.SendPreorderConvertedNotificationAsync(order, preorder, fulfilledItems, droppedItems);
|
||||
// await _fruitBankNotificationService.SendPreOrderConvertedNotificationAsync(order, preorder, fulfilledItems, droppedItems);
|
||||
|
||||
Console.WriteLine($"[PreorderConversion] Created Order #{order.Id} from Preorder #{preorder.Id} — " +
|
||||
Console.WriteLine($"[PreOrderConversion] Created Order #{order.Id} from PreOrder #{preorder.Id} — " +
|
||||
$"{fulfilledItems.Count} fulfilled, {droppedItems.Count} dropped, total {orderTotal:N0} Ft");
|
||||
}
|
||||
|
||||
// ── Append to existing order (subsequent documents) ───────────────────────
|
||||
|
||||
private async Task AppendItemsToOrderAsync(
|
||||
Preorder preorder,
|
||||
List<PreorderItem> newlyFulfilled,
|
||||
List<PreorderItem> newlyDropped,
|
||||
PreOrder preorder,
|
||||
List<PreOrderItem> newlyFulfilled,
|
||||
List<PreOrderItem> newlyDropped,
|
||||
int shippingDocumentId)
|
||||
{
|
||||
var order = await _dbContext.Orders.GetByIdAsync(preorder.OrderId!.Value);
|
||||
if (order == null)
|
||||
{
|
||||
Console.WriteLine($"[PreorderConversion] Preorder #{preorder.Id} references Order #{preorder.OrderId} which no longer exists — creating fresh");
|
||||
Console.WriteLine($"[PreOrderConversion] PreOrder #{preorder.Id} references Order #{preorder.OrderId} which no longer exists — creating fresh");
|
||||
preorder.OrderId = null;
|
||||
await CreateOrderAsync(preorder, newlyFulfilled, newlyDropped, shippingDocumentId);
|
||||
return;
|
||||
|
|
@ -397,7 +397,7 @@ public partial class PreorderConversionService
|
|||
|
||||
if (!newlyFulfilled.Any() && !newlyDropped.Any())
|
||||
{
|
||||
Console.WriteLine($"[PreorderConversion] Preorder #{preorder.Id}: no new items to append to Order #{order.Id}");
|
||||
Console.WriteLine($"[PreOrderConversion] PreOrder #{preorder.Id}: no new items to append to Order #{order.Id}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -422,16 +422,16 @@ public partial class PreorderConversionService
|
|||
await InsertOrderNoteAsync(order.Id, preorder.Id, shippingDocumentId, newlyFulfilled, newlyDropped);
|
||||
|
||||
// TODO: Send update notification email (same template as initial, but framed as an update)
|
||||
// await _fruitBankNotificationService.SendPreorderConvertedNotificationAsync(order, preorder, newlyFulfilled, newlyDropped);
|
||||
// await _fruitBankNotificationService.SendPreOrderConvertedNotificationAsync(order, preorder, newlyFulfilled, newlyDropped);
|
||||
|
||||
Console.WriteLine($"[PreorderConversion] Appended {newlyFulfilled.Count} items to Order #{order.Id} " +
|
||||
$"from Preorder #{preorder.Id} via document #{shippingDocumentId}. " +
|
||||
Console.WriteLine($"[PreOrderConversion] Appended {newlyFulfilled.Count} items to Order #{order.Id} " +
|
||||
$"from PreOrder #{preorder.Id} via document #{shippingDocumentId}. " +
|
||||
$"New total: {newTotal:N0} Ft");
|
||||
}
|
||||
|
||||
// ── Shared helpers ────────────────────────────────────────────────────────
|
||||
|
||||
private async Task InsertOrderItemsAsync(Order order, List<PreorderItem> items)
|
||||
private async Task InsertOrderItemsAsync(Order order, List<PreOrderItem> items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
|
|
@ -475,13 +475,13 @@ public partial class PreorderConversionService
|
|||
product,
|
||||
-item.FulfilledQuantity,
|
||||
string.Empty,
|
||||
$"Előrendelés #{item.PreorderId} — rendelés #{order.Id} létrehozása");
|
||||
$"Előrendelés #{item.PreOrderId} — rendelés #{order.Id} létrehozása");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InsertOrderNoteAsync(
|
||||
int orderId, int preorderId, int shippingDocumentId,
|
||||
List<PreorderItem> fulfilled, List<PreorderItem> dropped)
|
||||
List<PreOrderItem> fulfilled, List<PreOrderItem> dropped)
|
||||
{
|
||||
var fulfilledDesc = fulfilled.Any()
|
||||
? $"Teljesített: {string.Join(", ", fulfilled.Select(i => $"#{i.ProductId} ({i.FulfilledQuantity} db)"))}"
|
||||
|
|
@ -521,10 +521,10 @@ public partial class PreorderConversionService
|
|||
await _fruitBankAttributeService
|
||||
.InsertOrUpdateGenericAttributeAsync<Product, int>(
|
||||
productId, nameof(IIncomingQuantity.IncomingQuantity), updated, storeId);
|
||||
Console.WriteLine($"[PreorderConversion] SyncIncomingQty product #{productId}: {current}+({delta})={updated}");
|
||||
Console.WriteLine($"[PreOrderConversion] SyncIncomingQty product #{productId}: {current}+({delta})={updated}");
|
||||
}
|
||||
|
||||
private async Task<decimal> CalculateTotalAsync(List<PreorderItem> items)
|
||||
private async Task<decimal> CalculateTotalAsync(List<PreOrderItem> items)
|
||||
{
|
||||
var total = 0m;
|
||||
foreach (var item in items)
|
||||
|
|
@ -549,17 +549,17 @@ public partial class PreorderConversionService
|
|||
p => p.Id,
|
||||
p => p.AvailableQuantity);
|
||||
|
||||
var activeItemStatuses = new[] { PreorderItemStatus.Fulfilled, PreorderItemStatus.PartiallyFulfilled };
|
||||
var activeItemStatuses = new[] { PreOrderItemStatus.Fulfilled, PreOrderItemStatus.PartiallyFulfilled };
|
||||
|
||||
// 2. Subtract quantities already committed to preorders in previous runs
|
||||
// Fetch by productId only, filter by status in memory
|
||||
var allCommittedItems = await _preorderDbContext.PreorderItems.Table
|
||||
var allCommittedItems = await _preorderDbContext.PreOrderItems.Table
|
||||
.Where(i => productIds.Contains(i.ProductId))
|
||||
.ToListAsync();
|
||||
|
||||
var alreadyAllocated = allCommittedItems
|
||||
.Where(i => i.Status == PreorderItemStatus.Fulfilled ||
|
||||
i.Status == PreorderItemStatus.PartiallyFulfilled)
|
||||
.Where(i => i.Status == PreOrderItemStatus.Fulfilled ||
|
||||
i.Status == PreOrderItemStatus.PartiallyFulfilled)
|
||||
.GroupBy(i => i.ProductId)
|
||||
.Select(g => new { ProductId = g.Key, Allocated = g.Sum(i => i.FulfilledQuantity) })
|
||||
.ToList();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@using FruitBank.Common.Enums
|
||||
@using Nop.Plugin.Misc.FruitBankPlugin.Controllers
|
||||
@model List<CustomerPreorderController.CustomerPreorderRow>
|
||||
@model List<CustomerPreOrderController.CustomerPreOrderRow>
|
||||
|
||||
@{
|
||||
Layout = "_ColumnsTwo";
|
||||
|
|
@ -28,23 +28,23 @@
|
|||
{
|
||||
var statusClass = preorder.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 = preorder.Status switch
|
||||
{
|
||||
PreorderStatus.Confirmed => "Megerősítve",
|
||||
PreorderStatus.PartiallyFulfilled => "Részben teljesítve",
|
||||
PreorderStatus.Cancelled => "Törölve / Lejárt",
|
||||
PreOrderStatus.Confirmed => "Megerősítve",
|
||||
PreOrderStatus.PartiallyFulfilled => "Részben teljesítve",
|
||||
PreOrderStatus.Cancelled => "Törölve / Lejárt",
|
||||
_ => "Függőben"
|
||||
};
|
||||
|
||||
<div class="po-customer-card">
|
||||
<div class="po-card-header">
|
||||
<div class="po-card-meta">
|
||||
<span class="po-card-id">#@preorder.PreorderId előrendelés</span>
|
||||
<span class="po-card-id">#@preorder.PreOrderId előrendelés</span>
|
||||
<span class="po-card-date">
|
||||
<i class="fa fa-calendar"></i>
|
||||
Kért szállítás: <strong>@preorder.DateOfReceipt.ToLocalTime().ToString("yyyy. MM. dd. HH:mm")</strong>
|
||||
|
|
@ -89,16 +89,16 @@
|
|||
{
|
||||
var itemStatusLabel = item.Status switch
|
||||
{
|
||||
PreorderItemStatus.Fulfilled => "✓ Teljesítve",
|
||||
PreorderItemStatus.PartiallyFulfilled => "◑ Részben",
|
||||
PreorderItemStatus.Dropped => "✕ Ejtve",
|
||||
PreOrderItemStatus.Fulfilled => "✓ Teljesítve",
|
||||
PreOrderItemStatus.PartiallyFulfilled => "◑ Részben",
|
||||
PreOrderItemStatus.Dropped => "✕ Ejtve",
|
||||
_ => "⏳ Vár"
|
||||
};
|
||||
var itemStatusClass = item.Status switch
|
||||
{
|
||||
PreorderItemStatus.Fulfilled => "item-fulfilled",
|
||||
PreorderItemStatus.PartiallyFulfilled => "item-partial",
|
||||
PreorderItemStatus.Dropped => "item-dropped",
|
||||
PreOrderItemStatus.Fulfilled => "item-fulfilled",
|
||||
PreOrderItemStatus.PartiallyFulfilled => "item-partial",
|
||||
PreOrderItemStatus.Dropped => "item-dropped",
|
||||
_ => "item-pending"
|
||||
};
|
||||
var unitPrice = item.IsMeasurable
|
||||
|
|
@ -147,7 +147,7 @@
|
|||
|
||||
.no-data p { margin-bottom: 16px; font-size: 15px; }
|
||||
|
||||
/* ── Preorder card ────────────────────────────────────────────── */
|
||||
/* ── PreOrder card ────────────────────────────────────────────── */
|
||||
.po-customer-card {
|
||||
background: #fff;
|
||||
border: 1px solid #dde8da;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<li class="customer-navigation-item @(Context.Request.Path.Value?.Contains("elorerendeles") == true ? "active" : "")">
|
||||
<a href="@Url.Action("List", "CustomerPreorder")">
|
||||
<a href="@Url.Action("List", "CustomerPreOrder")">
|
||||
Előrendeléseim
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -499,7 +499,7 @@
|
|||
<i class="fa fa-chevron-down"></i>
|
||||
</button>
|
||||
<div class="help-faq-a">
|
||||
A <a href="@Url.Action("List", "CustomerPreorder")" style="color:#2d7a3a;font-weight:600;">Saját fiók → Előrendeléseim</a> oldalon látod az összes leadott előrendelést, azok állapotát és a létrejött rendelésekre mutató hivatkozást.
|
||||
A <a href="@Url.Action("List", "CustomerPreOrder")" style="color:#2d7a3a;font-weight:600;">Saját fiók → Előrendeléseim</a> oldalon látod az összes leadott előrendelést, azok állapotát és a létrejött rendelésekre mutató hivatkozást.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@
|
|||
</div><!-- /#sectionQuickOrder -->
|
||||
|
||||
<!-- ══ PREORDER SECTION ══════════════════════════════════════════════ -->
|
||||
<div id="sectionPreorder" style="display:none;">
|
||||
<div id="sectionPreOrder" style="display:none;">
|
||||
<div class="po-info-banner">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
Az előrendelés egy kívánságlista — az áruk megerősítése a szállítmány beérkezésekor történik, és az esetleges változásokról értesítünk.
|
||||
|
|
@ -211,7 +211,7 @@
|
|||
|
||||
<div class="po-submit-row">
|
||||
<div id="poSelectionSummary" class="po-selection-summary">Még nincs kiválasztott termék</div>
|
||||
<button type="button" id="submitPreorderBtn" class="po-submit-btn" disabled>
|
||||
<button type="button" id="submitPreOrderBtn" class="po-submit-btn" disabled>
|
||||
<i class="fa fa-paper-plane"></i> Előrendelés leadása
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -237,11 +237,11 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /#sectionPreorder -->
|
||||
</div><!-- /#sectionPreOrder -->
|
||||
|
||||
</div><!-- /#mainContent -->
|
||||
|
||||
<!-- ── Preorder success state ────────────────────────────────────────── -->
|
||||
<!-- ── PreOrder success state ────────────────────────────────────────── -->
|
||||
<div id="successState" style="display:none;" class="po-success-state">
|
||||
<div class="po-success-icon"><i class="fa fa-check-circle"></i></div>
|
||||
<h2>Előrendelés leadva!</h2>
|
||||
|
|
@ -408,7 +408,7 @@
|
|||
}
|
||||
@@keyframes fadeIn { from { opacity:0; transform:translateY(-4px); } to { opacity:1; transform:translateY(0); } }
|
||||
|
||||
/* ── Preorder stock label variant ──────────────────────────── */
|
||||
/* ── PreOrder stock label variant ──────────────────────────── */
|
||||
.pc-stock.stock-preorder {
|
||||
color: #c87500;
|
||||
font-style: italic;
|
||||
|
|
@ -500,7 +500,7 @@
|
|||
var selectedDayLabel = null;
|
||||
var currentFlowType = null; // "quickorder" | "preorder"
|
||||
|
||||
// Preorder state
|
||||
// PreOrder state
|
||||
var poProducts = [];
|
||||
var poQuantities = {};
|
||||
|
||||
|
|
@ -547,7 +547,7 @@
|
|||
|
||||
$('#recordBtn').click(startRecording);
|
||||
$('#stopBtn').click(function () { stopRecording(false); });
|
||||
$('#submitPreorderBtn').click(submitPreorder);
|
||||
$('#submitPreOrderBtn').click(submitPreOrder);
|
||||
|
||||
// Restore saved datetime
|
||||
$.ajax({
|
||||
|
|
@ -674,12 +674,12 @@
|
|||
|
||||
if (flowType === 'quickorder') {
|
||||
$('#sectionQuickOrder').show();
|
||||
$('#sectionPreorder').hide();
|
||||
$('#sectionPreOrder').hide();
|
||||
loadAllProducts();
|
||||
} else {
|
||||
$('#sectionPreorder').show();
|
||||
$('#sectionPreOrder').show();
|
||||
$('#sectionQuickOrder').hide();
|
||||
loadPreorderProducts();
|
||||
loadPreOrderProducts();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -942,21 +942,21 @@
|
|||
// PREORDER FLOW
|
||||
// ══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
function loadPreorderProducts() {
|
||||
function loadPreOrderProducts() {
|
||||
$('#poLoadingState').show(); $('#poNoProducts, #poProductSection').hide();
|
||||
|
||||
$.ajax({ url: '@Url.Action("GetPreorderProducts", "Order")', type: 'GET',
|
||||
$.ajax({ url: '@Url.Action("GetPreOrderProducts", "Order")', type: 'GET',
|
||||
success: function (r) {
|
||||
$('#poLoadingState').hide();
|
||||
if (!r.success || !r.products || r.products.length === 0) { $('#poNoProducts').show(); return; }
|
||||
poProducts = r.products; poQuantities = {};
|
||||
renderPreorderProducts(); $('#poProductSection').show();
|
||||
renderPreOrderProducts(); $('#poProductSection').show();
|
||||
},
|
||||
error: function () { $('#poLoadingState').hide(); $('#poNoProducts').show(); }
|
||||
});
|
||||
}
|
||||
|
||||
function renderPreorderProducts() {
|
||||
function renderPreOrderProducts() {
|
||||
var grid = $('#poProductGrid').empty();
|
||||
$.each(poProducts, function (_, p) {
|
||||
poQuantities[p.id] = 0;
|
||||
|
|
@ -1004,7 +1004,7 @@
|
|||
var selected = poProducts.filter(function (p) { return (poQuantities[p.id] || 0) > 0; });
|
||||
var count = selected.length;
|
||||
$('#poItemCountBadge').text(count);
|
||||
$('#submitPreorderBtn').prop('disabled', count === 0);
|
||||
$('#submitPreOrderBtn').prop('disabled', count === 0);
|
||||
$('#poSelectionSummary').text(count === 0 ? 'Még nincs kiválasztott termék' : count + ' termék kiválasztva');
|
||||
|
||||
if (count === 0) { $('#poSummaryEmpty').show(); $('#poSummaryList, #poSummaryNote').hide(); return; }
|
||||
|
|
@ -1022,14 +1022,14 @@
|
|||
if (hasMeasurable) $('#poSummaryNote').show(); else $('#poSummaryNote').hide();
|
||||
}
|
||||
|
||||
function submitPreorder() {
|
||||
function submitPreOrder() {
|
||||
var selected = poProducts.filter(function (p) { return (poQuantities[p.id] || 0) > 0; });
|
||||
if (!selected.length) return;
|
||||
var btn = $('#submitPreorderBtn').prop('disabled', true)
|
||||
var btn = $('#submitPreOrderBtn').prop('disabled', true)
|
||||
.html('<i class="fa fa-spinner fa-spin"></i> Előrendelés mentése...');
|
||||
|
||||
$.ajax({
|
||||
url : '@Url.Action("PlacePreorder", "Order")',
|
||||
url : '@Url.Action("PlacePreOrder", "Order")',
|
||||
type : 'POST',
|
||||
contentType: 'application/json',
|
||||
data : JSON.stringify({
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
@using System.Text.Encodings.Web
|
||||
@{
|
||||
Layout = "_Root";
|
||||
ViewBag.Title = T("Plugins.Misc.FruitBankPlugin.Preorder.PageTitle").Text;
|
||||
ViewBag.Title = T("Plugins.Misc.FruitBankPlugin.PreOrder.PageTitle").Text;
|
||||
}
|
||||
|
||||
<link rel="stylesheet" href="~/Plugins/Misc.FruitBankPlugin/css/quick-order.css" />
|
||||
|
|
@ -14,25 +14,25 @@
|
|||
<div class="ds-header">
|
||||
<i class="fa fa-calendar"></i>
|
||||
<div>
|
||||
<div class="ds-title">@T("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Title")</div>
|
||||
<div class="ds-subtitle">@T("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Subtitle")</div>
|
||||
<div class="ds-title">@T("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Title")</div>
|
||||
<div class="ds-subtitle">@T("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Subtitle")</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ds-body">
|
||||
<div class="ds-section-label">@T("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.DayLabel")</div>
|
||||
<div class="ds-section-label">@T("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.DayLabel")</div>
|
||||
<div class="ds-day-buttons" id="dayButtons"></div>
|
||||
|
||||
<div class="ds-section-label" style="margin-top:20px;">
|
||||
@T("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.TimeLabel")
|
||||
@T("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.TimeLabel")
|
||||
</div>
|
||||
<div class="ds-time-wrapper">
|
||||
<input type="time" id="deliveryTimePicker" class="ds-time-input" value="08:00" min="05:00" max="22:00" />
|
||||
<span class="ds-time-hint">@T("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.TimeHint")</span>
|
||||
<span class="ds-time-hint">@T("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.TimeHint")</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ds-footer">
|
||||
<button type="button" class="ds-confirm-btn" id="deliveryConfirmBtn" disabled>
|
||||
<i class="fa fa-arrow-right"></i> @T("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ConfirmButton")
|
||||
<i class="fa fa-arrow-right"></i> @T("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ConfirmButton")
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -40,10 +40,10 @@
|
|||
<!-- ── Delivery chip ────────────────────────────────────────────────── -->
|
||||
<div id="deliveryChip" class="qo-delivery-chip" style="display:none;">
|
||||
<i class="fa fa-calendar-check-o"></i>
|
||||
<span class="dc-label">@T("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ChangeLabel")</span>
|
||||
<span class="dc-label">@T("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ChangeLabel")</span>
|
||||
<strong id="deliveryChipText"></strong>
|
||||
<button type="button" class="dc-change-btn" id="deliveryChangeBtn">
|
||||
<i class="fa fa-pencil"></i> @T("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ChangeButton")
|
||||
<i class="fa fa-pencil"></i> @T("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ChangeButton")
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
<!-- Info banner -->
|
||||
<div class="po-info-banner">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
@T("Plugins.Misc.FruitBankPlugin.Preorder.InfoBanner")
|
||||
@T("Plugins.Misc.FruitBankPlugin.PreOrder.InfoBanner")
|
||||
</div>
|
||||
|
||||
<div class="qo-layout">
|
||||
|
|
@ -64,20 +64,20 @@
|
|||
<!-- Loading -->
|
||||
<div id="productsLoadingState" class="products-empty-state">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
<p>@T("Plugins.Misc.FruitBankPlugin.Preorder.LoadingProducts")</p>
|
||||
<p>@T("Plugins.Misc.FruitBankPlugin.PreOrder.LoadingProducts")</p>
|
||||
</div>
|
||||
|
||||
<!-- No products -->
|
||||
<div id="noProductsCard" class="no-results-card" style="display:none;">
|
||||
<i class="fa fa-calendar-times-o"></i>
|
||||
<p>@T("Plugins.Misc.FruitBankPlugin.Preorder.NoProductsAvailable")</p>
|
||||
<p>@T("Plugins.Misc.FruitBankPlugin.PreOrder.NoProductsAvailable")</p>
|
||||
</div>
|
||||
|
||||
<!-- Product grid -->
|
||||
<div id="productSection" style="display:none;">
|
||||
<div class="matches-label">
|
||||
<i class="fa fa-cubes"></i>
|
||||
<span>@T("Plugins.Misc.FruitBankPlugin.Preorder.ProductsLabel")</span>
|
||||
<span>@T("Plugins.Misc.FruitBankPlugin.PreOrder.ProductsLabel")</span>
|
||||
</div>
|
||||
<div id="productGrid" class="product-grid"></div>
|
||||
|
||||
|
|
@ -85,19 +85,19 @@
|
|||
<div class="po-note-section">
|
||||
<label class="po-note-label" for="customerNote">
|
||||
<i class="fa fa-comment-o"></i>
|
||||
@T("Plugins.Misc.FruitBankPlugin.Preorder.NoteLabel")
|
||||
@T("Plugins.Misc.FruitBankPlugin.PreOrder.NoteLabel")
|
||||
</label>
|
||||
<textarea id="customerNote" class="po-note-input"
|
||||
placeholder="@T("Plugins.Misc.FruitBankPlugin.Preorder.NotePlaceholder")"
|
||||
placeholder="@T("Plugins.Misc.FruitBankPlugin.PreOrder.NotePlaceholder")"
|
||||
rows="3" maxlength="1000"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Submit -->
|
||||
<div class="po-submit-row">
|
||||
<div id="selectionSummary" class="po-selection-summary"></div>
|
||||
<button type="button" id="submitPreorderBtn" class="po-submit-btn" disabled>
|
||||
<button type="button" id="submitPreOrderBtn" class="po-submit-btn" disabled>
|
||||
<i class="fa fa-paper-plane"></i>
|
||||
@T("Plugins.Misc.FruitBankPlugin.Preorder.SubmitButton")
|
||||
@T("Plugins.Misc.FruitBankPlugin.PreOrder.SubmitButton")
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -108,13 +108,13 @@
|
|||
<div class="qo-cart-panel">
|
||||
<div class="qo-section-title">
|
||||
<i class="fa fa-list-ul"></i>
|
||||
@T("Plugins.Misc.FruitBankPlugin.Preorder.SummaryTitle")
|
||||
@T("Plugins.Misc.FruitBankPlugin.PreOrder.SummaryTitle")
|
||||
<span id="itemCountBadge" class="cart-count-badge">0</span>
|
||||
</div>
|
||||
|
||||
<div id="summaryEmpty" class="cart-empty">
|
||||
<i class="fa fa-list-ul"></i>
|
||||
<p>@T("Plugins.Misc.FruitBankPlugin.Preorder.SummaryEmpty")</p>
|
||||
<p>@T("Plugins.Misc.FruitBankPlugin.PreOrder.SummaryEmpty")</p>
|
||||
</div>
|
||||
|
||||
<div id="summaryList" class="cart-items-list" style="display:none;"></div>
|
||||
|
|
@ -122,7 +122,7 @@
|
|||
<div id="summaryNote" class="cart-total-row" style="display:none;">
|
||||
<div class="cart-total-note">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
<small>@T("Plugins.Misc.FruitBankPlugin.Preorder.SummaryNote")</small>
|
||||
<small>@T("Plugins.Misc.FruitBankPlugin.PreOrder.SummaryNote")</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -133,10 +133,10 @@
|
|||
<!-- ── SUCCESS STATE ─────────────────────────────────────────────────── -->
|
||||
<div id="successState" style="display:none;" class="po-success-state">
|
||||
<div class="po-success-icon"><i class="fa fa-check-circle"></i></div>
|
||||
<h2>@T("Plugins.Misc.FruitBankPlugin.Preorder.SuccessTitle")</h2>
|
||||
<h2>@T("Plugins.Misc.FruitBankPlugin.PreOrder.SuccessTitle")</h2>
|
||||
<p id="successMessage"></p>
|
||||
<a href="@Url.RouteUrl("Homepage")" class="po-back-btn">
|
||||
<i class="fa fa-home"></i> @T("Plugins.Misc.FruitBankPlugin.Preorder.BackToHome")
|
||||
<i class="fa fa-home"></i> @T("Plugins.Misc.FruitBankPlugin.PreOrder.BackToHome")
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
|
@ -146,19 +146,19 @@
|
|||
|
||||
<script asp-location="Footer">
|
||||
var poStr = {
|
||||
dsToday : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Today").Text))',
|
||||
dsTomorrow : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Tomorrow").Text))',
|
||||
dsSaving : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.Saving").Text))',
|
||||
dsConfirm : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.DeliveryStep.ConfirmButton").Text))',
|
||||
measurable : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.MeasurableBadge").Text))',
|
||||
pricePerPc : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.PricePerPiece").Text))',
|
||||
pieceUnit : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.PieceUnit").Text))',
|
||||
stockLabel : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.StockLabel").Text))',
|
||||
selNone : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.SelectionNone").Text))',
|
||||
selItems : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.SelectionItems").Text))',
|
||||
submitting : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.Submitting").Text))',
|
||||
successMsg : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.SuccessMessage").Text))',
|
||||
errorPfx : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.ErrorPrefix").Text))',
|
||||
dsToday : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Today").Text))',
|
||||
dsTomorrow : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Tomorrow").Text))',
|
||||
dsSaving : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.Saving").Text))',
|
||||
dsConfirm : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.DeliveryStep.ConfirmButton").Text))',
|
||||
measurable : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.MeasurableBadge").Text))',
|
||||
pricePerPc : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.PricePerPiece").Text))',
|
||||
pieceUnit : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.PieceUnit").Text))',
|
||||
stockLabel : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.StockLabel").Text))',
|
||||
selNone : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.SelectionNone").Text))',
|
||||
selItems : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.SelectionItems").Text))',
|
||||
submitting : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.Submitting").Text))',
|
||||
successMsg : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.SuccessMessage").Text))',
|
||||
errorPfx : '@Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.ErrorPrefix").Text))',
|
||||
huDayNames : ['vas\u00e1rnap','h\u00e9tf\u0151','kedd','szerda','cs\u00fct\u00f6rt\u00f6k','p\u00e9ntek','szombat']
|
||||
};
|
||||
</script>
|
||||
|
|
@ -196,11 +196,11 @@ var poStr = {
|
|||
$('#deliveryStep').show();
|
||||
});
|
||||
|
||||
$('#submitPreorderBtn').click(submitPreorder);
|
||||
$('#submitPreOrderBtn').click(submitPreOrder);
|
||||
|
||||
// Restore saved delivery datetime if revisiting
|
||||
$.ajax({
|
||||
url: '@Url.Action("GetDeliveryDateTime", "Preorder")',
|
||||
url: '@Url.Action("GetDeliveryDateTime", "PreOrder")',
|
||||
type: 'GET',
|
||||
success: function (result) {
|
||||
if (!result.success || !result.hasValue) return;
|
||||
|
|
@ -251,7 +251,7 @@ var poStr = {
|
|||
|
||||
var deliveryDateTime = selectedDeliveryDate + 'T' + selectedDeliveryTime;
|
||||
$.ajax({
|
||||
url : '@Url.Action("SetDeliveryDateTime", "Preorder")',
|
||||
url : '@Url.Action("SetDeliveryDateTime", "PreOrder")',
|
||||
type: 'POST',
|
||||
data: {
|
||||
deliveryDateTime: deliveryDateTime,
|
||||
|
|
@ -288,7 +288,7 @@ var poStr = {
|
|||
$('#productSection').hide();
|
||||
|
||||
$.ajax({
|
||||
url : '@Url.Action("GetAvailableProducts", "Preorder")',
|
||||
url : '@Url.Action("GetAvailableProducts", "PreOrder")',
|
||||
type: 'GET',
|
||||
success: function (result) {
|
||||
$('#productsLoadingState').hide();
|
||||
|
|
@ -369,7 +369,7 @@ var poStr = {
|
|||
var count = selectedItems.length;
|
||||
|
||||
$('#itemCountBadge').text(count);
|
||||
$('#submitPreorderBtn').prop('disabled', count === 0);
|
||||
$('#submitPreOrderBtn').prop('disabled', count === 0);
|
||||
|
||||
// Selection summary text
|
||||
if (count === 0) {
|
||||
|
|
@ -413,11 +413,11 @@ var poStr = {
|
|||
|
||||
// ── Submit ────────────────────────────────────────────────────────────────
|
||||
|
||||
function submitPreorder() {
|
||||
function submitPreOrder() {
|
||||
var selectedItems = products.filter(function (p) { return (quantities[p.id] || 0) > 0; });
|
||||
if (!selectedItems.length) return;
|
||||
|
||||
var btn = $('#submitPreorderBtn');
|
||||
var btn = $('#submitPreOrderBtn');
|
||||
btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> ' + poStr.submitting);
|
||||
|
||||
var payload = {
|
||||
|
|
@ -429,7 +429,7 @@ var poStr = {
|
|||
};
|
||||
|
||||
$.ajax({
|
||||
url : '@Url.Action("PlacePreorder", "Preorder")',
|
||||
url : '@Url.Action("PlacePreOrder", "PreOrder")',
|
||||
type : 'POST',
|
||||
contentType: 'application/json',
|
||||
data : JSON.stringify(payload),
|
||||
|
|
@ -442,13 +442,13 @@ var poStr = {
|
|||
} else {
|
||||
alert(poStr.errorPfx + (result.message || ''));
|
||||
btn.prop('disabled', false)
|
||||
.html('<i class="fa fa-paper-plane"></i> @Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.SubmitButton").Text))');
|
||||
.html('<i class="fa fa-paper-plane"></i> @Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrder.SubmitButton").Text))');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert(poStr.errorPfx);
|
||||
btn.prop('disabled', false)
|
||||
.html('<i class="fa fa-paper-plane"></i> @Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.Preorder.SubmitButton").Text))');
|
||||
.html('<i class="fa fa-paper-plane"></i> @Html.Raw(JavaScriptEncoder.Default.Encode(T("Plugins.Misc.FruitBankPlugin.PreOrderPreOrder.SubmitButton").Text))');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Preorder page — supplemental styles
|
||||
* PreOrder page — supplemental styles
|
||||
* Inherits all base styles from quick-order.css
|
||||
*/
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue