Implement product multi-buys and variants system
Major restructuring of product variations: - Renamed ProductVariation to ProductMultiBuy for quantity-based pricing (e.g., "3 for £25") - Added new ProductVariant model for string-based options (colors, flavors) - Complete separation of multi-buy pricing from variant selection Features implemented: - Multi-buy deals with automatic price-per-unit calculation - Product variants for colors/flavors/sizes with stock tracking - TeleBot checkout supports both multi-buys and variant selection - Shopping cart correctly calculates multi-buy bundle prices - Order system tracks selected variants and multi-buy choices - Real-time bot activity monitoring with SignalR - Public bot directory page with QR codes for Telegram launch - Admin dashboard shows multi-buy and variant metrics Technical changes: - Updated all DTOs, services, and controllers - Fixed cart total calculation for multi-buy bundles - Comprehensive test coverage for new functionality - All existing tests passing with new features Database changes: - Migrated ProductVariations to ProductMultiBuys - Added ProductVariants table - Updated OrderItems to track variants 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
55
LittleShop/Areas/Admin/Controllers/ActivityController.cs
Normal file
55
LittleShop/Areas/Admin/Controllers/ActivityController.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using LittleShop.Services;
|
||||
|
||||
namespace LittleShop.Areas.Admin.Controllers;
|
||||
|
||||
[Area("Admin")]
|
||||
[Authorize(Policy = "AdminOnly")]
|
||||
public class ActivityController : Controller
|
||||
{
|
||||
private readonly IBotActivityService _activityService;
|
||||
private readonly ILogger<ActivityController> _logger;
|
||||
|
||||
public ActivityController(IBotActivityService activityService, ILogger<ActivityController> logger)
|
||||
{
|
||||
_activityService = activityService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
// GET: /Admin/Activity
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
// GET: /Admin/Activity/Live
|
||||
public IActionResult Live()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
// API endpoint for initial data load
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetSummary()
|
||||
{
|
||||
var summary = await _activityService.GetLiveActivitySummaryAsync();
|
||||
return Json(summary);
|
||||
}
|
||||
|
||||
// API endpoint for activity stats
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetStats(int hoursBack = 24)
|
||||
{
|
||||
var stats = await _activityService.GetActivityTypeStatsAsync(hoursBack);
|
||||
return Json(stats);
|
||||
}
|
||||
|
||||
// API endpoint for recent activities
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetRecent(int minutesBack = 5)
|
||||
{
|
||||
var activities = await _activityService.GetRecentActivitiesAsync(minutesBack);
|
||||
return Json(activities);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user