MAJ Mathilde

This commit is contained in:
2025-10-09 15:16:08 +02:00
parent f155d03559
commit d1fa3aca68
24 changed files with 628 additions and 211 deletions

View File

@@ -1,10 +1,13 @@
using FastEndpoints;
using PyroFetes.DTO.Product.Request;
using PyroFetes.DTO.Product.Response;
using API.DTO.Product.Request;
using API.DTO.Product.Response;
using FastEndpoints;
using Microsoft.EntityFrameworkCore;
using PyroFetes.Models;
namespace PyroFetes.Endpoints.Product;
public class CreateProductEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoint<CreateProductDto, GetProductDto>
public class CreateProductEndpoint(PyroFetesDbContext db)
: Endpoint<CreateProductDto, GetProductDto>
{
public override void Configure()
{
@@ -14,7 +17,7 @@ public class CreateProductEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endp
public override async Task HandleAsync(CreateProductDto req, CancellationToken ct)
{
Models.Product product = new ()
var product = new Models.Product
{
References = req.References,
Name = req.Name!,
@@ -29,13 +32,48 @@ public class CreateProductEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endp
ProductCategoryId = req.ProductCategoryId,
ClassificationId = req.ClassificationId
};
pyrofetesdbcontext.Products.Add(product);
await pyrofetesdbcontext.SaveChangesAsync(ct);
Console.WriteLine("Product créé avec succès !");
GetProductDto responseDto = new ()
db.Products.Add(product);
await db.SaveChangesAsync(ct);
// Ajout des fournisseurs liés
if (req.Suppliers is not null && req.Suppliers.Any())
{
foreach (var s in req.Suppliers)
{
var price = new Price
{
ProductId = product.Id,
SupplierId = s.SupplierId,
SellingPrice = s.SellingPrice
};
db.Prices.Add(price);
}
await db.SaveChangesAsync(ct);
}
// Ajout des entrepôts liés
if (req.Warehouses is not null && req.Warehouses.Any())
{
foreach (var w in req.Warehouses)
{
var exists = await db.Warehouses.AnyAsync(x => x.Id == w.WarehouseId, ct);
if (!exists)
continue; // sécurité : on ignore les warehouses inexistants
var warehouseProduct = new WarehouseProduct
{
ProductId = product.Id,
WarehouseId = w.WarehouseId,
Quantity = w.Quantity
};
db.WarehouseProducts.Add(warehouseProduct);
}
await db.SaveChangesAsync(ct);
}
// Construction de la réponse
var response = new GetProductDto
{
Id = product.Id,
Reference = req.References,
@@ -49,9 +87,20 @@ public class CreateProductEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endp
Image = req.Image,
Link = req.Link,
ProductCategoryId = req.ProductCategoryId,
ClassificationId = req.ClassificationId
ClassificationId = req.ClassificationId,
Suppliers = req.Suppliers?.Select(s => new ProductSupplierPriceDto
{
SupplierId = s.SupplierId,
SellingPrice = s.SellingPrice
}).ToList() ?? new(),
Warehouses = req.Warehouses?.Select(w => new GetProductWarehouseDto
{
WarehouseId = w.WarehouseId,
Quantity = w.Quantity,
WarehouseName = db.Warehouses.FirstOrDefault(x => x.Id == w.WarehouseId)?.Name ?? string.Empty
}).ToList() ?? new()
};
await Send.OkAsync(responseDto, ct);
await Send.OkAsync(response, ct);
}
}
}

View File

