Skip to content

Commit

Permalink
Resolves #2012 Make bestseller report pageable
Browse files Browse the repository at this point in the history
  • Loading branch information
mgesing committed Jul 15, 2020
1 parent d98f4c2 commit c2c14f2
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 125 deletions.
25 changes: 17 additions & 8 deletions src/Libraries/SmartStore.Services/Orders/IOrderReportService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SmartStore.Core;
using SmartStore.Core.Domain.Catalog;
Expand All @@ -10,6 +9,14 @@

namespace SmartStore.Services.Orders
{
public enum ReportSorting
{
ByQuantityAsc = 0,
ByQuantityDesc,
ByAmountAsc,
ByAmountDesc
}

/// <summary>
/// Order report service interface
/// </summary>
Expand Down Expand Up @@ -52,7 +59,7 @@ OrderAverageReportLine GetOrderAverageReportLine(int storeId,
OrderAverageReportLineSummary OrderAverageReport(int storeId, OrderStatus os);

/// <summary>
/// Get best sellers report
/// Get best sellers report.
/// </summary>
/// <param name="storeId">Store identifier</param>
/// <param name="startTime">Order start time; null to load all</param>
Expand All @@ -61,20 +68,22 @@ OrderAverageReportLine GetOrderAverageReportLine(int storeId,
/// <param name="ps">Order payment status; null to load all records</param>
/// <param name="ss">Shipping status; null to load all records</param>
/// <param name="billingCountryId">Billing country identifier; 0 to load all records</param>
/// <param name="recordsToReturn">Records to return</param>
/// <param name="orderBy">1 - order by quantity, 2 - order by total amount</param>
/// <param name="pageIndex">Page index.</param>
/// <param name="pageSize">Page size.</param>
/// <param name="order">Order of report items.</param>
/// <param name="showHidden">A value indicating whether to show hidden records</param>
/// <returns>Result</returns>
IList<BestsellersReportLine> BestSellersReport(
/// <returns>Best selling products.</returns>
IPagedList<BestsellersReportLine> BestSellersReport(
int storeId,
DateTime? startTime,
DateTime? endTime,
OrderStatus? os,
PaymentStatus? ps,
ShippingStatus? ss,
int billingCountryId = 0,
int recordsToReturn = 5,
int orderBy = 1,
int pageIndex = 0,
int pageSize = int.MaxValue,
ReportSorting order = ReportSorting.ByQuantityDesc,
bool showHidden = false);

/// <summary>
Expand Down
109 changes: 45 additions & 64 deletions src/Libraries/SmartStore.Services/Orders/OrderReportService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Globalization;
using System.Linq;
Expand All @@ -21,7 +20,8 @@ public partial class OrderReportService : IOrderReportService
private readonly IRepository<Product> _productRepository;
private readonly IDateTimeHelper _dateTimeHelper;

public OrderReportService(IRepository<Order> orderRepository,
public OrderReportService(
IRepository<Order> orderRepository,
IRepository<OrderItem> orderItemRepository,
IRepository<Product> productRepository,
IDateTimeHelper dateTimeHelper)
Expand Down Expand Up @@ -181,87 +181,68 @@ public virtual OrderAverageReportLineSummary OrderAverageReport(int storeId, Ord
return item;
}

public virtual IList<BestsellersReportLine> BestSellersReport(
public virtual IPagedList<BestsellersReportLine> BestSellersReport(
int storeId,
DateTime? startTime,
DateTime? endTime,
OrderStatus? os,
PaymentStatus? ps,
ShippingStatus? ss,
OrderStatus? orderStatus,
PaymentStatus? paymentStatus,
ShippingStatus? shippingStatus,
int billingCountryId = 0,
int recordsToReturn = 5,
int orderBy = 1,
int pageIndex = 0,
int pageSize = int.MaxValue,
ReportSorting order = ReportSorting.ByQuantityDesc,
bool showHidden = false)
{
int? orderStatusId = null;
if (os.HasValue)
orderStatusId = (int)os.Value;
var orderStatusId = orderStatus.HasValue ? (int)orderStatus.Value : (int?)null;
var paymentStatusId = paymentStatus.HasValue ? (int)paymentStatus.Value : (int?)null;
var shippingStatusId = shippingStatus.HasValue ? (int)shippingStatus : (int?)null;

int? paymentStatusId = null;
if (ps.HasValue)
paymentStatusId = (int)ps.Value;

int? shippingStatusId = null;
if (ss.HasValue)
shippingStatusId = (int)ss.Value;


var query1 = from orderItem in _orderItemRepository.Table
join o in _orderRepository.Table on orderItem.OrderId equals o.Id
join p in _productRepository.Table on orderItem.ProductId equals p.Id
where (storeId == 0 || storeId == o.StoreId) &&
(!startTime.HasValue || startTime.Value <= o.CreatedOnUtc) &&
(!endTime.HasValue || endTime.Value >= o.CreatedOnUtc) &&
(!orderStatusId.HasValue || orderStatusId == o.OrderStatusId) &&
(!paymentStatusId.HasValue || paymentStatusId == o.PaymentStatusId) &&
(!shippingStatusId.HasValue || shippingStatusId == o.ShippingStatusId) &&
(!o.Deleted) &&
(!p.Deleted) && (!p.IsSystemProduct) &&
(billingCountryId == 0 || o.BillingAddress.CountryId == billingCountryId) &&
(showHidden || p.Published)
select orderItem;
var query =
from orderItem in _orderItemRepository.TableUntracked
join o in _orderRepository.TableUntracked on orderItem.OrderId equals o.Id
join p in _productRepository.TableUntracked on orderItem.ProductId equals p.Id
where (storeId == 0 || storeId == o.StoreId) &&
(!startTime.HasValue || startTime.Value <= o.CreatedOnUtc) &&
(!endTime.HasValue || endTime.Value >= o.CreatedOnUtc) &&
(!orderStatusId.HasValue || orderStatusId == o.OrderStatusId) &&
(!paymentStatusId.HasValue || paymentStatusId == o.PaymentStatusId) &&
(!shippingStatusId.HasValue || shippingStatusId == o.ShippingStatusId) &&
(!o.Deleted) &&
(!p.Deleted) && (!p.IsSystemProduct) &&
(billingCountryId == 0 || o.BillingAddress.CountryId == billingCountryId) &&
(showHidden || p.Published)
select orderItem;

var query2 =
//group by products
from orderItem in query1
// Group by product ID.
var groupedQuery =
from orderItem in query
group orderItem by orderItem.ProductId into g
select new
select new BestsellersReportLine
{
EntityId = g.Key,
ProductId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
TotalQuantity = g.Sum(x => x.Quantity)
};

switch (orderBy)
switch (order)
{
case 1:
{
query2 = query2.OrderByDescending(x => x.TotalQuantity).ThenByDescending(x => x.TotalAmount);
}
case ReportSorting.ByAmountAsc:
groupedQuery = groupedQuery.OrderBy(x => x.TotalAmount);
break;
case ReportSorting.ByAmountDesc:
groupedQuery = groupedQuery.OrderByDescending(x => x.TotalAmount);
break;
case 2:
{
query2 = query2.OrderByDescending(x => x.TotalAmount);
}
case ReportSorting.ByQuantityAsc:
groupedQuery = groupedQuery.OrderBy(x => x.TotalQuantity).ThenByDescending(x => x.TotalAmount);
break;
case ReportSorting.ByQuantityDesc:
default:
throw new ArgumentException("Wrong orderBy parameter", "orderBy");
groupedQuery = groupedQuery.OrderByDescending(x => x.TotalQuantity).ThenByDescending(x => x.TotalAmount);
break;
}

if (recordsToReturn != 0 && recordsToReturn != int.MaxValue)
query2 = query2.Take(() => recordsToReturn);

var result = query2.ToList().Select(x =>
{
var reportLine = new BestsellersReportLine()
{
ProductId = x.EntityId,
TotalAmount = x.TotalAmount,
TotalQuantity = x.TotalQuantity
};
return reportLine;
}).ToList();

var result = new PagedList<BestsellersReportLine>(groupedQuery, pageIndex, pageSize);
return result;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
Expand Down Expand Up @@ -2495,9 +2496,9 @@ public ActionResult OrderNoteDelete(int orderId, int orderNoteId, GridCommand co
#region Reports

[NonAction]
protected IList<BestsellersReportLineModel> GetBestsellersBriefReportModel(int recordsToReturn, int orderBy)
protected IList<BestsellersReportLineModel> GetBestsellersBriefReportModel(int recordsToReturn, ReportSorting order)
{
var reportLines = _orderReportService.BestSellersReport(0, null, null, null, null, null, 0, recordsToReturn, orderBy, true);
var reportLines = _orderReportService.BestSellersReport(0, null, null, null, null, null, 0, 0, recordsToReturn, order, true);
var products = _productService.GetProductsByIds(reportLines.Select(x => x.ProductId).ToArray()).ToDictionarySafe(x => x.Id);

var model = reportLines.Select(x =>
Expand All @@ -2506,7 +2507,7 @@ protected IList<BestsellersReportLineModel> GetBestsellersBriefReportModel(int r
{
ProductId = x.ProductId,
TotalAmount = x.TotalAmount.ToString("C0"),
TotalQuantity = x.TotalQuantity.ToString("N0"),
TotalQuantity = x.TotalQuantity.ToString("N0")
};

var product = products.Get(x.ProductId);
Expand All @@ -2527,8 +2528,8 @@ public ActionResult BestsellersDashboardReport()
{
var model = new BestsellersDashboardReportModel
{
BestsellersByQuantity = GetBestsellersBriefReportModel(7, 1),
BestsellersByAmount = GetBestsellersBriefReportModel(7, 2)
BestsellersByQuantity = GetBestsellersBriefReportModel(7, ReportSorting.ByQuantityDesc),
BestsellersByAmount = GetBestsellersBriefReportModel(7, ReportSorting.ByAmountDesc)
};

return PartialView(model);
Expand All @@ -2540,7 +2541,8 @@ public ActionResult BestsellersReport()
var model = new BestsellersReportModel
{
AvailableOrderStatuses = OrderStatus.Pending.ToSelectList(false).ToList(),
AvailablePaymentStatuses = PaymentStatus.Pending.ToSelectList(false).ToList()
AvailablePaymentStatuses = PaymentStatus.Pending.ToSelectList(false).ToList(),
GridPageSize = _adminAreaSettings.GridPageSize
};

foreach (var c in _countryService.GetAllCountriesForBilling())
Expand All @@ -2563,43 +2565,77 @@ public ActionResult BestsellersReportList(GridCommand command, BestsellersReport
DateTime? endDateValue = (model.EndDate == null) ? null
: (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.EndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1);

OrderStatus? orderStatus = model.OrderStatusId > 0 ? (OrderStatus?)(model.OrderStatusId) : null;
PaymentStatus? paymentStatus = model.PaymentStatusId > 0 ? (PaymentStatus?)(model.PaymentStatusId) : null;
OrderStatus? orderStatus = model.OrderStatusId > 0 ? (OrderStatus?)model.OrderStatusId : null;
PaymentStatus? paymentStatus = model.PaymentStatusId > 0 ? (PaymentStatus?)model.PaymentStatusId : null;

var items = _orderReportService.BestSellersReport(0, startDateValue, endDateValue,
orderStatus, paymentStatus, null, model.BillingCountryId, 100, 2, true);
// Sorting.
var sorting = ReportSorting.ByAmountDesc;

var gridModel = new GridModel<BestsellersReportLineModel>
if (command.SortDescriptors?.Any() ?? false)
{
Data = items.Select(x =>
var sort = command.SortDescriptors.First();
if (sort.Member == "TotalQuantity")
{
var product = _productService.GetProductById(x.ProductId);
sorting = sort.SortDirection == ListSortDirection.Ascending
? ReportSorting.ByQuantityAsc
: ReportSorting.ByQuantityDesc;
}
else if (sort.Member == "TotalAmount")
{
sorting = sort.SortDirection == ListSortDirection.Ascending
? ReportSorting.ByAmountAsc
: ReportSorting.ByAmountDesc;
}
}

var m = new BestsellersReportLineModel
{
ProductId = x.ProductId,
TotalAmount = _priceFormatter.FormatPrice(x.TotalAmount, true, false),
TotalQuantity = x.TotalQuantity.ToString()
};
var items = _orderReportService.BestSellersReport(
0,
startDateValue,
endDateValue,
orderStatus,
paymentStatus,
null,
model.BillingCountryId,
command.Page - 1,
command.PageSize,
sorting,
true);

if (product != null)
{
m.ProductName = product.Name;
m.ProductTypeName = product.GetProductTypeLabel(_localizationService);
m.ProductTypeLabelHint = product.ProductTypeLabelHint;
}
return m;
}),
Total = items.Count
var productIds = items.Select(x => x.ProductId).Distinct().ToArray();
var products = _productService.GetProductsByIds(productIds).ToDictionary(x => x.Id);

var gridModel = new GridModel<BestsellersReportLineModel>
{
Total = items.TotalCount
};

gridModel.Data = items.Select(x =>
{
products.TryGetValue(x.ProductId, out var product);

var m = new BestsellersReportLineModel
{
ProductId = x.ProductId,
TotalAmount = _priceFormatter.FormatPrice(x.TotalAmount, true, false),
TotalQuantity = x.TotalQuantity.ToString("N0")
};

if (product != null)
{
m.ProductName = product.Name;
m.ProductTypeName = product.GetProductTypeLabel(_localizationService);
m.ProductTypeLabelHint = product.ProductTypeLabelHint;
}

return m;
});

return new JsonResult
{
Data = gridModel
};
}


[Permission(Permissions.Order.Read)]
public ActionResult NeverSoldReport()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ public BestsellersReportModel()

[SmartResourceDisplayName("Admin.SalesReport.Bestsellers.OrderStatus")]
public int OrderStatusId { get; set; }

[SmartResourceDisplayName("Admin.SalesReport.Bestsellers.PaymentStatus")]
public int PaymentStatusId { get; set; }

public IList<SelectListItem> AvailableOrderStatuses { get; set; }
public IList<SelectListItem> AvailablePaymentStatuses { get; set; }
public IList<SelectListItem> AvailableCountries { get; set; }

public int GridPageSize { get; set; }
}
}
Loading

0 comments on commit c2c14f2

Please sign in to comment.