From e52cef083b753c09544f8e44cbc5b8724aceaafa Mon Sep 17 00:00:00 2001 From: lumijiez <59575049+lumijiez@users.noreply.github.com> Date: Mon, 26 May 2025 11:42:52 +0300 Subject: [PATCH] Remove almost everything :( --- .../Printbase.Application.csproj | 4 - .../CreateProduct/CreateProductCommand.cs | 12 - .../CreateProductCommandHandler.cs | 95 ------- .../CreateProduct/CreateProductVariantDto.cs | 11 - .../Products/Dtos/AllProductsDto.cs | 6 - .../Products/Dtos/ProductDto.cs | 15 -- .../Products/Dtos/ProductVariantDto.cs | 14 -- .../GetAllProducts/GetAllProductsQuery.cs | 9 - .../GetAllProductsQueryHandler.cs | 48 ---- .../GetProductById/GetProductByIdQuery.cs | 10 - .../GetProductByIdQueryHandler.cs | 56 ----- .../Entities/Products/Product.cs | 14 -- .../Entities/Products/ProductGroup.cs | 12 - .../Entities/Products/ProductType.cs | 14 -- .../Entities/Products/ProductVariant.cs | 27 -- .../Repositories/IProductGroupRepository.cs | 13 - .../Repositories/IProductRepository.cs | 14 -- .../Repositories/IProductTypeRepository.cs | 14 -- .../Repositories/IProductVariantRepository.cs | 14 -- .../Database/ApplicationDbContext.cs | 35 --- .../DbEntities/Products/ProductDbEntity.cs | 34 --- .../Products/ProductGroupDbEntity.cs | 30 --- .../Products/ProductTypeDbEntity.cs | 36 --- .../Products/ProductVariantDbEntity.cs | 47 ---- .../Mappings/ProductMappingProfile.cs | 61 ----- .../20250504210542_InitialCreate.Designer.cs | 231 ------------------ .../20250504210542_InitialCreate.cs | 149 ----------- .../ApplicationDbContextModelSnapshot.cs | 228 ----------------- .../Repositories/ProductGroupRepository.cs | 80 ------ .../Repositories/ProductRepository.cs | 119 --------- .../Repositories/ProductTypeRepository.cs | 112 --------- .../Repositories/ProductVariantRepository.cs | 102 -------- .../Controllers/ProductsController.cs | 56 ----- src/Printbase.WebApi/Startup.cs | 27 +- .../CreateProduct/GenerateSkuTests.cs | 187 -------------- 35 files changed, 1 insertion(+), 1935 deletions(-) delete mode 100644 src/Printbase.Application/Products/Commands/CreateProduct/CreateProductCommand.cs delete mode 100644 src/Printbase.Application/Products/Commands/CreateProduct/CreateProductCommandHandler.cs delete mode 100644 src/Printbase.Application/Products/Commands/CreateProduct/CreateProductVariantDto.cs delete mode 100644 src/Printbase.Application/Products/Dtos/AllProductsDto.cs delete mode 100644 src/Printbase.Application/Products/Dtos/ProductDto.cs delete mode 100644 src/Printbase.Application/Products/Dtos/ProductVariantDto.cs delete mode 100644 src/Printbase.Application/Products/Queries/GetAllProducts/GetAllProductsQuery.cs delete mode 100644 src/Printbase.Application/Products/Queries/GetAllProducts/GetAllProductsQueryHandler.cs delete mode 100644 src/Printbase.Application/Products/Queries/GetProductById/GetProductByIdQuery.cs delete mode 100644 src/Printbase.Application/Products/Queries/GetProductById/GetProductByIdQueryHandler.cs delete mode 100644 src/Printbase.Domain/Entities/Products/Product.cs delete mode 100644 src/Printbase.Domain/Entities/Products/ProductGroup.cs delete mode 100644 src/Printbase.Domain/Entities/Products/ProductType.cs delete mode 100644 src/Printbase.Domain/Entities/Products/ProductVariant.cs delete mode 100644 src/Printbase.Domain/Repositories/IProductGroupRepository.cs delete mode 100644 src/Printbase.Domain/Repositories/IProductRepository.cs delete mode 100644 src/Printbase.Domain/Repositories/IProductTypeRepository.cs delete mode 100644 src/Printbase.Domain/Repositories/IProductVariantRepository.cs delete mode 100644 src/Printbase.Infrastructure/DbEntities/Products/ProductDbEntity.cs delete mode 100644 src/Printbase.Infrastructure/DbEntities/Products/ProductGroupDbEntity.cs delete mode 100644 src/Printbase.Infrastructure/DbEntities/Products/ProductTypeDbEntity.cs delete mode 100644 src/Printbase.Infrastructure/DbEntities/Products/ProductVariantDbEntity.cs delete mode 100644 src/Printbase.Infrastructure/Mappings/ProductMappingProfile.cs delete mode 100644 src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.Designer.cs delete mode 100644 src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.cs delete mode 100644 src/Printbase.Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs delete mode 100644 src/Printbase.Infrastructure/Repositories/ProductGroupRepository.cs delete mode 100644 src/Printbase.Infrastructure/Repositories/ProductRepository.cs delete mode 100644 src/Printbase.Infrastructure/Repositories/ProductTypeRepository.cs delete mode 100644 src/Printbase.Infrastructure/Repositories/ProductVariantRepository.cs delete mode 100644 src/Printbase.WebApi/Controllers/ProductsController.cs delete mode 100644 tests/Printbase.Application.Tests/Products/Commands/CreateProduct/GenerateSkuTests.cs diff --git a/src/Printbase.Application/Printbase.Application.csproj b/src/Printbase.Application/Printbase.Application.csproj index e80f671..da6040d 100644 --- a/src/Printbase.Application/Printbase.Application.csproj +++ b/src/Printbase.Application/Printbase.Application.csproj @@ -17,8 +17,4 @@ - - - - diff --git a/src/Printbase.Application/Products/Commands/CreateProduct/CreateProductCommand.cs b/src/Printbase.Application/Products/Commands/CreateProduct/CreateProductCommand.cs deleted file mode 100644 index f107b64..0000000 --- a/src/Printbase.Application/Products/Commands/CreateProduct/CreateProductCommand.cs +++ /dev/null @@ -1,12 +0,0 @@ -using MediatR; -using Printbase.Application.Products.Dtos; - -namespace Printbase.Application.Products.Commands.CreateProduct; - -public class CreateProductCommand : IRequest -{ - public string Name { get; set; } = string.Empty; - public string? Description { get; set; } - public Guid TypeId { get; set; } - public List? Variants { get; set; } -} \ No newline at end of file diff --git a/src/Printbase.Application/Products/Commands/CreateProduct/CreateProductCommandHandler.cs b/src/Printbase.Application/Products/Commands/CreateProduct/CreateProductCommandHandler.cs deleted file mode 100644 index b02d710..0000000 --- a/src/Printbase.Application/Products/Commands/CreateProduct/CreateProductCommandHandler.cs +++ /dev/null @@ -1,95 +0,0 @@ -using MediatR; -using Printbase.Application.Products.Dtos; -using Printbase.Domain.Entities.Products; -using Printbase.Domain.Repositories; - -namespace Printbase.Application.Products.Commands.CreateProduct; - -public class CreateProductCommandHandler( - IProductRepository productRepository, - IProductVariantRepository variantRepository, - IProductTypeRepository typeRepository) - : IRequestHandler -{ - private readonly IProductRepository _productRepository = productRepository ?? throw new ArgumentNullException(nameof(productRepository)); - private readonly IProductVariantRepository _variantRepository = variantRepository ?? throw new ArgumentNullException(nameof(variantRepository)); - private readonly IProductTypeRepository _typeRepository = typeRepository ?? throw new ArgumentNullException(nameof(typeRepository)); - - public async Task Handle(CreateProductCommand request, CancellationToken cancellationToken) - { - var productType = await _typeRepository.GetByIdAsync(request.TypeId, includeRelations: true, cancellationToken); - if (productType == null) - { - throw new ArgumentException($"Product type with ID {request.TypeId} not found"); - } - - var product = new Product - { - Id = Guid.NewGuid(), - Name = request.Name, - Description = request.Description, - TypeId = request.TypeId, - CreatedAt = DateTime.UtcNow, - IsActive = true - }; - - var createdProduct = await _productRepository.AddAsync(product, cancellationToken); - - var productVariants = new List(); - if (request.Variants != null && request.Variants.Count != 0) - { - foreach (var variant in request.Variants.Select(variantDto => new ProductVariant - { - Id = Guid.NewGuid(), - ProductId = createdProduct.Id, - Color = variantDto.Color, - Size = variantDto.Size, - Price = variantDto.Price, - Discount = variantDto.Discount, - Stock = variantDto.Stock, - SKU = variantDto.SKU ?? GenerateSku(createdProduct.Name, variantDto.Color, variantDto.Size), - CreatedAt = DateTime.UtcNow, - IsActive = true - })) - { - var createdVariant = await _variantRepository.AddAsync(variant, cancellationToken); - productVariants.Add(createdVariant); - } - } - - var productDto = new ProductDto - { - Id = createdProduct.Id, - Name = createdProduct.Name, - Description = createdProduct.Description, - TypeId = createdProduct.TypeId, - TypeName = productType.Name, - GroupName = productType.Group.Name, - CreatedAt = createdProduct.CreatedAt, - IsActive = createdProduct.IsActive, - Variants = productVariants.Select(v => new ProductVariantDto - { - Id = v.Id, - Color = v.Color, - Size = v.Size, - Price = v.Price, - Discount = v.Discount, - Stock = v.Stock, - SKU = v.SKU, - IsActive = v.IsActive - }).ToList() - }; - - return productDto; - } - - public static string GenerateSku(string productName, string? color, string? size) - { - var prefix = productName.Length >= 3 ? productName[..3].ToUpper() : productName.ToUpper(); - var colorPart = !string.IsNullOrEmpty(color) ? color[..Math.Min(3, color.Length)].ToUpper() : "XXX"; - var sizePart = !string.IsNullOrEmpty(size) ? size.ToUpper() : "OS"; - var randomPart = new Random().Next(100, 999).ToString(); - - return $"{prefix}-{colorPart}-{sizePart}-{randomPart}"; - } -} \ No newline at end of file diff --git a/src/Printbase.Application/Products/Commands/CreateProduct/CreateProductVariantDto.cs b/src/Printbase.Application/Products/Commands/CreateProduct/CreateProductVariantDto.cs deleted file mode 100644 index ac2ffbb..0000000 --- a/src/Printbase.Application/Products/Commands/CreateProduct/CreateProductVariantDto.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Printbase.Application.Products.Commands.CreateProduct; - -public class CreateProductVariantDto -{ - public string? Color { get; set; } - public string? Size { get; set; } - public decimal Price { get; set; } - public decimal? Discount { get; set; } - public int Stock { get; set; } - public string? SKU { get; set; } -} \ No newline at end of file diff --git a/src/Printbase.Application/Products/Dtos/AllProductsDto.cs b/src/Printbase.Application/Products/Dtos/AllProductsDto.cs deleted file mode 100644 index 0363924..0000000 --- a/src/Printbase.Application/Products/Dtos/AllProductsDto.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Printbase.Application.Products.Dtos; - -public class AllProductsDto -{ - public ICollection Products {get;set;} -} \ No newline at end of file diff --git a/src/Printbase.Application/Products/Dtos/ProductDto.cs b/src/Printbase.Application/Products/Dtos/ProductDto.cs deleted file mode 100644 index d7b0acd..0000000 --- a/src/Printbase.Application/Products/Dtos/ProductDto.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Printbase.Application.Products.Dtos; - -public class ProductDto -{ - public Guid Id { get; set; } - public string Name { get; set; } = string.Empty; - public string? Description { get; set; } - public Guid TypeId { get; set; } - public string TypeName { get; set; } = string.Empty; - public string GroupName { get; set; } = string.Empty; - public ICollection Variants { get; set; } = new List(); - public DateTime CreatedAt { get; set; } - public DateTime? UpdatedAt { get; set; } - public bool IsActive { get; set; } -} \ No newline at end of file diff --git a/src/Printbase.Application/Products/Dtos/ProductVariantDto.cs b/src/Printbase.Application/Products/Dtos/ProductVariantDto.cs deleted file mode 100644 index 78fab47..0000000 --- a/src/Printbase.Application/Products/Dtos/ProductVariantDto.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Printbase.Application.Products.Dtos; - -public class ProductVariantDto -{ - public Guid Id { get; set; } - public string? Color { get; set; } - public string? Size { get; set; } - public decimal Price { get; set; } - public decimal? Discount { get; set; } - public decimal DiscountedPrice => Discount is > 0 ? Price - Price * Discount.Value / 100m : Price; - public int Stock { get; set; } - public string? SKU { get; set; } - public bool IsActive { get; set; } -} \ No newline at end of file diff --git a/src/Printbase.Application/Products/Queries/GetAllProducts/GetAllProductsQuery.cs b/src/Printbase.Application/Products/Queries/GetAllProducts/GetAllProductsQuery.cs deleted file mode 100644 index e3b29f8..0000000 --- a/src/Printbase.Application/Products/Queries/GetAllProducts/GetAllProductsQuery.cs +++ /dev/null @@ -1,9 +0,0 @@ -using MediatR; -using Printbase.Application.Products.Dtos; - -namespace Printbase.Application.Products.Queries.GetAllProducts; - -public class GetAllProductsQuery(bool includeVariants = true) : IRequest -{ - public bool IncludeVariants { get; } = includeVariants; -} \ No newline at end of file diff --git a/src/Printbase.Application/Products/Queries/GetAllProducts/GetAllProductsQueryHandler.cs b/src/Printbase.Application/Products/Queries/GetAllProducts/GetAllProductsQueryHandler.cs deleted file mode 100644 index a856c49..0000000 --- a/src/Printbase.Application/Products/Queries/GetAllProducts/GetAllProductsQueryHandler.cs +++ /dev/null @@ -1,48 +0,0 @@ -using MediatR; -using Printbase.Application.Products.Dtos; -using Printbase.Domain.Repositories; - -namespace Printbase.Application.Products.Queries.GetAllProducts; - -public class GetAllProductsQueryHandler(IProductRepository productRepository) - : IRequestHandler -{ - private readonly IProductRepository _productRepository = productRepository - ?? throw new ArgumentNullException(nameof(productRepository)); - - public async Task Handle(GetAllProductsQuery request, CancellationToken cancellationToken) - { - var products = await _productRepository.GetAllAsync(true, cancellationToken); - - var allProducts = new AllProductsDto - { - Products = products.Select(p => new ProductDto - { - Id = p.Id, - Name = p.Name, - Description = p.Description, - TypeId = p.TypeId, - TypeName = p.Type.Name, - GroupName = p.Type.Group.Name, - CreatedAt = p.CreatedAt, - UpdatedAt = p.UpdatedAt, - IsActive = p.IsActive, - Variants = request.IncludeVariants - ? p.Variants.Select(v => new ProductVariantDto - { - Id = v.Id, - Color = v.Color, - Size = v.Size, - Price = v.Price, - Discount = v.Discount, - Stock = v.Stock, - SKU = v.SKU, - IsActive = v.IsActive - }).ToList() - : [] - }).ToList() - }; - - return allProducts; - } -} \ No newline at end of file diff --git a/src/Printbase.Application/Products/Queries/GetProductById/GetProductByIdQuery.cs b/src/Printbase.Application/Products/Queries/GetProductById/GetProductByIdQuery.cs deleted file mode 100644 index 6fef39d..0000000 --- a/src/Printbase.Application/Products/Queries/GetProductById/GetProductByIdQuery.cs +++ /dev/null @@ -1,10 +0,0 @@ -using MediatR; -using Printbase.Application.Products.Dtos; - -namespace Printbase.Application.Products.Queries.GetProductById; - -public class GetProductByIdQuery(Guid id, bool includeVariants = true) : IRequest -{ - public Guid Id { get; } = id; - public bool IncludeVariants { get; } = includeVariants; -} \ No newline at end of file diff --git a/src/Printbase.Application/Products/Queries/GetProductById/GetProductByIdQueryHandler.cs b/src/Printbase.Application/Products/Queries/GetProductById/GetProductByIdQueryHandler.cs deleted file mode 100644 index 87ee864..0000000 --- a/src/Printbase.Application/Products/Queries/GetProductById/GetProductByIdQueryHandler.cs +++ /dev/null @@ -1,56 +0,0 @@ -using AutoMapper; -using MediatR; -using Printbase.Application.Products.Dtos; -using Printbase.Domain.Repositories; - -namespace Printbase.Application.Products.Queries.GetProductById; - -public class GetProductByIdQueryHandler(IProductRepository productRepository, IMapper mapper) - : IRequestHandler -{ - private readonly IProductRepository _productRepository = productRepository - ?? throw new ArgumentNullException(nameof(productRepository)); - private readonly IMapper _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); - - public async Task Handle(GetProductByIdQuery request, CancellationToken cancellationToken) - { - var product = await _productRepository.GetByIdAsync(request.Id, includeRelations: true, cancellationToken); - - if (product == null) - { - return null; - } - - var productDto = new ProductDto - { - Id = product.Id, - Name = product.Name, - Description = product.Description, - TypeId = product.TypeId, - TypeName = product.Type.Name, - GroupName = product.Type.Group.Name, - CreatedAt = product.CreatedAt, - UpdatedAt = product.UpdatedAt, - IsActive = product.IsActive - }; - - if (request.IncludeVariants) - { - productDto.Variants = product.Variants - .Select(v => new ProductVariantDto - { - Id = v.Id, - Color = v.Color, - Size = v.Size, - Price = v.Price, - Discount = v.Discount, - Stock = v.Stock, - SKU = v.SKU, - IsActive = v.IsActive - }) - .ToList(); - } - - return productDto; - } -} \ No newline at end of file diff --git a/src/Printbase.Domain/Entities/Products/Product.cs b/src/Printbase.Domain/Entities/Products/Product.cs deleted file mode 100644 index 573ed8d..0000000 --- a/src/Printbase.Domain/Entities/Products/Product.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Printbase.Domain.Entities.Products; - -public class Product -{ - public Guid Id { get; set; } - public string Name { get; set; } = string.Empty; - public string? Description { get; set; } - public Guid TypeId { get; set; } - public ProductType Type { get; set; } = null!; - public ICollection Variants { get; set; } = new List(); - public DateTime CreatedAt { get; set; } - public DateTime? UpdatedAt { get; set; } - public bool IsActive { get; set; } -} \ No newline at end of file diff --git a/src/Printbase.Domain/Entities/Products/ProductGroup.cs b/src/Printbase.Domain/Entities/Products/ProductGroup.cs deleted file mode 100644 index e608022..0000000 --- a/src/Printbase.Domain/Entities/Products/ProductGroup.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Printbase.Domain.Entities.Products; - -public class ProductGroup -{ - public Guid Id { get; set; } - public string Name { get; set; } = string.Empty; - public string? Description { get; set; } - public ICollection Types { get; set; } = new List(); - public DateTime CreatedAt { get; set; } - public DateTime? UpdatedAt { get; set; } - public bool IsActive { get; set; } -} \ No newline at end of file diff --git a/src/Printbase.Domain/Entities/Products/ProductType.cs b/src/Printbase.Domain/Entities/Products/ProductType.cs deleted file mode 100644 index b12d6b0..0000000 --- a/src/Printbase.Domain/Entities/Products/ProductType.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Printbase.Domain.Entities.Products; - -public class ProductType -{ - public Guid Id { get; set; } - public string Name { get; set; } = string.Empty; - public string? Description { get; set; } - public Guid GroupId { get; set; } - public ProductGroup Group { get; set; } = null!; - public ICollection Products { get; set; } = new List(); - public DateTime CreatedAt { get; set; } - public DateTime? UpdatedAt { get; set; } - public bool IsActive { get; set; } -} \ No newline at end of file diff --git a/src/Printbase.Domain/Entities/Products/ProductVariant.cs b/src/Printbase.Domain/Entities/Products/ProductVariant.cs deleted file mode 100644 index c6246ba..0000000 --- a/src/Printbase.Domain/Entities/Products/ProductVariant.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Printbase.Domain.Entities.Products; - -public class ProductVariant -{ - public Guid Id { get; set; } - public Guid ProductId { get; set; } - public string? Color { get; set; } - public string? Size { get; set; } - public decimal Price { get; set; } - public decimal? Discount { get; set; } - public int Stock { get; set; } - public string? SKU { get; set; } - public Product Product { get; set; } = null!; - public DateTime CreatedAt { get; set; } - public DateTime? UpdatedAt { get; set; } - public bool IsActive { get; set; } - - public decimal GetDiscountedPrice() - { - if (Discount is > 0) - { - return Price - Price * Discount.Value / 100m; - } - - return Price; - } -} \ No newline at end of file diff --git a/src/Printbase.Domain/Repositories/IProductGroupRepository.cs b/src/Printbase.Domain/Repositories/IProductGroupRepository.cs deleted file mode 100644 index ab963a0..0000000 --- a/src/Printbase.Domain/Repositories/IProductGroupRepository.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Printbase.Domain.Entities.Products; - -namespace Printbase.Domain.Repositories; - -public interface IProductGroupRepository -{ - Task GetByIdAsync(Guid id, bool includeRelations = false, CancellationToken cancellationToken = default); - Task> GetAllAsync(bool includeRelations = false, CancellationToken cancellationToken = default); - Task AddAsync(ProductGroup group, CancellationToken cancellationToken = default); - Task UpdateAsync(ProductGroup group, CancellationToken cancellationToken = default); - Task DeleteAsync(Guid id, CancellationToken cancellationToken = default); - Task ExistsAsync(Guid id, CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/src/Printbase.Domain/Repositories/IProductRepository.cs b/src/Printbase.Domain/Repositories/IProductRepository.cs deleted file mode 100644 index f810121..0000000 --- a/src/Printbase.Domain/Repositories/IProductRepository.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Printbase.Domain.Entities.Products; - -namespace Printbase.Domain.Repositories; - -public interface IProductRepository -{ - Task GetByIdAsync(Guid id, bool includeRelations = false, CancellationToken cancellationToken = default); - Task> GetAllAsync(bool includeRelations = false, CancellationToken cancellationToken = default); - Task> GetByTypeIdAsync(Guid typeId, bool includeRelations = false, CancellationToken cancellationToken = default); - Task AddAsync(Product product, CancellationToken cancellationToken = default); - Task UpdateAsync(Product product, CancellationToken cancellationToken = default); - Task DeleteAsync(Guid id, CancellationToken cancellationToken = default); - Task ExistsAsync(Guid id, CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/src/Printbase.Domain/Repositories/IProductTypeRepository.cs b/src/Printbase.Domain/Repositories/IProductTypeRepository.cs deleted file mode 100644 index 0603b59..0000000 --- a/src/Printbase.Domain/Repositories/IProductTypeRepository.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Printbase.Domain.Entities.Products; - -namespace Printbase.Domain.Repositories; - -public interface IProductTypeRepository -{ - Task GetByIdAsync(Guid id, bool includeRelations = false, CancellationToken cancellationToken = default); - Task> GetAllAsync(bool includeRelations = false, CancellationToken cancellationToken = default); - Task> GetByGroupIdAsync(Guid groupId, CancellationToken cancellationToken = default); - Task AddAsync(ProductType type, CancellationToken cancellationToken = default); - Task UpdateAsync(ProductType type, CancellationToken cancellationToken = default); - Task DeleteAsync(Guid id, CancellationToken cancellationToken = default); - Task ExistsAsync(Guid id, CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/src/Printbase.Domain/Repositories/IProductVariantRepository.cs b/src/Printbase.Domain/Repositories/IProductVariantRepository.cs deleted file mode 100644 index de6b560..0000000 --- a/src/Printbase.Domain/Repositories/IProductVariantRepository.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Printbase.Domain.Entities.Products; - -namespace Printbase.Domain.Repositories; - -public interface IProductVariantRepository -{ - Task GetByIdAsync(Guid id, bool includeRelations = false, CancellationToken cancellationToken = default); - Task> GetAllAsync(bool includeRelations = false, CancellationToken cancellationToken = default); - Task> GetByProductIdAsync(Guid productId, CancellationToken cancellationToken = default); - Task AddAsync(ProductVariant variant, CancellationToken cancellationToken = default); - Task UpdateAsync(ProductVariant variant, CancellationToken cancellationToken = default); - Task DeleteAsync(Guid id, CancellationToken cancellationToken = default); - Task ExistsAsync(Guid id, CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/src/Printbase.Infrastructure/Database/ApplicationDbContext.cs b/src/Printbase.Infrastructure/Database/ApplicationDbContext.cs index 5e056f5..a8aaeb4 100644 --- a/src/Printbase.Infrastructure/Database/ApplicationDbContext.cs +++ b/src/Printbase.Infrastructure/Database/ApplicationDbContext.cs @@ -5,39 +5,4 @@ namespace Printbase.Infrastructure.Database; public class ApplicationDbContext(DbContextOptions? options) : DbContext(options) { - public DbSet Products { get; set; } = null!; - public DbSet ProductVariants { get; set; } = null!; - public DbSet ProductTypes { get; set; } = null!; - public DbSet ProductGroups { get; set; } = null!; - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - modelBuilder.Entity() - .HasMany(p => p.Variants) - .WithOne(v => v.Product) - .HasForeignKey(v => v.ProductId) - .OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity() - .HasOne(p => p.Type) - .WithMany(t => t.Products) - .HasForeignKey(p => p.TypeId) - .OnDelete(DeleteBehavior.Restrict); - - modelBuilder.Entity() - .HasOne(t => t.Group) - .WithMany(g => g.Types) - .HasForeignKey(t => t.GroupId) - .OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity() - .Property(v => v.Price) - .HasPrecision(18, 2); - - modelBuilder.Entity() - .Property(v => v.Discount) - .HasPrecision(18, 2); - } } \ No newline at end of file diff --git a/src/Printbase.Infrastructure/DbEntities/Products/ProductDbEntity.cs b/src/Printbase.Infrastructure/DbEntities/Products/ProductDbEntity.cs deleted file mode 100644 index 06a7e96..0000000 --- a/src/Printbase.Infrastructure/DbEntities/Products/ProductDbEntity.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace Printbase.Infrastructure.DbEntities.Products; - -[Table("Products")] -public class ProductDbEntity -{ - [Key, Required] - public Guid Id { get; set; } - - [MaxLength(50), Required] - public required string Name { get; set; } - - [MaxLength(1000)] - public string? Description { get; set; } - - [Required] - public Guid TypeId { get; set; } - - [Required] - public DateTime CreatedAt { get; set; } = DateTime.UtcNow; - - public DateTime? UpdatedAt { get; set; } - - [Required] - public bool IsActive { get; set; } = true; - - [ForeignKey(nameof(TypeId)), Required] - public required ProductTypeDbEntity Type { get; set; } - - [InverseProperty(nameof(ProductVariantDbEntity.Product)), Required] - public required ICollection Variants { get; set; } = []; -} \ No newline at end of file diff --git a/src/Printbase.Infrastructure/DbEntities/Products/ProductGroupDbEntity.cs b/src/Printbase.Infrastructure/DbEntities/Products/ProductGroupDbEntity.cs deleted file mode 100644 index b9b4285..0000000 --- a/src/Printbase.Infrastructure/DbEntities/Products/ProductGroupDbEntity.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Microsoft.EntityFrameworkCore; - -namespace Printbase.Infrastructure.DbEntities.Products; - -[Table("ProductGroups")] -[Index(nameof(Name), IsUnique = true)] -public class ProductGroupDbEntity -{ - [Key, Required] - public Guid Id { get; set; } - - [MaxLength(50), Required] - public required string Name { get; set; } - - [MaxLength(255)] - public string? Description { get; set; } - - [InverseProperty(nameof(ProductTypeDbEntity.Group)), Required] - public required ICollection Types { get; set; } = []; - - [Required] - public DateTime CreatedAt { get; set; } = DateTime.UtcNow; - - public DateTime? UpdatedAt { get; set; } - - [Required] - public bool IsActive { get; set; } = true; -} \ No newline at end of file diff --git a/src/Printbase.Infrastructure/DbEntities/Products/ProductTypeDbEntity.cs b/src/Printbase.Infrastructure/DbEntities/Products/ProductTypeDbEntity.cs deleted file mode 100644 index 4cda53f..0000000 --- a/src/Printbase.Infrastructure/DbEntities/Products/ProductTypeDbEntity.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Microsoft.EntityFrameworkCore; - -namespace Printbase.Infrastructure.DbEntities.Products; - -[Table("ProductTypes")] -[Index(nameof(Name), nameof(GroupId), IsUnique = true)] -public class ProductTypeDbEntity -{ - [Key, Required] - public Guid Id { get; set; } - - [MaxLength(50), Required] - public required string Name { get; set; } - - [MaxLength(255)] - public string? Description { get; set; } - - [Required] - public Guid GroupId { get; set; } - - [ForeignKey(nameof(GroupId)), Required] - public required ProductGroupDbEntity Group { get; set; } - - [InverseProperty(nameof(ProductDbEntity.Type)), Required] - public required ICollection Products { get; set; } = []; - - [Required] - public DateTime CreatedAt { get; set; } = DateTime.UtcNow; - - public DateTime? UpdatedAt { get; set; } - - [Required] - public bool IsActive { get; set; } = true; -} \ No newline at end of file diff --git a/src/Printbase.Infrastructure/DbEntities/Products/ProductVariantDbEntity.cs b/src/Printbase.Infrastructure/DbEntities/Products/ProductVariantDbEntity.cs deleted file mode 100644 index 0c5f48b..0000000 --- a/src/Printbase.Infrastructure/DbEntities/Products/ProductVariantDbEntity.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Microsoft.EntityFrameworkCore; - -namespace Printbase.Infrastructure.DbEntities.Products; - -[Table("ProductVariants")] -[Index(nameof(ProductId), nameof(Color), nameof(Size), IsUnique = true)] -public class ProductVariantDbEntity -{ - [Key, Required] - public Guid Id { get; set; } - - [Required] - public Guid ProductId { get; set; } - - [MaxLength(50)] - public string? Color { get; set; } - - [MaxLength(20)] - public string? Size { get; set; } - - [Column(TypeName = "decimal(18,2)"), Required] - [Range(0.01, 9999999.99)] - public decimal Price { get; set; } - - [Range(0, 100)] - public decimal? Discount { get; set; } - - [Required] - [Range(0, int.MaxValue)] - public int Stock { get; set; } - - [MaxLength(50)] - public string? SKU { get; set; } - - [ForeignKey(nameof(ProductId)), Required] - public required ProductDbEntity Product { get; set; } - - [Required] - public DateTime CreatedAt { get; set; } = DateTime.UtcNow; - - public DateTime? UpdatedAt { get; set; } - - [Required] - public bool IsActive { get; set; } = true; -} \ No newline at end of file diff --git a/src/Printbase.Infrastructure/Mappings/ProductMappingProfile.cs b/src/Printbase.Infrastructure/Mappings/ProductMappingProfile.cs deleted file mode 100644 index 8a7e2ab..0000000 --- a/src/Printbase.Infrastructure/Mappings/ProductMappingProfile.cs +++ /dev/null @@ -1,61 +0,0 @@ -using AutoMapper; -using Printbase.Application.Products.Commands.CreateProduct; -using Printbase.Application.Products.Dtos; -using Printbase.Domain.Entities.Products; -using Printbase.Infrastructure.DbEntities.Products; - -namespace Printbase.Infrastructure.Mappings; - -public class ProductMappingProfile : Profile -{ - public ProductMappingProfile() - { - // Product DbEntity -> Domain Entity - CreateMap() - .ForMember(dest => dest.Type, - opt => opt.MapFrom(src => src.Type)) - .ForMember(dest => dest.Variants, - opt => opt.MapFrom(src => src.Variants)); - - // ProductGroup DbEntity -> Domain Entity - CreateMap() - .ForMember(dest => dest.Types, - opt => opt.MapFrom(src => src.Types)); - - // ProductType DbEntity -> Domain Entity - CreateMap() - .ForMember(dest => dest.Group, - opt => opt.MapFrom(src => src.Group)) - .ForMember(dest => dest.Products, - opt => opt.MapFrom(src => src.Products)); - - // ProductVariant DbEntity -> Domain Entity - CreateMap() - .ForMember(dest => dest.Product, - opt => opt.MapFrom(src => src.Product)); - - // Product Domain Entity -> DbEntity - CreateMap() - .ForMember(dest => dest.Type, - opt => opt.Ignore()) // in repo - .ForMember(dest => dest.Variants, - opt => opt.Ignore()); // in repo - - // ProductVariant Domain Entity -> DbEntity - CreateMap() - .ForMember(dest => dest.Product, - opt => opt.Ignore()); // in repo - - // ProductType Domain Entity -> DbEntity - CreateMap() - .ForMember(dest => dest.Group, - opt => opt.Ignore()) // in repo - .ForMember(dest => dest.Products, - opt => opt.Ignore()); // in repo - - // ProductGroup Domain Entity -> DbEntity - CreateMap() - .ForMember(dest => dest.Types, - opt => opt.Ignore()); // in repo - } -} \ No newline at end of file diff --git a/src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.Designer.cs b/src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.Designer.cs deleted file mode 100644 index a12209d..0000000 --- a/src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.Designer.cs +++ /dev/null @@ -1,231 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Printbase.Infrastructure.Database; - -#nullable disable - -namespace Printbase.Infrastructure.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - [Migration("20250504210542_InitialCreate")] - partial class InitialCreate - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.4") - .HasAnnotation("Relational:MaxIdentifierLength", 128); - - SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("Description") - .HasMaxLength(1000) - .HasColumnType("nvarchar(1000)"); - - b.Property("IsActive") - .HasColumnType("bit"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("TypeId") - .HasColumnType("uniqueidentifier"); - - b.Property("UpdatedAt") - .HasColumnType("datetime2"); - - b.HasKey("Id"); - - b.HasIndex("TypeId"); - - b.ToTable("Products"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductGroupDbEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("Description") - .HasMaxLength(255) - .HasColumnType("nvarchar(255)"); - - b.Property("IsActive") - .HasColumnType("bit"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("UpdatedAt") - .HasColumnType("datetime2"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("ProductGroups"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("Description") - .HasMaxLength(255) - .HasColumnType("nvarchar(255)"); - - b.Property("GroupId") - .HasColumnType("uniqueidentifier"); - - b.Property("IsActive") - .HasColumnType("bit"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("UpdatedAt") - .HasColumnType("datetime2"); - - b.HasKey("Id"); - - b.HasIndex("GroupId"); - - b.HasIndex("Name", "GroupId") - .IsUnique(); - - b.ToTable("ProductTypes"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductVariantDbEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("Color") - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("Discount") - .HasPrecision(18, 2) - .HasColumnType("decimal(18,2)"); - - b.Property("IsActive") - .HasColumnType("bit"); - - b.Property("Price") - .HasPrecision(18, 2) - .HasColumnType("decimal(18,2)"); - - b.Property("ProductId") - .HasColumnType("uniqueidentifier"); - - b.Property("SKU") - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("Size") - .HasMaxLength(20) - .HasColumnType("nvarchar(20)"); - - b.Property("Stock") - .HasColumnType("int"); - - b.Property("UpdatedAt") - .HasColumnType("datetime2"); - - b.HasKey("Id"); - - b.HasIndex("ProductId", "Color", "Size") - .IsUnique() - .HasFilter("[Color] IS NOT NULL AND [Size] IS NOT NULL"); - - b.ToTable("ProductVariants"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", b => - { - b.HasOne("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", "Type") - .WithMany("Products") - .HasForeignKey("TypeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Type"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", b => - { - b.HasOne("Printbase.Infrastructure.DbEntities.Products.ProductGroupDbEntity", "Group") - .WithMany("Types") - .HasForeignKey("GroupId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Group"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductVariantDbEntity", b => - { - b.HasOne("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", "Product") - .WithMany("Variants") - .HasForeignKey("ProductId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Product"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", b => - { - b.Navigation("Variants"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductGroupDbEntity", b => - { - b.Navigation("Types"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", b => - { - b.Navigation("Products"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.cs b/src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.cs deleted file mode 100644 index c5e1a22..0000000 --- a/src/Printbase.Infrastructure/Migrations/20250504210542_InitialCreate.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Printbase.Infrastructure.Migrations -{ - /// - public partial class InitialCreate : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "ProductGroups", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), - Description = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: true), - CreatedAt = table.Column(type: "datetime2", nullable: false), - UpdatedAt = table.Column(type: "datetime2", nullable: true), - IsActive = table.Column(type: "bit", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ProductGroups", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "ProductTypes", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), - Description = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: true), - GroupId = table.Column(type: "uniqueidentifier", nullable: false), - CreatedAt = table.Column(type: "datetime2", nullable: false), - UpdatedAt = table.Column(type: "datetime2", nullable: true), - IsActive = table.Column(type: "bit", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ProductTypes", x => x.Id); - table.ForeignKey( - name: "FK_ProductTypes_ProductGroups_GroupId", - column: x => x.GroupId, - principalTable: "ProductGroups", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Products", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), - Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), - TypeId = table.Column(type: "uniqueidentifier", nullable: false), - CreatedAt = table.Column(type: "datetime2", nullable: false), - UpdatedAt = table.Column(type: "datetime2", nullable: true), - IsActive = table.Column(type: "bit", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Products", x => x.Id); - table.ForeignKey( - name: "FK_Products_ProductTypes_TypeId", - column: x => x.TypeId, - principalTable: "ProductTypes", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "ProductVariants", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - ProductId = table.Column(type: "uniqueidentifier", nullable: false), - Color = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - Size = table.Column(type: "nvarchar(20)", maxLength: 20, nullable: true), - Price = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), - Discount = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true), - Stock = table.Column(type: "int", nullable: false), - SKU = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - CreatedAt = table.Column(type: "datetime2", nullable: false), - UpdatedAt = table.Column(type: "datetime2", nullable: true), - IsActive = table.Column(type: "bit", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ProductVariants", x => x.Id); - table.ForeignKey( - name: "FK_ProductVariants_Products_ProductId", - column: x => x.ProductId, - principalTable: "Products", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_ProductGroups_Name", - table: "ProductGroups", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Products_TypeId", - table: "Products", - column: "TypeId"); - - migrationBuilder.CreateIndex( - name: "IX_ProductTypes_GroupId", - table: "ProductTypes", - column: "GroupId"); - - migrationBuilder.CreateIndex( - name: "IX_ProductTypes_Name_GroupId", - table: "ProductTypes", - columns: new[] { "Name", "GroupId" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_ProductVariants_ProductId_Color_Size", - table: "ProductVariants", - columns: new[] { "ProductId", "Color", "Size" }, - unique: true, - filter: "[Color] IS NOT NULL AND [Size] IS NOT NULL"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "ProductVariants"); - - migrationBuilder.DropTable( - name: "Products"); - - migrationBuilder.DropTable( - name: "ProductTypes"); - - migrationBuilder.DropTable( - name: "ProductGroups"); - } - } -} diff --git a/src/Printbase.Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Printbase.Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs deleted file mode 100644 index c26eaeb..0000000 --- a/src/Printbase.Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs +++ /dev/null @@ -1,228 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Printbase.Infrastructure.Database; - -#nullable disable - -namespace Printbase.Infrastructure.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - partial class ApplicationDbContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.4") - .HasAnnotation("Relational:MaxIdentifierLength", 128); - - SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("Description") - .HasMaxLength(1000) - .HasColumnType("nvarchar(1000)"); - - b.Property("IsActive") - .HasColumnType("bit"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("TypeId") - .HasColumnType("uniqueidentifier"); - - b.Property("UpdatedAt") - .HasColumnType("datetime2"); - - b.HasKey("Id"); - - b.HasIndex("TypeId"); - - b.ToTable("Products"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductGroupDbEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("Description") - .HasMaxLength(255) - .HasColumnType("nvarchar(255)"); - - b.Property("IsActive") - .HasColumnType("bit"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("UpdatedAt") - .HasColumnType("datetime2"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("ProductGroups"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("Description") - .HasMaxLength(255) - .HasColumnType("nvarchar(255)"); - - b.Property("GroupId") - .HasColumnType("uniqueidentifier"); - - b.Property("IsActive") - .HasColumnType("bit"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("UpdatedAt") - .HasColumnType("datetime2"); - - b.HasKey("Id"); - - b.HasIndex("GroupId"); - - b.HasIndex("Name", "GroupId") - .IsUnique(); - - b.ToTable("ProductTypes"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductVariantDbEntity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("Color") - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("Discount") - .HasPrecision(18, 2) - .HasColumnType("decimal(18,2)"); - - b.Property("IsActive") - .HasColumnType("bit"); - - b.Property("Price") - .HasPrecision(18, 2) - .HasColumnType("decimal(18,2)"); - - b.Property("ProductId") - .HasColumnType("uniqueidentifier"); - - b.Property("SKU") - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("Size") - .HasMaxLength(20) - .HasColumnType("nvarchar(20)"); - - b.Property("Stock") - .HasColumnType("int"); - - b.Property("UpdatedAt") - .HasColumnType("datetime2"); - - b.HasKey("Id"); - - b.HasIndex("ProductId", "Color", "Size") - .IsUnique() - .HasFilter("[Color] IS NOT NULL AND [Size] IS NOT NULL"); - - b.ToTable("ProductVariants"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", b => - { - b.HasOne("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", "Type") - .WithMany("Products") - .HasForeignKey("TypeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Type"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", b => - { - b.HasOne("Printbase.Infrastructure.DbEntities.Products.ProductGroupDbEntity", "Group") - .WithMany("Types") - .HasForeignKey("GroupId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Group"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductVariantDbEntity", b => - { - b.HasOne("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", "Product") - .WithMany("Variants") - .HasForeignKey("ProductId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Product"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductDbEntity", b => - { - b.Navigation("Variants"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductGroupDbEntity", b => - { - b.Navigation("Types"); - }); - - modelBuilder.Entity("Printbase.Infrastructure.DbEntities.Products.ProductTypeDbEntity", b => - { - b.Navigation("Products"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Printbase.Infrastructure/Repositories/ProductGroupRepository.cs b/src/Printbase.Infrastructure/Repositories/ProductGroupRepository.cs deleted file mode 100644 index 29e04c4..0000000 --- a/src/Printbase.Infrastructure/Repositories/ProductGroupRepository.cs +++ /dev/null @@ -1,80 +0,0 @@ -using AutoMapper; -using Microsoft.EntityFrameworkCore; -using Printbase.Domain.Entities.Products; -using Printbase.Domain.Repositories; -using Printbase.Infrastructure.Database; -using Printbase.Infrastructure.DbEntities.Products; - -namespace Printbase.Infrastructure.Repositories; - -public class ProductGroupRepository(ApplicationDbContext dbContext, IMapper mapper) : IProductGroupRepository -{ - private readonly ApplicationDbContext _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); - private readonly IMapper _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); - - public async Task GetByIdAsync(Guid id, bool includeRelations = false, CancellationToken cancellationToken = default) - { - IQueryable query = _dbContext.ProductGroups; - - if (includeRelations) query = query.Include(g => g.Types); - - var dbEntity = await query.FirstOrDefaultAsync(g => g.Id == id, cancellationToken); - - return dbEntity == null ? null : _mapper.Map(dbEntity); - } - - public async Task> GetAllAsync(bool includeRelations = false, CancellationToken cancellationToken = default) - { - IQueryable query = _dbContext.ProductGroups; - - if (includeRelations) query = query.Include(g => g.Types); - - var dbEntities = await query.ToListAsync(cancellationToken); - - return _mapper.Map>(dbEntities); - } - - public async Task AddAsync(ProductGroup group, CancellationToken cancellationToken = default) - { - var dbEntity = _mapper.Map(group); - - _dbContext.ProductGroups.Add(dbEntity); - await _dbContext.SaveChangesAsync(cancellationToken); - - return _mapper.Map(dbEntity); - } - - public async Task UpdateAsync(ProductGroup group, CancellationToken cancellationToken = default) - { - var existingEntity = await _dbContext.ProductGroups - .Include(g => g.Types) - .FirstOrDefaultAsync(g => g.Id == group.Id, cancellationToken); - - if (existingEntity == null) throw new KeyNotFoundException($"ProductGroup with ID {group.Id} not found"); - - _mapper.Map(group, existingEntity); - - existingEntity.UpdatedAt = DateTime.UtcNow; - - await _dbContext.SaveChangesAsync(cancellationToken); - - return _mapper.Map(existingEntity); - } - - public async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default) - { - var entity = await _dbContext.ProductGroups.FindAsync([id], cancellationToken); - - if (entity == null) return false; - - _dbContext.ProductGroups.Remove(entity); - await _dbContext.SaveChangesAsync(cancellationToken); - - return true; - } - - public async Task ExistsAsync(Guid id, CancellationToken cancellationToken = default) - { - return await _dbContext.ProductGroups.AnyAsync(g => g.Id == id, cancellationToken); - } -} \ No newline at end of file diff --git a/src/Printbase.Infrastructure/Repositories/ProductRepository.cs b/src/Printbase.Infrastructure/Repositories/ProductRepository.cs deleted file mode 100644 index fa33590..0000000 --- a/src/Printbase.Infrastructure/Repositories/ProductRepository.cs +++ /dev/null @@ -1,119 +0,0 @@ -using AutoMapper; -using Microsoft.EntityFrameworkCore; -using Printbase.Domain.Entities.Products; -using Printbase.Domain.Repositories; -using Printbase.Infrastructure.Database; -using Printbase.Infrastructure.DbEntities.Products; - -namespace Printbase.Infrastructure.Repositories; - -public class ProductRepository(ApplicationDbContext dbContext, IMapper mapper) : IProductRepository -{ - private readonly ApplicationDbContext _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); - private readonly IMapper _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); - - public async Task GetByIdAsync(Guid id, bool includeRelations = false, CancellationToken cancellationToken = default) - { - IQueryable query = _dbContext.Products; - - if (includeRelations) - { - query = query - .Include(p => p.Type) - .ThenInclude(t => t.Group) - .Include(p => p.Variants); - } - - var dbEntity = await query.FirstOrDefaultAsync(p => p.Id == id, cancellationToken); - - return dbEntity == null ? null : _mapper.Map(dbEntity); - } - - public async Task> GetAllAsync(bool includeRelations = false, CancellationToken cancellationToken = default) - { - IQueryable query = _dbContext.Products; - - if (includeRelations) - { - query = query - .Include(p => p.Type) - .ThenInclude(t => t.Group) - .Include(p => p.Variants); - } - - var dbEntities = await query.ToListAsync(cancellationToken); - - return _mapper.Map>(dbEntities); - } - - public async Task> GetByTypeIdAsync(Guid typeId, bool includeRelations = false, CancellationToken cancellationToken = default) - { - var query = _dbContext.Products.Where(p => p.TypeId == typeId); - - if (includeRelations) - { - query = query - .Include(p => p.Type) - .ThenInclude(t => t.Group) - .Include(p => p.Variants); - } - - var dbEntities = await query.ToListAsync(cancellationToken); - - return _mapper.Map>(dbEntities); - } - - public async Task AddAsync(Product product, CancellationToken cancellationToken = default) - { - var dbEntity = _mapper.Map(product); - - dbEntity.Type = await _dbContext.ProductTypes.FindAsync([product.TypeId], cancellationToken) - ?? throw new InvalidOperationException($"ProductType with ID {product.TypeId} not found"); - - _dbContext.Products.Add(dbEntity); - await _dbContext.SaveChangesAsync(cancellationToken); - - return _mapper.Map(dbEntity); - } - - public async Task UpdateAsync(Product product, CancellationToken cancellationToken = default) - { - var existingEntity = await _dbContext.Products - .Include(p => p.Variants) - .FirstOrDefaultAsync(p => p.Id == product.Id, cancellationToken); - - if (existingEntity == null) throw new KeyNotFoundException($"Product with ID {product.Id} not found"); - - _mapper.Map(product, existingEntity); - - if (existingEntity.TypeId != product.TypeId) - { - existingEntity.Type = await _dbContext.ProductTypes.FindAsync([product.TypeId], cancellationToken) - ?? throw new InvalidOperationException($"ProductType with ID {product.TypeId} not found"); - existingEntity.TypeId = product.TypeId; - } - - existingEntity.UpdatedAt = DateTime.UtcNow; - - await _dbContext.SaveChangesAsync(cancellationToken); - - return _mapper.Map(existingEntity); - } - - public async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default) - { - var entity = await _dbContext.Products.FindAsync([id], cancellationToken); - - if (entity == null) return false; - - _dbContext.Products.Remove(entity); - await _dbContext.SaveChangesAsync(cancellationToken); - - return true; - } - - public async Task ExistsAsync(Guid id, CancellationToken cancellationToken = default) - { - return await _dbContext.Products.AnyAsync(p => p.Id == id, cancellationToken); - } -} \ No newline at end of file diff --git a/src/Printbase.Infrastructure/Repositories/ProductTypeRepository.cs b/src/Printbase.Infrastructure/Repositories/ProductTypeRepository.cs deleted file mode 100644 index b016b72..0000000 --- a/src/Printbase.Infrastructure/Repositories/ProductTypeRepository.cs +++ /dev/null @@ -1,112 +0,0 @@ -using AutoMapper; -using Microsoft.EntityFrameworkCore; -using Printbase.Domain.Entities.Products; -using Printbase.Domain.Repositories; -using Printbase.Infrastructure.Database; -using Printbase.Infrastructure.DbEntities.Products; - -namespace Printbase.Infrastructure.Repositories; - -public class ProductTypeRepository(ApplicationDbContext dbContext, IMapper mapper) : IProductTypeRepository -{ - private readonly ApplicationDbContext _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); - private readonly IMapper _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); - - public async Task GetByIdAsync(Guid id, bool includeRelations = false, CancellationToken cancellationToken = default) - { - IQueryable query = _dbContext.ProductTypes; - - if (includeRelations) - { - query = query - .Include(t => t.Group) - .Include(t => t.Products); - } - - var dbEntity = await query.FirstOrDefaultAsync(t => t.Id == id, cancellationToken); - - return dbEntity == null ? null : _mapper.Map(dbEntity); - } - - public async Task> GetAllAsync(bool includeRelations = false, CancellationToken cancellationToken = default) - { - IQueryable query = _dbContext.ProductTypes; - - if (includeRelations) - { - query = query - .Include(t => t.Group) - .Include(t => t.Products); - } - - var dbEntities = await query.ToListAsync(cancellationToken); - - return _mapper.Map>(dbEntities); - } - - public async Task> GetByGroupIdAsync(Guid groupId, CancellationToken cancellationToken = default) - { - var dbEntities = await _dbContext.ProductTypes - .Where(t => t.GroupId == groupId) - .ToListAsync(cancellationToken); - - return _mapper.Map>(dbEntities); - } - - public async Task AddAsync(ProductType type, CancellationToken cancellationToken = default) - { - var dbEntity = _mapper.Map(type); - - dbEntity.Group = await _dbContext.ProductGroups.FindAsync([type.GroupId], cancellationToken) - ?? throw new InvalidOperationException($"ProductGroup with ID {type.GroupId} not found"); - - _dbContext.ProductTypes.Add(dbEntity); - await _dbContext.SaveChangesAsync(cancellationToken); - - return _mapper.Map(dbEntity); - } - - public async Task UpdateAsync(ProductType type, CancellationToken cancellationToken = default) - { - var existingEntity = await _dbContext.ProductTypes - .Include(t => t.Products) - .FirstOrDefaultAsync(t => t.Id == type.Id, cancellationToken); - - if (existingEntity == null) throw new KeyNotFoundException($"ProductType with ID {type.Id} not found"); - - _mapper.Map(type, existingEntity); - - if (existingEntity.GroupId != type.GroupId) - { - existingEntity.Group = await _dbContext.ProductGroups.FindAsync([type.GroupId], cancellationToken) - ?? throw new InvalidOperationException($"ProductGroup with ID {type.GroupId} not found"); - existingEntity.GroupId = type.GroupId; - } - - existingEntity.UpdatedAt = DateTime.UtcNow; - - await _dbContext.SaveChangesAsync(cancellationToken); - - return _mapper.Map(existingEntity); - } - - public async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default) - { - var entity = await _dbContext.ProductTypes.FindAsync([id], cancellationToken); - - if (entity == null) - { - return false; - } - - _dbContext.ProductTypes.Remove(entity); - await _dbContext.SaveChangesAsync(cancellationToken); - - return true; - } - - public async Task ExistsAsync(Guid id, CancellationToken cancellationToken = default) - { - return await _dbContext.ProductTypes.AnyAsync(t => t.Id == id, cancellationToken); - } -} \ No newline at end of file diff --git a/src/Printbase.Infrastructure/Repositories/ProductVariantRepository.cs b/src/Printbase.Infrastructure/Repositories/ProductVariantRepository.cs deleted file mode 100644 index e2761fb..0000000 --- a/src/Printbase.Infrastructure/Repositories/ProductVariantRepository.cs +++ /dev/null @@ -1,102 +0,0 @@ -using AutoMapper; -using Microsoft.EntityFrameworkCore; -using Printbase.Domain.Entities.Products; -using Printbase.Domain.Repositories; -using Printbase.Infrastructure.Database; -using Printbase.Infrastructure.DbEntities.Products; - -namespace Printbase.Infrastructure.Repositories; - -public class ProductVariantRepository(ApplicationDbContext dbContext, IMapper mapper) : IProductVariantRepository -{ - private readonly ApplicationDbContext _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); - private readonly IMapper _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); - - public async Task GetByIdAsync(Guid id, bool includeRelations = false, CancellationToken cancellationToken = default) - { - IQueryable query = _dbContext.ProductVariants; - - if (includeRelations) - query = query.Include(v => v.Product) - .ThenInclude(p => p.Type); - - var dbEntity = await query.FirstOrDefaultAsync(v => v.Id == id, cancellationToken); - - return dbEntity == null ? null : _mapper.Map(dbEntity); - } - - public async Task> GetAllAsync(bool includeRelations = false, CancellationToken cancellationToken = default) - { - IQueryable query = _dbContext.ProductVariants; - - if (includeRelations) - query = query.Include(v => v.Product) - .ThenInclude(p => p.Type); - - var dbEntities = await query.ToListAsync(cancellationToken); - - return _mapper.Map>(dbEntities); - } - - public async Task> GetByProductIdAsync(Guid productId, CancellationToken cancellationToken = default) - { - var dbEntities = await _dbContext.ProductVariants - .Where(v => v.ProductId == productId) - .ToListAsync(cancellationToken); - - return _mapper.Map>(dbEntities); - } - - public async Task AddAsync(ProductVariant variant, CancellationToken cancellationToken = default) - { - var dbEntity = _mapper.Map(variant); - - dbEntity.Product = await _dbContext.Products.FindAsync([variant.ProductId], cancellationToken) - ?? throw new InvalidOperationException($"Product with ID {variant.ProductId} not found"); - - _dbContext.ProductVariants.Add(dbEntity); - await _dbContext.SaveChangesAsync(cancellationToken); - - return _mapper.Map(dbEntity); - } - - public async Task UpdateAsync(ProductVariant variant, CancellationToken cancellationToken = default) - { - var existingEntity = await _dbContext.ProductVariants - .FindAsync([variant.Id], cancellationToken); - - if (existingEntity == null) throw new KeyNotFoundException($"ProductVariant with ID {variant.Id} not found"); - - _mapper.Map(variant, existingEntity); - - if (existingEntity.ProductId != variant.ProductId) - { - existingEntity.Product = await _dbContext.Products.FindAsync([variant.ProductId], cancellationToken) - ?? throw new InvalidOperationException($"Product with ID {variant.ProductId} not found"); - existingEntity.ProductId = variant.ProductId; - } - - existingEntity.UpdatedAt = DateTime.UtcNow; - - await _dbContext.SaveChangesAsync(cancellationToken); - - return _mapper.Map(existingEntity); - } - - public async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default) - { - var entity = await _dbContext.ProductVariants.FindAsync([id], cancellationToken); - - if (entity == null) return false; - - _dbContext.ProductVariants.Remove(entity); - await _dbContext.SaveChangesAsync(cancellationToken); - - return true; - } - - public async Task ExistsAsync(Guid id, CancellationToken cancellationToken = default) - { - return await _dbContext.ProductVariants.AnyAsync(v => v.Id == id, cancellationToken); - } -} \ No newline at end of file diff --git a/src/Printbase.WebApi/Controllers/ProductsController.cs b/src/Printbase.WebApi/Controllers/ProductsController.cs deleted file mode 100644 index 337f398..0000000 --- a/src/Printbase.WebApi/Controllers/ProductsController.cs +++ /dev/null @@ -1,56 +0,0 @@ -using MediatR; -using Microsoft.AspNetCore.Mvc; -using Printbase.Application.Products.Commands.CreateProduct; -using Printbase.Application.Products.Queries.GetAllProducts; -using Printbase.Application.Products.Queries.GetProductById; - -namespace Printbase.WebApi.Controllers; - -[ApiController] -[Route("api/[controller]")] -public class ProductsController(IMediator mediator) : ControllerBase -{ - private readonly IMediator _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); - - [HttpGet] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task GetAllProducts() - { - var query = new GetAllProductsQuery(); - var result = await _mediator.Send(query); - - if (result == null) return NotFound(); - return Ok(result); - } - - [HttpGet("{id:guid}")] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task GetProductById(Guid id, [FromQuery] bool includeVariants = true) - { - var query = new GetProductByIdQuery(id, includeVariants); - var result = await _mediator.Send(query); - - if (result == null) return NotFound(); - return Ok(result); - } - - [HttpPost] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - public async Task CreateProduct([FromBody] CreateProductCommand command) - { - if (!ModelState.IsValid) return BadRequest(ModelState); - - try - { - var result = await _mediator.Send(command); - return CreatedAtAction(nameof(GetProductById), new { id = result.Id }, result); - } - catch (ArgumentException ex) - { - return BadRequest(ex.Message); - } - } -} \ No newline at end of file diff --git a/src/Printbase.WebApi/Startup.cs b/src/Printbase.WebApi/Startup.cs index 000273e..9ec1ea7 100644 --- a/src/Printbase.WebApi/Startup.cs +++ b/src/Printbase.WebApi/Startup.cs @@ -1,10 +1,5 @@ -using System.Reflection; using Microsoft.EntityFrameworkCore; -using Printbase.Application.Products.Commands.CreateProduct; -using Printbase.Domain.Repositories; using Printbase.Infrastructure.Database; -using Printbase.Infrastructure.Mappings; -using Printbase.Infrastructure.Repositories; namespace Printbase.WebApi; @@ -13,29 +8,11 @@ public static class Startup public static void ConfigureServices(WebApplicationBuilder builder) { var services = builder.Services; - + services.AddDbContext(options => options.UseSqlServer( builder.Configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName))); - - services.AddMediatR(cfg => { - cfg.RegisterServicesFromAssembly(typeof(CreateProductCommand).Assembly); - cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()); - }); - - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.AddAutoMapper(cfg => - { - cfg.AddProfile(); - }, typeof(ProductMappingProfile).Assembly); - services.AddSwaggerGen(); - services.AddControllers(); - services.AddOpenApi(); } public static void Configure(IApplicationBuilder app, IWebHostEnvironment env) @@ -57,14 +34,12 @@ public static class Startup if (env.IsDevelopment()) { - Console.WriteLine("Development environment variables applied"); app.UseSwagger(); app.UseSwaggerUI(); app.UseDeveloperExceptionPage(); } else { - Console.WriteLine("Production environment variables applied"); app.UseExceptionHandler("/Error"); app.UseHsts(); app.UseHttpsRedirection(); diff --git a/tests/Printbase.Application.Tests/Products/Commands/CreateProduct/GenerateSkuTests.cs b/tests/Printbase.Application.Tests/Products/Commands/CreateProduct/GenerateSkuTests.cs deleted file mode 100644 index d08bcac..0000000 --- a/tests/Printbase.Application.Tests/Products/Commands/CreateProduct/GenerateSkuTests.cs +++ /dev/null @@ -1,187 +0,0 @@ -using Printbase.Application.Products.Commands.CreateProduct; - -namespace Printbase.Application.Tests.Products.Commands.CreateProduct; - -using Xunit; - -public class GenerateSkuTests -{ - [Fact] - public void GenerateSku_WithValidInputs_ReturnsCorrectFormat() - { - // Arrange - const string productName = "Shirt"; - const string color = "Blue"; - const string size = "Medium"; - - // Act - var sku = CreateProductCommandHandler.GenerateSku(productName, color, size); - var parts = sku.Split('-'); - - // Assert - Assert.Equal(4, parts.Length); - Assert.Equal("SHI", parts[0]); - Assert.Equal("BLU", parts[1]); - Assert.Equal("MEDIUM", parts[2]); - Assert.Matches(@"^\d{3}$", parts[3]); - } - - [Fact] - public void GenerateSku_WithShortProductName_UsesEntireProductName() - { - // Arrange - const string productName = "CU"; - const string color = "Black"; - const string size = "Large"; - - // Act - var sku = CreateProductCommandHandler.GenerateSku(productName, color, size); - var parts = sku.Split('-'); - - // Assert - Assert.Equal("CU", parts[0]); - Assert.Equal("BLA", parts[1]); - Assert.Equal("LARGE", parts[2]); - } - - [Fact] - public void GenerateSku_WithShortColor_UsesEntireColor() - { - // Arrange - const string productName = "Mug"; - const string color = "Red"; - const string size = "Small"; - - // Act - var sku = CreateProductCommandHandler.GenerateSku(productName, color, size); - var parts = sku.Split('-'); - - // Assert - Assert.Equal("MUG", parts[0]); - Assert.Equal("RED", parts[1]); - Assert.Equal("SMALL", parts[2]); - } - - [Fact] - public void GenerateSku_WithNullColor_UsesXXX() - { - // Arrange - const string productName = "Case"; - string? color = null; - const string size = "Standard"; - - // Act - var sku = CreateProductCommandHandler.GenerateSku(productName, color, size); - var parts = sku.Split('-'); - - // Assert - Assert.Equal("CAS", parts[0]); - Assert.Equal("XXX", parts[1]); - Assert.Equal("STANDARD", parts[2]); - } - - [Fact] - public void GenerateSku_WithEmptyColor_UsesXXX() - { - // Arrange - const string productName = "Notebook"; - const string color = ""; - const string size = "Standard"; - - // Act - var sku = CreateProductCommandHandler.GenerateSku(productName, color, size); - var parts = sku.Split('-'); - - // Assert - Assert.Equal("NOT", parts[0]); - Assert.Equal("XXX", parts[1]); - Assert.Equal("STANDARD", parts[2]); - } - - [Fact] - public void GenerateSku_WithNullSize_UsesOS() - { - // Arrange - const string productName = "Watch"; - const string color = "Silver"; - string? size = null; - - // Act - var sku = CreateProductCommandHandler.GenerateSku(productName, color, size); - var parts = sku.Split('-'); - - // Assert - Assert.Equal("WAT", parts[0]); - Assert.Equal("SIL", parts[1]); - Assert.Equal("OS", parts[2]); - } - - [Fact] - public void GenerateSku_WithEmptySize_UsesOS() - { - // Arrange - const string productName = "Shirt"; - const string color = "Black"; - const string size = ""; - - // Act - var sku = CreateProductCommandHandler.GenerateSku(productName, color, size); - var parts = sku.Split('-'); - - // Assert - Assert.Equal("SHI", parts[0]); - Assert.Equal("BLA", parts[1]); - Assert.Equal("OS", parts[2]); - } - - [Fact] - public void GenerateSku_CaseInsensitivity_OutputsUppercase() - { - // Arrange - const string productName = "hat"; - const string color = "red"; - const string size = "small"; - - // Act - var sku = CreateProductCommandHandler.GenerateSku(productName, color, size); - var parts = sku.Split('-'); - - // Assert - Assert.Equal("HAT", parts[0]); - Assert.Equal("RED", parts[1]); - Assert.Equal("SMALL", parts[2]); - } - - [Fact] - public void GenerateSku_RandomPartIsInRange() - { - // Arrange - const string productName = "Book"; - const string color = "Green"; - const string size = "Medium"; - - // Act - var sku = CreateProductCommandHandler.GenerateSku(productName, color, size); - var parts = sku.Split('-'); - var randomPart = int.Parse(parts[3]); - - // Assert - Assert.InRange(randomPart, 100, 999); - } - - [Fact] - public void GenerateSku_GeneratesUniqueSKUs() - { - // Arrange - const string productName = "Mug"; - const string color = "White"; - const string size = "Regular"; - - // Act - var sku1 = CreateProductCommandHandler.GenerateSku(productName, color, size); - var sku2 = CreateProductCommandHandler.GenerateSku(productName, color, size); - - // Assert - Assert.NotEqual(sku1, sku2); - } -} \ No newline at end of file