namespace GrossesMitainesAPI.Controllers; #region Dependencies using GrossesMitainesAPI.Data; using GrossesMitainesAPI.Models; using GrossesMitainesAPI.Services; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.AspNet.Identity; using System.Data; using System.Linq; #endregion [EnableCors("_myAllowSpecificOrigins"), ApiController, Route("api/[controller]"), Authorize(AuthenticationSchemes = "Identity.Application", Roles = "Administrateur")] public class InvoiceController : Controller { #region DI Fields private readonly ILogger _logger; private readonly InventoryContext _context; private readonly DatabaseCacheService _cache; private readonly SignInManager _signInMan; private readonly Microsoft.AspNetCore.Identity.UserManager _userMan; #endregion #region Ctor public InvoiceController(ILogger logger, InventoryContext context, DatabaseCacheService cache, SignInManager signInMan, Microsoft.AspNetCore.Identity.UserManager userMan) { _logger = logger; _context = context; _cache = cache; _userMan = userMan; _signInMan = signInMan; } #endregion #region API Methods [HttpGet, Authorize(Roles = "Client, Administrateur")] public async Task>> Get(bool? all = false) { IList roles; string id; try { // Trouver les rôles de l'utilisateur, assumer non-admin si impossible à trouver. var user = await _userMan.GetUserAsync(_signInMan.Context.User); roles = await _userMan.GetRolesAsync(user); } catch (Exception e) { _logger.LogError(10, e.Message); roles = new List(); } try { id = _signInMan.Context.User.Identity.GetUserId(); if (all is not null && all == true && roles.Contains("Administrateur")) return Ok(_context.Invoices .Include("ShippingAddress") .Include(x => x.Products) .ThenInclude(y => y.Product) .ToList()); else return Ok(_context.Invoices .Include("ShippingAddress") .Include(x => x.Products) .ThenInclude(y => y.Product) .Where(x => x.LinkedAccount != null && x.LinkedAccount.Id == id).ToList()); } catch (Exception e) { _logger.LogError(10, e.Message); return BadRequest(); } } [HttpGet("{id}"), Authorize(Roles = "Client, Administrateur")] public async Task> Get(int id) { IList roles; InvoiceModel inv; try { // Trouver les rôles de l'utilisateur, assumer non-admin si impossible à trouver. roles = await _userMan.GetRolesAsync(await _userMan.GetUserAsync(_signInMan.Context.User)); } catch (Exception e) { _logger.LogError(10, e.Message); roles = new List(); } try { inv = _context.Invoices.Where(x => x.Id == id).Include("ShippingAddress").First(); } catch (Exception e) { _logger.LogError(10, e.Message); return BadRequest(); } if (roles.Contains("Administrateur") || (inv.LinkedAccount is not null && inv.LinkedAccount.Id == _signInMan.Context.User.Identity.GetUserId())) return inv; else return Unauthorized(); } [HttpPost, AllowAnonymous] public async Task> Post(SendInvoiceModel sinv) { var user = await _userMan.GetUserAsync(_signInMan.Context.User); var prodcom = sinv.ProdQuant; Dictionary badprods = new(); List prods; InvoiceModel inv = new() { FirstName = sinv.FirstName, LastName = sinv.LastName, EmailAddress = sinv.EmailAddress, PhoneNumber = sinv.PhoneNumber, PurchaseDate = DateTime.Now }; AddressModel ad = _context.Addresses.FirstOrDefault(x => x.CivicNumber == sinv.CivicNumber && x.Appartment == sinv.Appartment && x.Street == sinv.Street && x.City == sinv.City && x.Province == sinv.Province && x.Country == sinv.Country) ?? new() { CivicNumber = sinv.CivicNumber, Appartment = sinv.Appartment, Street = sinv.Street, City = sinv.City, Province = sinv.Province, Country = sinv.Country, PostalCode = sinv.PostalCode }; inv.ShippingAddress = ad; if (user is not null) inv.LinkedAccount = user; try { prods = _context.Products.Where(x => sinv.ProdQuant.Select(x => x.Key).Contains(x.Id)).ToList(); } catch (Exception e) { _logger.LogError(8, e.Message); return BadRequest(); } if (prods.Count == 0) return BadRequest("Vous devez inclure au moins un produit à votre commande."); foreach (var prod in sinv.ProdQuant) { // Update de quantités dans l'inventaire. ProductModel inventProd = prods.Where(x => x.Id == prod.Key).First(); if (inventProd.Quantity > prod.Value) badprods.Add(prod.Key, prod.Value); if (inventProd.Quantity == prod.Value) { inventProd.Quantity = 0; inventProd.Status = inventProd.Status == ProductModel.States.Clearance ? ProductModel.States.Discontinued : ProductModel.States.BackOrder; } else inventProd.Quantity -= prod.Value; inventProd.LastSale = DateTime.Now; inventProd.Sales += prod.Value; } if (badprods.Count > 0) // Retour des produits non-achetable avec l'inventaire restant. return BadRequest(badprods.ToArray()); try { // Faire les updates dans la BD. _context.Addresses.Add(ad); _context.Invoices.Add(inv); _context.Products.UpdateRange(prods); _context.SaveChanges(); } catch (Exception e) { _logger.LogError(8, e.Message); return BadRequest(e.InnerException.Message); } _cache.askForRefresh(); return Ok(inv); } [HttpPost("Cancel/{id}"), Authorize(Roles = "Client, Administrateur")] public async Task> Cancel(int id) { InvoiceModel inv; IList roles; try { // Trouver la commande. inv = _context.Invoices.Where(x => x.Id == id) .Include("Product").First(); } catch (Exception e) { _logger.LogError(8, e.Message); return BadRequest(); } try { // Trouver les rôles de l'utilisateur, assumer non-admin si impossible à trouver. roles = await _userMan.GetRolesAsync(await _userMan.GetUserAsync(_signInMan.Context.User)); } catch (Exception e) { _logger.LogError(10, e.Message); roles = new List(); } // Pour ne pas pouvoir arbitrairement annuler la commande d'un autre client en tant que client. if (!((inv.LinkedAccount is not null && inv.LinkedAccount.Id == _signInMan.Context.User.Identity.GetUserId()) || roles.Contains("Administrateur"))) return Unauthorized(); if (inv.Status == InvoiceModel.InStates.Cancelled || inv.Status == InvoiceModel.InStates.Returned) return BadRequest("La commande à déjà été annulée."); if (inv.Status == InvoiceModel.InStates.Shipped) return BadRequest("Il est trop tard pour annuler votre commande, veuillez contacter le service à la clientèle pour retourner la commande."); inv.Status = InvoiceModel.InStates.Cancelled; foreach (var prod in inv.Products) { // Revert l'inventaire. if (prod.Product.Quantity == 0) if (prod.Product.Status == ProductModel.States.Discontinued) prod.Product.Status = ProductModel.States.Clearance; else prod.Product.Status = ProductModel.States.Available; prod.Product.Quantity = prod.Product.Quantity + prod.Quantity; prod.Product.Sales -= prod.Quantity; } try { _context.Update(inv); _context.SaveChanges(); } catch (Exception e) { _logger.LogError(8, e.Message); return BadRequest(); } _cache.askForRefresh(); return Ok(inv); } #endregion }