diff --git a/src/Libraries/Nop.Core/Domain/Catalog/LowStockProductReportLine.cs b/src/Libraries/Nop.Core/Domain/Catalog/LowStockProductReportLine.cs new file mode 100644 index 00000000000..5c7118bd41d --- /dev/null +++ b/src/Libraries/Nop.Core/Domain/Catalog/LowStockProductReportLine.cs @@ -0,0 +1,37 @@ +namespace Nop.Core.Domain.Catalog; + +/// +/// Represents low stock report line +/// +public partial class LowStockProductReportLine +{ + /// + /// Product Id + /// + public int Id { get; set; } + + /// + /// Product Name + /// + public string Name { get; set; } + + /// + /// Product Attributes + /// + public string Attributes { get; set; } + + /// + /// Manage Inventory Method + /// + public string ManageInventoryMethod { get; set; } + + /// + /// Stock Quantity + /// + public int StockQuantity { get; set; } + + /// + /// Published + /// + public bool Published { get; set; } +} \ No newline at end of file diff --git a/src/Libraries/Nop.Core/Domain/Customers/BestCustomerReportLine.cs b/src/Libraries/Nop.Core/Domain/Customers/BestCustomerReportLine.cs index a7cd7a78f05..6886d7c2e19 100644 --- a/src/Libraries/Nop.Core/Domain/Customers/BestCustomerReportLine.cs +++ b/src/Libraries/Nop.Core/Domain/Customers/BestCustomerReportLine.cs @@ -9,12 +9,21 @@ public partial class BestCustomerReportLine /// Gets or sets the customer identifier /// public int CustomerId { get; set; } + /// + /// Gets or sets the customer name + /// + public string CustomerName { get; set; } /// /// Gets or sets the order total /// public decimal OrderTotal { get; set; } + /// + /// Gets or sets the order total string + /// + public string OrderTotalStr { get; set; } + /// /// Gets or sets the order count /// diff --git a/src/Libraries/Nop.Core/Domain/Customers/RegisteredCustomersReportLine.cs b/src/Libraries/Nop.Core/Domain/Customers/RegisteredCustomersReportLine.cs new file mode 100644 index 00000000000..2683f0089da --- /dev/null +++ b/src/Libraries/Nop.Core/Domain/Customers/RegisteredCustomersReportLine.cs @@ -0,0 +1,17 @@ +namespace Nop.Core.Domain.Customers; + +/// +/// Represents a registered customer report line +/// +public partial class RegisteredCustomersReportLine +{ + /// + /// Gets or sets the period. + /// + public string Period { get; set; } + + /// + /// Gets or sets the customers. + /// + public int Customers { get; set; } +} \ No newline at end of file diff --git a/src/Libraries/Nop.Core/Domain/Orders/BestsellersReportLine.cs b/src/Libraries/Nop.Core/Domain/Orders/BestsellersReportLine.cs index 8212f738c37..f59740d2af0 100644 --- a/src/Libraries/Nop.Core/Domain/Orders/BestsellersReportLine.cs +++ b/src/Libraries/Nop.Core/Domain/Orders/BestsellersReportLine.cs @@ -21,6 +21,11 @@ public partial class BestsellersReportLine /// public decimal TotalAmount { get; set; } + /// + /// Gets or sets the total amount string + /// + public string TotalAmountStr { get; set; } + /// /// Gets or sets the total quantity /// diff --git a/src/Libraries/Nop.Core/Domain/Orders/OrderByCountryReportLine.cs b/src/Libraries/Nop.Core/Domain/Orders/OrderByCountryReportLine.cs index f6ebbb85f61..af5d2958a75 100644 --- a/src/Libraries/Nop.Core/Domain/Orders/OrderByCountryReportLine.cs +++ b/src/Libraries/Nop.Core/Domain/Orders/OrderByCountryReportLine.cs @@ -10,6 +10,11 @@ public partial class OrderByCountryReportLine /// public int? CountryId { get; set; } + /// + /// Country name; null for unknown country + /// + public string CountryName { get; set; } + /// /// Gets or sets the number of orders /// @@ -19,4 +24,9 @@ public partial class OrderByCountryReportLine /// Gets or sets the order total summary /// public decimal SumOrders { get; set; } + + /// + /// Gets or sets the order total summary string + /// + public string SumOrdersStr { get; set; } } \ No newline at end of file diff --git a/src/Libraries/Nop.Services/ExportImport/ExportManager.cs b/src/Libraries/Nop.Services/ExportImport/ExportManager.cs index 3289ea7e433..c7c8962b611 100644 --- a/src/Libraries/Nop.Services/ExportImport/ExportManager.cs +++ b/src/Libraries/Nop.Services/ExportImport/ExportManager.cs @@ -1998,6 +1998,484 @@ await _customerActivityService.InsertActivityAsync("ExportOrders", : await new PropertyManager(properties, _catalogSettings).ExportToXlsxAsync(orders); } + /// + /// Export sales summary report to XML + /// + /// Sales summaries + /// A task that represents the asynchronous operation + public virtual async Task ExportSalesSummaryToXmlAsync(IList salesSummaries) + { + var settings = new XmlWriterSettings + { + Async = true, + ConformanceLevel = ConformanceLevel.Auto + }; + + await using var stringWriter = new StringWriter(); + await using var xmlWriter = XmlWriter.Create(stringWriter, settings); + + await xmlWriter.WriteStartDocumentAsync(); + await xmlWriter.WriteStartElementAsync("SalesSummaryReport"); + await xmlWriter.WriteAttributeStringAsync("Version", NopVersion.CURRENT_VERSION); + + foreach (var saleSummary in salesSummaries) + { + await xmlWriter.WriteStartElementAsync("Summary"); + + await xmlWriter.WriteStringAsync("Summary", saleSummary.Summary); + await xmlWriter.WriteStringAsync("SummaryDate", saleSummary.SummaryDate); + await xmlWriter.WriteStringAsync("NumberOfOrders", saleSummary.NumberOfOrders); + await xmlWriter.WriteStringAsync("Profit", saleSummary.Profit); + await xmlWriter.WriteStringAsync("ProfitStr", saleSummary.ProfitStr); + await xmlWriter.WriteStringAsync("Shipping", saleSummary.Shipping); + await xmlWriter.WriteStringAsync("Tax", saleSummary.Tax); + await xmlWriter.WriteStringAsync("OrderTotal", saleSummary.OrderTotal); + await xmlWriter.WriteStringAsync("SummaryType", saleSummary.SummaryType); + + await xmlWriter.WriteEndElementAsync(); + } + + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndDocumentAsync(); + await xmlWriter.FlushAsync(); + + return stringWriter.ToString(); + } + + /// + /// Export sales summary report to XLSX + /// + /// Sales Summaries. + /// A task that represents the asynchronous operation. + public virtual async Task ExportSalesSummaryToXlsxAsync(IList salesSummaries) + { + var manager = new PropertyManager(new[] + { + new PropertyByName("Summary", (p, _) => p.Summary), + new PropertyByName("SummaryDate", (p, _) => p.SummaryDate), + new PropertyByName("NumberOfOrders", (p, _) => p.NumberOfOrders), + new PropertyByName("Profit", (p, _) => p.Profit), + new PropertyByName("ProfitStr", (p, _) => p.ProfitStr), + new PropertyByName("Shipping", (p, _) => p.Shipping), + new PropertyByName("Tax", (p, _) => p.Tax), + new PropertyByName("OrderTotal", (p, _) => p.OrderTotal), + new PropertyByName("SummaryType", (p, _) => p.SummaryType) + + }, _catalogSettings); + + return await manager.ExportToXlsxAsync(salesSummaries); + } + + /// + /// Export low stock report to XML. + /// + /// Low stock products. + /// A task that represents the asynchronous operation. + public virtual async Task ExportLowStockToXmlAsync(IList products) + { + var settings = new XmlWriterSettings + { + Async = true, + ConformanceLevel = ConformanceLevel.Auto + }; + + await using var stringWriter = new StringWriter(); + await using var xmlWriter = XmlWriter.Create(stringWriter, settings); + + await xmlWriter.WriteStartDocumentAsync(); + await xmlWriter.WriteStartElementAsync("LowStock"); + await xmlWriter.WriteAttributeStringAsync("Version", NopVersion.CURRENT_VERSION); + await xmlWriter.WriteStartElementAsync("Products"); + + foreach (var product in products) + { + await xmlWriter.WriteStartElementAsync("Product"); + + await xmlWriter.WriteStringAsync("Id", product.Id); + await xmlWriter.WriteStringAsync("Name", product.Name); + await xmlWriter.WriteStringAsync("ManageInventoryMethod", product.ManageInventoryMethod); + await xmlWriter.WriteStringAsync("StockQuantity", product.StockQuantity); + await xmlWriter.WriteStringAsync("Published", product.Published); + + await xmlWriter.WriteEndElementAsync(); + } + + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndDocumentAsync(); + await xmlWriter.FlushAsync(); + + return stringWriter.ToString(); + } + + /// + /// Export low stock report to XLSX. + /// + /// Low stock products. + /// A task that represents the asynchronous operation. + public virtual async Task ExportLowStockToXlsxAsync(IList products) + { + var manager = new PropertyManager(new[] + { + new PropertyByName("Id", (p, _) => p.Id), + new PropertyByName("Name", (p, _) => p.Name), + new PropertyByName("StockQuantity", (p, _) => p.StockQuantity), + new PropertyByName("ManageInventoryMethod", (p, _) => p.ManageInventoryMethod), + new PropertyByName("Published", (p, _) => p.Published) + + }, _catalogSettings); + + return await manager.ExportToXlsxAsync(products); + } + + /// + /// Export best seller report to XML. + /// + /// Low stock products. + /// A task that represents the asynchronous operation. + public virtual async Task ExportBestSellersToXmlAsync(IList products) + { + var settings = new XmlWriterSettings + { + Async = true, + ConformanceLevel = ConformanceLevel.Auto + }; + + await using var stringWriter = new StringWriter(); + await using var xmlWriter = XmlWriter.Create(stringWriter, settings); + + await xmlWriter.WriteStartDocumentAsync(); + await xmlWriter.WriteStartElementAsync("BestSellers"); + await xmlWriter.WriteAttributeStringAsync("Version", NopVersion.CURRENT_VERSION); + await xmlWriter.WriteStartElementAsync("Products"); + + foreach (var product in products) + { + await xmlWriter.WriteStartElementAsync("Product"); + + await xmlWriter.WriteStringAsync("ProductId", product.ProductId); + await xmlWriter.WriteStringAsync("ProductName", product.ProductName); + await xmlWriter.WriteStringAsync("TotalQuantity", product.TotalQuantity); + await xmlWriter.WriteStringAsync("TotalAmountStr", product.TotalAmountStr); + + await xmlWriter.WriteEndElementAsync(); + } + + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndDocumentAsync(); + await xmlWriter.FlushAsync(); + + return stringWriter.ToString(); + } + + /// + /// Export best seller report to XLSX. + /// + /// Low stock products. + /// A task that represents the asynchronous operation. + public virtual async Task ExportBestSellersToXlsxAsync(IList products) + { + var manager = new PropertyManager(new[] + { + new PropertyByName("ProductId", (p, _) => p.ProductId), + new PropertyByName("ProductName", (p, _) => p.ProductName), + new PropertyByName("TotalQuantity", (p, _) => p.TotalQuantity), + new PropertyByName("TotalAmountStr", (p, _) => p.TotalAmountStr) + + }, _catalogSettings); + + return await manager.ExportToXlsxAsync(products); + } + + /// + /// Export never sold report to XML. + /// + /// Never sold products. + /// A task that represents the asynchronous operation. + public virtual async Task ExportNeverSoldToXmlAsync(IList products) + { + var settings = new XmlWriterSettings + { + Async = true, + ConformanceLevel = ConformanceLevel.Auto + }; + + await using var stringWriter = new StringWriter(); + await using var xmlWriter = XmlWriter.Create(stringWriter, settings); + + await xmlWriter.WriteStartDocumentAsync(); + await xmlWriter.WriteStartElementAsync("NeverPurchased"); + await xmlWriter.WriteAttributeStringAsync("Version", NopVersion.CURRENT_VERSION); + await xmlWriter.WriteStartElementAsync("Products"); + + foreach (var product in products) + { + await xmlWriter.WriteStartElementAsync("Product"); + + await xmlWriter.WriteStringAsync("Id", product.Id); + await xmlWriter.WriteStringAsync("Name", product.Name); + + await xmlWriter.WriteEndElementAsync(); + } + + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndDocumentAsync(); + await xmlWriter.FlushAsync(); + + return stringWriter.ToString(); + } + + /// + /// Export never sold report to XLSX. + /// + /// Never sold products. + /// A task that represents the asynchronous operation. + public virtual async Task ExportNeverSoldToXlsxAsync(IList products) + { + + //property manager + var manager = new PropertyManager(new[] + { + new PropertyByName("Id", (p, _) => p.Id), + new PropertyByName("Name", (p, _) => p.Name) + + }, _catalogSettings); + + return await manager.ExportToXlsxAsync(products); + } + + /// + /// Export country sales report to XML. + /// + /// Orders. + /// A task that represents the asynchronous operation. + public virtual async Task ExportCountrySalesToXmlAsync(IList orders) + { + var settings = new XmlWriterSettings + { + Async = true, + ConformanceLevel = ConformanceLevel.Auto + }; + + await using var stringWriter = new StringWriter(); + await using var xmlWriter = XmlWriter.Create(stringWriter, settings); + + await xmlWriter.WriteStartDocumentAsync(); + await xmlWriter.WriteStartElementAsync("CountrySales"); + await xmlWriter.WriteAttributeStringAsync("Version", NopVersion.CURRENT_VERSION); + await xmlWriter.WriteStartElementAsync("Sales"); + + foreach (var order in orders) + { + await xmlWriter.WriteStartElementAsync("Sale"); + + await xmlWriter.WriteStringAsync("CountryName", order.CountryName); + await xmlWriter.WriteStringAsync("TotalOrders", order.TotalOrders); + await xmlWriter.WriteStringAsync("SumOrdersStr", order.SumOrdersStr); + + await xmlWriter.WriteEndElementAsync(); + } + + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndDocumentAsync(); + await xmlWriter.FlushAsync(); + + return stringWriter.ToString(); + } + + /// + /// Export country sales report to XLSX. + /// + /// Orders. + /// A task that represents the asynchronous operation. + public virtual async Task ExportCountrySalesToXlsxAsync(IList orders) + { + var manager = new PropertyManager(new[] + { + new PropertyByName("CountryName", (p, _) => p.CountryName), + new PropertyByName("TotalOrders", (p, _) => p.TotalOrders), + new PropertyByName("SumOrdersStr", (p, _) => p.SumOrdersStr) + + }, _catalogSettings); + + return await manager.ExportToXlsxAsync(orders); + } + + /// + /// Export registered customers report to XML. + /// + /// Registered customers. + /// A task that represents the asynchronous operation. + public virtual async Task ExportRegisteredCustomersToXmlAsync(IList customers) + { + var settings = new XmlWriterSettings + { + Async = true, + ConformanceLevel = ConformanceLevel.Auto + }; + + await using var stringWriter = new StringWriter(); + await using var xmlWriter = XmlWriter.Create(stringWriter, settings); + + await xmlWriter.WriteStartDocumentAsync(); + await xmlWriter.WriteStartElementAsync("RegisteredCustomers"); + await xmlWriter.WriteAttributeStringAsync("Version", NopVersion.CURRENT_VERSION); + await xmlWriter.WriteStartElementAsync("Customers"); + + foreach (var customer in customers) + { + await xmlWriter.WriteStartElementAsync("Customer"); + + await xmlWriter.WriteStringAsync("Period", customer.Period); + await xmlWriter.WriteStringAsync("Customers", customer.Customers); + + await xmlWriter.WriteEndElementAsync(); + } + + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndDocumentAsync(); + await xmlWriter.FlushAsync(); + + return stringWriter.ToString(); + } + + /// + /// Export registered customers report to XLSX. + /// + /// Registered customers. + /// A task that represents the asynchronous operation. + public virtual async Task ExportRegisteredCustomersToXlsxAsync(IList customers) + { + var manager = new PropertyManager(new[] + { + new PropertyByName("Period", (p, _) => p.Period), + new PropertyByName("Customers", (p, _) => p.Customers) + + }, _catalogSettings); + + return await manager.ExportToXlsxAsync(customers); + } + + /// + /// Export best customers by order total report to XML. + /// + /// Best customers. + /// A task that represents the asynchronous operation. + public virtual async Task ExportBestCustomersByOrderTotalToXmlAsync(IList customers) + { + var settings = new XmlWriterSettings + { + Async = true, + ConformanceLevel = ConformanceLevel.Auto + }; + + await using var stringWriter = new StringWriter(); + await using var xmlWriter = XmlWriter.Create(stringWriter, settings); + + await xmlWriter.WriteStartDocumentAsync(); + await xmlWriter.WriteStartElementAsync("BestCustomersByOrderTotal"); + await xmlWriter.WriteAttributeStringAsync("Version", NopVersion.CURRENT_VERSION); + await xmlWriter.WriteStartElementAsync("Customers"); + + foreach (var customer in customers) + { + await xmlWriter.WriteStartElementAsync("Customer"); + + await xmlWriter.WriteStringAsync("Name", customer.CustomerName); + await xmlWriter.WriteStringAsync("OrderTotal", customer.OrderTotalStr); + await xmlWriter.WriteStringAsync("OrderCount", customer.OrderCount); + + await xmlWriter.WriteEndElementAsync(); + } + + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndDocumentAsync(); + await xmlWriter.FlushAsync(); + + return stringWriter.ToString(); + } + + /// + /// Export best customers by order total report to XLSX. + /// + /// Best customers. + /// A task that represents the asynchronous operation. + public virtual async Task ExportBestCustomersByOrderTotalToXlsxAsync(IList customers) + { + var manager = new PropertyManager(new[] + { + new PropertyByName("Name", (p, _) => p.CustomerName), + new PropertyByName("OrderTotal", (p, _) => p.OrderTotalStr), + new PropertyByName("OrderCount", (p, _) => p.OrderCount) + + }, _catalogSettings); + + return await manager.ExportToXlsxAsync(customers); + } + + /// + /// Export best customers by number of orders report to XML. + /// + /// Best customers. + /// A task that represents the asynchronous operation. + public virtual async Task ExportBestCustomersByNumberOfOrdersToXmlAsync(IList customers) + { + var settings = new XmlWriterSettings + { + Async = true, + ConformanceLevel = ConformanceLevel.Auto + }; + + await using var stringWriter = new StringWriter(); + await using var xmlWriter = XmlWriter.Create(stringWriter, settings); + + await xmlWriter.WriteStartDocumentAsync(); + await xmlWriter.WriteStartElementAsync("BestCustomersByNumberOfOrders"); + await xmlWriter.WriteAttributeStringAsync("Version", NopVersion.CURRENT_VERSION); + await xmlWriter.WriteStartElementAsync("Customers"); + + foreach (var customer in customers) + { + await xmlWriter.WriteStartElementAsync("Customer"); + + await xmlWriter.WriteStringAsync("Name", customer.CustomerName); + await xmlWriter.WriteStringAsync("OrderTotal", customer.OrderTotalStr); + await xmlWriter.WriteStringAsync("OrderCount", customer.OrderCount); + + await xmlWriter.WriteEndElementAsync(); + } + + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndElementAsync(); + await xmlWriter.WriteEndDocumentAsync(); + await xmlWriter.FlushAsync(); + + return stringWriter.ToString(); + } + + /// + /// Export best customers by number of orders report to XLSX. + /// + /// Best customers. + /// A task that represents the asynchronous operation. + public virtual async Task ExportBestCustomersByNumberOfOrdersToXlsxAsync(IList customers) + { + var manager = new PropertyManager(new[] + { + new PropertyByName("Name", (p, _) => p.CustomerName), + new PropertyByName("OrderTotal", (p, _) => p.OrderTotalStr), + new PropertyByName("OrderCount", (p, _) => p.OrderCount) + + }, _catalogSettings); + + return await manager.ExportToXlsxAsync(customers); + } + /// /// Export customer list to XLSX /// diff --git a/src/Libraries/Nop.Services/ExportImport/IExportManager.cs b/src/Libraries/Nop.Services/ExportImport/IExportManager.cs index e6af4668143..6a94996b9cb 100644 --- a/src/Libraries/Nop.Services/ExportImport/IExportManager.cs +++ b/src/Libraries/Nop.Services/ExportImport/IExportManager.cs @@ -78,6 +78,38 @@ public partial interface IExportManager /// A task that represents the asynchronous operation Task ExportOrdersToXlsxAsync(IList orders); + Task ExportSalesSummaryToXmlAsync(IList salesSummaries); + + Task ExportSalesSummaryToXlsxAsync(IList salesSummaries); + + Task ExportLowStockToXmlAsync(IList products); + + Task ExportLowStockToXlsxAsync(IList products); + + Task ExportBestSellersToXmlAsync(IList products); + + Task ExportBestSellersToXlsxAsync(IList products); + + Task ExportNeverSoldToXmlAsync(IList products); + + Task ExportNeverSoldToXlsxAsync(IList products); + + Task ExportCountrySalesToXmlAsync(IList orders); + + Task ExportCountrySalesToXlsxAsync(IList orders); + + Task ExportRegisteredCustomersToXmlAsync(IList customers); + + Task ExportRegisteredCustomersToXlsxAsync(IList customers); + + Task ExportBestCustomersByOrderTotalToXmlAsync(IList customers); + + Task ExportBestCustomersByOrderTotalToXlsxAsync(IList customers); + + Task ExportBestCustomersByNumberOfOrdersToXmlAsync(IList customers); + + Task ExportBestCustomersByNumberOfOrdersToXlsxAsync(IList customers); + /// /// Export customer list to XLSX /// diff --git a/src/Presentation/Nop.Web/Areas/Admin/Controllers/ReportController.cs b/src/Presentation/Nop.Web/Areas/Admin/Controllers/ReportController.cs index 7fc12570c38..47a7a392ed2 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Controllers/ReportController.cs +++ b/src/Presentation/Nop.Web/Areas/Admin/Controllers/ReportController.cs @@ -1,7 +1,23 @@ -using Microsoft.AspNetCore.Mvc; +using System.Text; +using Microsoft.AspNetCore.Mvc; +using Nop.Core; +using Nop.Core.Domain.Catalog; +using Nop.Core.Domain.Customers; +using Nop.Core.Domain.Orders; +using Nop.Core.Domain.Payments; +using Nop.Core.Domain.Shipping; +using Nop.Services.Catalog; +using Nop.Services.Customers; +using Nop.Services.Directory; +using Nop.Services.ExportImport; +using Nop.Services.Helpers; +using Nop.Services.Localization; +using Nop.Services.Messages; +using Nop.Services.Orders; using Nop.Services.Security; using Nop.Web.Areas.Admin.Factories; using Nop.Web.Areas.Admin.Models.Reports; +using Nop.Web.Framework.Controllers; using Nop.Web.Framework.Mvc.Filters; namespace Nop.Web.Areas.Admin.Controllers; @@ -10,19 +26,58 @@ public partial class ReportController : BaseAdminController { #region Fields + protected readonly ICountryService _countryService; + protected readonly ICustomerReportService _customerReportService; + protected readonly ICustomerService _customerService; + protected readonly IDateTimeHelper _dateTimeHelper; + protected readonly IExportManager _exportManager; + protected readonly ILocalizationService _localizationService; + protected readonly INotificationService _notificationService; + protected readonly IOrderReportService _orderReportService; protected readonly IPermissionService _permissionService; + protected readonly IPriceFormatter _priceFormatter; + protected readonly IProductAttributeFormatter _productAttributeFormatter; + protected readonly IProductService _productService; protected readonly IReportModelFactory _reportModelFactory; + protected readonly IStoreContext _storeContext; + protected readonly IWorkContext _workContext; #endregion #region Ctor public ReportController( + ICountryService countryService, + ICustomerReportService customerReportService, + ICustomerService customerService, + IDateTimeHelper dateTimeHelper, + IExportManager exportManager, + ILocalizationService localizationService, + INotificationService notificationService, + IOrderReportService orderReportService, IPermissionService permissionService, - IReportModelFactory reportModelFactory) + IPriceFormatter priceFormatter, + IProductAttributeFormatter productAttributeFormatter, + IProductService productService, + IReportModelFactory reportModelFactory, + IStoreContext storeContext, + IWorkContext workContext) { + _countryService = countryService; + _customerReportService = customerReportService; + _customerService = customerService; + _dateTimeHelper = dateTimeHelper; + _exportManager = exportManager; + _localizationService = localizationService; + _notificationService = notificationService; + _orderReportService = orderReportService; _permissionService = permissionService; + _priceFormatter = priceFormatter; + _productAttributeFormatter = productAttributeFormatter; + _productService = productService; _reportModelFactory = reportModelFactory; + _storeContext = storeContext; + _workContext = workContext; } #endregion @@ -57,6 +112,92 @@ public virtual async Task SalesSummaryList(SalesSummarySearchMode } + [HttpPost] + [FormValueRequired("exportxml-all")] + [CheckPermission(StandardPermission.Orders.ORDERS_VIEW)] + [CheckPermission(StandardPermission.Reports.SALES_SUMMARY)] + public virtual async Task ExportSalesSummaryXmlAll(SalesSummarySearchModel searchModel) + { + var orderStatusIds = (searchModel.OrderStatusIds?.Contains(0) ?? true) ? null : searchModel.OrderStatusIds.ToList(); + var paymentStatusIds = (searchModel.PaymentStatusIds?.Contains(0) ?? true) ? null : searchModel.PaymentStatusIds.ToList(); + + var currentVendor = await _workContext.GetCurrentVendorAsync(); + + var startDateValue = !searchModel.StartDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); + var endDateValue = !searchModel.EndDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.EndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); + + var salesSummary = await _orderReportService.SalesSummaryReportAsync( + createdFromUtc: startDateValue, + createdToUtc: endDateValue, + osIds: orderStatusIds, + psIds: paymentStatusIds, + billingCountryId: searchModel.BillingCountryId, + groupBy: (GroupByOptions)searchModel.SearchGroupId, + categoryId: searchModel.CategoryId, + productId: searchModel.ProductId, + manufacturerId: searchModel.ManufacturerId, + vendorId: currentVendor?.Id ?? searchModel.VendorId, + storeId: searchModel.StoreId, + pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize); + + try + { + var xml = await _exportManager.ExportSalesSummaryToXmlAsync(salesSummary); + return File(Encoding.UTF8.GetBytes(xml), MimeTypes.ApplicationXml, "SalesSummary.xml"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("SalesSummary"); + } + } + + + [HttpPost] + [FormValueRequired("exportexcel-all")] + [CheckPermission(StandardPermission.Orders.ORDERS_VIEW)] + [CheckPermission(StandardPermission.Reports.SALES_SUMMARY)] + public virtual async Task ExportSalesSummaryExcelAll(SalesSummarySearchModel searchModel) + { + var orderStatusIds = (searchModel.OrderStatusIds?.Contains(0) ?? true) ? null : searchModel.OrderStatusIds.ToList(); + var paymentStatusIds = (searchModel.PaymentStatusIds?.Contains(0) ?? true) ? null : searchModel.PaymentStatusIds.ToList(); + + var currentVendor = await _workContext.GetCurrentVendorAsync(); + + var startDateValue = !searchModel.StartDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); + var endDateValue = !searchModel.EndDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.EndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); + + var salesSummary = await _orderReportService.SalesSummaryReportAsync( + createdFromUtc: startDateValue, + createdToUtc: endDateValue, + osIds: orderStatusIds, + psIds: paymentStatusIds, + billingCountryId: searchModel.BillingCountryId, + groupBy: (GroupByOptions)searchModel.SearchGroupId, + categoryId: searchModel.CategoryId, + productId: searchModel.ProductId, + manufacturerId: searchModel.ManufacturerId, + vendorId: currentVendor?.Id ?? searchModel.VendorId, + storeId: searchModel.StoreId, + pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize); + + try + { + var bytes = await _exportManager.ExportSalesSummaryToXlsxAsync(salesSummary); + return File(bytes, MimeTypes.TextXlsx, "SalesSummary.xlsx"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("SalesSummary"); + } + } + + #endregion #region Low stock @@ -82,6 +223,122 @@ public virtual async Task LowStockList(LowStockProductSearchModel return Json(model); } + + [HttpPost] + [FormValueRequired("exportxml-all")] + [CheckPermission(StandardPermission.Reports.LOW_STOCK)] + [CheckPermission(StandardPermission.Catalog.PRODUCTS_VIEW)] + public virtual async Task ExportLowStockXmlAll(LowStockProductSearchModel searchModel) + { + var publishedOnly = searchModel.SearchPublishedId == 0 ? null : searchModel.SearchPublishedId == 1 ? true : (bool?)false; + var vendor = await _workContext.GetCurrentVendorAsync(); + var vendorId = vendor?.Id ?? 0; + + var products = await _productService.GetLowStockProductsAsync(vendorId: vendorId, loadPublishedOnly: publishedOnly); + var combinations = await _productService.GetLowStockProductCombinationsAsync(vendorId: vendorId, loadPublishedOnly: publishedOnly); + + var lowStockProducts = new List(); + lowStockProducts.AddRange(await products.SelectAwait(async product => new LowStockProductReportLine + { + Id = product.Id, + Name = product.Name, + + ManageInventoryMethod = await _localizationService.GetLocalizedEnumAsync(product.ManageInventoryMethod), + StockQuantity = await _productService.GetTotalStockQuantityAsync(product), + Published = product.Published + }).ToListAsync()); + + var currentCustomer = await _workContext.GetCurrentCustomerAsync(); + var currentStore = await _storeContext.GetCurrentStoreAsync(); + + lowStockProducts.AddRange(await combinations.SelectAwait(async combination => + { + var product = await _productService.GetProductByIdAsync(combination.ProductId); + + return new LowStockProductReportLine + { + Id = combination.ProductId, + Name = product.Name, + + Attributes = await _productAttributeFormatter + .FormatAttributesAsync(product, combination.AttributesXml, currentCustomer, currentStore, "
", true, true, true, false), + ManageInventoryMethod = await _localizationService.GetLocalizedEnumAsync(product.ManageInventoryMethod), + + StockQuantity = combination.StockQuantity, + Published = product.Published + }; + }).ToListAsync()); + + try + { + var xml = await _exportManager.ExportLowStockToXmlAsync(lowStockProducts); + return File(Encoding.UTF8.GetBytes(xml), MimeTypes.ApplicationXml, "LowStock.xml"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("LowStock"); + } + } + + + [HttpPost] + [FormValueRequired("exportexcel-all")] + [CheckPermission(StandardPermission.Reports.LOW_STOCK)] + [CheckPermission(StandardPermission.Catalog.PRODUCTS_VIEW)] + public virtual async Task ExportLowStockExcelAll(LowStockProductSearchModel searchModel) + { + var publishedOnly = searchModel.SearchPublishedId == 0 ? null : searchModel.SearchPublishedId == 1 ? true : (bool?)false; + var vendor = await _workContext.GetCurrentVendorAsync(); + var vendorId = vendor?.Id ?? 0; + + var products = await _productService.GetLowStockProductsAsync(vendorId: vendorId, loadPublishedOnly: publishedOnly); + var combinations = await _productService.GetLowStockProductCombinationsAsync(vendorId: vendorId, loadPublishedOnly: publishedOnly); + + var lowStockProducts = new List(); + lowStockProducts.AddRange(await products.SelectAwait(async product => new LowStockProductReportLine + { + Id = product.Id, + Name = product.Name, + + ManageInventoryMethod = await _localizationService.GetLocalizedEnumAsync(product.ManageInventoryMethod), + StockQuantity = await _productService.GetTotalStockQuantityAsync(product), + Published = product.Published + }).ToListAsync()); + + var currentCustomer = await _workContext.GetCurrentCustomerAsync(); + var currentStore = await _storeContext.GetCurrentStoreAsync(); + + lowStockProducts.AddRange(await combinations.SelectAwait(async combination => + { + var product = await _productService.GetProductByIdAsync(combination.ProductId); + + return new LowStockProductReportLine + { + Id = combination.ProductId, + Name = product.Name, + + Attributes = await _productAttributeFormatter + .FormatAttributesAsync(product, combination.AttributesXml, currentCustomer, currentStore, "
", true, true, true, false), + ManageInventoryMethod = await _localizationService.GetLocalizedEnumAsync(product.ManageInventoryMethod), + + StockQuantity = combination.StockQuantity, + Published = product.Published + }; + }).ToListAsync()); + + try + { + var bytes = await _exportManager.ExportLowStockToXlsxAsync(lowStockProducts); + return File(bytes, MimeTypes.TextXlsx, "LowStock.xlsx"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("LowStock"); + } + } + #endregion #region Bestsellers @@ -118,6 +375,104 @@ public virtual async Task BestsellersReportAggregates(BestsellerS return Json(new { aggregatortotal = totalAmount }); } + + [HttpPost] + [FormValueRequired("exportxml-all")] + [CheckPermission(StandardPermission.Orders.ORDERS_VIEW)] + [CheckPermission(StandardPermission.Reports.BESTSELLERS)] + public virtual async Task ExportBestSellersXmlAll(BestsellerSearchModel searchModel) + { + var orderStatus = searchModel.OrderStatusId > 0 ? (OrderStatus?)searchModel.OrderStatusId : null; + var paymentStatus = searchModel.PaymentStatusId > 0 ? (PaymentStatus?)searchModel.PaymentStatusId : null; + var currentVendor = await _workContext.GetCurrentVendorAsync(); + if (currentVendor != null) + searchModel.VendorId = currentVendor.Id; + var startDateValue = !searchModel.StartDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); + var endDateValue = !searchModel.EndDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.EndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); + + var bestsellers = await _orderReportService.BestSellersReportAsync(showHidden: true, + createdFromUtc: startDateValue, + createdToUtc: endDateValue, + os: orderStatus, + ps: paymentStatus, + billingCountryId: searchModel.BillingCountryId, + orderBy: OrderByEnum.OrderByTotalAmount, + vendorId: searchModel.VendorId, + categoryId: searchModel.CategoryId, + manufacturerId: searchModel.ManufacturerId, + storeId: searchModel.StoreId, + pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize); + + var models = await bestsellers.SelectAwait(async item => + { + item.TotalAmountStr= await _priceFormatter.FormatPriceAsync(item.TotalAmount, true, false); + return item; + } + ).ToListAsync(); + + try + { + var xml = await _exportManager.ExportBestSellersToXmlAsync(models); + return File(Encoding.UTF8.GetBytes(xml), MimeTypes.ApplicationXml, "BestSellers.xml"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("BestSellers"); + } + } + + + [HttpPost] + [FormValueRequired("exportexcel-all")] + [CheckPermission(StandardPermission.Orders.ORDERS_VIEW)] + [CheckPermission(StandardPermission.Reports.BESTSELLERS)] + public virtual async Task ExportBestSellersExcelAll(BestsellerSearchModel searchModel) + { + var orderStatus = searchModel.OrderStatusId > 0 ? (OrderStatus?)searchModel.OrderStatusId : null; + var paymentStatus = searchModel.PaymentStatusId > 0 ? (PaymentStatus?)searchModel.PaymentStatusId : null; + var currentVendor = await _workContext.GetCurrentVendorAsync(); + if (currentVendor != null) + searchModel.VendorId = currentVendor.Id; + var startDateValue = !searchModel.StartDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); + var endDateValue = !searchModel.EndDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.EndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); + + var bestsellers = await _orderReportService.BestSellersReportAsync(showHidden: true, + createdFromUtc: startDateValue, + createdToUtc: endDateValue, + os: orderStatus, + ps: paymentStatus, + billingCountryId: searchModel.BillingCountryId, + orderBy: OrderByEnum.OrderByTotalAmount, + vendorId: searchModel.VendorId, + categoryId: searchModel.CategoryId, + manufacturerId: searchModel.ManufacturerId, + storeId: searchModel.StoreId, + pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize); + + var models = await bestsellers.SelectAwait(async item => + { + item.TotalAmountStr= await _priceFormatter.FormatPriceAsync(item.TotalAmount, true, false); + return item; + } + ).ToListAsync(); + + try + { + var bytes = await _exportManager.ExportBestSellersToXlsxAsync(models); + return File(bytes, MimeTypes.TextXlsx, "BestSellers.xlsx"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("BestSellers"); + } + } + #endregion #region Never Sold @@ -143,6 +498,78 @@ public virtual async Task NeverSoldList(NeverSoldReportSearchMode return Json(model); } + + [HttpPost] + [FormValueRequired("exportxml-all")] + [CheckPermission(StandardPermission.Orders.ORDERS_VIEW)] + [CheckPermission(StandardPermission.Reports.PRODUCTS_NEVER_PURCHASED)] + public virtual async Task ExportNeverSoldXmlAll(NeverSoldReportSearchModel searchModel) + { + var currentVendor = await _workContext.GetCurrentVendorAsync(); + if (currentVendor != null) + searchModel.SearchVendorId = currentVendor.Id; + var startDateValue = !searchModel.StartDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); + var endDateValue = !searchModel.EndDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.EndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); + + var items = await _orderReportService.ProductsNeverSoldAsync(showHidden: true, + vendorId: searchModel.SearchVendorId, + storeId: searchModel.SearchStoreId, + categoryId: searchModel.SearchCategoryId, + manufacturerId: searchModel.SearchManufacturerId, + createdFromUtc: startDateValue, + createdToUtc: endDateValue, + pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize); + + try + { + var xml = await _exportManager.ExportNeverSoldToXmlAsync(items); + return File(Encoding.UTF8.GetBytes(xml), MimeTypes.ApplicationXml, "NeverPurchased.xml"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("NeverSold"); + } + } + + + [HttpPost] + [FormValueRequired("exportexcel-all")] + [CheckPermission(StandardPermission.Orders.ORDERS_VIEW)] + [CheckPermission(StandardPermission.Reports.PRODUCTS_NEVER_PURCHASED)] + public virtual async Task ExportNeverSoldExcelAll(NeverSoldReportSearchModel searchModel) + { + var currentVendor = await _workContext.GetCurrentVendorAsync(); + if (currentVendor != null) + searchModel.SearchVendorId = currentVendor.Id; + var startDateValue = !searchModel.StartDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); + var endDateValue = !searchModel.EndDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.EndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); + + var items = await _orderReportService.ProductsNeverSoldAsync(showHidden: true, + vendorId: searchModel.SearchVendorId, + storeId: searchModel.SearchStoreId, + categoryId: searchModel.SearchCategoryId, + manufacturerId: searchModel.SearchManufacturerId, + createdFromUtc: startDateValue, + createdToUtc: endDateValue, + pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize); + + try + { + var bytes = await _exportManager.ExportNeverSoldToXlsxAsync(items); + return File(bytes, MimeTypes.TextXlsx, "NeverPurchased.xlsx"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("NeverSold"); + } + } + #endregion #region Country sales @@ -168,6 +595,88 @@ public virtual async Task CountrySalesList(CountryReportSearchMod return Json(model); } + + [HttpPost] + [FormValueRequired("exportxml-all")] + [CheckPermission(StandardPermission.Orders.ORDERS_VIEW)] + [CheckPermission(StandardPermission.Reports.COUNTRY_SALES)] + public virtual async Task ExportCountrySalesXmlAll(CountryReportSearchModel searchModel) + { + var orderStatus = searchModel.OrderStatusId > 0 ? (OrderStatus?)searchModel.OrderStatusId : null; + var paymentStatus = searchModel.PaymentStatusId > 0 ? (PaymentStatus?)searchModel.PaymentStatusId : null; + var startDateValue = !searchModel.StartDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); + var endDateValue = !searchModel.EndDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.EndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); + + var items = await _orderReportService.GetCountryReportAsync(os: orderStatus, + ps: paymentStatus, + storeId: searchModel.SearchStoreId, + startTimeUtc: startDateValue, + endTimeUtc: endDateValue); + + var models = await items.SelectAwait(async item => + { + item.SumOrdersStr = await _priceFormatter.FormatPriceAsync(item.SumOrders, true, false); + item.CountryName = (await _countryService.GetCountryByIdAsync(item.CountryId ?? 0))?.Name; + + return item; + } + ).ToListAsync(); + + try + { + var xml = await _exportManager.ExportCountrySalesToXmlAsync(models); + return File(Encoding.UTF8.GetBytes(xml), MimeTypes.ApplicationXml, "CountrySales.xml"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("CountrySales"); + } + } + + + [HttpPost] + [FormValueRequired("exportexcel-all")] + [CheckPermission(StandardPermission.Orders.ORDERS_VIEW)] + [CheckPermission(StandardPermission.Reports.COUNTRY_SALES)] + public virtual async Task ExportCountrySalesExcelAll(CountryReportSearchModel searchModel) + { + var orderStatus = searchModel.OrderStatusId > 0 ? (OrderStatus?)searchModel.OrderStatusId : null; + var paymentStatus = searchModel.PaymentStatusId > 0 ? (PaymentStatus?)searchModel.PaymentStatusId : null; + var startDateValue = !searchModel.StartDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); + var endDateValue = !searchModel.EndDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.EndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); + + var items = await _orderReportService.GetCountryReportAsync(os: orderStatus, + ps: paymentStatus, + storeId: searchModel.SearchStoreId, + startTimeUtc: startDateValue, + endTimeUtc: endDateValue); + + var models = await items.SelectAwait(async item => + { + item.SumOrdersStr = await _priceFormatter.FormatPriceAsync(item.SumOrders, true, false); + item.CountryName = (await _countryService.GetCountryByIdAsync(item.CountryId ?? 0))?.Name; + + return item; + } + ).ToListAsync(); + + try + { + var bytes = await _exportManager.ExportCountrySalesToXlsxAsync(models); + return File(bytes, MimeTypes.TextXlsx, "CountrySales.xlsx"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("CountrySales"); + } + } + #endregion #region Customer reports @@ -235,6 +744,293 @@ public virtual async Task ReportRegisteredCustomersList(Registere return Json(model); } + + [HttpPost] + [FormValueRequired("exportxml-all")] + [CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)] + [CheckPermission(StandardPermission.Reports.REGISTERED_CUSTOMERS)] + public virtual async Task ExportRegisteredCustomersXmlAll(RegisteredCustomersReportSearchModel searchModel) + { + var reportItems = new List + { + new() { + Period = await _localizationService.GetResourceAsync("Admin.Reports.Customers.RegisteredCustomers.Fields.Period.7days"), + Customers = await _customerReportService.GetRegisteredCustomersReportAsync(7) + }, + new() { + Period = await _localizationService.GetResourceAsync("Admin.Reports.Customers.RegisteredCustomers.Fields.Period.14days"), + Customers = await _customerReportService.GetRegisteredCustomersReportAsync(14) + }, + new() { + Period = await _localizationService.GetResourceAsync("Admin.Reports.Customers.RegisteredCustomers.Fields.Period.month"), + Customers = await _customerReportService.GetRegisteredCustomersReportAsync(30) + }, + new() { + Period = await _localizationService.GetResourceAsync("Admin.Reports.Customers.RegisteredCustomers.Fields.Period.year"), + Customers = await _customerReportService.GetRegisteredCustomersReportAsync(365) + } + }; + + try + { + var xml = await _exportManager.ExportRegisteredCustomersToXmlAsync(reportItems); + return File(Encoding.UTF8.GetBytes(xml), MimeTypes.ApplicationXml, "RegisteredCustomers.xml"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("RegisteredCustomers"); + } + } + + + [HttpPost] + [FormValueRequired("exportexcel-all")] + [CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)] + [CheckPermission(StandardPermission.Reports.REGISTERED_CUSTOMERS)] + public virtual async Task ExportRegisteredCustomersExcelAll(CountryReportSearchModel searchModel) + { + var reportItems = new List + { + new() { + Period = await _localizationService.GetResourceAsync("Admin.Reports.Customers.RegisteredCustomers.Fields.Period.7days"), + Customers = await _customerReportService.GetRegisteredCustomersReportAsync(7) + }, + new() { + Period = await _localizationService.GetResourceAsync("Admin.Reports.Customers.RegisteredCustomers.Fields.Period.14days"), + Customers = await _customerReportService.GetRegisteredCustomersReportAsync(14) + }, + new() { + Period = await _localizationService.GetResourceAsync("Admin.Reports.Customers.RegisteredCustomers.Fields.Period.month"), + Customers = await _customerReportService.GetRegisteredCustomersReportAsync(30) + }, + new() { + Period = await _localizationService.GetResourceAsync("Admin.Reports.Customers.RegisteredCustomers.Fields.Period.year"), + Customers = await _customerReportService.GetRegisteredCustomersReportAsync(365) + } + }; + + try + { + var bytes = await _exportManager.ExportRegisteredCustomersToXlsxAsync(reportItems); + return File(bytes, MimeTypes.TextXlsx, "RegisteredCustomers.xlsx"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("RegisteredCustomers"); + } + } + + + [HttpPost] + [FormValueRequired("exportxml-all")] + [CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)] + [CheckPermission(StandardPermission.Reports.REGISTERED_CUSTOMERS)] + public virtual async Task ExportBestCustomersByOrderTotalXmlAll(CustomerReportsSearchModel search) + { + var searchModel = search.BestCustomersByOrderTotal; + + var startDateValue = !searchModel.StartDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); + var endDateValue = !searchModel.EndDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.EndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); + var orderStatus = searchModel.OrderStatusId > 0 ? (OrderStatus?)searchModel.OrderStatusId : null; + var paymentStatus = searchModel.PaymentStatusId > 0 ? (PaymentStatus?)searchModel.PaymentStatusId : null; + var shippingStatus = searchModel.ShippingStatusId > 0 ? (ShippingStatus?)searchModel.ShippingStatusId : null; + + var reportItems = await _customerReportService.GetBestCustomersReportAsync(createdFromUtc: startDateValue, + createdToUtc: endDateValue, + os: orderStatus, + ps: paymentStatus, + ss: shippingStatus, + orderBy: OrderByEnum.OrderByTotalAmount, + pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize); + + var models = await reportItems.SelectAwait(async item => + { + var customer = await _customerService.GetCustomerByIdAsync(item.CustomerId); + if (customer != null) + { + item.CustomerName = (await _customerService.IsRegisteredAsync(customer)) + ? customer.Email + : await _localizationService.GetResourceAsync("Admin.Customers.Guest"); + } + item.OrderTotalStr = await _priceFormatter.FormatPriceAsync(item.OrderTotal, true, false); + return item; + } + ).ToListAsync(); + + try + { + var xml = await _exportManager.ExportBestCustomersByOrderTotalToXmlAsync(models); + return File(Encoding.UTF8.GetBytes(xml), MimeTypes.ApplicationXml, "BestCustomersByOrderTotal.xml"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("BestCustomersByOrderTotal"); + } + } + + + [HttpPost] + [FormValueRequired("exportexcel-all")] + [CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)] + [CheckPermission(StandardPermission.Reports.REGISTERED_CUSTOMERS)] + public virtual async Task ExportBestCustomersByOrderTotalExcelAll(CustomerReportsSearchModel search) + { + var searchModel = search.BestCustomersByOrderTotal; + + var startDateValue = !searchModel.StartDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); + var endDateValue = !searchModel.EndDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.EndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); + var orderStatus = searchModel.OrderStatusId > 0 ? (OrderStatus?)searchModel.OrderStatusId : null; + var paymentStatus = searchModel.PaymentStatusId > 0 ? (PaymentStatus?)searchModel.PaymentStatusId : null; + var shippingStatus = searchModel.ShippingStatusId > 0 ? (ShippingStatus?)searchModel.ShippingStatusId : null; + + var reportItems = await _customerReportService.GetBestCustomersReportAsync(createdFromUtc: startDateValue, + createdToUtc: endDateValue, + os: orderStatus, + ps: paymentStatus, + ss: shippingStatus, + orderBy: OrderByEnum.OrderByTotalAmount, + pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize); + + var models = await reportItems.SelectAwait(async item => + { + var customer = await _customerService.GetCustomerByIdAsync(item.CustomerId); + if (customer != null) + { + item.CustomerName = (await _customerService.IsRegisteredAsync(customer)) + ? customer.Email + : await _localizationService.GetResourceAsync("Admin.Customers.Guest"); + } + + item.OrderTotalStr = await _priceFormatter.FormatPriceAsync(item.OrderTotal, true, false); + return item; + } + ).ToListAsync(); + + try + { + var bytes = await _exportManager.ExportBestCustomersByOrderTotalToXlsxAsync(models); + return File(bytes, MimeTypes.TextXlsx, "BestCustomersByOrderTotal.xlsx"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("BestCustomersByOrderTotal"); + } + } + + + [HttpPost] + [FormValueRequired("exportxml-all")] + [CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)] + [CheckPermission(StandardPermission.Reports.REGISTERED_CUSTOMERS)] + public virtual async Task ExportBestCustomersByNumberOfOrdersXmlAll(CustomerReportsSearchModel search) + { + var searchModel = search.BestCustomersByNumberOfOrders; + + var startDateValue = !searchModel.StartDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); + var endDateValue = !searchModel.EndDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.EndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); + var orderStatus = searchModel.OrderStatusId > 0 ? (OrderStatus?)searchModel.OrderStatusId : null; + var paymentStatus = searchModel.PaymentStatusId > 0 ? (PaymentStatus?)searchModel.PaymentStatusId : null; + var shippingStatus = searchModel.ShippingStatusId > 0 ? (ShippingStatus?)searchModel.ShippingStatusId : null; + + var reportItems = await _customerReportService.GetBestCustomersReportAsync(createdFromUtc: startDateValue, + createdToUtc: endDateValue, + os: orderStatus, + ps: paymentStatus, + ss: shippingStatus, + orderBy: OrderByEnum.OrderByQuantity, + pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize); + + var models = await reportItems.SelectAwait(async item => + { + var customer = await _customerService.GetCustomerByIdAsync(item.CustomerId); + if (customer != null) + { + item.CustomerName = (await _customerService.IsRegisteredAsync(customer)) + ? customer.Email + : await _localizationService.GetResourceAsync("Admin.Customers.Guest"); + } + + item.OrderTotalStr = await _priceFormatter.FormatPriceAsync(item.OrderTotal, true, false); + return item; + } + ).ToListAsync(); + + try + { + var xml = await _exportManager.ExportBestCustomersByNumberOfOrdersToXmlAsync(models); + return File(Encoding.UTF8.GetBytes(xml), MimeTypes.ApplicationXml, "BestCustomersByNumberOfOrders.xml"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("BestCustomersByNumberOfOrders"); + } + } + + + [HttpPost] + [FormValueRequired("exportexcel-all")] + [CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)] + [CheckPermission(StandardPermission.Reports.REGISTERED_CUSTOMERS)] + public virtual async Task ExportBestCustomersByNumberOfOrdersExcelAll(CustomerReportsSearchModel search) + { + var searchModel = search.BestCustomersByNumberOfOrders; + + var startDateValue = !searchModel.StartDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); + var endDateValue = !searchModel.EndDate.HasValue ? null + : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.EndDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); + var orderStatus = searchModel.OrderStatusId > 0 ? (OrderStatus?)searchModel.OrderStatusId : null; + var paymentStatus = searchModel.PaymentStatusId > 0 ? (PaymentStatus?)searchModel.PaymentStatusId : null; + var shippingStatus = searchModel.ShippingStatusId > 0 ? (ShippingStatus?)searchModel.ShippingStatusId : null; + + var reportItems = await _customerReportService.GetBestCustomersReportAsync(createdFromUtc: startDateValue, + createdToUtc: endDateValue, + os: orderStatus, + ps: paymentStatus, + ss: shippingStatus, + orderBy: OrderByEnum.OrderByQuantity, + pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize); + + var models = await reportItems.SelectAwait(async item => + { + //fill in additional values (not existing in the entity) + var customer = await _customerService.GetCustomerByIdAsync(item.CustomerId); + if (customer != null) + { + item.CustomerName = (await _customerService.IsRegisteredAsync(customer)) + ? customer.Email + : await _localizationService.GetResourceAsync("Admin.Customers.Guest"); + } + + item.OrderTotalStr = await _priceFormatter.FormatPriceAsync(item.OrderTotal, true, false); + return item; + } + ).ToListAsync(); + + try + { + + var bytes = await _exportManager.ExportBestCustomersByNumberOfOrdersToXlsxAsync(models); + return File(bytes, MimeTypes.TextXlsx, "BestCustomersByNumberOfOrders.xlsx"); + } + catch (Exception exc) + { + await _notificationService.ErrorNotificationAsync(exc); + return RedirectToAction("BestCustomersByNumberOfOrders"); + } + } + #endregion #endregion diff --git a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/BestCustomersByNumberOfOrders.cshtml b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/BestCustomersByNumberOfOrders.cshtml index 084527fdad9..04e8b752ed1 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/BestCustomersByNumberOfOrders.cshtml +++ b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/BestCustomersByNumberOfOrders.cshtml @@ -13,130 +13,158 @@ var hideSearchBlock = await genericAttributeService.GetAttributeAsync(await workContext.GetCurrentCustomerAsync(), hideSearchBlockAttributeName); } -
-

