admin starts

This commit is contained in:
Adam 2025-09-20 11:01:13 +02:00
parent 4c4bc11335
commit 68b8f523f2
11 changed files with 1605 additions and 2 deletions

View File

@ -0,0 +1,654 @@
@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">&nbsp;</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">&nbsp;</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">
<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('&times;');
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">&times;</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>

View File

@ -0,0 +1,4 @@
@{
Layout = "_AdminLayout";
}
<h1>TEST VIEW FROM PLUGIN</h1>

View File

@ -0,0 +1,213 @@
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Routing;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Shipping;
using Nop.Core.Domain.Tax;
using Nop.Core;
using Nop.Plugin.Misc.FruitBankPlugin.Services;
using Nop.Services.Affiliates;
using Nop.Services.Catalog;
using Nop.Services.Common;
using Nop.Services.Configuration;
using Nop.Services.Customers;
using Nop.Services.Directory;
using Nop.Services.Discounts;
using Nop.Services.Helpers;
using Nop.Services.Localization;
using Nop.Services.Media;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Nop.Services.Security;
using Nop.Services.Seo;
using Nop.Services.Shipping;
using Nop.Services.Stores;
using Nop.Services.Tax;
using Nop.Services.Vendors;
using Nop.Web.Areas.Admin.Factories;
using Nop.Web.Areas.Admin.Models.Orders;
using Nop.Plugin.Misc.FruitBankPlugin.Models;
using System.Reflection;
using Nop.Plugin.Misc.FruitBankPlugin.Helpers;
namespace Nop.Plugin.Misc.FruitBankPlugin.Factories
{
public class CustomOrderModelFactory : OrderModelFactory
{
private readonly IOrderMeasurementService _orderMeasurementService;
public CustomOrderModelFactory(
IOrderMeasurementService orderMeasurementService,
AddressSettings addressSettings,
CatalogSettings catalogSettings,
CurrencySettings currencySettings,
IActionContextAccessor actionContextAccessor,
IAddressModelFactory addressModelFactory,
IAddressService addressService,
IAffiliateService affiliateService,
IBaseAdminModelFactory baseAdminModelFactory,
ICountryService countryService,
ICurrencyService currencyService,
ICustomerService customerService,
IDateTimeHelper dateTimeHelper,
IDiscountService discountService,
IDownloadService downloadService,
IEncryptionService encryptionService,
IGiftCardService giftCardService,
ILocalizationService localizationService,
IMeasureService measureService,
IOrderProcessingService orderProcessingService,
IOrderReportService orderReportService,
IOrderService orderService,
IPaymentPluginManager paymentPluginManager,
IPaymentService paymentService,
IPictureService pictureService,
IPriceCalculationService priceCalculationService,
IPriceFormatter priceFormatter,
IProductAttributeService productAttributeService,
IProductService productService,
IReturnRequestService returnRequestService,
IRewardPointService rewardPointService,
ISettingService settingService,
IShipmentService shipmentService,
IShippingService shippingService,
IStateProvinceService stateProvinceService,
IStoreService storeService,
ITaxService taxService,
IUrlHelperFactory urlHelperFactory,
IVendorService vendorService,
IWorkContext workContext,
MeasureSettings measureSettings,
NopHttpClient nopHttpClient,
OrderSettings orderSettings,
ShippingSettings shippingSettings,
IUrlRecordService urlRecordService,
TaxSettings taxSettings
) : base(addressSettings,
catalogSettings,
currencySettings,
actionContextAccessor,
addressModelFactory,
addressService,
affiliateService,
baseAdminModelFactory,
countryService,
currencyService,
customerService,
dateTimeHelper,
discountService,
downloadService,
encryptionService,
giftCardService,
localizationService,
measureService,
orderProcessingService,
orderReportService,
orderService,
paymentPluginManager,
paymentService,
pictureService,
priceCalculationService,
priceFormatter,
productAttributeService,
productService,
returnRequestService,
rewardPointService,
settingService,
shipmentService,
shippingService,
stateProvinceService,
storeService,
taxService,
urlHelperFactory,
vendorService,
workContext,
measureSettings,
nopHttpClient,
orderSettings,
shippingSettings,
urlRecordService,
taxSettings
)
{
_orderMeasurementService = orderMeasurementService;
}
public override async Task<OrderSearchModel> PrepareOrderSearchModelAsync(OrderSearchModel searchModel)
{
// let base prepare default model first
var baseModel = await base.PrepareOrderSearchModelAsync(searchModel);
// create derived/extended instance
var extended = new OrderSearchModelExtended();
// copy all public instance properties from baseModel to extended
CopyModelHelper.CopyPublicProperties(baseModel, extended);
// try to obtain NeedsMeasurement from the incoming searchModel (if it's extended)
bool? needsMeasurement = null;
var prop = searchModel?.GetType().GetProperty("NeedsMeasurement", BindingFlags.Public | BindingFlags.Instance);
if (prop != null && prop.PropertyType == typeof(bool?))
{
needsMeasurement = (bool?)prop.GetValue(searchModel);
}
extended.NeedsMeasurement = needsMeasurement;
// return the extended object (it's assignable to OrderSearchModel)
return extended;
}
public override async Task<OrderListModel> PrepareOrderListModelAsync(OrderSearchModel searchModel)
{
// get the default model first
var baseModel = await base.PrepareOrderListModelAsync(searchModel);
// project the rows into your extended row type
var extendedRows = baseModel.Data.Select(async order => new OrderModelExtended
{
Id = order.Id,
CustomOrderNumber = order.CustomOrderNumber,
OrderStatus = order.OrderStatus,
PaymentStatus = order.PaymentStatus,
ShippingStatus = order.ShippingStatus,
OrderTotal = order.OrderTotal,
CreatedOn = order.CreatedOn,
// custom field
NeedsMeasurement = await ShouldMarkAsNeedsMeasurementAsync(order)
}).ToList();
// build a new OrderListModel but replace Data with the extended items
var model = new OrderListModel
{
Data = extendedRows.Cast<OrderModel>().ToList(), // still satisfies the grid
//Total = baseModel.Total
};
return model;
}
// example async custom logic
private async Task<bool> ShouldMarkAsNeedsMeasurementAsync(OrderModel order)
{
// TODO: your logic (e.g. check if order has products that need measuring)
if (order == null)
return false;
var fullOrder = await _orderService.GetOrderByIdAsync(order.Id);
if (fullOrder != null)
{
return await _orderMeasurementService.IsPendingMeasurementAsync(fullOrder);
}
return await Task.FromResult(false);
}
}
}