@@ -1,5 +1,6 @@
using FastEndpoints;
using Microsoft.EntityFrameworkCore;
using PyroFetes.Models;
namespace PyroFetes.Endpoints.Product;
@@ -8,29 +9,50 @@ public class DeleteProductRequest
public int Id { get; set; }
}
public class DeleteProductEndpoint(PyroFetesDbContext pyrofetesdbcontext) : Endpoint<DeleteProductRequest>
public class DeleteProductEndpoint(PyroFetesDbContext db) : Endpoint<DeleteProductRequest>
{
public override void Configure()
{
Delete("/api/products/{@id}", x => new { x.Id });
AllowAnonymous();
}
public override async Task HandleAsync(DeleteProductRequest req, CancellationToken ct)
{
Models.Product? productToDelete = await pyrofetesdbcontext
.Products
.SingleOrDefaultAsync(p => p.Id == req.Id, cancellationToken: ct);
// Récupérer le produit
var productToDelete = await db.Products
.SingleOrDefaultAsync(p => p.Id == req.Id, ct);
if (productToDelete == null)
if (productToDelete is null)
{
Console.WriteLine($"Aucun produit avec l'ID {req.Id} trouvé.");
await Send.NotFoundAsync(ct);
return;
}
pyrofetesdbcontext.Products.Remove(productToDelete);
await pyrofetesdbcontext.SaveChangesAsync(ct);
// Supprimer les liaisons Price
var relatedPrices = await db.Prices
.Where(p => p.ProductId == req.Id)
.ToListAsync(ct);
if (relatedPrices.Any())
{
db.Prices.RemoveRange(relatedPrices);
}
// Supprimer les liaisons WarehouseProduct
var relatedWarehouseProducts = await db.WarehouseProducts
.Where(wp => wp.ProductId == req.Id)
.ToListAsync(ct);
if (relatedWarehouseProducts.Any())
{
db.WarehouseProducts.RemoveRange(relatedWarehouseProducts);
}
// Supprimer le produit
db.Products.Remove(productToDelete);
await db.SaveChangesAsync(ct);
Console.WriteLine($"Produit {req.Id}, ses prix et ses entrepôts liés ont été supprimés avec succès.");
await Send.NoContentAsync(ct);
}

View File

@@ -1,10 +1,13 @@
using FastEndpoints;
using API.DTO.Product.Request;
using API.DTO.Product.Response;
using FastEndpoints;
using Microsoft.EntityFrameworkCore;
using PyroFetes.DTO.Product.Response;
using PyroFetes.Models;
namespace PyroFetes.Endpoints.Product;
public class GetAllProductsEndpoint(PyroFetesDbContext pyrofetesdbcontext) : EndpointWithoutRequest<List<GetProductDto>>
public class GetAllProductsEndpoint(PyroFetesDbContext db)
: EndpointWithoutRequest<List<GetProductDto>>
{
public override void Configure()
{
@@ -14,27 +17,45 @@ public class GetAllProductsEndpoint(PyroFetesDbContext pyrofetesdbcontext) : End
public override async Task HandleAsync(CancellationToken ct)
{
List<GetProductDto> responseDto = await pyrofetesdbcontext.Products
.Select(p => new GetProductDto()
{
Id = p.Id,
Reference = p.References,
Name = p.Name,
Duration = p.Duration,
Caliber = p.Caliber,
ApprovalNumber = p.ApprovalNumber,
Weight = p.Weight,
Nec = p.Nec,
SellingPrice = p.SellingPrice,
Image = p.Image,
Link = p.Link,
ClassificationId = p.ClassificationId,
ClassificationLabel = p.Classification!.Label,
ProductCategoryId = p.ProductCategoryId,
ProductCategoryLabel = p.ProductCategory!.Label,
}
).ToListAsync(ct);
// Inclure toutes les relations nécessaires : Prices + WarehouseProducts + Warehouse
var products = await db.Products
.Include(p => p.Prices)
.Include(p => p.WarehouseProducts)
.ThenInclude(wp => wp.Warehouse)
.ToListAsync(ct);
var responseDto = products.Select(p => new GetProductDto
{
Id = p.Id,
Reference = p.References,
Name = p.Name,
Duration = p.Duration,
Caliber = p.Caliber,
ApprovalNumber = p.ApprovalNumber,
Weight = p.Weight,
Nec = p.Nec,
SellingPrice = p.SellingPrice,
Image = p.Image,
Link = p.Link,
ClassificationId = p.ClassificationId,
ProductCategoryId = p.ProductCategoryId,
// Liste des fournisseurs liés via Price
Suppliers = p.Prices.Select(pr => new ProductSupplierPriceDto
{
SupplierId = pr.SupplierId,
SellingPrice = pr.SellingPrice
}).ToList(),
// Liste des entrepôts via WarehouseProduct
Warehouses = p.WarehouseProducts.Select(wp => new GetProductWarehouseDto
{
WarehouseId = wp.WarehouseId,
WarehouseName = wp.Warehouse?.Name ?? string.Empty,
Quantity = wp.Quantity
}).ToList()
}).ToList();
await Send.OkAsync(responseDto, ct);
}
}
}

View File

@@ -1,6 +1,8 @@
using FastEndpoints;
using API.DTO.Product.Request;
using API.DTO.Product.Response;
using FastEndpoints;
using Microsoft.EntityFrameworkCore;
using PyroFetes.DTO.Product.Response;
using PyroFetes.Models;
namespace PyroFetes.Endpoints.Product;
@@ -9,20 +11,23 @@ public class GetProductRequest
public int Id { get; set; }
}
public class GetProductEndpoint(PyroFetesDbContext pyrofetesdbcontext) :Endpoint<GetProductRequest, GetProductDto>
public class GetProductEndpoint(PyroFetesDbContext db)
: Endpoint<GetProductRequest, GetProductDto>
{
public override void Configure()
{
Get("/api/product/{@id}", x => new { x.Id });
Get("/api/products/{@id}", x => new { x.Id });
AllowAnonymous();
}
public override async Task HandleAsync(GetProductRequest req, CancellationToken ct)
{
Models.Product? product = await pyrofetesdbcontext
.Products.Include(product => product.Classification).Include(product => product.ProductCategory)
.SingleOrDefaultAsync(p => p.Id == req.Id, cancellationToken: ct);
// Inclure toutes les relations : Prices + WarehouseProducts + Warehouse
var product = await db.Products
.Include(p => p.Prices)
.Include(p => p.WarehouseProducts)
.ThenInclude(wp => wp.Warehouse)
.SingleOrDefaultAsync(p => p.Id == req.Id, ct);
if (product == null)
{
@@ -31,7 +36,7 @@ public class GetProductEndpoint(PyroFetesDbContext pyrofetesdbcontext) :Endpoint
return;
}
GetProductDto responseDto = new()
var responseDto = new GetProductDto
{
Id = product.Id,
Reference = product.References,
@@ -45,11 +50,24 @@ public class GetProductEndpoint(PyroFetesDbContext pyrofetesdbcontext) :Endpoint
Image = product.Image,
Link = product.Link,
ClassificationId = product.ClassificationId,
ClassificationLabel = product.Classification!.Label,
ProductCategoryId = product.ProductCategoryId,
ProductCategoryLabel = product.ProductCategory!.Label,
ProductCategoryId = product.ProductCategoryId,
// Fournisseurs liés via Price
Suppliers = product.Prices.Select(pr => new ProductSupplierPriceDto
{
SupplierId = pr.SupplierId,
SellingPrice = pr.SellingPrice
}).ToList(),
// Entrepôts liés via WarehouseProduct
Warehouses = product.WarehouseProducts.Select(wp => new GetProductWarehouseDto
{
WarehouseId = wp.WarehouseId,
WarehouseName = wp.Warehouse?.Name ?? string.Empty,
Quantity = wp.Quantity
}).ToList()
};
await Send.OkAsync(responseDto, ct);
}
}
}

