shipment, plugin basic things, invoicing
This commit is contained in:
parent
4f9eb4b06e
commit
1f38c24548
|
|
@ -0,0 +1,150 @@
|
||||||
|
using ExCSS;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Nop.Core;
|
||||||
|
using Nop.Core.Domain.Common;
|
||||||
|
using Nop.Core.Domain.Customers;
|
||||||
|
using Nop.Services.Common;
|
||||||
|
using Nop.Services.Configuration;
|
||||||
|
using Nop.Services.Localization;
|
||||||
|
using Nop.Services.Messages;
|
||||||
|
using Nop.Services.Security;
|
||||||
|
using Nop.Web.Areas.Admin.Controllers;
|
||||||
|
using Nop.Web.Areas.Admin.Factories;
|
||||||
|
using Nop.Web.Areas.Admin.Models.Common;
|
||||||
|
using Nop.Web.Areas.Admin.Models.Home;
|
||||||
|
using Nop.Web.Framework.Models.DataTables;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
|
{
|
||||||
|
public partial class CustomDashboardController : BaseAdminController
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
protected readonly AdminAreaSettings _adminAreaSettings;
|
||||||
|
protected readonly ICommonModelFactory _commonModelFactory;
|
||||||
|
protected readonly IHomeModelFactory _homeModelFactory;
|
||||||
|
protected readonly ILocalizationService _localizationService;
|
||||||
|
protected readonly INotificationService _notificationService;
|
||||||
|
protected readonly IPermissionService _permissionService;
|
||||||
|
protected readonly ISettingService _settingService;
|
||||||
|
protected readonly IGenericAttributeService _genericAttributeService;
|
||||||
|
protected readonly IWorkContext _workContext;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Ctor
|
||||||
|
|
||||||
|
public CustomDashboardController(AdminAreaSettings adminAreaSettings,
|
||||||
|
ICommonModelFactory commonModelFactory,
|
||||||
|
IHomeModelFactory homeModelFactory,
|
||||||
|
ILocalizationService localizationService,
|
||||||
|
INotificationService notificationService,
|
||||||
|
IPermissionService permissionService,
|
||||||
|
ISettingService settingService,
|
||||||
|
IGenericAttributeService genericAttributeService,
|
||||||
|
IWorkContext workContext)
|
||||||
|
{
|
||||||
|
_adminAreaSettings = adminAreaSettings;
|
||||||
|
_commonModelFactory = commonModelFactory;
|
||||||
|
_homeModelFactory = homeModelFactory;
|
||||||
|
_localizationService = localizationService;
|
||||||
|
_notificationService = notificationService;
|
||||||
|
_permissionService = permissionService;
|
||||||
|
_settingService = settingService;
|
||||||
|
_workContext = workContext;
|
||||||
|
_genericAttributeService = genericAttributeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public virtual async Task<IActionResult> Index()
|
||||||
|
{
|
||||||
|
//display a warning to a store owner if there are some error
|
||||||
|
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||||
|
var hideCard = await _genericAttributeService.GetAttributeAsync<bool>(customer, NopCustomerDefaults.HideConfigurationStepsAttribute);
|
||||||
|
var closeCard = await _genericAttributeService.GetAttributeAsync<bool>(customer, NopCustomerDefaults.CloseConfigurationStepsAttribute);
|
||||||
|
|
||||||
|
if ((hideCard || closeCard) && await _permissionService.AuthorizeAsync(StandardPermission.System.MANAGE_MAINTENANCE))
|
||||||
|
{
|
||||||
|
var warnings = await _commonModelFactory.PrepareSystemWarningModelsAsync();
|
||||||
|
if (warnings.Any(warning => warning.Level == SystemWarningLevel.Fail || warning.Level == SystemWarningLevel.Warning))
|
||||||
|
{
|
||||||
|
var locale = await _localizationService.GetResourceAsync("Admin.System.Warnings.Errors");
|
||||||
|
_notificationService.WarningNotification(string.Format(locale, Url.Action("Warnings", "Common")), false); //do not encode URLs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//progress of localization
|
||||||
|
var currentLanguage = await _workContext.GetWorkingLanguageAsync();
|
||||||
|
var progress = await _genericAttributeService.GetAttributeAsync<string>(currentLanguage, NopCommonDefaults.LanguagePackProgressAttribute);
|
||||||
|
if (!string.IsNullOrEmpty(progress))
|
||||||
|
{
|
||||||
|
var locale = await _localizationService.GetResourceAsync("Admin.Configuration.LanguagePackProgressMessage");
|
||||||
|
_notificationService.SuccessNotification(string.Format(locale, progress, NopLinksDefaults.OfficialSite.Translations), false);
|
||||||
|
await _genericAttributeService.SaveAttributeAsync(currentLanguage, NopCommonDefaults.LanguagePackProgressAttribute, string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
//prepare model
|
||||||
|
var model = await _homeModelFactory.PrepareDashboardModelAsync(new DashboardModel());
|
||||||
|
|
||||||
|
//return View(model);
|
||||||
|
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Index.cshtml", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public virtual async Task<IActionResult> NopCommerceNewsHideAdv()
|
||||||
|
{
|
||||||
|
_adminAreaSettings.HideAdvertisementsOnAdminArea = !_adminAreaSettings.HideAdvertisementsOnAdminArea;
|
||||||
|
await _settingService.SaveSettingAsync(_adminAreaSettings);
|
||||||
|
|
||||||
|
return Content("Setting changed");
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<IActionResult> GetPopularSearchTerm()
|
||||||
|
{
|
||||||
|
var model = new DataTablesModel();
|
||||||
|
model = await _homeModelFactory.PreparePopularSearchTermReportModelAsync(model);
|
||||||
|
return PartialView("Table", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<IActionResult> GetBestsellersBriefReportByAmount()
|
||||||
|
{
|
||||||
|
var model = new DataTablesModel();
|
||||||
|
model = await _homeModelFactory.PrepareBestsellersBriefReportByAmountModelAsync(model);
|
||||||
|
return PartialView("Table", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<IActionResult> GetBestsellersBriefReportByQuantity()
|
||||||
|
{
|
||||||
|
var model = new DataTablesModel();
|
||||||
|
model = await _homeModelFactory.PrepareBestsellersBriefReportByQuantityModelAsync(model);
|
||||||
|
return PartialView("Table", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<IActionResult> GetLatestOrders()
|
||||||
|
{
|
||||||
|
var model = new DataTablesModel();
|
||||||
|
model = await _homeModelFactory.PrepareLatestOrdersModelAsync(model);
|
||||||
|
return PartialView("Table", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<IActionResult> GetOrderIncomplete()
|
||||||
|
{
|
||||||
|
var model = new DataTablesModel();
|
||||||
|
model = await _homeModelFactory.PrepareOrderIncompleteModelAsync(model);
|
||||||
|
return PartialView("Table", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<IActionResult> GetOrderAverage()
|
||||||
|
{
|
||||||
|
var model = new DataTablesModel();
|
||||||
|
model = await _homeModelFactory.PrepareOrderAverageModelAsync(model);
|
||||||
|
return PartialView("Table", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Nop.Services.Orders;
|
||||||
|
using Nop.Web.Areas.Admin.Controllers;
|
||||||
|
using Nop.Web.Framework.Mvc.Filters;
|
||||||
|
using Nop.Web.Framework;
|
||||||
|
using Nop.Web.Areas.Admin.Models.Orders;
|
||||||
|
using Nop.Services.Security;
|
||||||
|
using Nop.Plugin.Misc.FruitBankPlugin.Factories;
|
||||||
|
using Nop.Web.Areas.Admin.Factories;
|
||||||
|
using Nop.Plugin.Misc.FruitBankPlugin.Models;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
|
{
|
||||||
|
[Area(AreaNames.ADMIN)]
|
||||||
|
[AuthorizeAdmin]
|
||||||
|
public class CustomOrderController : BaseAdminController
|
||||||
|
{
|
||||||
|
private readonly IOrderService _orderService;
|
||||||
|
private readonly IOrderModelFactory _orderModelFactory;
|
||||||
|
private readonly IPermissionService _permissionService;
|
||||||
|
// ... other dependencies
|
||||||
|
|
||||||
|
public CustomOrderController(IOrderService orderService, IOrderModelFactory orderModelFactory, IPermissionService permissionService)
|
||||||
|
{
|
||||||
|
_orderService = orderService;
|
||||||
|
_orderModelFactory = orderModelFactory;
|
||||||
|
_permissionService = permissionService;
|
||||||
|
// ... initialize other deps
|
||||||
|
}
|
||||||
|
|
||||||
|
[CheckPermission(StandardPermission.Orders.ORDERS_VIEW)]
|
||||||
|
public virtual async Task<IActionResult> List(List<int> orderStatuses = null, List<int> paymentStatuses = null, List<int> shippingStatuses = null)
|
||||||
|
{
|
||||||
|
//prepare model
|
||||||
|
var model = await _orderModelFactory.PrepareOrderSearchModelAsync(new OrderSearchModel
|
||||||
|
{
|
||||||
|
OrderStatusIds = orderStatuses,
|
||||||
|
PaymentStatusIds = paymentStatuses,
|
||||||
|
ShippingStatusIds = shippingStatuses,
|
||||||
|
});
|
||||||
|
|
||||||
|
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Order/List.cshtml", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[CheckPermission(StandardPermission.Orders.ORDERS_VIEW)]
|
||||||
|
public virtual async Task<IActionResult> OrderList(OrderSearchModel searchModel)
|
||||||
|
{
|
||||||
|
//prepare model
|
||||||
|
var model = await _orderModelFactory.PrepareOrderListModelAsync(searchModel);
|
||||||
|
|
||||||
|
|
||||||
|
Console.WriteLine($"Total: {model.RecordsTotal}, Data Count: {model.Data.Count()}");
|
||||||
|
foreach (var item in model.Data.Take(3))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Order: {item.Id}, {item.CustomOrderNumber}");
|
||||||
|
}
|
||||||
|
var valami = Json(model);
|
||||||
|
Console.WriteLine(valami);
|
||||||
|
return valami;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IActionResult Test()
|
||||||
|
{
|
||||||
|
// Your custom logic here
|
||||||
|
// This will use your custom List.cshtml view
|
||||||
|
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Order/Test.cshtml");
|
||||||
|
}
|
||||||
|
|
||||||
|
//[HttpPost]
|
||||||
|
//[CheckPermission(Nop.Services.Security.StandardPermission.Orders.ORDERS_VIEW)]
|
||||||
|
//public virtual async Task<IActionResult> OrderList(OrderSearchModel searchModel)
|
||||||
|
//{
|
||||||
|
// //prepare model
|
||||||
|
// var model = await _orderModelFactory.PrepareOrderListModelAsync(searchModel);
|
||||||
|
|
||||||
|
// return Json(model);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Nop.Web.Areas.Admin.Controllers;
|
||||||
|
using Nop.Web.Framework.Mvc.Filters;
|
||||||
|
using Nop.Web.Framework;
|
||||||
|
using Nop.Services.Security;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
|
{
|
||||||
|
[Area(AreaNames.ADMIN)]
|
||||||
|
[AuthorizeAdmin]
|
||||||
|
public class InvoiceController : BaseAdminController
|
||||||
|
{
|
||||||
|
private readonly IPermissionService _permissionService;
|
||||||
|
|
||||||
|
public InvoiceController(IPermissionService permissionService)
|
||||||
|
{
|
||||||
|
_permissionService = permissionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> List()
|
||||||
|
{
|
||||||
|
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
|
||||||
|
return AccessDeniedView();
|
||||||
|
|
||||||
|
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Invoice/List.cshtml");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Nop.Web.Areas.Admin.Controllers;
|
||||||
|
using Nop.Web.Framework.Mvc.Filters;
|
||||||
|
using Nop.Web.Framework;
|
||||||
|
using Nop.Services.Security;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models;
|
||||||
|
using Nop.Services.Messages;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
|
{
|
||||||
|
[Area(AreaNames.ADMIN)]
|
||||||
|
[AuthorizeAdmin]
|
||||||
|
public class ShipmentController : BaseAdminController
|
||||||
|
{
|
||||||
|
private readonly IPermissionService _permissionService;
|
||||||
|
protected readonly INotificationService _notificationService;
|
||||||
|
|
||||||
|
public ShipmentController(IPermissionService permissionService, INotificationService notificationService)
|
||||||
|
{
|
||||||
|
_permissionService = permissionService;
|
||||||
|
_notificationService = notificationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> List()
|
||||||
|
{
|
||||||
|
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
|
||||||
|
return AccessDeniedView();
|
||||||
|
|
||||||
|
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipment/List.cshtml");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> Create()
|
||||||
|
{
|
||||||
|
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
|
||||||
|
return AccessDeniedView();
|
||||||
|
|
||||||
|
var model = new CreateShipmentModel
|
||||||
|
{
|
||||||
|
ShipmentDate = DateTime.Now
|
||||||
|
};
|
||||||
|
|
||||||
|
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipment/Create.cshtml", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> Create(CreateShipmentModel model)
|
||||||
|
{
|
||||||
|
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
|
||||||
|
return AccessDeniedView();
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipment/Create.cshtml", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// TODO: Save shipment to database
|
||||||
|
// var shipment = new Shipment
|
||||||
|
// {
|
||||||
|
// Name = model.ShipmentName,
|
||||||
|
// Description = model.Description,
|
||||||
|
// ShipmentDate = model.ShipmentDate,
|
||||||
|
// TrackingNumber = model.TrackingNumber,
|
||||||
|
// CreatedOnUtc = DateTime.UtcNow
|
||||||
|
// };
|
||||||
|
// await _shipmentService.InsertShipmentAsync(shipment);
|
||||||
|
|
||||||
|
_notificationService.SuccessNotification("Shipment created successfully");
|
||||||
|
return RedirectToAction("List");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_notificationService.ErrorNotification($"Error creating shipment: {ex.Message}");
|
||||||
|
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipment/Create.cshtml", model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> UploadFile(IFormFile file)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (file == null || file.Length == 0)
|
||||||
|
return Json(new FileUploadResult { Success = false, ErrorMessage = "No file selected" });
|
||||||
|
|
||||||
|
// Validate file type (PDF only)
|
||||||
|
if (!file.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return Json(new FileUploadResult { Success = false, ErrorMessage = "Only PDF files are allowed" });
|
||||||
|
|
||||||
|
// Validate file size (e.g., max 10MB)
|
||||||
|
if (file.Length > 10 * 1024 * 1024)
|
||||||
|
return Json(new FileUploadResult { Success = false, ErrorMessage = "File size must be less than 10MB" });
|
||||||
|
|
||||||
|
// Create upload directory if it doesn't exist
|
||||||
|
var uploadsPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads", "shipments");
|
||||||
|
Directory.CreateDirectory(uploadsPath);
|
||||||
|
|
||||||
|
// Generate unique filename
|
||||||
|
var fileName = $"{Guid.NewGuid()}_{file.FileName}";
|
||||||
|
var filePath = Path.Combine(uploadsPath, fileName);
|
||||||
|
|
||||||
|
// Save file
|
||||||
|
using (var stream = new FileStream(filePath, FileMode.Create))
|
||||||
|
{
|
||||||
|
await file.CopyToAsync(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Json(new FileUploadResult
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
FileName = file.FileName,
|
||||||
|
FilePath = $"/uploads/shipments/{fileName}"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Json(new FileUploadResult { Success = false, ErrorMessage = ex.Message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult DeleteUploadedFile(string filePath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(filePath))
|
||||||
|
return Json(new { success = false, message = "Invalid file path" });
|
||||||
|
|
||||||
|
var fullPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", filePath.TrimStart('/'));
|
||||||
|
|
||||||
|
if (System.IO.File.Exists(fullPath))
|
||||||
|
{
|
||||||
|
System.IO.File.Delete(fullPath);
|
||||||
|
return Json(new { success = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
return Json(new { success = false, message = "File not found" });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message = ex.Message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Nop.Web.Framework.Models;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models
|
||||||
|
{
|
||||||
|
public record CreateShipmentModel : BaseNopModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string ShipmentName { get; set; }
|
||||||
|
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public DateTime ShipmentDate { get; set; } = DateTime.Now;
|
||||||
|
|
||||||
|
public string TrackingNumber { get; set; }
|
||||||
|
|
||||||
|
public List<string> UploadedFiles { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FileUploadResult
|
||||||
|
{
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public string FileName { get; set; }
|
||||||
|
public string FilePath { get; set; }
|
||||||
|
public string ErrorMessage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
using Nop.Web.Framework.Models;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a dashboard model
|
||||||
|
/// </summary>
|
||||||
|
public partial record DashboardModel : BaseNopModel
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public bool IsLoggedInAsVendor { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
@model DashboardModel
|
||||||
|
@inject IPermissionService permissionService
|
||||||
|
@using Nop.Services.Security
|
||||||
|
@{
|
||||||
|
//page title
|
||||||
|
ViewBag.PageTitle = T("Admin.Dashboard").Text;
|
||||||
|
|
||||||
|
var canManageOrders = await permissionService.AuthorizeAsync(StandardPermission.Orders.ORDERS_VIEW);
|
||||||
|
var canManageCustomers = await permissionService.AuthorizeAsync(StandardPermission.Customers.CUSTOMERS_VIEW);
|
||||||
|
var canManageProducts = await permissionService.AuthorizeAsync(StandardPermission.Catalog.PRODUCTS_VIEW);
|
||||||
|
var canManageReturnRequests = await permissionService.AuthorizeAsync(StandardPermission.Orders.RETURN_REQUESTS_VIEW);
|
||||||
|
|
||||||
|
//close configuration steps value
|
||||||
|
const string closeCardAttributeName = "CloseConfigurationSteps";
|
||||||
|
var closeConfigurationStepsCard = await genericAttributeService.GetAttributeAsync<bool>(await workContext.GetCurrentCustomerAsync(), closeCardAttributeName);
|
||||||
|
|
||||||
|
//active menu item (system name)
|
||||||
|
NopHtml.SetActiveMenuItemSystemName("Dashboard");
|
||||||
|
}
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="~/lib_npm/ionicons/css/ionicons.min.css" />
|
||||||
|
<script src="~/js/admin.table.js" asp-location="Footer"></script>
|
||||||
|
|
||||||
|
<div class="content-header">
|
||||||
|
<h1>
|
||||||
|
Fruit Bank @T("Admin.Dashboard")
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<section class="content">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
@if (!closeConfigurationStepsCard)
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
@await Html.PartialAsync("~/Areas/Admin/Views/Home/_ConfigurationSteps.cshtml")
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.DashboardTop, additionalData = Model })
|
||||||
|
@if (!Model.IsLoggedInAsVendor)
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
@await Component.InvokeAsync(typeof(NopCommerceNewsViewComponent))
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.DashboardNewsAfter, additionalData = Model })
|
||||||
|
@if (!Model.IsLoggedInAsVendor && canManageOrders && canManageCustomers && canManageProducts && canManageReturnRequests)
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
@await Component.InvokeAsync(typeof(CommonStatisticsViewComponent))
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.DashboardCommonstatisticsAfter, additionalData = Model })
|
||||||
|
@if (!Model.IsLoggedInAsVendor && (canManageOrders || canManageCustomers))
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
@if (!Model.IsLoggedInAsVendor && canManageOrders)
|
||||||
|
{
|
||||||
|
<div class="col-md-6">
|
||||||
|
@await Html.PartialAsync("~/Areas/Admin/Views/Home/_OrderStatistics.cshtml")
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (!Model.IsLoggedInAsVendor && canManageCustomers)
|
||||||
|
{
|
||||||
|
<div class="col-md-6">
|
||||||
|
@await Html.PartialAsync("~/Areas/Admin/Views/Home/_CustomerStatistics.cshtml")
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.DashboardCustomerorderchartsAfter, additionalData = Model })
|
||||||
|
@if (!Model.IsLoggedInAsVendor && canManageOrders)
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
@await Html.PartialAsync("~/Areas/Admin/Views/Home/_OrderAverageReport.cshtml")
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
@await Html.PartialAsync("~/Areas/Admin/Views/Home/_OrderIncompleteReport.cshtml")
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.DashboardOrderreportsAfter, additionalData = Model })
|
||||||
|
@if (!Model.IsLoggedInAsVendor && (canManageOrders || canManageProducts))
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
@if (canManageOrders)
|
||||||
|
{
|
||||||
|
<div class="col-md-8">
|
||||||
|
@await Html.PartialAsync("~/Areas/Admin/Views/Home/_LatestOrders.cshtml")
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="col-md-4">
|
||||||
|
@if (canManageProducts)
|
||||||
|
{
|
||||||
|
@await Html.PartialAsync("~/Areas/Admin/Views/Home/_PopularSearchTermsReport.cshtml")
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.DashboardLatestordersSearchtermsAfter, additionalData = Model })
|
||||||
|
@if (canManageOrders)
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
@await Html.PartialAsync("~/Areas/Admin/Views/Home/_BestsellersBriefReportByQuantity.cshtml")
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
@await Html.PartialAsync("~/Areas/Admin/Views/Home/_BestsellersBriefReportByAmount.cshtml")
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.DashboardBottom, additionalData = Model })
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<nop-alert asp-alert-id="loadOrderStatisticsAlert" asp-alert-message="@T("Admin.SalesReport.OrderStatistics.Alert.FailedLoad")" />
|
||||||
|
<nop-alert asp-alert-id="loadCustomerStatisticsAlert" asp-alert-message="@T("Admin.Reports.Customers.CustomerStatistics.Alert.FailedLoad")" />
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
@{
|
||||||
|
// Layout = "_AdminLayout";
|
||||||
|
ViewBag.PageTitle = "Invoice";
|
||||||
|
NopHtml.SetActiveMenuItemSystemName("Invoices");
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="content-header clearfix">
|
||||||
|
<h1 class="float-left">
|
||||||
|
<i class="fas fa-shipping-fast"></i>
|
||||||
|
Invoices
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="content">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="form-horizontal">
|
||||||
|
<div class="cards-group">
|
||||||
|
<div class="card card-default">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">
|
||||||
|
Shipment Management
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>This is our custom Invoices page.</p>
|
||||||
|
<p>Add shipment functionality here.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
@model OrderSearchModel
|
@model OrderSearchModel
|
||||||
|
|
||||||
@inject IStoreService storeService
|
@inject IStoreService storeService
|
||||||
|
@using Nop.Plugin.Misc.FruitBankPlugin.Models
|
||||||
@using Nop.Services.Stores
|
@using Nop.Services.Stores
|
||||||
|
@using Nop.Web.Areas.Admin.Components
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Orders
|
||||||
|
@using Nop.Web.Framework.Infrastructure
|
||||||
|
@using Nop.Web.Framework.Models.DataTables
|
||||||
|
@using static Nop.Services.Common.NopLinksDefaults
|
||||||
|
|
||||||
@{
|
@{
|
||||||
//page title
|
//page title
|
||||||
|
|
@ -284,6 +290,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card card-default">
|
<div class="card card-default">
|
||||||
|
<div class="card-header">
|
||||||
|
<h1>RTTTTTTTTTT</h1>
|
||||||
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<nop-doc-reference asp-string-resource="@T("Admin.Documentation.Reference.Orders", Docs.Orders + Utm.OnAdmin)" />
|
<nop-doc-reference asp-string-resource="@T("Admin.Documentation.Reference.Orders", Docs.Orders + Utm.OnAdmin)" />
|
||||||
|
|
||||||
|
|
@ -291,7 +300,7 @@
|
||||||
var gridModel = new DataTablesModel
|
var gridModel = new DataTablesModel
|
||||||
{
|
{
|
||||||
Name = "orders-grid",
|
Name = "orders-grid",
|
||||||
UrlRead = new DataUrl("OrderList", "Order", null),
|
UrlRead = new DataUrl("OrderList", "CustomOrder", null),
|
||||||
SearchButtonId = "search-orders",
|
SearchButtonId = "search-orders",
|
||||||
Length = Model.PageSize,
|
Length = Model.PageSize,
|
||||||
LengthMenu = Model.AvailablePageSizes,
|
LengthMenu = Model.AvailablePageSizes,
|
||||||
|
|
@ -398,30 +407,35 @@
|
||||||
});
|
});
|
||||||
var orderSummaryColumnNumber = 8;
|
var orderSummaryColumnNumber = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@await Html.PartialAsync("Table", gridModel)
|
@await Html.PartialAsync("Table", gridModel)
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function renderColumnOrderStatus(data, type, row, meta) {
|
function renderColumnOrderStatus(data, type, row, meta) {
|
||||||
|
try {
|
||||||
|
console.log("OrderStatus render - data:", data, "row:", row);
|
||||||
|
|
||||||
|
if (!row.OrderStatusId) {
|
||||||
|
console.error("OrderStatusId is missing from row data");
|
||||||
|
return data || '';
|
||||||
|
}
|
||||||
|
|
||||||
var color;
|
var color;
|
||||||
switch (row.OrderStatusId) {
|
switch (row.OrderStatusId) {
|
||||||
case 10:
|
case 10: color = 'yellow'; break;
|
||||||
color = 'yellow';
|
case 20: color = 'blue'; break;
|
||||||
break;
|
case 30: color = 'green'; break;
|
||||||
case 20:
|
case 40: color = 'red'; break;
|
||||||
color = 'blue';
|
default: color = 'gray';
|
||||||
break;
|
}
|
||||||
case 30:
|
return '<span class="grid-report-item ' + color + '">' + data + '</span>';
|
||||||
color = 'green';
|
} catch (e) {
|
||||||
break;
|
console.error("Error in renderColumnOrderStatus:", e);
|
||||||
case 40:
|
return data || '';
|
||||||
color = 'red';
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return '<span class="grid-report-item ' + color + '">' + data + '</span >';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderColumnCustomer(data, type, row, meta) {
|
function renderColumnCustomer(data, type, row, meta) {
|
||||||
|
console.log("Hello World 2");
|
||||||
var link = '@Url.Content("~/Admin/Customer/Edit/")' + row.CustomerId;
|
var link = '@Url.Content("~/Admin/Customer/Edit/")' + row.CustomerId;
|
||||||
var textRenderer = $.fn.dataTable.render.text().display;
|
var textRenderer = $.fn.dataTable.render.text().display;
|
||||||
return `${textRenderer(row.CustomerFullName)} <br /><a href="${link}">${data}</a > `;
|
return `${textRenderer(row.CustomerFullName)} <br /><a href="${link}">${data}</a > `;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,362 @@
|
||||||
|
@model Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.CreateShipmentModel
|
||||||
|
@{
|
||||||
|
// Layout = "_AdminLayout";
|
||||||
|
ViewBag.PageTitle = "Create Shipment";
|
||||||
|
NopHtml.SetActiveMenuItemSystemName("Shipments.Create");
|
||||||
|
}
|
||||||
|
|
||||||
|
<form asp-action="Create" method="post" enctype="multipart/form-data">
|
||||||
|
<div class="content-header clearfix">
|
||||||
|
<h1 class="float-left">
|
||||||
|
<i class="fas fa-plus"></i>
|
||||||
|
Create New Shipment
|
||||||
|
</h1>
|
||||||
|
<div class="float-right">
|
||||||
|
<button type="submit" name="save" class="btn btn-primary">
|
||||||
|
<i class="far fa-save"></i>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
<a asp-action="List" class="btn btn-default">
|
||||||
|
<i class="fas fa-arrow-left"></i>
|
||||||
|
Back to List
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="content">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="form-horizontal">
|
||||||
|
<div class="cards-group">
|
||||||
|
<!-- Basic Information -->
|
||||||
|
<div class="card card-default">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">Shipment Information</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<nop-label asp-for="ShipmentName" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<nop-editor asp-for="ShipmentName" required="true" />
|
||||||
|
<span asp-validation-for="ShipmentName"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<nop-label asp-for="Description" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<textarea asp-for="Description" class="form-control" rows="3"></textarea>
|
||||||
|
<span asp-validation-for="Description"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<nop-label asp-for="ShipmentDate" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<nop-editor asp-for="ShipmentDate" asp-template="DateTime" required="true" />
|
||||||
|
<span asp-validation-for="ShipmentDate"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<nop-label asp-for="TrackingNumber" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<nop-editor asp-for="TrackingNumber" />
|
||||||
|
<span asp-validation-for="TrackingNumber"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- File Upload Section -->
|
||||||
|
<div class="card card-default">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">
|
||||||
|
<i class="fas fa-file-pdf"></i>
|
||||||
|
Upload Documents (PDF only)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<!-- Drag & Drop Zone -->
|
||||||
|
<div id="dropZone" class="drop-zone">
|
||||||
|
<div class="drop-zone-content">
|
||||||
|
<i class="fas fa-cloud-upload-alt fa-3x text-muted"></i>
|
||||||
|
<h4>Drag & Drop PDF files here</h4>
|
||||||
|
<p class="text-muted">or click to select files</p>
|
||||||
|
<input type="file" id="fileInput" multiple accept=".pdf" style="display: none;">
|
||||||
|
<button type="button" id="selectFilesBtn" class="btn btn-outline-primary">
|
||||||
|
<i class="fas fa-folder-open"></i>
|
||||||
|
Select Files
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Upload Progress -->
|
||||||
|
<div id="uploadProgress" style="display: none;">
|
||||||
|
<div class="progress mb-3">
|
||||||
|
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%"></div>
|
||||||
|
</div>
|
||||||
|
<p id="uploadStatus" class="text-center"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Uploaded Files List -->
|
||||||
|
<div id="uploadedFiles" class="mt-3">
|
||||||
|
<h5>Uploaded Files:</h5>
|
||||||
|
<div id="filesList" class="list-group">
|
||||||
|
<!-- Uploaded files will appear here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.drop-zone {
|
||||||
|
border: 2px dashed #dee2e6;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 40px;
|
||||||
|
text-align: center;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
min-height: 200px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drop-zone:hover,
|
||||||
|
.drop-zone.drag-over {
|
||||||
|
border-color: #007bff;
|
||||||
|
background-color: rgba(0, 123, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.drop-zone-content {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 15px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-item .file-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-item .file-info i {
|
||||||
|
margin-right: 10px;
|
||||||
|
color: #dc3545;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-item .file-actions button {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-error {
|
||||||
|
border-color: #dc3545;
|
||||||
|
background-color: rgba(220, 53, 69, 0.05);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
let uploadedFiles = [];
|
||||||
|
|
||||||
|
// File input and drop zone elements
|
||||||
|
const dropZone = document.getElementById('dropZone');
|
||||||
|
const fileInput = document.getElementById('fileInput');
|
||||||
|
const selectFilesBtn = document.getElementById('selectFilesBtn');
|
||||||
|
|
||||||
|
// Click to select files
|
||||||
|
selectFilesBtn.addEventListener('click', () => fileInput.click());
|
||||||
|
dropZone.addEventListener('click', (e) => {
|
||||||
|
if (e.target === dropZone || e.target.closest('.drop-zone-content')) {
|
||||||
|
fileInput.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// File input change
|
||||||
|
fileInput.addEventListener('change', handleFiles);
|
||||||
|
|
||||||
|
// Drag and drop events
|
||||||
|
dropZone.addEventListener('dragover', handleDragOver);
|
||||||
|
dropZone.addEventListener('dragenter', handleDragEnter);
|
||||||
|
dropZone.addEventListener('dragleave', handleDragLeave);
|
||||||
|
dropZone.addEventListener('drop', handleDrop);
|
||||||
|
|
||||||
|
function handleDragOver(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
dropZone.classList.add('drag-over');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragEnter(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
dropZone.classList.add('drag-over');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragLeave(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!dropZone.contains(e.relatedTarget)) {
|
||||||
|
dropZone.classList.remove('drag-over');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrop(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
dropZone.classList.remove('drag-over');
|
||||||
|
|
||||||
|
const files = e.dataTransfer.files;
|
||||||
|
processFiles(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFiles(e) {
|
||||||
|
const files = e.target.files;
|
||||||
|
processFiles(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
function processFiles(files) {
|
||||||
|
Array.from(files).forEach(file => {
|
||||||
|
if (file.type === 'application/pdf') {
|
||||||
|
uploadFile(file);
|
||||||
|
} else {
|
||||||
|
showError(`"${file.name}" is not a PDF file. Only PDF files are allowed.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadFile(file) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
|
||||||
|
// Show upload progress
|
||||||
|
showUploadProgress(`Uploading ${file.name}...`);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '@Url.Action("UploadFile")',
|
||||||
|
type: 'POST',
|
||||||
|
data: formData,
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
success: function(result) {
|
||||||
|
hideUploadProgress();
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
uploadedFiles.push(result);
|
||||||
|
addFileToList(result);
|
||||||
|
showSuccess(`"${result.fileName}" uploaded successfully`);
|
||||||
|
} else {
|
||||||
|
showError(`Upload failed: ${result.errorMessage}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
hideUploadProgress();
|
||||||
|
showError(`Upload failed: ${error}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFileToList(file) {
|
||||||
|
const filesList = document.getElementById('filesList');
|
||||||
|
const fileItem = document.createElement('div');
|
||||||
|
fileItem.className = 'file-item';
|
||||||
|
fileItem.innerHTML = `
|
||||||
|
<div class="file-info">
|
||||||
|
<i class="fas fa-file-pdf"></i>
|
||||||
|
<span>${file.fileName}</span>
|
||||||
|
</div>
|
||||||
|
<div class="file-actions">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="viewFile('${file.filePath}')">
|
||||||
|
<i class="fas fa-eye"></i> View
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-danger" onclick="deleteFile('${file.filePath}', this)">
|
||||||
|
<i class="fas fa-trash"></i> Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
filesList.appendChild(fileItem);
|
||||||
|
|
||||||
|
// Show the uploaded files section
|
||||||
|
document.getElementById('uploadedFiles').style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showUploadProgress(message) {
|
||||||
|
const progressDiv = document.getElementById('uploadProgress');
|
||||||
|
const statusText = document.getElementById('uploadStatus');
|
||||||
|
|
||||||
|
statusText.textContent = message;
|
||||||
|
progressDiv.style.display = 'block';
|
||||||
|
|
||||||
|
// Animate progress bar
|
||||||
|
const progressBar = progressDiv.querySelector('.progress-bar');
|
||||||
|
progressBar.style.width = '100%';
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideUploadProgress() {
|
||||||
|
document.getElementById('uploadProgress').style.display = 'none';
|
||||||
|
const progressBar = document.querySelector('#uploadProgress .progress-bar');
|
||||||
|
progressBar.style.width = '0%';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showError(message) {
|
||||||
|
// Use nopCommerce's notification system
|
||||||
|
displayBarNotification(message, 'error', 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showSuccess(message) {
|
||||||
|
// Use nopCommerce's notification system
|
||||||
|
displayBarNotification(message, 'success', 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global functions for file actions
|
||||||
|
window.viewFile = function(filePath) {
|
||||||
|
window.open(filePath, '_blank');
|
||||||
|
};
|
||||||
|
|
||||||
|
window.deleteFile = function(filePath, button) {
|
||||||
|
if (confirm('Are you sure you want to delete this file?')) {
|
||||||
|
$.post('@Url.Action("DeleteUploadedFile")', { filePath: filePath })
|
||||||
|
.done(function(result) {
|
||||||
|
if (result.success) {
|
||||||
|
// Remove from uploaded files array
|
||||||
|
uploadedFiles = uploadedFiles.filter(f => f.filePath !== filePath);
|
||||||
|
|
||||||
|
// Remove from DOM
|
||||||
|
const fileItem = button.closest('.file-item');
|
||||||
|
fileItem.remove();
|
||||||
|
|
||||||
|
// Hide uploaded files section if no files remain
|
||||||
|
if (uploadedFiles.length === 0) {
|
||||||
|
document.getElementById('uploadedFiles').style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
showSuccess('File deleted successfully');
|
||||||
|
} else {
|
||||||
|
showError('Failed to delete file: ' + result.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fail(function() {
|
||||||
|
showError('Failed to delete file');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
@{
|
||||||
|
// Layout = "_AdminLayout";
|
||||||
|
ViewBag.PageTitle = "Shipments";
|
||||||
|
NopHtml.SetActiveMenuItemSystemName("Shipments");
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="content-header clearfix">
|
||||||
|
<h1 class="float-left">
|
||||||
|
<i class="fas fa-shipping-fast"></i>
|
||||||
|
Shipments
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="content">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="form-horizontal">
|
||||||
|
<div class="cards-group">
|
||||||
|
<div class="card card-default">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">
|
||||||
|
Shipment Management
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>This is our custom Shipments page.</p>
|
||||||
|
<p>Add shipment functionality here.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
@ -3,10 +3,71 @@
|
||||||
@addTagHelper *, Nop.Web.Framework
|
@addTagHelper *, Nop.Web.Framework
|
||||||
|
|
||||||
@inject INopHtmlHelper NopHtml
|
@inject INopHtmlHelper NopHtml
|
||||||
|
@inject IGenericAttributeService genericAttributeService
|
||||||
|
@inject IWorkContext workContext
|
||||||
|
|
||||||
@using Microsoft.AspNetCore.Mvc.ViewFeatures
|
@using Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
|
@using Nop.Core
|
||||||
|
@using Nop.Services.Common
|
||||||
@using Nop.Web.Framework.UI
|
@using Nop.Web.Framework.UI
|
||||||
@using Nop.Web.Framework.Extensions
|
@using Nop.Web.Framework.Extensions
|
||||||
@using System.Text.Encodings.Web
|
@using System.Text.Encodings.Web
|
||||||
@using Nop.Services.Events
|
@using Nop.Services.Events
|
||||||
@using Nop.Web.Framework.Events
|
@using Nop.Web.Framework.Events
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@using System.Globalization;
|
||||||
|
@using System.Net;
|
||||||
|
@using Microsoft.AspNetCore.Routing
|
||||||
|
@using Microsoft.AspNetCore.StaticFiles
|
||||||
|
@using Microsoft.Extensions.Primitives
|
||||||
|
@using Nop.Core.Domain.Common
|
||||||
|
@using Nop.Core.Events
|
||||||
|
@using Nop.Core.Infrastructure
|
||||||
|
@using static Nop.Services.Common.NopLinksDefaults
|
||||||
|
@using Nop.Web.Areas.Admin.Components
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Affiliates
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Blogs
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Catalog
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Cms
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Common
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Customers
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Directory
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Discounts
|
||||||
|
@using Nop.Web.Areas.Admin.Models.ExternalAuthentication
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Forums
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Home
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Localization
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Logging
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Messages
|
||||||
|
@using Nop.Web.Areas.Admin.Models.MultiFactorAuthentication
|
||||||
|
@using Nop.Web.Areas.Admin.Models.News
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Orders
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Payments
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Plugins
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Plugins.Marketplace
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Polls
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Reports
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Security
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Settings
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Shipping
|
||||||
|
@using Nop.Web.Areas.Admin.Models.ShoppingCart
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Stores
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Tasks
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Tax
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Templates
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Topics
|
||||||
|
@using Nop.Web.Areas.Admin.Models.Vendors
|
||||||
|
@using Nop.Web.Components
|
||||||
|
@using Nop.Web.Extensions
|
||||||
|
@using Nop.Web.Framework
|
||||||
|
@using Nop.Web.Framework.Infrastructure
|
||||||
|
@using Nop.Web.Framework.Models
|
||||||
|
@using Nop.Web.Framework.Models.Cms
|
||||||
|
@using Nop.Web.Framework.Models.DataTables
|
||||||
|
@using Nop.Web.Framework.Mvc.Routing
|
||||||
|
@using Nop.Web.Framework.Security.Captcha
|
||||||
|
@using Nop.Web.Framework.Security.Honeypot
|
||||||
|
@using Nop.Web.Framework.Themes
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
@{
|
||||||
|
Layout = "_AdminLayout";
|
||||||
|
}
|
||||||
|
|
@ -31,6 +31,7 @@ using Nop.Web.Areas.Admin.Models.Orders;
|
||||||
using Nop.Plugin.Misc.FruitBankPlugin.Models;
|
using Nop.Plugin.Misc.FruitBankPlugin.Models;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Nop.Plugin.Misc.FruitBankPlugin.Helpers;
|
using Nop.Plugin.Misc.FruitBankPlugin.Helpers;
|
||||||
|
using Microsoft.AspNetCore.Mvc.TagHelpers;
|
||||||
|
|
||||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Factories
|
namespace Nop.Plugin.Misc.FruitBankPlugin.Factories
|
||||||
{
|
{
|
||||||
|
|
@ -140,24 +141,28 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Factories
|
||||||
// let base prepare default model first
|
// let base prepare default model first
|
||||||
var baseModel = await base.PrepareOrderSearchModelAsync(searchModel);
|
var baseModel = await base.PrepareOrderSearchModelAsync(searchModel);
|
||||||
|
|
||||||
|
//foreach (var order in baseModel.order)
|
||||||
|
|
||||||
|
|
||||||
// create derived/extended instance
|
// create derived/extended instance
|
||||||
var extended = new OrderSearchModelExtended();
|
//var extended = new OrderSearchModelExtended();
|
||||||
|
|
||||||
// copy all public instance properties from baseModel to extended
|
// copy all public instance properties from baseModel to extended
|
||||||
CopyModelHelper.CopyPublicProperties(baseModel, extended);
|
//CopyModelHelper.CopyPublicProperties(baseModel, extended);
|
||||||
|
|
||||||
// try to obtain NeedsMeasurement from the incoming searchModel (if it's extended)
|
// try to obtain NeedsMeasurement from the incoming searchModel (if it's extended)
|
||||||
bool? needsMeasurement = null;
|
//bool? needsMeasurement = null;
|
||||||
var prop = searchModel?.GetType().GetProperty("NeedsMeasurement", BindingFlags.Public | BindingFlags.Instance);
|
//var prop = searchModel?.GetType().GetProperty("NeedsMeasurement", BindingFlags.Public | BindingFlags.Instance);
|
||||||
if (prop != null && prop.PropertyType == typeof(bool?))
|
//if (prop != null && prop.PropertyType == typeof(bool?))
|
||||||
{
|
//{
|
||||||
needsMeasurement = (bool?)prop.GetValue(searchModel);
|
// needsMeasurement = (bool?)prop.GetValue(searchModel);
|
||||||
}
|
//}
|
||||||
|
|
||||||
extended.NeedsMeasurement = needsMeasurement;
|
//extended.NeedsMeasurement = needsMeasurement;
|
||||||
|
|
||||||
// return the extended object (it's assignable to OrderSearchModel)
|
// return the extended object (it's assignable to OrderSearchModel)
|
||||||
return extended;
|
//return extended;
|
||||||
|
return baseModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<OrderListModel> PrepareOrderListModelAsync(OrderSearchModel searchModel)
|
public override async Task<OrderListModel> PrepareOrderListModelAsync(OrderSearchModel searchModel)
|
||||||
|
|
@ -165,29 +170,26 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Factories
|
||||||
// get the default model first
|
// get the default model first
|
||||||
var baseModel = await base.PrepareOrderListModelAsync(searchModel);
|
var baseModel = await base.PrepareOrderListModelAsync(searchModel);
|
||||||
|
|
||||||
|
var extendedRows = new List<OrderModelExtended>();
|
||||||
|
|
||||||
|
foreach (var order in baseModel.Data)
|
||||||
// project the rows into your extended row type
|
|
||||||
var extendedRows = baseModel.Data.Select(async order => new OrderModelExtended
|
|
||||||
{
|
{
|
||||||
Id = order.Id,
|
var extendedOrder = new OrderModelExtended();
|
||||||
CustomOrderNumber = order.CustomOrderNumber,
|
CopyModelHelper.CopyPublicProperties(order, extendedOrder);
|
||||||
OrderStatus = order.OrderStatus,
|
extendedOrder.NeedsMeasurement = await ShouldMarkAsNeedsMeasurementAsync(order);
|
||||||
PaymentStatus = order.PaymentStatus,
|
Console.WriteLine(extendedOrder.Id);
|
||||||
ShippingStatus = order.ShippingStatus,
|
extendedRows.Add(extendedOrder);
|
||||||
OrderTotal = order.OrderTotal,
|
}
|
||||||
CreatedOn = order.CreatedOn,
|
|
||||||
|
|
||||||
// custom field
|
//var model = new OrderListModel
|
||||||
NeedsMeasurement = await ShouldMarkAsNeedsMeasurementAsync(order)
|
//{
|
||||||
}).ToList();
|
// Data = extendedRows.Cast<OrderModel>().ToList(),
|
||||||
|
// RecordsTotal = baseModel.RecordsTotal
|
||||||
|
//};
|
||||||
|
|
||||||
// build a new OrderListModel but replace Data with the extended items
|
var model = new OrderListModel();
|
||||||
var model = new OrderListModel
|
CopyModelHelper.CopyPublicProperties(baseModel, model);
|
||||||
{
|
model.Data = extendedRows.ToList<OrderModel>(); // Different cast approach
|
||||||
Data = extendedRows.Cast<OrderModel>().ToList(), // still satisfies the grid
|
|
||||||
//Total = baseModel.Total
|
|
||||||
};
|
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Filters
|
||||||
if (order != null && await _orderMeasurementService.IsPendingMeasurementAsync(order))
|
if (order != null && await _orderMeasurementService.IsPendingMeasurementAsync(order))
|
||||||
{
|
{
|
||||||
order.OrderStatus = OrderStatus.Processing;
|
order.OrderStatus = OrderStatus.Processing;
|
||||||
|
order.PaymentStatus = Core.Domain.Payments.PaymentStatus.Pending;
|
||||||
context.Result = new RedirectToRouteResult(new
|
context.Result = new RedirectToRouteResult(new
|
||||||
{
|
{
|
||||||
controller = "Checkout",
|
controller = "Checkout",
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,8 @@ namespace Nop.Plugin.Misc.FruitBankPlugin
|
||||||
ApiKey = string.Empty
|
ApiKey = string.Empty
|
||||||
};
|
};
|
||||||
await _settingService.SaveSettingAsync(settings);
|
await _settingService.SaveSettingAsync(settings);
|
||||||
|
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.ShipmentsList", "Shipment", "EN");
|
||||||
|
await _localizationService.AddOrUpdateLocaleResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.ShipmentsList", "Shipment", "HU");
|
||||||
await base.InstallAsync();
|
await base.InstallAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,48 +107,6 @@ namespace Nop.Plugin.Misc.FruitBankPlugin
|
||||||
if (!await _permissionService.AuthorizeAsync(StandardPermission.Configuration.MANAGE_PLUGINS))
|
if (!await _permissionService.AuthorizeAsync(StandardPermission.Configuration.MANAGE_PLUGINS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var configurationItem = rootNode.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Configuration"));
|
|
||||||
if (configurationItem is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var shippingItem = configurationItem.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Shipping"));
|
|
||||||
var widgetsItem = configurationItem.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Widgets"));
|
|
||||||
if (shippingItem is null && widgetsItem is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var index = shippingItem is not null ? configurationItem.ChildNodes.IndexOf(shippingItem) : -1;
|
|
||||||
if (index < 0)
|
|
||||||
index = widgetsItem is not null ? configurationItem.ChildNodes.IndexOf(widgetsItem) : -1;
|
|
||||||
if (index < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
configurationItem.ChildNodes.Insert(index + 1, new AdminMenuItem
|
|
||||||
{
|
|
||||||
|
|
||||||
Visible = true,
|
|
||||||
SystemName = "AI plugins",
|
|
||||||
Title = await _localizationService.GetResourceAsync("Plugins.Misc.SignalRApi.Menu.AI"),
|
|
||||||
IconClass = "far fa-dot-circle",
|
|
||||||
ChildNodes = new List<AdminMenuItem>
|
|
||||||
{
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
// SystemName = "FruitBankPlugin.Configure",
|
|
||||||
// Title = "AI Assistant",
|
|
||||||
// Url = $"{_webHelper.GetStoreLocation()}Admin/FruitBankPluginAdmin/Configure",
|
|
||||||
// Visible = true
|
|
||||||
Visible = true,
|
|
||||||
SystemName = PluginDescriptor.SystemName,
|
|
||||||
Title = PluginDescriptor.FriendlyName,
|
|
||||||
IconClass = "far fa-circle",
|
|
||||||
Url = _adminMenu.GetMenuItemUrl("FruitBankPlugin", "Configure"),
|
|
||||||
//Url = "Admin/SignalRApi/Configure",
|
|
||||||
//ControllerName = "SignalRApi",
|
|
||||||
//ActionName = "Configure",
|
|
||||||
//RouteValues = new RouteValueDictionary { { "area", AreaNames.ADMIN } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetConfigurationPageUrl()
|
public override string GetConfigurationPageUrl()
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Nop.Core.Domain.Orders;
|
||||||
using Nop.Core.Infrastructure;
|
using Nop.Core.Infrastructure;
|
||||||
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
|
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
|
||||||
using Nop.Plugin.Misc.FruitBankPlugin.Factories;
|
using Nop.Plugin.Misc.FruitBankPlugin.Factories;
|
||||||
|
|
@ -18,6 +19,8 @@ using Nop.Plugin.Misc.FruitBankPlugin.Filters;
|
||||||
using Nop.Plugin.Misc.FruitBankPlugin.Models;
|
using Nop.Plugin.Misc.FruitBankPlugin.Models;
|
||||||
using Nop.Plugin.Misc.FruitBankPlugin.Services;
|
using Nop.Plugin.Misc.FruitBankPlugin.Services;
|
||||||
using Nop.Services.Catalog;
|
using Nop.Services.Catalog;
|
||||||
|
using Nop.Services.Common;
|
||||||
|
using Nop.Services.Events;
|
||||||
using Nop.Web.Areas.Admin.Factories;
|
using Nop.Web.Areas.Admin.Factories;
|
||||||
using Nop.Web.Areas.Admin.Models.Catalog;
|
using Nop.Web.Areas.Admin.Models.Catalog;
|
||||||
using Nop.Web.Areas.Admin.Models.Orders;
|
using Nop.Web.Areas.Admin.Models.Orders;
|
||||||
|
|
@ -58,12 +61,14 @@ public class PluginNopStartup : INopStartup
|
||||||
//services.AddScoped<CustomModelFactory, ICustomerModelFactory>();
|
//services.AddScoped<CustomModelFactory, ICustomerModelFactory>();
|
||||||
services.AddScoped<IPriceCalculationService, CustomPriceCalculationService>();
|
services.AddScoped<IPriceCalculationService, CustomPriceCalculationService>();
|
||||||
services.AddScoped<PriceCalculationService, CustomPriceCalculationService>();
|
services.AddScoped<PriceCalculationService, CustomPriceCalculationService>();
|
||||||
|
services.AddScoped<IConsumer<OrderPlacedEvent>, EventConsumer>();
|
||||||
services.AddScoped<IOrderMeasurementService, OrderMeasurementService>();
|
services.AddScoped<IOrderMeasurementService, OrderMeasurementService>();
|
||||||
services.AddScoped<PendingMeasurementCheckoutFilter>();
|
services.AddScoped<PendingMeasurementCheckoutFilter>();
|
||||||
services.AddScoped<OrderListModel, OrderListModelExtended>();
|
services.AddScoped<OrderListModel, OrderListModelExtended>();
|
||||||
services.AddScoped<OrderModel, OrderModelExtended>();
|
services.AddScoped<OrderModel, OrderModelExtended>();
|
||||||
services.AddScoped<OrderSearchModel, OrderSearchModelExtended>();
|
services.AddScoped<OrderSearchModel, OrderSearchModelExtended>();
|
||||||
services.AddScoped<OrderModelFactory, CustomOrderModelFactory>();
|
services.AddScoped<IOrderModelFactory, CustomOrderModelFactory>();
|
||||||
|
services.AddScoped<IGenericAttributeService, GenericAttributeService>();
|
||||||
services.AddControllersWithViews(options =>
|
services.AddControllersWithViews(options =>
|
||||||
{
|
{
|
||||||
options.Filters.AddService<PendingMeasurementCheckoutFilter>();
|
options.Filters.AddService<PendingMeasurementCheckoutFilter>();
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,58 @@ public class RouteProvider : IRouteProvider
|
||||||
defaults: new { controller = "FruitBankPluginAdmin", action = "Configure", area = AreaNames.ADMIN });
|
defaults: new { controller = "FruitBankPluginAdmin", action = "Configure", area = AreaNames.ADMIN });
|
||||||
|
|
||||||
//endpointRouteBuilder.MapHub<FruitBankHub>("/fbhub");//.RequireCors("AllowBlazorClient");
|
//endpointRouteBuilder.MapHub<FruitBankHub>("/fbhub");//.RequireCors("AllowBlazorClient");
|
||||||
|
|
||||||
|
endpointRouteBuilder.MapControllerRoute(
|
||||||
|
name: "Plugin.FruitBank.Admin.Order.List",
|
||||||
|
pattern: "Admin/Order/List",
|
||||||
|
defaults: new { controller = "CustomOrder", action = "List", area = AreaNames.ADMIN }
|
||||||
|
//constraints: new { area = AreaNames.ADMIN }
|
||||||
|
);
|
||||||
|
|
||||||
|
endpointRouteBuilder.MapControllerRoute(
|
||||||
|
name: "Plugin.FruitBank.Admin.Order.OrderList",
|
||||||
|
pattern: "Admin/Order/OrderList",
|
||||||
|
defaults: new { controller = "CustomOrder", action = "OrderList", area = AreaNames.ADMIN });
|
||||||
|
|
||||||
|
endpointRouteBuilder.MapControllerRoute(
|
||||||
|
name: "Plugin.FruitBank.Admin.Order.Test",
|
||||||
|
pattern: "Admin/Order/Test",
|
||||||
|
defaults: new { controller = "CustomOrder", action = "Test", area = AreaNames.ADMIN }
|
||||||
|
//constraints: new { area = AreaNames.ADMIN }
|
||||||
|
);
|
||||||
|
|
||||||
|
endpointRouteBuilder.MapControllerRoute(
|
||||||
|
name: "Plugin.FruitBank.Admin.Index",
|
||||||
|
pattern: "Admin",
|
||||||
|
defaults: new { controller = "CustomDashboard", action = "Index", area = AreaNames.ADMIN }
|
||||||
|
//constraints: new { area = AreaNames.ADMIN }
|
||||||
|
);
|
||||||
|
|
||||||
|
endpointRouteBuilder.MapControllerRoute(
|
||||||
|
name: "Plugin.FruitBank.Admin.Shipment.List",
|
||||||
|
pattern: "Admin/Shipment/List",
|
||||||
|
defaults: new { controller = "Shipment", action = "List", area = AreaNames.ADMIN }
|
||||||
|
);
|
||||||
|
|
||||||
|
endpointRouteBuilder.MapControllerRoute(
|
||||||
|
name: "Plugin.FruitBank.Admin.Invoices.List",
|
||||||
|
pattern: "Admin/Invoices/List",
|
||||||
|
defaults: new { controller = "Invoice", action = "List", area = AreaNames.ADMIN }
|
||||||
|
);
|
||||||
|
|
||||||
|
endpointRouteBuilder.MapControllerRoute(
|
||||||
|
name: "Plugin.FruitBank.Admin.Shipment.Create",
|
||||||
|
pattern: "Admin/Shipment/Create",
|
||||||
|
defaults: new { controller = "Shipment", action = "Create", area = AreaNames.ADMIN });
|
||||||
|
|
||||||
|
endpointRouteBuilder.MapControllerRoute(
|
||||||
|
name: "Plugin.FruitBank.Admin.Shipment.UploadFile",
|
||||||
|
pattern: "Admin/Shipment/UploadFile",
|
||||||
|
defaults: new { controller = "Shipment", action = "UploadFile", area = AreaNames.ADMIN });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a priority of route provider
|
/// Gets a priority of route provider
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Priority => 0;
|
public int Priority => 3000;
|
||||||
}
|
}
|
||||||
|
|
@ -20,6 +20,16 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Content Include="Areas\Admin\Views\Index.cshtml">
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Areas\Admin\Views\_ViewStart.cshtml">
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="logo.jpg">
|
<Content Include="logo.jpg">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
|
@ -33,7 +43,7 @@
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="Areas\Admin\Views\_ViewImports.cshtml">
|
<Content Update="Areas\Admin\Views\_ViewImports.cshtml">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="Views\_ViewImports.cshtml">
|
<Content Update="Views\_ViewImports.cshtml">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
|
@ -56,6 +66,7 @@
|
||||||
<Folder Include="Domains\Entities\" />
|
<Folder Include="Domains\Entities\" />
|
||||||
<Folder Include="Extensions\" />
|
<Folder Include="Extensions\" />
|
||||||
<Folder Include="Validators\" />
|
<Folder Include="Validators\" />
|
||||||
|
<Folder Include="Views\Admin\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
@ -133,16 +144,22 @@
|
||||||
<None Update="Areas\Admin\Views\Configure\Configure.cshtml">
|
<None Update="Areas\Admin\Views\Configure\Configure.cshtml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="Areas\Admin\Views\Invoice\List.cshtml">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<None Update="Areas\Admin\Views\Order\Test.cshtml">
|
<None Update="Areas\Admin\Views\Order\Test.cshtml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="Areas\Admin\Views\Order\List.cshtml">
|
<None Update="Areas\Admin\Views\Order\List.cshtml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="Views\Checkout\PendingMeasurementWarning.cshtml">
|
<None Update="Areas\Admin\Views\Shipment\Create.cshtml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="Views\Admin\Order\List.cshtml">
|
<None Update="Areas\Admin\Views\Shipment\List.cshtml">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Views\Checkout\PendingMeasurementWarning.cshtml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="Views\ProductAIListWidget.cshtml">
|
<None Update="Views\ProductAIListWidget.cshtml">
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,56 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Nop.Core;
|
||||||
using Nop.Core.Domain.Catalog;
|
using Nop.Core.Domain.Catalog;
|
||||||
using Nop.Core.Domain.Orders;
|
using Nop.Core.Domain.Orders;
|
||||||
using Nop.Services.Catalog;
|
using Nop.Services.Catalog;
|
||||||
using Nop.Services.Common;
|
using Nop.Services.Common;
|
||||||
using Nop.Services.Events;
|
using Nop.Services.Events;
|
||||||
|
using Nop.Services.Localization;
|
||||||
using Nop.Services.Orders;
|
using Nop.Services.Orders;
|
||||||
|
using Nop.Services.Plugins;
|
||||||
|
using Nop.Web.Framework.Events;
|
||||||
|
using Nop.Web.Framework.Menu;
|
||||||
|
using Nop.Web.Models.Sitemap;
|
||||||
|
|
||||||
namespace Nop.Plugin.YourCompany.Measurement.Services
|
namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
||||||
{
|
{
|
||||||
public class OrderPlacedConsumer : IConsumer<OrderPlacedEvent>
|
public class EventConsumer : BaseAdminMenuCreatedEventConsumer, IConsumer<OrderPlacedEvent>, IConsumer<AdminMenuCreatedEvent>
|
||||||
{
|
{
|
||||||
private readonly IGenericAttributeService _genericAttributeService;
|
private readonly IGenericAttributeService _genericAttributeService;
|
||||||
private readonly IProductService _productService;
|
private readonly IProductService _productService;
|
||||||
|
private readonly ISpecificationAttributeService _specificationAttributeService;
|
||||||
private readonly IOrderService _orderService;
|
private readonly IOrderService _orderService;
|
||||||
private readonly IProductAttributeService _productAttributeService;
|
private readonly IProductAttributeService _productAttributeService;
|
||||||
|
private readonly IWorkContext _workContext;
|
||||||
|
private readonly IStoreContext _storeContext;
|
||||||
|
private readonly IAdminMenu _adminMenu;
|
||||||
|
private readonly ILocalizationService _localizationService;
|
||||||
|
|
||||||
public OrderPlacedConsumer(
|
public EventConsumer(
|
||||||
IGenericAttributeService genericAttributeService,
|
IGenericAttributeService genericAttributeService,
|
||||||
IProductService productService,
|
IProductService productService,
|
||||||
|
ISpecificationAttributeService specificationAttributeService,
|
||||||
IOrderService orderService,
|
IOrderService orderService,
|
||||||
IProductAttributeService productAttributeService)
|
IProductAttributeService productAttributeService,
|
||||||
|
IPluginManager<IPlugin> pluginManager,
|
||||||
|
IWorkContext workContext,
|
||||||
|
IStoreContext storeContext,
|
||||||
|
IAdminMenu adminMenu,
|
||||||
|
ILocalizationService localizationService) : base(pluginManager)
|
||||||
{
|
{
|
||||||
_genericAttributeService = genericAttributeService;
|
_genericAttributeService = genericAttributeService;
|
||||||
_productService = productService;
|
_productService = productService;
|
||||||
|
_specificationAttributeService = specificationAttributeService;
|
||||||
_orderService = orderService;
|
_orderService = orderService;
|
||||||
_productAttributeService = productAttributeService;
|
_productAttributeService = productAttributeService;
|
||||||
|
_workContext = workContext;
|
||||||
|
_storeContext = storeContext;
|
||||||
|
_adminMenu = adminMenu;
|
||||||
|
_localizationService = localizationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override string PluginSystemName => "Misc.FruitBankPlugin";
|
||||||
|
|
||||||
public async Task HandleEventAsync(OrderPlacedEvent eventMessage)
|
public async Task HandleEventAsync(OrderPlacedEvent eventMessage)
|
||||||
{
|
{
|
||||||
var order = eventMessage.Order;
|
var order = eventMessage.Order;
|
||||||
|
|
@ -41,31 +65,159 @@ namespace Nop.Plugin.YourCompany.Measurement.Services
|
||||||
// akár egy product attribute is lehet, vagy egy saját extension metódus
|
// akár egy product attribute is lehet, vagy egy saját extension metódus
|
||||||
if (product != null)
|
if (product != null)
|
||||||
{
|
{
|
||||||
var productAttributeMappings = await _productAttributeService.GetProductAttributeMappingsByProductIdAsync(product.Id);
|
//var productAttributeMappings = await _productAttributeService.GetProductAttributeMappingsByProductIdAsync(product.Id);
|
||||||
//Product Attributes
|
////Product Attributes
|
||||||
foreach (var pam in productAttributeMappings)
|
//foreach (var pam in productAttributeMappings)
|
||||||
|
//{
|
||||||
|
// var attributes = await _productAttributeService.GetProductAttributeValuesAsync(pam.Id);
|
||||||
|
// foreach (var attr in attributes)
|
||||||
|
// {
|
||||||
|
// // you can check for specific attribute by its name or id
|
||||||
|
// if (attr.Name == "NeedsToBeMeasured" && attr.IsPreSelected)
|
||||||
|
// {
|
||||||
|
// requiresMeasurement = true;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
var productSpecAttributes = await _specificationAttributeService.GetProductSpecificationAttributesAsync(product.Id);
|
||||||
|
|
||||||
|
foreach (var specAttribute in productSpecAttributes)
|
||||||
{
|
{
|
||||||
var attributes = await _productAttributeService.GetProductAttributeValuesAsync(pam.Id);
|
// Get the specification attribute
|
||||||
foreach (var attr in attributes)
|
var specificationAttribute = await _specificationAttributeService
|
||||||
{
|
.GetSpecificationAttributeByIdAsync(specAttribute.Id);
|
||||||
// you can check for specific attribute by its name or id
|
|
||||||
if (attr.Name == "NeedsToBeMeasured" && attr.IsPreSelected)
|
// Get the specification attribute option
|
||||||
|
var specificationAttributeOption = await _specificationAttributeService
|
||||||
|
.GetSpecificationAttributeOptionByIdAsync(specAttribute.SpecificationAttributeOptionId);
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.WriteLine($"Spec Attribute: {specificationAttribute.Name}, Option: {specificationAttributeOption.Name}");
|
||||||
|
|
||||||
|
// Check if this is your "NeedsToBeMeasured" specification attribute
|
||||||
|
if (specificationAttribute.Name == "Measureable" &&
|
||||||
|
specificationAttributeOption.Name == "Yes") // or whatever value you set
|
||||||
{
|
{
|
||||||
requiresMeasurement = true;
|
requiresMeasurement = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requiresMeasurement)
|
if (requiresMeasurement)
|
||||||
{
|
{
|
||||||
|
var store = await _storeContext.GetCurrentStoreAsync();
|
||||||
// itt adjuk hozzá a GenericAttribute flag-et az orderhez
|
// itt adjuk hozzá a GenericAttribute flag-et az orderhez
|
||||||
await _genericAttributeService.SaveAttributeAsync(order,
|
await _genericAttributeService.SaveAttributeAsync(order,
|
||||||
"PendingMeasurement", true);
|
"PendingMeasurement", true, store.Id);
|
||||||
|
// status pending
|
||||||
|
// paymentstatus pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task HandleEventAsync(AdminMenuCreatedEvent eventMessage)
|
||||||
|
{
|
||||||
|
var rootNode = eventMessage.RootMenuItem;
|
||||||
|
|
||||||
|
|
||||||
|
var shipmentsListMenuItem = new AdminMenuItem
|
||||||
|
{
|
||||||
|
Visible = true,
|
||||||
|
SystemName = "FruitBank",
|
||||||
|
Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.ShipmentsList"), // You can localize this with await _localizationService.GetResourceAsync("...")
|
||||||
|
IconClass = "fas fa-shipping-fast",
|
||||||
|
Url = _adminMenu.GetMenuItemUrl("Shipment", "List")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var createShipmentMenuItem = new AdminMenuItem
|
||||||
|
{
|
||||||
|
Visible = true,
|
||||||
|
SystemName = "Shipments.Create",
|
||||||
|
Title = "Create Shipment",
|
||||||
|
IconClass = "far fa-circle",
|
||||||
|
Url = _adminMenu.GetMenuItemUrl("Shipment", "Create")
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new top-level menu item
|
||||||
|
var shipmentsMenuItem = new AdminMenuItem
|
||||||
|
{
|
||||||
|
Visible = true,
|
||||||
|
SystemName = "FruitBank",
|
||||||
|
Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.Shipments"), // You can localize this with await _localizationService.GetResourceAsync("...")
|
||||||
|
IconClass = "fas fa-shipping-fast",
|
||||||
|
//Url = _adminMenu.GetMenuItemUrl("Shipment", "List")
|
||||||
|
ChildNodes = new[] { shipmentsListMenuItem, createShipmentMenuItem }
|
||||||
|
};
|
||||||
|
|
||||||
|
var shipmentConfigurationItem = rootNode;
|
||||||
|
shipmentConfigurationItem.ChildNodes.Insert(2, shipmentsMenuItem);
|
||||||
|
|
||||||
|
|
||||||
|
var invoiceListMenuItem = new AdminMenuItem
|
||||||
|
{
|
||||||
|
Visible = true,
|
||||||
|
SystemName = "FruitBank",
|
||||||
|
Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.InvoicesList"), // You can localize this with await _localizationService.GetResourceAsync("...")
|
||||||
|
IconClass = "fas fa-file-invoice",
|
||||||
|
Url = _adminMenu.GetMenuItemUrl("Invoices", "List")
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new top-level menu item
|
||||||
|
var invoicesMenuItem = new AdminMenuItem
|
||||||
|
{
|
||||||
|
Visible = true,
|
||||||
|
SystemName = "FruitBank",
|
||||||
|
Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.Invoices"), // You can localize this with await _localizationService.GetResourceAsync("...")
|
||||||
|
IconClass = "fas fa-file-invoice",
|
||||||
|
//Url = _adminMenu.GetMenuItemUrl("Shipment", "List")
|
||||||
|
ChildNodes = new[] { invoiceListMenuItem }
|
||||||
|
};
|
||||||
|
|
||||||
|
var invoiceConfigurationItem = rootNode;
|
||||||
|
invoiceConfigurationItem.ChildNodes.Insert(2, invoicesMenuItem);
|
||||||
|
|
||||||
|
|
||||||
|
var configurationItem = rootNode.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Configuration"));
|
||||||
|
if (configurationItem is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var shippingItem = configurationItem.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Shipping"));
|
||||||
|
var widgetsItem = configurationItem.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Widgets"));
|
||||||
|
if (shippingItem is null && widgetsItem is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var index = shippingItem is not null ? configurationItem.ChildNodes.IndexOf(shippingItem) : -1;
|
||||||
|
if (index < 0)
|
||||||
|
index = widgetsItem is not null ? configurationItem.ChildNodes.IndexOf(widgetsItem) : -1;
|
||||||
|
if (index < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
configurationItem.ChildNodes.Insert(index + 1, new AdminMenuItem
|
||||||
|
{
|
||||||
|
|
||||||
|
Visible = true,
|
||||||
|
SystemName = "FruitBank",
|
||||||
|
Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.AI"),
|
||||||
|
IconClass = "far fa-dot-circle",
|
||||||
|
ChildNodes = new List<AdminMenuItem>
|
||||||
|
{
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
|
||||||
|
Visible = true,
|
||||||
|
SystemName = "FruitBank",
|
||||||
|
Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.Configure"),
|
||||||
|
IconClass = "far fa-circle",
|
||||||
|
Url = _adminMenu.GetMenuItemUrl("FruitBankPlugin", "Configure"),
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,657 +0,0 @@
|
||||||
@model OrderSearchModel
|
|
||||||
|
|
||||||
@inject IStoreService storeService
|
|
||||||
@using Nop.Services.Stores
|
|
||||||
|
|
||||||
@{
|
|
||||||
//page title
|
|
||||||
ViewBag.PageTitle = T("Admin.Orders").Text;
|
|
||||||
//active menu item (system name)
|
|
||||||
NopHtml.SetActiveMenuItemSystemName("Orders");
|
|
||||||
}
|
|
||||||
|
|
||||||
@{
|
|
||||||
const string hideSearchBlockAttributeName = "OrdersPage.HideSearchBlock";
|
|
||||||
var hideSearchBlock = await genericAttributeService.GetAttributeAsync<bool>(await workContext.GetCurrentCustomerAsync(), hideSearchBlockAttributeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (Model.LicenseCheckModel.BlockPages != true)
|
|
||||||
{
|
|
||||||
<form asp-controller="Order" asp-action="List" method="post">
|
|
||||||
<div class="content-header clearfix">
|
|
||||||
<h1 class="float-left">
|
|
||||||
@T("Admin.Orders")
|
|
||||||
</h1>
|
|
||||||
<div class="float-right">
|
|
||||||
<div class="btn-group">
|
|
||||||
<button type="button" class="btn btn-success">
|
|
||||||
<i class="fas fa-download"></i>
|
|
||||||
@T("Admin.Common.Export")
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-success dropdown-toggle dropdown-icon" data-toggle="dropdown" aria-expanded="false">
|
|
||||||
<span class="sr-only"> </span>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu" role="menu">
|
|
||||||
<li class="dropdown-item">
|
|
||||||
<button asp-action="ExportXml" type="submit" name="exportxml-all">
|
|
||||||
<i class="far fa-file-code"></i>
|
|
||||||
@T("Admin.Common.ExportToXml.All")
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li class="dropdown-item">
|
|
||||||
<button type="button" id="exportxml-selected">
|
|
||||||
<i class="far fa-file-code"></i>
|
|
||||||
@T("Admin.Common.ExportToXml.Selected")
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li class="dropdown-divider"></li>
|
|
||||||
<li class="dropdown-item">
|
|
||||||
<button asp-action="ExportExcel" type="submit" name="exportexcel-all">
|
|
||||||
<i class="far fa-file-excel"></i>
|
|
||||||
@T("Admin.Common.ExportToExcel.All")
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li class="dropdown-item">
|
|
||||||
<button type="button" id="exportexcel-selected">
|
|
||||||
<i class="far fa-file-excel"></i>
|
|
||||||
@T("Admin.Common.ExportToExcel.Selected")
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<button type="button" name="importexcel" class="btn bg-olive" data-toggle="modal" data-target="#importexcel-window">
|
|
||||||
<i class="fas fa-upload"></i>
|
|
||||||
@T("Admin.Common.Import")
|
|
||||||
</button>
|
|
||||||
<div class="btn-group">
|
|
||||||
<button type="button" class="btn btn-info">
|
|
||||||
<i class="far fa-file-pdf"></i>
|
|
||||||
@T("Admin.Orders.PdfInvoices")
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-info dropdown-toggle dropdown-icon" data-toggle="dropdown" aria-expanded="false">
|
|
||||||
<span class="sr-only"> </span>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu" role="menu">
|
|
||||||
<li class="dropdown-item">
|
|
||||||
<button asp-action="PdfInvoice" type="submit" name="pdf-invoice-all">
|
|
||||||
@T("Admin.Orders.PdfInvoices.All")
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li class="dropdown-item">
|
|
||||||
<button type="button" id="pdf-invoice-selected">
|
|
||||||
@T("Admin.Orders.PdfInvoices.Selected")
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
@await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.OrderListButtons, additionalData = Model })
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<section class="content">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="form-horizontal">
|
|
||||||
<div class="cards-group">
|
|
||||||
<div class="card card-default card-search">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row search-row @(!hideSearchBlock ? "opened" : "")" data-hideAttribute="@hideSearchBlockAttributeName">
|
|
||||||
<div class="search-text">@T("Admin.Common.Search")</div>
|
|
||||||
<div class="icon-search"><i class="fas fa-magnifying-glass" aria-hidden="true"></i></div>
|
|
||||||
<div class="icon-collapse"><i class="far fa-angle-@(!hideSearchBlock ? "up" : "down")" aria-hidden="true"></i></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-body @(hideSearchBlock ? "closed" : "")">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-5">
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="StartDate" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-editor asp-for="StartDate" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="EndDate" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-editor asp-for="EndDate" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row" @(Model.AvailableWarehouses.SelectionIsNotPossible() ? Html.Raw("style=\"display:none\"") : null)>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="WarehouseId" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-select asp-for="WarehouseId" asp-items="Model.AvailableWarehouses" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="ProductId" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<input type="text" id="search-product-name" autocomplete="off" class="form-control" />
|
|
||||||
<span id="search-product-friendly-name"></span>
|
|
||||||
<button type="button" id="search-product-clear" class="btn bg-gray" style="display: none; margin-top: 5px;">@T("Admin.Common.Clear")</button>
|
|
||||||
<input asp-for="ProductId" autocomplete="off" style="display: none;" />
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$('#search-product-name').autocomplete({
|
|
||||||
delay: 500,
|
|
||||||
minLength: 3,
|
|
||||||
source: '@Url.Action("SearchAutoComplete", "SearchComplete")',
|
|
||||||
select: function(event, ui) {
|
|
||||||
$('#@Html.IdFor(model => model.ProductId)').val(ui.item.productid);
|
|
||||||
$('#search-product-friendly-name').text(ui.item.label);
|
|
||||||
|
|
||||||
$('#search-product-clear').show();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//remove button
|
|
||||||
$('#search-product-clear').click(function() {
|
|
||||||
$('#@Html.IdFor(model => model.ProductId)').val('0');
|
|
||||||
$('#search-product-friendly-name').text('');
|
|
||||||
$('#search-product-clear').hide();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row" @(Model.IsLoggedInAsVendor ? Html.Raw("style='display: none;'") : null)>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="OrderStatusIds" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-select asp-for="OrderStatusIds" asp-items="Model.AvailableOrderStatuses" asp-multiple="true" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="PaymentStatusIds" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-select asp-for="PaymentStatusIds" asp-items="Model.AvailablePaymentStatuses" asp-multiple="true" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row" @(Model.IsLoggedInAsVendor ? Html.Raw("style='display: none;'") : null)>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="ShippingStatusIds" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-select asp-for="ShippingStatusIds" asp-items="Model.AvailableShippingStatuses" asp-multiple="true" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-7">
|
|
||||||
<div class="form-group row" @(Model.HideStoresList ? Html.Raw("style=\"display:none\"") : null)>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="StoreId" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-select asp-for="StoreId" asp-items="Model.AvailableStores" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row" @(Model.AvailableVendors.SelectionIsNotPossible() || Model.IsLoggedInAsVendor ? Html.Raw("style='display: none;'") : null)>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="VendorId" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-select asp-for="VendorId" asp-items="Model.AvailableVendors" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@if (Model.BillingPhoneEnabled)
|
|
||||||
{
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="BillingPhone" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-editor asp-for="BillingPhone" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="BillingEmail" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-editor asp-for="BillingEmail" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="BillingLastName" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-editor asp-for="BillingLastName" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row" @(Model.AvailableCountries.SelectionIsNotPossible() ? Html.Raw("style=\"display:none\"") : null)>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="BillingCountryId" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-select asp-for="BillingCountryId" asp-items="Model.AvailableCountries" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row" @(Model.AvailablePaymentMethods.SelectionIsNotPossible() || Model.IsLoggedInAsVendor ? Html.Raw("style='display: none;'") : null)>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="PaymentMethodSystemName" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-select asp-for="PaymentMethodSystemName" asp-items="Model.AvailablePaymentMethods" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="OrderNotes" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<nop-editor asp-for="OrderNotes" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<nop-label asp-for="GoDirectlyToCustomOrderNumber" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<div class="input-group input-group-short">
|
|
||||||
<nop-editor asp-for="GoDirectlyToCustomOrderNumber" />
|
|
||||||
<span class="input-group-append">
|
|
||||||
<button type="submit" id="go-to-order-by-number" name="go-to-order-by-number" class="btn btn-info btn-flat">
|
|
||||||
@T("Admin.Common.Go")
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="text-center col-12">
|
|
||||||
<button type="button" id="search-orders" class="btn btn-primary btn-search">
|
|
||||||
<i class="fas fa-magnifying-glass"></i>
|
|
||||||
@T("Admin.Common.Search")
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card card-default">
|
|
||||||
<h1>
|
|
||||||
khfdsjklfkl fklsh fjsklhfjskl fhsjklhf sjklhfdsklhf djkfldsh fjklsdjkl
|
|
||||||
</h1>
|
|
||||||
<div class="card-body">
|
|
||||||
<nop-doc-reference asp-string-resource="@T("Admin.Documentation.Reference.Orders", Docs.Orders + Utm.OnAdmin)" />
|
|
||||||
|
|
||||||
@{
|
|
||||||
var gridModel = new DataTablesModel
|
|
||||||
{
|
|
||||||
Name = "orders-grid",
|
|
||||||
UrlRead = new DataUrl("OrderList", "Order", null),
|
|
||||||
SearchButtonId = "search-orders",
|
|
||||||
Length = Model.PageSize,
|
|
||||||
LengthMenu = Model.AvailablePageSizes,
|
|
||||||
FooterCallback = !Model.IsLoggedInAsVendor ? "ordersfootercallback" : null,
|
|
||||||
FooterColumns = !Model.IsLoggedInAsVendor ? 10 : 0,
|
|
||||||
Filters = new List<FilterParameter>
|
|
||||||
{
|
|
||||||
new FilterParameter(nameof(Model.StartDate), typeof(DateTime?)),
|
|
||||||
new FilterParameter(nameof(Model.EndDate), typeof(DateTime?)),
|
|
||||||
new FilterParameter(nameof(Model.OrderStatusIds)),
|
|
||||||
new FilterParameter(nameof(Model.PaymentStatusIds)),
|
|
||||||
new FilterParameter(nameof(Model.ShippingStatusIds)),
|
|
||||||
new FilterParameter(nameof(Model.StoreId)),
|
|
||||||
new FilterParameter(nameof(Model.VendorId)),
|
|
||||||
new FilterParameter(nameof(Model.WarehouseId)),
|
|
||||||
new FilterParameter(nameof(Model.BillingEmail)),
|
|
||||||
new FilterParameter(nameof(Model.BillingPhone)),
|
|
||||||
new FilterParameter(nameof(Model.BillingLastName)),
|
|
||||||
new FilterParameter(nameof(Model.BillingCountryId)),
|
|
||||||
new FilterParameter(nameof(Model.PaymentMethodSystemName)),
|
|
||||||
new FilterParameter(nameof(Model.ProductId)),
|
|
||||||
new FilterParameter(nameof(Model.OrderNotes))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
gridModel.ColumnCollection = new List<ColumnProperty>
|
|
||||||
{
|
|
||||||
new ColumnProperty(nameof(OrderModel.Id))
|
|
||||||
{
|
|
||||||
IsMasterCheckBox = true,
|
|
||||||
Render = new RenderCheckBox("checkbox_orders"),
|
|
||||||
ClassName = NopColumnClassDefaults.CenterAll,
|
|
||||||
Width = "50"
|
|
||||||
},
|
|
||||||
new ColumnProperty(nameof(OrderModel.CustomOrderNumber))
|
|
||||||
{
|
|
||||||
Title = T("Admin.Orders.Fields.CustomOrderNumber").Text,
|
|
||||||
Width = "80"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModelExtended.NeedsMeasurement))
|
|
||||||
{
|
|
||||||
Title = "Needs Measurement",
|
|
||||||
Width = "100",
|
|
||||||
Render = new RenderCustom("renderColumnNeedsMeasurement"),
|
|
||||||
ClassName = NopColumnClassDefaults.CenterAll
|
|
||||||
});
|
|
||||||
|
|
||||||
//a vendor does not have access to this functionality
|
|
||||||
if (!Model.IsLoggedInAsVendor)
|
|
||||||
{
|
|
||||||
gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.OrderStatus))
|
|
||||||
{
|
|
||||||
Title = T("Admin.Orders.Fields.OrderStatus").Text,
|
|
||||||
Width = "100",
|
|
||||||
Render = new RenderCustom("renderColumnOrderStatus")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.PaymentStatus))
|
|
||||||
{
|
|
||||||
Title = T("Admin.Orders.Fields.PaymentStatus").Text,
|
|
||||||
Width = "150"
|
|
||||||
});
|
|
||||||
//a vendor does not have access to this functionality
|
|
||||||
if (!Model.IsLoggedInAsVendor)
|
|
||||||
{
|
|
||||||
gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.ShippingStatus))
|
|
||||||
{
|
|
||||||
Title = T("Admin.Orders.Fields.ShippingStatus").Text,
|
|
||||||
Width = "150"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.CustomerEmail))
|
|
||||||
{
|
|
||||||
Title = T("Admin.Orders.Fields.Customer").Text,
|
|
||||||
Render = new RenderCustom("renderColumnCustomer")
|
|
||||||
});
|
|
||||||
gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.StoreName))
|
|
||||||
{
|
|
||||||
Title = T("Admin.Orders.Fields.Store").Text,
|
|
||||||
Width = "100",
|
|
||||||
Visible = (await storeService.GetAllStoresAsync()).Count > 1
|
|
||||||
});
|
|
||||||
gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.CreatedOn))
|
|
||||||
{
|
|
||||||
Title = T("Admin.Orders.Fields.CreatedOn").Text,
|
|
||||||
Width = "120",
|
|
||||||
Render = new RenderDate()
|
|
||||||
});
|
|
||||||
//a vendor does not have access to this functionality
|
|
||||||
if (!Model.IsLoggedInAsVendor)
|
|
||||||
{
|
|
||||||
gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.OrderTotal))
|
|
||||||
{
|
|
||||||
Title = T("Admin.Orders.Fields.OrderTotal").Text,
|
|
||||||
Width = "100",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.Id))
|
|
||||||
{
|
|
||||||
Title = T("Admin.Common.View").Text,
|
|
||||||
Width = "50",
|
|
||||||
ClassName = NopColumnClassDefaults.Button,
|
|
||||||
Render = new RenderButtonView(new DataUrl("~/Admin/Order/Edit"))
|
|
||||||
});
|
|
||||||
var orderSummaryColumnNumber = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
@await Html.PartialAsync("Table", gridModel)
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function renderColumnOrderStatus(data, type, row, meta) {
|
|
||||||
var color;
|
|
||||||
switch (row.OrderStatusId) {
|
|
||||||
case 10:
|
|
||||||
color = 'yellow';
|
|
||||||
break;
|
|
||||||
case 20:
|
|
||||||
color = 'blue';
|
|
||||||
break;
|
|
||||||
case 30:
|
|
||||||
color = 'green';
|
|
||||||
break;
|
|
||||||
case 40:
|
|
||||||
color = 'red';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return '<span class="grid-report-item ' + color + '">' + data + '</span >';
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderColumnCustomer(data, type, row, meta) {
|
|
||||||
var link = '@Url.Content("~/Admin/Customer/Edit/")' + row.CustomerId;
|
|
||||||
var textRenderer = $.fn.dataTable.render.text().display;
|
|
||||||
return `${textRenderer(row.CustomerFullName)} <br /><a href="${link}">${data}</a > `;
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderColumnNeedsMeasurement(data, type, row, meta) {
|
|
||||||
if(data === true) {
|
|
||||||
return '<span class="badge badge-warning">Yes</span>';
|
|
||||||
}
|
|
||||||
return '<span class="badge badge-secondary">No</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$(function() {
|
|
||||||
$("#@Html.IdFor(model => model.GoDirectlyToCustomOrderNumber)").keydown(
|
|
||||||
function(event) {
|
|
||||||
if (event.keyCode === 13) {
|
|
||||||
$("#go-to-order-by-number").trigger("click");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
function ordersfootercallback(tfoot, data, start, end, display) {
|
|
||||||
//update order totals summary
|
|
||||||
var postData = {
|
|
||||||
StartDate: $('#@Html.IdFor(model => model.StartDate)').val(),
|
|
||||||
EndDate: $('#@Html.IdFor(model => model.EndDate)').val(),
|
|
||||||
OrderStatusIds: $('#@Html.IdFor(model => model.OrderStatusIds)').val(),
|
|
||||||
PaymentStatusIds: $('#@Html.IdFor(model => model.PaymentStatusIds)').val(),
|
|
||||||
ShippingStatusIds: $('#@Html.IdFor(model => model.ShippingStatusIds)').val(),
|
|
||||||
StoreId: $('#@Html.IdFor(model => model.StoreId)').val(),
|
|
||||||
VendorId: $('#@Html.IdFor(model => model.VendorId)').val(),
|
|
||||||
WarehouseId: $('#@Html.IdFor(model => model.WarehouseId)').val(),
|
|
||||||
BillingEmail: $('#@Html.IdFor(model => model.BillingEmail)').val(),
|
|
||||||
BillingPhone: $('#@Html.IdFor(model => model.BillingPhone)').val(),
|
|
||||||
BillingLastName: $('#@Html.IdFor(model => model.BillingLastName)').val(),
|
|
||||||
BillingCountryId: $('#@Html.IdFor(model => model.BillingCountryId)').val(),
|
|
||||||
PaymentMethodSystemName: $('#@Html.IdFor(model => model.PaymentMethodSystemName)').val(),
|
|
||||||
ProductId: $('#@Html.IdFor(model => model.ProductId)').val(),
|
|
||||||
OrderNotes: $('#@Html.IdFor(model => model.OrderNotes)').val()
|
|
||||||
};
|
|
||||||
addAntiForgeryToken(postData);
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
type: "POST",
|
|
||||||
url: "@(Url.Action("ReportAggregates", "Order"))",
|
|
||||||
data: postData,
|
|
||||||
success: function (data, textStatus, jqXHR) {
|
|
||||||
if (data) {
|
|
||||||
for (var key in data) {
|
|
||||||
var reportSummary = '<div><strong>@T("Admin.Orders.Report.Summary").Text</strong></div>' +
|
|
||||||
'<div>@T("Admin.Orders.Report.Profit").Text <span>' + data['AggregatorProfit'] +'</span></div>' +
|
|
||||||
'<div>@T("Admin.Orders.Report.Shipping").Text <span>' + data['AggregatorShipping'] + '</span></div>' +
|
|
||||||
'<div>@T("Admin.Orders.Report.Tax").Text <span>' + data['AggregatorTax'] + '</span></div>' +
|
|
||||||
'<div>@T("Admin.Orders.Report.Total").Text <span>' + data['AggregatorTotal'] + '</span></div>'
|
|
||||||
var orderTotalsColumn = $('#orders-grid').DataTable().column(@(orderSummaryColumnNumber));
|
|
||||||
$(orderTotalsColumn.footer()).html(reportSummary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</form>
|
|
||||||
}
|
|
||||||
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
var displayModal = @((Model.LicenseCheckModel.DisplayWarning == true || Model.LicenseCheckModel?.BlockPages == true).ToString().ToLower());
|
|
||||||
if (displayModal){
|
|
||||||
$('#license-window').modal({
|
|
||||||
backdrop: 'static',
|
|
||||||
keyboard: false
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#license-window').on('shown.bs.modal', function (event) {
|
|
||||||
var modalCloseEl = $(this).find('button.close');
|
|
||||||
var closeTextEl = $('span', modalCloseEl);
|
|
||||||
|
|
||||||
var startFrom = 5;
|
|
||||||
closeTextEl.text(startFrom);
|
|
||||||
|
|
||||||
const timer = setInterval(function() {
|
|
||||||
if (startFrom-- > 0)
|
|
||||||
closeTextEl.text(startFrom);
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
closeTextEl.html('×');
|
|
||||||
modalCloseEl.on('click', function() {
|
|
||||||
$('#license-window').modal('hide')
|
|
||||||
});
|
|
||||||
clearInterval(timer);
|
|
||||||
}, startFrom*1000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<div id="license-window" class="modal fade" tabindex="-1" role="dialog">
|
|
||||||
<div class="modal-dialog" role="document">
|
|
||||||
<div class="modal-content">
|
|
||||||
@Html.Raw(Model.LicenseCheckModel?.WarningText)
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@*export selected (XML). We don't use GET approach because it's limited to 2K-4K chars and won't work for large number of entities*@
|
|
||||||
<form asp-controller="Order" asp-action="ExportXmlSelected" method="post" id="export-xml-selected-form">
|
|
||||||
<input type="hidden" id="selectedIds" name="selectedIds" value="" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$('#exportxml-selected').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
var ids = selectedIds.join(",");
|
|
||||||
if (!ids) {
|
|
||||||
$('#exportXmlSelected-info').text("@T("Admin.Orders.NoOrders")");
|
|
||||||
$("#exportXmlSelected").trigger("click");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$('#export-xml-selected-form #selectedIds').val(ids);
|
|
||||||
$('#export-xml-selected-form').submit();
|
|
||||||
updateTable('#orders-grid');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<nop-alert asp-alert-id="exportXmlSelected" />
|
|
||||||
|
|
||||||
@*export selected (Excel). We don't use GET approach because it's limited to 2K-4K chars and won't work for large number of entities*@
|
|
||||||
<form asp-controller="Order" asp-action="ExportExcelSelected" method="post" id="export-excel-selected-form">
|
|
||||||
<input type="hidden" id="selectedIds" name="selectedIds" value="" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$('#exportexcel-selected').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
var ids = selectedIds.join(",");
|
|
||||||
if (!ids) {
|
|
||||||
$('#exportExcelSelected-info').text("@T("Admin.Orders.NoOrders")");
|
|
||||||
$("#exportExcelSelected").trigger("click");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$('#export-excel-selected-form #selectedIds').val(ids);
|
|
||||||
$('#export-excel-selected-form').submit();
|
|
||||||
updateTable('#orders-grid');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<nop-alert asp-alert-id="exportExcelSelected" />
|
|
||||||
|
|
||||||
@*Print packaging slips selected (XML). We don't use GET approach because it's limited to 2K-4K chars and won't work for large number of entities*@
|
|
||||||
<form asp-controller="Order" asp-action="PdfInvoiceSelected" method="post" id="pdf-invoice-selected-form">
|
|
||||||
<input type="hidden" id="selectedIds" name="selectedIds" value="" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$('#pdf-invoice-selected').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
var ids = selectedIds.join(",");
|
|
||||||
if (!ids) {
|
|
||||||
$('#pdfInvoiceSelected-info').text("@T("Admin.Orders.NoOrders")");
|
|
||||||
$("#pdfInvoiceSelected").trigger("click");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$('#pdf-invoice-selected-form #selectedIds').val(ids);
|
|
||||||
$('#pdf-invoice-selected-form').submit();
|
|
||||||
updateTable('#orders-grid');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<nop-alert asp-alert-id="pdfInvoiceSelected" />
|
|
||||||
|
|
||||||
@*import orders form*@
|
|
||||||
<div id="importexcel-window" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="importexcel-window-title">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h4 class="modal-title" id="importexcel-window-title">@T("Admin.Common.ImportFromExcel")</h4>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
|
||||||
</div>
|
|
||||||
<form asp-controller="Order" asp-action="ImportFromXlsx" method="post" enctype="multipart/form-data">
|
|
||||||
<div class="form-horizontal">
|
|
||||||
<div class="modal-body">
|
|
||||||
<ul class="common-list">
|
|
||||||
<li>
|
|
||||||
<em>@T("Admin.Orders.List.ImportFromExcelTip")</em>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<em>@T("Admin.Common.ImportFromExcel.ManyRecordsWarning")</em>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-md-2">
|
|
||||||
<div class="label-wrapper">
|
|
||||||
<label class="col-form-label">
|
|
||||||
@T("Admin.Common.ExcelFile")
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-10">
|
|
||||||
<input type="file" id="importexcelfile" name="importexcelfile" class="form-control" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-primary">
|
|
||||||
@T("Admin.Common.ImportFromExcel")
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue