using KernelRecordsMVC.Application.ViewModels; using KernelRecordsMVC.Domain.Enums; using KernelRecordsMVC.Infrastructure.Data; using KernelRecordsMVC.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace KernelRecordsMVC.Web.Controllers; public class OrderController : Controller { private readonly KernelRecordsContext _context; public OrderController(KernelRecordsContext context) { _context = context; } // ========================================== // ADD PRODUCT TO ORDER // UC007 // ========================================== [HttpGet] public IActionResult AddProduct(long id) { var userId = GetUserId(); if (userId == null) return RedirectToAction( "Login", "Account"); var product = _context.Products .Include(p => p.Release) .FirstOrDefault(p => p.ProductId == id); if (product == null) return NotFound(); if (product.Stock <= 0) { TempData["Error"] = "This product is currently out of stock."; return RedirectToAction( "Details", "Release", new { id = product.ReleaseId }); } using var transaction = _context.Database.BeginTransaction(); try { var order = _context.Orders .Include(o => o.OrderProducts) .FirstOrDefault(o => o.UserId == userId.Value && o.Status == OrderStatusType.PENDING); if (order == null) { order = new Order { UserId = userId.Value, PaymentMethod = PaymentMethodType.CARD, PurchaseDate = DateTime.Today, PointsEarned = 0, PointsUsed = null, Status = OrderStatusType.PENDING }; _context.Orders.Add(order); _context.SaveChanges(); } var existingItem = order.OrderProducts .FirstOrDefault(x => x.ProductId == product.ProductId); if (existingItem != null) { if (existingItem.Quantity + 1 > product.Stock) { TempData["Error"] = "There is not enough stock available."; transaction.Rollback(); return RedirectToAction( "Details", "Release", new { id = product.ReleaseId }); } existingItem.Quantity++; } else { var discount = _context.ModificationProducts .Include(mp => mp.Modification) .Where(mp => mp.ProductId == product.ProductId && mp.Modification.TypeOfModification == ModificationType.DISCOUNT && mp.Modification.Discount.HasValue && mp.Modification.Discount.Value > 0) .Select(mp => mp.Modification) .OrderByDescending(m => m.DateModified) .FirstOrDefault(); var priceAtPurchase = product.Price; if (discount != null) { priceAtPurchase = product.Price - ( product.Price * discount.Discount!.Value / 100m ); priceAtPurchase = Math.Round( priceAtPurchase, 2); } var orderProduct = new OrderProduct { OrderId = order.OrderId, ProductId = product.ProductId, PriceAtPurchase = priceAtPurchase, Quantity = 1 }; _context.OrderProducts.Add(orderProduct); } _context.SaveChanges(); transaction.Commit(); return RedirectToAction(nameof(Cart)); } catch { transaction.Rollback(); throw; } } // ========================================== // CART // ========================================== [HttpGet] public IActionResult Cart() { var userId = GetUserId(); if (userId == null) { return RedirectToAction( "Login", "Account"); } var order = _context.Orders .Include(o => o.OrderProducts) .ThenInclude(op => op.Product) .ThenInclude(p => p.Release) .FirstOrDefault(o => o.UserId == userId.Value && o.Status == OrderStatusType.PENDING); var viewModel = new CartViewModel(); if (order != null) { viewModel.Items = order.OrderProducts .Select(op => new CartItemViewModel { ProductId = op.ProductId, ReleaseId = op.Product.ReleaseId, ReleaseTitle = op.Product.Release.Title, Format = op.Product.Format.ToString(), Price = op.PriceAtPurchase, Quantity = op.Quantity, Stock = op.Product.Stock, CoverPhoto = op.Product.Release.CoverPhoto }) .ToList(); } return View(viewModel); } // ========================================== // REMOVE PRODUCT // ========================================== [HttpPost] [ValidateAntiForgeryToken] public IActionResult RemoveProduct(long id) { var userId = GetUserId(); if (userId == null) return RedirectToAction( "Login", "Account"); var item = _context.OrderProducts .Include(x => x.Order) .FirstOrDefault(x => x.ProductId == id && x.Order.UserId == userId.Value && x.Order.Status == OrderStatusType.PENDING); if (item != null) { _context.OrderProducts.Remove(item); _context.SaveChanges(); } return RedirectToAction(nameof(Cart)); } // ========================================== // UPDATE QUANTITY // ========================================== [HttpPost] [ValidateAntiForgeryToken] public IActionResult UpdateQuantity( long id, long quantity) { var userId = GetUserId(); if (userId == null) return RedirectToAction( "Login", "Account"); if (quantity <= 0) { return RemoveProduct(id); } var item = _context.OrderProducts .Include(x => x.Order) .Include(x => x.Product) .FirstOrDefault(x => x.ProductId == id && x.Order.UserId == userId.Value && x.Order.Status == OrderStatusType.PENDING); if (item == null) return NotFound(); if (quantity > item.Product.Stock) { TempData["Error"] = "The requested quantity exceeds available stock."; return RedirectToAction(nameof(Cart)); } item.Quantity = quantity; _context.SaveChanges(); return RedirectToAction(nameof(Cart)); } // ========================================== // USER ID // ========================================== private long? GetUserId() { var userId = HttpContext.Session.GetInt32("UserId"); if (userId.HasValue) return userId.Value; return null; } }