View File

@@ -1,47 +1,88 @@
using FastEndpoints;
using API.DTO.Product.Request;
using API.DTO.Product.Response;
using FastEndpoints;
using Microsoft.EntityFrameworkCore;
using PyroFetes.DTO.Product.Request;
using PyroFetes.DTO.Product.Response;
using PyroFetes.Models;
namespace PyroFetes.Endpoints.Product;
public class UpdateProductEndpoint(PyroFetesDbContext pyrofetesdbcontext) :Endpoint<UpdateProductDto, GetProductDto>
// Endpoint permettant de mettre à jour un produit existant
public class UpdateProductEndpoint(PyroFetesDbContext db)
: Endpoint<UpdateProductDto, GetProductDto>
{
public override void Configure()
{
// Route HTTP PUT avec un paramètre d'identifiant dans l'URL
Put("/api/products/{@id}", x => new { x.Id });
// Autorise les requêtes anonymes (sans authentification)
AllowAnonymous();
}
public override async Task HandleAsync(UpdateProductDto req, CancellationToken ct)
{
Models.Product? productToEdit = await pyrofetesdbcontext
.Products
.SingleOrDefaultAsync(p => p.Id == req.Id, cancellationToken: ct);
// Recherche du produit à mettre à jour, en incluant les relations Prices et WarehouseProducts
var product = await db.Products
.Include(p => p.Prices)
.Include(p => p.WarehouseProducts)
.SingleOrDefaultAsync(p => p.Id == req.Id, ct);
if (productToEdit == null)
// Si le produit n'existe pas, on retourne une réponse 404
if (product is null)
{
Console.WriteLine($"Aucun produit avec l'ID {req.Id} trouvé.");
await Send.NotFoundAsync(ct);
return;
}
productToEdit.References = req.Reference;
productToEdit.Name = req.Name;
productToEdit.Duration = req.Duration;
productToEdit.Caliber = req.Caliber;
productToEdit.ApprovalNumber = req.ApprovalNumber;
productToEdit.Weight = req.Weight;
productToEdit.Nec = req.Nec;
productToEdit.SellingPrice = req.SellingPrice;
productToEdit.Image = req.Image;
productToEdit.Link = req.Link;
await pyrofetesdbcontext.SaveChangesAsync(ct);
// Mise à jour des propriétés principales du produit
product.References = req.References;
product.Name = req.Name;
product.Duration = req.Duration;
product.Caliber = req.Caliber;
product.ApprovalNumber = req.ApprovalNumber;
product.Weight = req.Weight;
product.Nec = req.Nec;
product.SellingPrice = req.SellingPrice;
product.Image = req.Image;
product.Link = req.Link;
product.ClassificationId = req.ClassificationId;
product.ProductCategoryId = req.ProductCategoryId;
GetProductDto responseDto = new()
// Mise à jour des prix fournisseurs associés
// On supprime les anciens enregistrements pour les remplacer
db.Prices.RemoveRange(product.Prices);
foreach (var s in req.Suppliers)
{
Id = req.Id,
Reference = req.Reference,
db.Prices.Add(new Price
{
ProductId = product.Id,
SupplierId = s.SupplierId,
SellingPrice = s.SellingPrice
});
}
// Mise à jour des entrepôts associés
// On supprime les anciens liens avant d'ajouter les nouveaux
db.WarehouseProducts.RemoveRange(product.WarehouseProducts);
foreach (var w in req.Warehouses)
{
db.WarehouseProducts.Add(new WarehouseProduct
{
ProductId = product.Id,
WarehouseId = w.WarehouseId,
Quantity = w.Quantity
});
}
// Sauvegarde des modifications dans la base de données
await db.SaveChangesAsync(ct);
// Construction de la réponse renvoyée au client
// On reconstruit les listes Suppliers et Warehouses au bon format de DTO
var response = new GetProductDto
{
Id = product.Id,
Reference = req.References,
Name = req.Name,
Duration = req.Duration,
Caliber = req.Caliber,
@@ -50,9 +91,27 @@ public class UpdateProductEndpoint(PyroFetesDbContext pyrofetesdbcontext) :Endpo
Nec = req.Nec,
SellingPrice = req.SellingPrice,
Image = req.Image,
Link = req.Link
Link = req.Link,
ClassificationId = req.ClassificationId,
ProductCategoryId = req.ProductCategoryId,
// Mapping des fournisseurs pour la réponse
Suppliers = req.Suppliers.Select(s => new ProductSupplierPriceDto
{
SupplierId = s.SupplierId,
SellingPrice = s.SellingPrice
}).ToList(),
// Mapping des entrepôts pour la réponse
Warehouses = req.Warehouses.Select(w => new GetProductWarehouseDto
{
WarehouseId = w.WarehouseId,
Quantity = w.Quantity,
WarehouseName = db.Warehouses.FirstOrDefault(x => x.Id == w.WarehouseId)?.Name ?? string.Empty
}).ToList()
};
await Send.OkAsync(responseDto, ct);
// Envoi de la réponse HTTP 200 avec les données du produit mis à jour
await Send.OkAsync(response, ct);
}
}
}