- @T("Admin.Reports.Customers.BestBy.BestByNumberOfOrders") -

-
+
+
+

+ @T("Admin.Reports.Customers.BestBy.BestByNumberOfOrders") +

+
+
+ + + +
+
+
-
-
-
-
-
+
\ No newline at end of file diff --git a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/BestCustomersByOrderTotal.cshtml b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/BestCustomersByOrderTotal.cshtml index f7c14aa3221..fdecc8efe3d 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/BestCustomersByOrderTotal.cshtml +++ b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/BestCustomersByOrderTotal.cshtml @@ -13,130 +13,158 @@ var hideSearchBlock = await genericAttributeService.GetAttributeAsync(await workContext.GetCurrentCustomerAsync(), hideSearchBlockAttributeName); } -
-

- @T("Admin.Reports.Customers.BestBy.BestByOrderTotal") -

-
+
+
+

+ @T("Admin.Reports.Customers.BestBy.BestByOrderTotal") +

+
+
+ + + +
+
+
-
-
-
-
-
+
\ No newline at end of file diff --git a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/Bestsellers.cshtml b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/Bestsellers.cshtml index 53fb48e55c4..0e6ef5b24c4 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/Bestsellers.cshtml +++ b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/Bestsellers.cshtml @@ -13,204 +13,228 @@ const string hideSearchBlockAttributeName = "BestsellersPage.HideSearchBlock"; var hideSearchBlock = await genericAttributeService.GetAttributeAsync(await workContext.GetCurrentCustomerAsync(), hideSearchBlockAttributeName); } - -
-

