analytics and statistics
This commit is contained in:
116
Webshop.Application/Services/Admin/AdminAnalyticsService.cs
Normal file
116
Webshop.Application/Services/Admin/AdminAnalyticsService.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
// src/Webshop.Application/Services/Admin/AdminAnalyticsService.cs
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Webshop.Application.DTOs.Admin;
|
||||
using Webshop.Application.Services.Admin.Interfaces;
|
||||
using Webshop.Domain.Enums;
|
||||
using Webshop.Domain.Interfaces;
|
||||
using Webshop.Infrastructure.Data;
|
||||
|
||||
namespace Webshop.Application.Services.Admin
|
||||
{
|
||||
public class AdminAnalyticsService : IAdminAnalyticsService
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly ISettingService _settingService;
|
||||
|
||||
public AdminAnalyticsService(ApplicationDbContext context, ISettingService settingService)
|
||||
{
|
||||
_context = context;
|
||||
_settingService = settingService;
|
||||
}
|
||||
|
||||
public async Task<AnalyticsDto> GetAnalyticsAsync(AnalyticsPeriod period)
|
||||
{
|
||||
var startDate = GetStartDateFromPeriod(period);
|
||||
|
||||
var filteredOrders = await _context.Orders
|
||||
.Where(o => o.OrderDate >= startDate && o.OrderStatus != OrderStatus.Cancelled.ToString())
|
||||
.ToListAsync();
|
||||
|
||||
var analyticsDto = new AnalyticsDto
|
||||
{
|
||||
KpiSummary = await GetKpiSummaryAsync(startDate, filteredOrders),
|
||||
SalesOverTime = GetSalesOverTime(filteredOrders),
|
||||
TopPerformingProducts = await GetTopPerformingProductsAsync(startDate),
|
||||
InventoryStatus = await GetInventoryStatusAsync()
|
||||
};
|
||||
|
||||
return analyticsDto;
|
||||
}
|
||||
|
||||
private async Task<KpiSummaryDto> GetKpiSummaryAsync(DateTimeOffset startDate, List<Domain.Entities.Order> filteredOrders)
|
||||
{
|
||||
var totalRevenue = filteredOrders.Sum(o => o.OrderTotal);
|
||||
var totalOrders = filteredOrders.Count;
|
||||
|
||||
return new KpiSummaryDto
|
||||
{
|
||||
TotalRevenue = totalRevenue,
|
||||
TotalOrders = totalOrders,
|
||||
TotalCustomers = await _context.Customers.CountAsync(),
|
||||
NewCustomersThisPeriod = await _context.Users.CountAsync(u => u.CreatedDate >= startDate),
|
||||
AverageOrderValue = totalOrders > 0 ? totalRevenue / totalOrders : 0
|
||||
};
|
||||
}
|
||||
|
||||
private List<SalesDataPointDto> GetSalesOverTime(List<Domain.Entities.Order> orders)
|
||||
{
|
||||
return orders
|
||||
.GroupBy(o => o.OrderDate.Date)
|
||||
.Select(g => new SalesDataPointDto
|
||||
{
|
||||
Date = g.Key.ToString("yyyy-MM-dd"),
|
||||
Revenue = g.Sum(o => o.OrderTotal)
|
||||
})
|
||||
.OrderBy(dp => dp.Date)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private async Task<List<TopProductDto>> GetTopPerformingProductsAsync(DateTimeOffset startDate)
|
||||
{
|
||||
return await _context.OrderItems
|
||||
.Where(oi => oi.Order.OrderDate >= startDate && oi.ProductId.HasValue)
|
||||
.GroupBy(oi => new { oi.ProductId, oi.ProductName, oi.ProductSKU })
|
||||
.Select(g => new TopProductDto
|
||||
{
|
||||
ProductId = g.Key.ProductId!.Value,
|
||||
Name = g.Key.ProductName,
|
||||
Sku = g.Key.ProductSKU,
|
||||
UnitsSold = g.Sum(oi => oi.Quantity),
|
||||
TotalRevenue = g.Sum(oi => oi.TotalPrice)
|
||||
})
|
||||
.OrderByDescending(p => p.UnitsSold)
|
||||
.Take(10)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
private async Task<InventoryStatusDto> GetInventoryStatusAsync()
|
||||
{
|
||||
var lowStockThreshold = await _settingService.GetSettingValueAsync<int>("LowStockThreshold", 10);
|
||||
|
||||
var totalProducts = await _context.Products.CountAsync(p => p.IsActive);
|
||||
var productsInStock = await _context.Products.CountAsync(p => p.IsActive && p.StockQuantity > 0);
|
||||
var productsWithLowStock = await _context.Products.CountAsync(p => p.IsActive && p.StockQuantity > 0 && p.StockQuantity <= lowStockThreshold);
|
||||
|
||||
return new InventoryStatusDto
|
||||
{
|
||||
ProductsWithLowStock = productsWithLowStock,
|
||||
OverallStockAvailabilityPercentage = totalProducts > 0 ? Math.Round((double)productsInStock / totalProducts * 100, 2) : 0
|
||||
};
|
||||
}
|
||||
|
||||
private DateTimeOffset GetStartDateFromPeriod(AnalyticsPeriod period)
|
||||
{
|
||||
return period switch
|
||||
{
|
||||
AnalyticsPeriod.Last7Days => DateTimeOffset.UtcNow.AddDays(-7),
|
||||
AnalyticsPeriod.Last30Days => DateTimeOffset.UtcNow.AddDays(-30),
|
||||
_ => DateTimeOffset.MinValue
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user