analytics and statistics
This commit is contained in:
36
Webshop.Api/Controllers/Admin/AdminAnalyticsController.cs
Normal file
36
Webshop.Api/Controllers/Admin/AdminAnalyticsController.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// src/Webshop.Api/Controllers/Admin/AdminAnalyticsController.cs
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Webshop.Application.DTOs.Admin;
|
||||||
|
using Webshop.Application.Services.Admin.Interfaces;
|
||||||
|
|
||||||
|
namespace Webshop.Api.Controllers.Admin
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Stellt aggregierte Analysedaten für das Admin-Dashboard bereit.
|
||||||
|
/// </summary>
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/v1/admin/[controller]")]
|
||||||
|
[Authorize(Roles = "Admin")]
|
||||||
|
public class AdminAnalyticsController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IAdminAnalyticsService _analyticsService;
|
||||||
|
|
||||||
|
public AdminAnalyticsController(IAdminAnalyticsService analyticsService)
|
||||||
|
{
|
||||||
|
_analyticsService = analyticsService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ruft die aggregierten Analysedaten und KPIs für den Admin-Bereich ab.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="period">Der Zeitraum für die Statistiken (Last7Days, Last30Days, AllTime). Standard ist Last30Days.</param>
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<AnalyticsDto>> GetAnalytics([FromQuery] AnalyticsPeriod period = AnalyticsPeriod.Last30Days)
|
||||||
|
{
|
||||||
|
var stats = await _analyticsService.GetAnalyticsAsync(period);
|
||||||
|
return Ok(stats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -149,6 +149,7 @@ builder.Services.AddScoped<IDiscountService, DiscountService>();
|
|||||||
builder.Services.AddScoped<IReviewService, ReviewService>();
|
builder.Services.AddScoped<IReviewService, ReviewService>();
|
||||||
builder.Services.AddScoped<ICustomerReviewService, CustomerReviewService>();
|
builder.Services.AddScoped<ICustomerReviewService, CustomerReviewService>();
|
||||||
builder.Services.AddScoped<IAdminReviewService, AdminReviewService>();
|
builder.Services.AddScoped<IAdminReviewService, AdminReviewService>();
|
||||||
|
builder.Services.AddScoped<IAdminAnalyticsService, AdminAnalyticsService>();
|
||||||
|
|
||||||
// Controller und API-Infrastruktur
|
// Controller und API-Infrastruktur
|
||||||
builder.Services.AddControllers()
|
builder.Services.AddControllers()
|
||||||
|
|||||||
114
Webshop.Application/DTOs/Admin/AnalyticsDto.cs
Normal file
114
Webshop.Application/DTOs/Admin/AnalyticsDto.cs
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
// src/Webshop.Application/DTOs/Admin/AnalyticsDto.cs
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Webshop.Application.DTOs.Admin
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Fasst alle relevanten Analysedaten und KPIs für den Admin-Bereich zusammen.
|
||||||
|
/// </summary>
|
||||||
|
public class AnalyticsDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Die wichtigsten Kennzahlen (Key Performance Indicators).
|
||||||
|
/// </summary>
|
||||||
|
public KpiSummaryDto KpiSummary { get; set; } = new KpiSummaryDto();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Eine Liste von Datenpunkten für Umsatz-Charts (z.B. Umsatz pro Tag).
|
||||||
|
/// </summary>
|
||||||
|
public List<SalesDataPointDto> SalesOverTime { get; set; } = new List<SalesDataPointDto>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Die Top 10 der meistverkauften Produkte im ausgewählten Zeitraum.
|
||||||
|
/// </summary>
|
||||||
|
public List<TopProductDto> TopPerformingProducts { get; set; } = new List<TopProductDto>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Informationen zum aktuellen Lagerbestand.
|
||||||
|
/// </summary>
|
||||||
|
public InventoryStatusDto InventoryStatus { get; set; } = new InventoryStatusDto();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Die wichtigsten Kennzahlen (Key Performance Indicators).
|
||||||
|
/// </summary>
|
||||||
|
public class KpiSummaryDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Der Gesamtumsatz (netto) im ausgewählten Zeitraum.
|
||||||
|
/// </summary>
|
||||||
|
public decimal TotalRevenue { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Die Gesamtzahl der Bestellungen im ausgewählten Zeitraum.
|
||||||
|
/// </summary>
|
||||||
|
public int TotalOrders { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Die Gesamtzahl aller registrierten Kunden.
|
||||||
|
/// </summary>
|
||||||
|
public int TotalCustomers { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Die Anzahl der Neukunden, die sich im ausgewählten Zeitraum registriert haben.
|
||||||
|
/// </summary>
|
||||||
|
public int NewCustomersThisPeriod { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Der durchschnittliche Wert einer Bestellung im ausgewählten Zeitraum.
|
||||||
|
/// </summary>
|
||||||
|
public decimal AverageOrderValue { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ein Datenpunkt für Umsatz-Charts (z.B. Umsatz pro Tag).
|
||||||
|
/// </summary>
|
||||||
|
public class SalesDataPointDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Das Datum des Datenpunkts im Format 'yyyy-MM-dd'.
|
||||||
|
/// </summary>
|
||||||
|
public string Date { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Der an diesem Tag generierte Umsatz.
|
||||||
|
/// </summary>
|
||||||
|
public decimal Revenue { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Repräsentiert ein gut verkauftes Produkt.
|
||||||
|
/// </summary>
|
||||||
|
public class TopProductDto
|
||||||
|
{
|
||||||
|
public Guid ProductId { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Sku { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Die Gesamtzahl der verkauften Einheiten im ausgewählten Zeitraum.
|
||||||
|
/// </summary>
|
||||||
|
public int UnitsSold { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Der Gesamtumsatz, der mit diesem Produkt im ausgewählten Zeitraum erzielt wurde.
|
||||||
|
/// </summary>
|
||||||
|
public decimal TotalRevenue { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Informationen zum Lagerbestand.
|
||||||
|
/// </summary>
|
||||||
|
public class InventoryStatusDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Die Anzahl der Produkte, deren Lagerbestand unter dem in den Einstellungen definierten Schwellenwert liegt.
|
||||||
|
/// </summary>
|
||||||
|
public int ProductsWithLowStock { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Der prozentuale Anteil der Produkte, die auf Lager sind (Menge > 0).
|
||||||
|
/// </summary>
|
||||||
|
public double OverallStockAvailabilityPercentage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// src/Webshop.Application/Services/Admin/Interfaces/IAdminAnalyticsService.cs
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Webshop.Application.DTOs.Admin;
|
||||||
|
|
||||||
|
namespace Webshop.Application.Services.Admin.Interfaces
|
||||||
|
{
|
||||||
|
public enum AnalyticsPeriod { Last7Days, Last30Days, AllTime }
|
||||||
|
|
||||||
|
public interface IAdminAnalyticsService
|
||||||
|
{
|
||||||
|
Task<AnalyticsDto> GetAnalyticsAsync(AnalyticsPeriod period);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user