- @T("Admin.Reports.Sales.Bestsellers") -

-
-   +
+
+

+ @T("Admin.Reports.Sales.Bestsellers") +

+
+
+ + + +
+
-
-
-
-
-
-
+ \ No newline at end of file diff --git a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/CountrySales.cshtml b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/CountrySales.cshtml index 64f0edc7897..a38545f88db 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/CountrySales.cshtml +++ b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/CountrySales.cshtml @@ -11,126 +11,151 @@ const string hideSearchBlockAttributeName = "CountrySalesPage.HideSearchBlock"; var hideSearchBlock = await genericAttributeService.GetAttributeAsync(await workContext.GetCurrentCustomerAsync(), hideSearchBlockAttributeName); } - -
-

- @T("Admin.Reports.Sales.Country") -

-
-   +
+
+

+ @T("Admin.Reports.Sales.Country") +

+ +
+
+ + + +
+
-
-
-
-
-
-
+ \ No newline at end of file diff --git a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/LowStock.cshtml b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/LowStock.cshtml index 21b08fc1cd0..c465edcf9a3 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/LowStock.cshtml +++ b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/LowStock.cshtml @@ -12,13 +12,36 @@ var hideSearchBlock = await genericAttributeService.GetAttributeAsync(await workContext.GetCurrentCustomerAsync(), hideSearchBlockAttributeName); } -
+

