Add base product DbEntities and domain Entities
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
namespace Printbase.Application;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
}
|
||||
@@ -6,4 +6,8 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Abstractions\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
namespace Printbase.Domain;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
}
|
||||
80
src/Printbase.Domain/Entities/Products/Product.cs
Normal file
80
src/Printbase.Domain/Entities/Products/Product.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
namespace Printbase.Domain.Entities.Products;
|
||||
|
||||
public class Product
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public string? Description { get; private set; }
|
||||
public decimal? Discount { get; private set; }
|
||||
public Guid TypeId { get; private set; }
|
||||
public IReadOnlyCollection<ProductVariant> Variants => _variants.AsReadOnly();
|
||||
|
||||
private readonly List<ProductVariant> _variants = [];
|
||||
|
||||
private Product() { }
|
||||
|
||||
public Product(Guid id, string name, Guid typeId, string? description = null, decimal? discount = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
throw new ArgumentException("Product name cannot be empty", nameof(name));
|
||||
|
||||
if (typeId == Guid.Empty)
|
||||
throw new ArgumentException("Type ID cannot be empty", nameof(typeId));
|
||||
|
||||
Id = id;
|
||||
Name = name;
|
||||
TypeId = typeId;
|
||||
Description = description;
|
||||
Discount = discount;
|
||||
}
|
||||
|
||||
public void AddVariant(ProductVariant variant)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(variant);
|
||||
|
||||
_variants.Add(variant);
|
||||
}
|
||||
|
||||
public void RemoveVariant(Guid variantId)
|
||||
{
|
||||
var variant = _variants.Find(v => v.Id == variantId);
|
||||
if (variant != null)
|
||||
{
|
||||
_variants.Remove(variant);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateName(string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
throw new ArgumentException("Product name cannot be empty", nameof(name));
|
||||
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public void UpdateDescription(string? description)
|
||||
{
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public void UpdateDiscount(decimal? discount)
|
||||
{
|
||||
if (discount.HasValue && (discount.Value < 0 || discount.Value > 100))
|
||||
throw new ArgumentException("Discount must be between 0 and 100", nameof(discount));
|
||||
|
||||
Discount = discount;
|
||||
}
|
||||
|
||||
public void UpdateType(Guid typeId)
|
||||
{
|
||||
if (typeId == Guid.Empty)
|
||||
throw new ArgumentException("Type ID cannot be empty", nameof(typeId));
|
||||
|
||||
TypeId = typeId;
|
||||
}
|
||||
|
||||
public decimal? GetEffectiveDiscount()
|
||||
{
|
||||
return Discount;
|
||||
}
|
||||
}
|
||||
49
src/Printbase.Domain/Entities/Products/ProductGroup.cs
Normal file
49
src/Printbase.Domain/Entities/Products/ProductGroup.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
namespace Printbase.Domain.Entities.Products;
|
||||
|
||||
public class ProductGroup
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public string? Description { get; private set; }
|
||||
public IReadOnlyCollection<ProductType> Types => _types.AsReadOnly();
|
||||
|
||||
private readonly List<ProductType> _types = new();
|
||||
|
||||
private ProductGroup() { }
|
||||
|
||||
public ProductGroup(Guid id, string name, string? description = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
throw new ArgumentException("Group name cannot be empty", nameof(name));
|
||||
|
||||
Id = id;
|
||||
Name = name;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public void AddType(ProductType type)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(type);
|
||||
|
||||
_types.Add(type);
|
||||
}
|
||||
|
||||
public void RemoveType(Guid typeId)
|
||||
{
|
||||
var type = _types.Find(t => t.Id == typeId);
|
||||
if (type != null) _types.Remove(type);
|
||||
}
|
||||
|
||||
public void UpdateName(string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
throw new ArgumentException("Group name cannot be empty", nameof(name));
|
||||
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public void UpdateDescription(string? description)
|
||||
{
|
||||
Description = description;
|
||||
}
|
||||
}
|
||||
38
src/Printbase.Domain/Entities/Products/ProductType.cs
Normal file
38
src/Printbase.Domain/Entities/Products/ProductType.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace Printbase.Domain.Entities.Products;
|
||||
|
||||
public class ProductType
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public string? Description { get; private set; }
|
||||
public Guid GroupId { get; private set; }
|
||||
|
||||
private ProductType() { }
|
||||
|
||||
public ProductType(Guid id, string name, Guid groupId, string? description = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
throw new ArgumentException("Type name cannot be empty", nameof(name));
|
||||
|
||||
if (groupId == Guid.Empty)
|
||||
throw new ArgumentException("Group ID cannot be empty", nameof(groupId));
|
||||
|
||||
Id = id;
|
||||
Name = name;
|
||||
GroupId = groupId;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public void UpdateName(string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
throw new ArgumentException("Type name cannot be empty", nameof(name));
|
||||
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public void UpdateDescription(string? description)
|
||||
{
|
||||
Description = description;
|
||||
}
|
||||
}
|
||||
97
src/Printbase.Domain/Entities/Products/ProductVariant.cs
Normal file
97
src/Printbase.Domain/Entities/Products/ProductVariant.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
namespace Printbase.Domain.Entities.Products;
|
||||
|
||||
public class ProductVariant
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
public Guid ProductId { get; private set; }
|
||||
public string? Color { get; private set; }
|
||||
public string? Size { get; private set; }
|
||||
public decimal Price { get; private set; }
|
||||
public decimal? Discount { get; private set; }
|
||||
public int Stock { get; private set; }
|
||||
|
||||
private ProductVariant() { }
|
||||
|
||||
public ProductVariant(Guid id, Guid productId, decimal price, string? color = null, string? size = null,
|
||||
decimal? discount = null, int stock = 0)
|
||||
{
|
||||
if (price < 0)
|
||||
throw new ArgumentException("Price cannot be negative", nameof(price));
|
||||
|
||||
Id = id;
|
||||
ProductId = productId;
|
||||
Color = color;
|
||||
Size = size;
|
||||
Price = price;
|
||||
Discount = discount;
|
||||
Stock = stock;
|
||||
}
|
||||
|
||||
public void UpdateColor(string? color)
|
||||
{
|
||||
Color = color;
|
||||
}
|
||||
|
||||
public void UpdateSize(string? size)
|
||||
{
|
||||
Size = size;
|
||||
}
|
||||
|
||||
public void UpdatePrice(decimal price)
|
||||
{
|
||||
if (price < 0) throw new ArgumentException("Price cannot be negative", nameof(price));
|
||||
|
||||
Price = price;
|
||||
}
|
||||
|
||||
public void UpdateDiscount(decimal? discount)
|
||||
{
|
||||
if (discount is < 0 or > 100)
|
||||
throw new ArgumentException("Discount must be between 0 and 100", nameof(discount));
|
||||
|
||||
Discount = discount;
|
||||
}
|
||||
|
||||
public void UpdateStock(int quantity)
|
||||
{
|
||||
if (quantity < 0)
|
||||
throw new ArgumentException("Stock quantity cannot be negative", nameof(quantity));
|
||||
|
||||
Stock = quantity;
|
||||
}
|
||||
|
||||
public void AddStock(int quantity)
|
||||
{
|
||||
if (quantity <= 0)
|
||||
throw new ArgumentException("Quantity to add must be positive", nameof(quantity));
|
||||
|
||||
Stock += quantity;
|
||||
}
|
||||
|
||||
public bool RemoveStock(int quantity)
|
||||
{
|
||||
if (quantity <= 0)
|
||||
throw new ArgumentException("Quantity to remove must be positive", nameof(quantity));
|
||||
|
||||
if (Stock < quantity) return false;
|
||||
|
||||
Stock -= quantity;
|
||||
return true;
|
||||
}
|
||||
|
||||
public decimal GetEffectivePrice(decimal? productDiscount = null)
|
||||
{
|
||||
var effectivePrice = Price;
|
||||
|
||||
var discountToApply = Discount ?? productDiscount;
|
||||
|
||||
if (discountToApply is > 0) effectivePrice -= (effectivePrice * discountToApply.Value / 100);
|
||||
|
||||
return Math.Round(effectivePrice, 2);
|
||||
}
|
||||
|
||||
public decimal? GetEffectiveDiscount(decimal? productDiscount = null)
|
||||
{
|
||||
return Discount ?? productDiscount;
|
||||
}
|
||||
}
|
||||
@@ -6,4 +6,8 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Exceptions\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
namespace Printbase.Infrastructure;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
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; }
|
||||
|
||||
[Column(TypeName = "decimal(18,2)")]
|
||||
public decimal? Discount { get; set; }
|
||||
|
||||
[Required]
|
||||
public Guid TypeId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(TypeId)), Required]
|
||||
public required ProductTypeDbEntity Type { get; set; }
|
||||
|
||||
[InverseProperty(nameof(ProductVariantDbEntity.Product)), Required]
|
||||
public required ICollection<ProductVariantDbEntity> Variants { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Printbase.Infrastructure.DbEntities.Products;
|
||||
|
||||
[Table("ProductGroups")]
|
||||
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<ProductTypeDbEntity> Types { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Printbase.Infrastructure.DbEntities.Products;
|
||||
|
||||
[Table("ProductTypes")]
|
||||
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))]
|
||||
public ICollection<ProductDbEntity>? Products { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Printbase.Infrastructure.DbEntities.Products;
|
||||
|
||||
[Table("ProductVariants")]
|
||||
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]
|
||||
public decimal Price { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,2)")]
|
||||
public decimal? Discount { get; set; }
|
||||
|
||||
[Required]
|
||||
public int Stock { get; set; }
|
||||
|
||||
[ForeignKey(nameof(ProductId)), Required]
|
||||
public required ProductDbEntity Product { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user