View File

@ -39,6 +39,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Filters
if (order != null && await _orderMeasurementService.IsPendingMeasurementAsync(order))
{
order.OrderStatus = OrderStatus.Processing;
context.Result = new RedirectToRouteResult(new
{
controller = "Checkout",

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Nop.Plugin.Misc.FruitBankPlugin.Helpers
{
public static class CopyModelHelper
{
public static void CopyPublicProperties<TSource, TDestination>(TSource src, TDestination dest)
{
if (src == null || dest == null) return;
var srcProps = typeof(TSource)
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanRead);
foreach (var sp in srcProps)
{
var dp = typeof(TDestination).GetProperty(sp.Name, BindingFlags.Public | BindingFlags.Instance);
if (dp == null || !dp.CanWrite) continue;
dp.SetValue(dest, sp.GetValue(src));
}
}
}
}

View File

@ -13,9 +13,14 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Nop.Core.Infrastructure;
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
using Nop.Plugin.Misc.FruitBankPlugin.Factories;
using Nop.Plugin.Misc.FruitBankPlugin.Filters;
using Nop.Plugin.Misc.FruitBankPlugin.Models;
using Nop.Plugin.Misc.FruitBankPlugin.Services;
using Nop.Services.Catalog;
using Nop.Web.Areas.Admin.Factories;
using Nop.Web.Areas.Admin.Models.Catalog;
using Nop.Web.Areas.Admin.Models.Orders;
using FruitBankDataController = Nop.Plugin.Misc.FruitBankPlugin.Controllers.FruitBankDataController;
namespace Nop.Plugin.Misc.FruitBankPlugin.Infrastructure;
@ -55,6 +60,10 @@ public class PluginNopStartup : INopStartup
services.AddScoped<PriceCalculationService, CustomPriceCalculationService>();
services.AddScoped<IOrderMeasurementService, OrderMeasurementService>();
services.AddScoped<PendingMeasurementCheckoutFilter>();
services.AddScoped<OrderListModel, OrderListModelExtended>();
services.AddScoped<OrderModel, OrderModelExtended>();
services.AddScoped<OrderSearchModel, OrderSearchModelExtended>();
services.AddScoped<OrderModelFactory, CustomOrderModelFactory>();
services.AddControllersWithViews(options =>
{
options.Filters.AddService<PendingMeasurementCheckoutFilter>();

View File

@ -0,0 +1,10 @@
using Nop.Web.Areas.Admin.Models.Orders;
namespace Nop.Plugin.Misc.FruitBankPlugin.Models
{
public partial record OrderListModelExtended : OrderListModel
{
public bool? NeedsMeasurement { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using Nop.Web.Areas.Admin.Models.Orders;
namespace Nop.Plugin.Misc.FruitBankPlugin.Models
{
public partial record OrderModelExtended : OrderModel
{
public bool NeedsMeasurement { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using Nop.Web.Areas.Admin.Models.Orders;
namespace Nop.Plugin.Misc.FruitBankPlugin.Models
{
public partial record OrderSearchModelExtended : OrderSearchModel
{
public bool? NeedsMeasurement { get; set; }
}
}

View File

@ -55,8 +55,6 @@
<Folder Include="Areas\Admin\Validators\" />
<Folder Include="Domains\Entities\" />
<Folder Include="Extensions\" />
<Folder Include="Factories\" />
<Folder Include="Models\" />
<Folder Include="Validators\" />
</ItemGroup>
@ -135,9 +133,18 @@
<None Update="Areas\Admin\Views\Configure\Configure.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Areas\Admin\Views\Order\Test.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Areas\Admin\Views\Order\List.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Views\Checkout\PendingMeasurementWarning.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Views\Admin\Order\List.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Views\ProductAIListWidget.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>

View File

@ -0,0 +1,657 @@
@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">&nbsp;</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">&nbsp;</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('&times;');
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">&times;</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>