@T("Admin.Reports.LowStock")

-   +
+ + + +
diff --git a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/NeverSold.cshtml b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/NeverSold.cshtml index 5ba4b4fd654..3ed876872eb 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/NeverSold.cshtml +++ b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/NeverSold.cshtml @@ -12,132 +12,157 @@ var hideSearchBlock = await genericAttributeService.GetAttributeAsync(await workContext.GetCurrentCustomerAsync(), hideSearchBlockAttributeName); } -
-

- @T("Admin.Reports.Sales.NeverSold") -

-
-   + +
+

+ @T("Admin.Reports.Sales.NeverSold") +

+
+
+ + + +
+
-
-
-
-
-
-
+ \ No newline at end of file diff --git a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/RegisteredCustomers.cshtml b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/RegisteredCustomers.cshtml index 5a524e2c710..69f95b22081 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/RegisteredCustomers.cshtml +++ b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/RegisteredCustomers.cshtml @@ -11,6 +11,34 @@

@T("Admin.Reports.Customers.RegisteredCustomers")

+
+
+
+ + + +
+
+
diff --git a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/SalesSummary.cshtml b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/SalesSummary.cshtml index 4edd146d1fd..4d38e18afdc 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Views/Report/SalesSummary.cshtml +++ b/src/Presentation/Nop.Web/Areas/Admin/Views/Report/SalesSummary.cshtml @@ -16,9 +16,34 @@

@T("Admin.Reports.SalesSummary")

-
-   -
+
+
+
+ + + +
+
+