first commit

This commit is contained in:
2026-04-16 21:05:21 +04:30
commit 49591985ac
283 changed files with 12716 additions and 0 deletions
@@ -0,0 +1,31 @@
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Members.TypeIds;
using Vizhvizh.Shop.Domain.Members.ValuesObjects;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Members.Entities;
public class Member : Entity<MemberId>, IAggregateRoot
{
private PhoneNumberVO _phoneNumber;
private MemberFullName _fullName;
private MemberAvatar? _avatar;
private Member()
{
}
private Member(PhoneNumberVO phoneNumber, MemberFullName fullName, MemberAvatar? avatar)
{
_fullName = fullName;
_phoneNumber = phoneNumber;
_avatar = avatar;
}
public static Member CreateNew(PhoneNumberVO phoneNumber, MemberFullName fullName, MemberAvatar? avatar = null)
{
return new Member(phoneNumber, fullName, avatar);
}
public MemberFullName? FullName => _fullName;
public PhoneNumberVO PhoneNumber => _phoneNumber;
public MemberAvatar? Avatar => _avatar;
}
@@ -0,0 +1,11 @@
using Vizhvizh.Shop.Domain.Resource.Members;
using Vizhvizh.BuildingBlocks.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Members.Exceptions;
public class MemberFullNameNullOrEmptyException : ValueObjectValidationException
{
public MemberFullNameNullOrEmptyException() : base(ExceptionResources.MemberFullNameNullOrEmptyException)
{
}
}
@@ -0,0 +1,16 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Members.TypeIds;
public class MemberId : TypedIdValueBase<long>
{
public MemberId(long value) : base(value)
{
}
public static implicit operator MemberId(long value)
=> new MemberId(value);
public static implicit operator long(MemberId value)
=> value.Value;
}
@@ -0,0 +1,17 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Members.ValuesObjects;
public class MemberAvatar : ValueObject
{
public const short Limit = 150;
public MemberAvatar(string value)
{
if (value.Length > Limit)
throw new CharacterLimitException(nameof(MemberAvatar), Limit);
Value = value;
}
public string Value { get; init; }
}
@@ -0,0 +1,30 @@
using Vizhvizh.Shared.Domain.Exceptions;
using Vizhvizh.Shop.Domain.Members.Exceptions;
using Vizhvizh.Shop.Domain.Resource.Members;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Members.ValuesObjects;
public class MemberFullName : ValueObject
{
public const short FirstNameLimit = 50;
public const short LastNameLimit = 50;
public MemberFullName(string firstName, string lastName)
{
if (string.IsNullOrWhiteSpace(firstName) || string.IsNullOrWhiteSpace(lastName))
throw new MemberFullNameNullOrEmptyException();
if (firstName.Length > FirstNameLimit || lastName.Length > LastNameLimit)
throw new CharacterLimitException(ValueObjectResources.MemberFullName, FirstNameLimit + LastNameLimit);
FirstName = firstName;
LastName = lastName;
}
public string FirstName { get; init; }
public string LastName { get; init; }
public override string ToString()
{
return $"{FirstName} {LastName}";
}
}
@@ -0,0 +1,61 @@
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Products.TypeIds;
using Vizhvizh.Shop.Domain.Products.ValuesObjects;
using Vizhvizh.BuildingBlocks.Domain;
using System.IO;
namespace Vizhvizh.Shop.Domain.Products.Entities;
/// <summary>
/// دسته بندی
/// </summary>
public class Category : Entity<CategoryId>
{
private TitleVO _title;
private DescriptionVO _description;
private CategoryImage _image;
private CategoryId? _parentId;
private CategoryPath _path;
#region Relationships
private List<Product> _products;
private List<CategoryVariantUnit> _categoryVariantUnits;
#endregion
private Category()
{
}
private Category(TitleVO title,
DescriptionVO description,
CategoryImage image,
CategoryPath path,
CategoryId? parentId = null)
{
_title = title;
_description = description;
_image = image;
_parentId = parentId;
_path = path;
}
public static Category CreateNew(TitleVO title,
DescriptionVO description,
CategoryImage image,
CategoryPath path,
CategoryId? parentId = null)
{
return new Category(title, description, image, path, parentId);
}
public TitleVO Title => _title;
public DescriptionVO Description => _description;
public CategoryImage Image => _image;
public CategoryId? ParentId => _parentId;
public CategoryPath Path => _path;
public IReadOnlyList<Product> Products => _products;
public IReadOnlyList<CategoryVariantUnit> CategoryVariantUnits => _categoryVariantUnits;
}
@@ -0,0 +1,37 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shop.Domain.Products.TypeIds;
namespace Vizhvizh.Shop.Domain.Products.Entities;
public class CategoryVariantUnit : Entity<CategoryVariantUnitId>
{
private CategoryId _categoryId;
private VariantUnitId _variantUnitId;
private Category _category;
private VariantUnit _variantUnit;
private CategoryVariantUnit()
{
}
private CategoryVariantUnit(Category category , VariantUnit variantUnit)
{
_category = category;
_variantUnit = variantUnit;
}
private CategoryVariantUnit(CategoryId categoryId, VariantUnitId variantUnitId)
{
_categoryId = categoryId;
_variantUnitId = variantUnitId;
}
public Category Category => _category;
public VariantUnit VariantUnit => _variantUnit;
public CategoryId CategoryId => _categoryId;
public VariantUnitId VariantUnitId => _variantUnitId;
public static CategoryVariantUnit CreateNew(Category category, VariantUnit variantUnit)
=> new(category, variantUnit);
public static CategoryVariantUnit CreateNew(CategoryId categoryId, VariantUnitId variantUnitId)
=> new(categoryId,variantUnitId);
}
@@ -0,0 +1,71 @@
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Products.TypeIds;
using Vizhvizh.Shop.Domain.Products.ValuesObjects;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.Entities;
/// <summary>
/// محصول
/// </summary>
public class Product : Entity<ProductId>, IAggregateRoot
{
private Category _category;
private List<Specifications> _specifications;
private ProductCondition _productCondition;
private TitleVO _title;
private DescriptionVO _description;
private ProductScore _score;
private List<ProductVariant> _variants;
/// <summary>
///عکس اصلی
/// </summary>
private ProductImage _image;
private Product()
{
}
private Product(TitleVO title,
DescriptionVO description,
ProductCondition productCondition,
Category category,
List<Specifications> specifications,
List<ProductVariant> variants,
ProductImage image
)
{
_title = title;
_description = description;
_productCondition = productCondition;
_category = category;
_category = category;
_specifications = specifications;
_variants = variants;
_image = image;
}
public static Product CreateNew(TitleVO title,
DescriptionVO description,
ProductCondition productCondition,
Category category,
List<Specifications> specifications,
List<ProductVariant> variants,
ProductImage image)
{
return new(title, description, productCondition, category, specifications, variants, image);
}
public Category Category => _category;
public ProductCondition ProductCondition => _productCondition;
public TitleVO Title => _title;
public DescriptionVO Description => _description;
public ProductScore Score => _score;
public ProductImage Image => _image;
public IReadOnlyList<ProductVariant> Variants => _variants;
public IReadOnlyList<Specifications> Specifications => _specifications;
}
@@ -0,0 +1,42 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shop.Domain.Products.TypeIds;
using Vizhvizh.Shop.Domain.Products.ValuesObjects;
namespace Vizhvizh.Shop.Domain.Products.Entities;
public class ProductVariant : Entity<ProductVariantId>
{
private VariantUnit _variantUnit;
private MoneyValue _price;
private ProductScore _score;
private ProductQuantity _quantity;
private ProductVariantValue _value;
private List<ProductImage> _gallery;
#region Relationships
private Product _product;
#endregion
private ProductVariant()
{
}
private ProductVariant(VariantUnit variantUnit, MoneyValue price, ProductQuantity quantity, ProductVariantValue value)
{
_variantUnit = variantUnit;
_price = price;
_quantity = quantity;
_value = value;
}
public VariantUnit VariantUnit => _variantUnit;
public MoneyValue Price => _price;
public ProductScore Score => _score;
public ProductQuantity Quantity => _quantity;
public ProductVariantValue Value => _value;
public Product Product => _product;
public IReadOnlyList<ProductImage> Gallery => _gallery;
public static ProductVariant CreateNew(VariantUnit variantUnit, MoneyValue price, ProductQuantity quantity, ProductVariantValue productVariantValue)
=> new(variantUnit, price, quantity, productVariantValue);
}
@@ -0,0 +1,37 @@
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Products.TypeIds;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.Entities;
/// <summary>
/// مشخصات محصول
/// </summary>
public class Specifications : Entity<SpecificationsId>
{
private TitleVO _title;
private List<string> _itemValues;
#region RelationShips
private Product _product;
private Specifications()
{
}
#endregion
private Specifications(TitleVO title, Product product, List<string> itemValues)
{
_title = title;
_itemValues = itemValues;
_product = product;
}
public static Specifications CreateNew(TitleVO title, Product product, List<string> values)
=> new Specifications(title, product, values);
public TitleVO Title => _title;
public Product Product => _product;
public IReadOnlyList<string> ItemValues => _itemValues;
}
@@ -0,0 +1,32 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Products.TypeIds;
namespace Vizhvizh.Shop.Domain.Products.Entities;
/// <summary>
/// واحد اندازه گیری
/// </summary>
public class Unit : Entity<UnitId>
{
private TitleVO _title;
#region RelationShips
private List<VariantUnit> _variantUnits;
#endregion
private Unit()
{
}
private Unit(TitleVO title)
{
_title = title;
}
public TitleVO Title => _title;
public IReadOnlyList<VariantUnit> VariantUnits => _variantUnits;
public static Unit CreateNew(TitleVO title)
=> new(title);
}
@@ -0,0 +1,27 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Products.TypeIds;
namespace Vizhvizh.Shop.Domain.Products.Entities;
public class Variant : Entity<VariantId>
{
private TitleVO _title;
#region RelationShips
private List<VariantUnit> _variantUnits;
#endregion
private Variant()
{
}
private Variant(TitleVO title)
{
_title = title;
}
public TitleVO Title => _title;
public IReadOnlyList<VariantUnit> VariantUnits => _variantUnits;
public static Variant CreateNew(TitleVO title)
=> new Variant(title);
}
@@ -0,0 +1,53 @@
using Microsoft.VisualBasic;
using System.ComponentModel.DataAnnotations;
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shop.Domain.Products.TypeIds;
namespace Vizhvizh.Shop.Domain.Products.Entities;
public class VariantUnit : Entity<VariantUnitId>
{
private VariantUnitType _variantUnitType;
#region Relationships
private Variant _variant;
private Unit _unit;
private List<ProductVariant> _productVariants;
private List<CategoryVariantUnit> _categoryVariantUnits;
#endregion
private VariantUnit()
{
}
private VariantUnit(Unit unit, Variant variant, VariantUnitType variantUnitType)
{
_variant = variant;
_unit = unit;
_variantUnitType = variantUnitType;
}
public Unit Unit => _unit;
public Variant Variant => _variant;
public VariantUnitType VariantUnitType => _variantUnitType;
public IReadOnlyList<ProductVariant> ProductVariants => _productVariants;
public IReadOnlyList<CategoryVariantUnit> CategoryVariantUnits => _categoryVariantUnits;
public static VariantUnit CreateNew(Unit unit, Variant variant, VariantUnitType variantUnitType)
=> new VariantUnit(unit, variant, variantUnitType);
}
public enum VariantUnitType
{
[Display(Name = "رنگ")]
Color,
[Display(Name = "عدد صحیح")]
Number,
[Display(Name = "ارز")]
Currency,
[Display(Name = "متن")]
Text,
[Display(Name = "عدد اعشاری")]
Decimal
}
@@ -0,0 +1,14 @@
using Vizhvizh.BuildingBlocks.Domain.Exceptions;
using Vizhvizh.Shop.Domain.Resource.Products;
namespace Vizhvizh.Shop.Domain.Products.Exceptions
{
public class InvalidProductVariantValueException : ValueObjectValidationException
{
public InvalidProductVariantValueException(string value, string typeName)
: base(string.Format(ExceptionResources.InvalidProductVariantValueException, value, typeName))
{
}
}
}
@@ -0,0 +1,9 @@
using Vizhvizh.Shop.Domain.Products.Entities;
using Vizhvizh.Shop.Domain.Products.TypeIds;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.Repositories;
public interface IProductRepository : IRepositoryBase<Product,ProductId>
{
}
@@ -0,0 +1,13 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.TypeIds;
/// <summary>
///
/// </summary>
public class CategoryId : TypedIdValueBase<long>
{
public CategoryId(long value) : base(value)
{
}
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.TypeIds;
public class CategoryVariantUnitId : TypedIdValueBase<long>
{
public CategoryVariantUnitId(long value) : base(value)
{
}
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.TypeIds;
public class ModelId : TypedIdValueBase<long>
{
public ModelId(long value) : base(value)
{
}
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.TypeIds;
public class ProductId : TypedIdValueBase<long>
{
public ProductId(long value) : base(value)
{
}
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.TypeIds;
public class ProductVariantId : TypedIdValueBase<long>
{
public ProductVariantId(long value) : base(value)
{
}
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.TypeIds;
public class SpecificationsId : TypedIdValueBase<long>
{
public SpecificationsId(long value) : base(value)
{
}
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.TypeIds;
public class UnitId : TypedIdValueBase<long>
{
public UnitId(long value) : base(value)
{
}
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.TypeIds;
public class VariantId : TypedIdValueBase<long>
{
public VariantId(long value) : base(value)
{
}
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.TypeIds;
public class VariantUnitId : TypedIdValueBase<long>
{
public VariantUnitId(long value) : base(value)
{
}
}
@@ -0,0 +1,20 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Products.ValuesObjects;
public class CategoryImage : ValueObject
{
public const short Limit = 150;
private CategoryImage(string value)
{
if (value.Length > Limit)
throw new CharacterLimitException(nameof(CategoryImage), Limit);
Value = value;
}
public static CategoryImage CreateNew(string value)
=> new CategoryImage(value);
public string Value { get; init; }
}
@@ -0,0 +1,16 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.ValuesObjects;
public class CategoryPath : ValueObject
{
private CategoryPath(string value)
{
Value = value;
}
public string Value { get; private set; }
public static CategoryPath CreateNew(string value)
=> new CategoryPath(value);
}
@@ -0,0 +1,34 @@
using Vizhvizh.Shared.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Products.ValuesObjects;
/// <summary>
/// پول
/// </summary>
public class MoneyValue
{
public const short CurrencyLimit = 150;
public decimal Value { get; }
public string Currency { get; }
public static MoneyValue CreateNew(decimal value, string currency)
{
return new MoneyValue(value, currency);
}
private MoneyValue(decimal value, string currency)
{
if(currency.Length > CurrencyLimit)
throw new CharacterLimitException(nameof(Currency), CurrencyLimit);
this.Value = value;
this.Currency = currency;
}
public static MoneyValue operator *(int left, MoneyValue right)
{
return new MoneyValue(right.Value * left, right.Currency);
}
}
@@ -0,0 +1,29 @@
using System.ComponentModel.DataAnnotations;
using Vizhvizh.Shop.Domain.Resource.Products;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.ValuesObjects;
/// <summary>
/// وضعیت محصول نو، کارکرده
/// </summary>
public class ProductCondition : ValueObject
{
private ProductCondition(ProductConditionEnum value)
{
Value = value;
}
public static ProductCondition CreateNew(ProductConditionEnum value)
=> new ProductCondition(value);
public ProductConditionEnum Value { get; init; }
}
public enum ProductConditionEnum
{
[Display(Name = nameof(ValueObjectResources.ProductConditionEnum_BrandNew), ResourceType = typeof(ValueObjectResources))]
BrandNew = 0,
[Display(Name = nameof(ValueObjectResources.ProductConditionEnum_LikeNew), ResourceType = typeof(ValueObjectResources))]
LikeNew = 1,
[Display(Name = nameof(ValueObjectResources.ProductConditionEnum_Used), ResourceType = typeof(ValueObjectResources))]
Used = 2,
}
@@ -0,0 +1,23 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Products.ValuesObjects;
/// <summary>
/// عکس محصولات
/// </summary>
public class ProductImage : ValueObject
{
public const short Limit = 150;
private ProductImage(string value)
{
if (value.Length > Limit)
throw new CharacterLimitException(nameof(ProductImage), Limit);
Value = value;
}
public static ProductImage CreateNew(string value)
=> new ProductImage(value);
public string Value { get; init; }
}
@@ -0,0 +1,18 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.ValuesObjects;
/// <summary>
/// تعداد
/// </summary>
public class ProductQuantity : ValueObject
{
private ProductQuantity(double value)
{
Value = value;
}
public static ProductQuantity CreateNew(double value)
=> new ProductQuantity(value);
public double Value { get; init; }
}
@@ -0,0 +1,20 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Products.ValuesObjects;
/// <summary>
/// امتیاز
/// </summary>
public class ProductScore : ValueObject
{
private ProductScore(byte score, int totalVoters)
{
Score = score;
TotalVoters = totalVoters;
}
public static ProductScore CreateNew(byte score, int totalVoters)
=> new ProductScore(score, totalVoters);
public byte Score { get; private set; }
public int TotalVoters { get; private set; }
}
@@ -0,0 +1,56 @@
using System.ComponentModel.DataAnnotations;
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.BuildingBlocks.Domain.Extensions;
using Vizhvizh.Shared.Domain.Exceptions;
using Vizhvizh.Shop.Domain.Products.Entities;
using Vizhvizh.Shop.Domain.Products.Exceptions;
namespace Vizhvizh.Shop.Domain.Products.ValuesObjects;
public class ProductVariantValue : ValueObject
{
public const short Limit = 120;
private ProductVariantValue()
{
}
private ProductVariantValue(string value, VariantUnitType type)
{
CheckValidation(value, type);
Value = value;
}
public string Value { get; private set; }
public static ProductVariantValue CreateNew(string value, VariantUnitType type)
=> new(value, type);
public static void CheckValidation(string value, VariantUnitType type)
{
if (string.IsNullOrWhiteSpace(value))
throw new InvalidProductVariantValueException(value, type.GetDisplayName());
if (value.Length > Limit)
throw new CharacterLimitException(type.GetDisplayName(), Limit);
switch (type)
{
case VariantUnitType.Color:
if (!value.StartsWith('#'))
throw new InvalidProductVariantValueException(value, type.GetDisplayName());
break;
case VariantUnitType.Number:
if (!long.TryParse(value, out var _))
throw new InvalidProductVariantValueException(value, type.GetDisplayName());
break;
case VariantUnitType.Currency:
if (!long.TryParse(value, out var _))
throw new InvalidProductVariantValueException(value, type.GetDisplayName());
break;
case VariantUnitType.Decimal:
if (!decimal.TryParse(value, out var _))
throw new InvalidProductVariantValueException(value, type.GetDisplayName());
break;
}
}
}
@@ -0,0 +1,19 @@
using Vizhvizh.Shop.Domain.Products.TypeIds;
using Vizhvizh.Shop.Domain.Shops.TypeIds;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Shops.Entities;
/// <summary>
/// مدیریت فروشگاه
/// </summary>
public class Management : Entity<ShopId>
{
private Shop _shop;
private Management()
{
}
internal static Management CreateNew()
=> new Management();
public Shop Shop => _shop;
}
@@ -0,0 +1,33 @@
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Shops.TypeIds;
using Vizhvizh.Shop.Domain.Shops.ValuesObjects;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Shops.Entities;
/// <summary>
/// (نوع ارسال (پست و تیپاکس
/// </summary>
public class ShippingMethod : Entity<ShippingMethodId>
{
private TitleVO _title;
private DescriptionVO _description;
private ShippingMethodImage _image;
private Shop _shop;
private ShippingMethod()
{
}
public ShippingMethod(TitleVO title, DescriptionVO description, ShippingMethodImage image)
{
_title = title;
_description = description;
_image = image;
}
public TitleVO Title => _title;
public DescriptionVO Description => _description;
public ShippingMethodImage Image => _image;
public Shop Shop => _shop;
}
@@ -0,0 +1,70 @@
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Members.Entities;
using Vizhvizh.Shop.Domain.Members.TypeIds;
using Vizhvizh.Shop.Domain.Products.Entities;
using Vizhvizh.Shop.Domain.Shops.TypeIds;
using Vizhvizh.Shop.Domain.Shops.ValuesObjects;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Shops.Entities;
public class Shop : Entity<ShopId>, IAggregateRoot
{
private Management _management;
private List<Product> _products;
private List<ShippingMethod> _shippingMethods;
private List<Member> _members;
private ShopLocation _location;
private TitleVO _title;
private DescriptionVO? _description;
private EmailVO? _email;
private TelephoneVO _telephoneVO;
private ShopLogo _logo;
private MemberId _ownerId;
private Shop()
{
}
private Shop(
MemberId ownerId,
TitleVO title,
ShopLocation location,
TelephoneVO telephone,
DescriptionVO? description = null,
EmailVO? email = null
)
{
_ownerId = ownerId;
_title = title;
_location = location;
_description = description;
_email = email;
_telephoneVO = telephone;
}
public static Shop CreateNew(MemberId ownerId,
TitleVO title,
ShopLocation location,
TelephoneVO telephone,
DescriptionVO? description = null,
EmailVO? email = null)
{
return new Shop(ownerId, title, location, telephone, description, email);
}
public MemberId OwnerId => _ownerId;
public Management Management => _management;
public ShopLocation Location => _location;
public TitleVO Title => _title;
public DescriptionVO? Description => _description;
public EmailVO? Email => _email;
public TelephoneVO Telephone => _telephoneVO;
public ShopLogo Logo => _logo;
public IReadOnlyList<Product> Products => _products;
public IReadOnlyList<ShippingMethod> ShippingMethods => _shippingMethods;
public IReadOnlyList<Member> Members => _members;
public void SetTitle(TitleVO title)
=> _title = title;
}
@@ -0,0 +1,9 @@
using Vizhvizh.Shop.Domain.Shops.TypeIds;
namespace Vizhvizh.Shop.Domain.Shops.Repositories;
public interface IShopRepository
{
Task AddAsync(Entities.Shop shop, CancellationToken cancellationToken);
Task<Entities.Shop?> FindByIdAsync(ShopId id, CancellationToken cancellationToken);
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Shops.TypeIds;
public class ShippingMethodId : TypedIdValueBase<byte>
{
public ShippingMethodId(byte value) : base(value)
{
}
}
@@ -0,0 +1,15 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Shops.TypeIds;
public class ShopId : TypedIdValueBase<long>
{
public ShopId(long value) : base(value)
{
}
public static implicit operator ShopId(long value)
=> new ShopId(value);
public static implicit operator long(ShopId value)
=> value.Value;
}
@@ -0,0 +1,19 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Shops.ValuesObjects;
public class ShippingMethodImage : ValueObject
{
public const short Limit = 150;
private ShippingMethodImage(string value)
{
if (value.Length > Limit)
throw new CharacterLimitException(nameof(ShippingMethodImage), Limit);
Value = value;
}
public static ShippingMethodImage CreateNew(string value)
=> new ShippingMethodImage(value);
public string Value { get; init; }
}
@@ -0,0 +1,26 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Shops.ValuesObjects;
public class ShopLocation : ValueObject
{
public ShopLocation(double latitude, double longitude, int provinceId, int cityId, string address, string postalCode)
{
Latitude = latitude;
Longitude = longitude;
ProvinceId = provinceId;
CityId = cityId;
Address = address;
PostalCode = postalCode;
}
public static ShopLocation CreateNew(double latitude, double longitude, int provinceId, int cityId, string address, string postalCode)
=> new ShopLocation(latitude, longitude, provinceId, cityId, address, postalCode);
public double Latitude { get; private set; }
public double Longitude { get; private set; }
public int ProvinceId { get; private set; }
public int CityId { get; private set; }
public string Address { get; private set; }
public string PostalCode { get; private set; }
}
@@ -0,0 +1,19 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Shops.ValuesObjects;
public class ShopLogo : ValueObject
{
public const short Limit = 150;
private ShopLogo(string value)
{
if (string.IsNullOrWhiteSpace(value) || value.Length > Limit)
throw new CharacterLimitException(nameof(ShopLogo), Limit);
Value = value;
}
public static ShopLogo CreateNew(string value)
=> new ShopLogo(value);
public string? Value { get; init; }
}
@@ -0,0 +1,35 @@
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Shops.ValuesObjects;
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shop.Domain.Sliders.TypeIds;
using Vizhvizh.Shop.Domain.Sliders.ValuesObjects;
namespace Vizhvizh.Shop.Domain.Sliders.Entities;
public class Slider : Entity<SliderId>
{
private TitleVO _title;
private SliderImage _image;
private SliderUrl _url;
private SliderKey _key;
private Slider()
{
}
private Slider(TitleVO title, SliderImage image, SliderUrl url, SliderKey key)
{
_title = title;
_image = image;
_url = url;
_key = key;
}
public static Slider CreateNew(TitleVO title, SliderImage image, SliderUrl url, SliderKey key)
{
return new Slider(title, image, url, key);
}
public TitleVO Title => _title;
public SliderImage Image => _image;
public SliderUrl Url => _url;
public SliderKey Key => _key;
}
@@ -0,0 +1,11 @@
using Vizhvizh.Shop.Domain.Resource.Shops;
using Vizhvizh.BuildingBlocks.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Sliders.Exceptions;
public class IsNullOrEmptySliderUrlException : ValueObjectValidationException
{
public IsNullOrEmptySliderUrlException() : base(ExceptionResources.IsNullOrEmptySliderUrlException)
{
}
}
@@ -0,0 +1,10 @@
using Vizhvizh.Shop.Domain.Sliders.Entities;
using Vizhvizh.Shop.Domain.Sliders.TypeIds;
namespace Vizhvizh.Shop.Domain.Sliders.Repositories;
public interface ISliderRepository
{
Task AddAsync(Slider slider, CancellationToken cancellationToken);
Task GetByIdAsync(SliderId id,CancellationToken cancellationToken);
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Sliders.TypeIds;
public class SliderId : TypedIdValueBase<long>
{
public SliderId(long value) : base(value)
{
}
}
@@ -0,0 +1,20 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Sliders.ValuesObjects;
public class SliderImage : ValueObject
{
public const short Limit = 150;
private SliderImage(string value)
{
if (value.Length > Limit)
throw new CharacterLimitException(nameof(SliderImage), Limit);
Value = value;
}
public static SliderImage CreateNew(string value)
=> new SliderImage(value);
public string Value { get; init; }
}
@@ -0,0 +1,30 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Sliders.ValuesObjects;
public class SliderKey : ValueObject
{
public const short Limit = 150;
private SliderKey()
{
}
public SliderKey(SliderKeyType type, string? key)
{
Type = type;
Value = $"{type}/{key}";
if (Value.Length > Limit)
throw new CharacterLimitException(nameof(SliderKey), Limit);
}
public SliderKeyType Type { get; private set; }
public string Value { get; private set; }
}
public enum SliderKeyType
{
Main = 1,
Shop,
Category
}
@@ -0,0 +1,23 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.Exceptions;
using Vizhvizh.Shop.Domain.Sliders.Exceptions;
namespace Vizhvizh.Shop.Domain.Sliders.ValuesObjects;
public class SliderUrl : ValueObject
{
public const short Limit = 150;
private SliderUrl(string value)
{
if (string.IsNullOrWhiteSpace(value))
throw new IsNullOrEmptySliderUrlException();
if(value.Length > Limit)
throw new CharacterLimitException(nameof(SliderUrl), Limit);
Value = value.Trim();
}
public static SliderUrl CreateNew(string value)
=> new SliderUrl(value);
public string Value { get; init; }
}
@@ -0,0 +1,36 @@
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Users.TypeIds;
using Vizhvizh.Shop.Domain.Users.ValueObjects;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Users.Entities;
public class Resource : Entity<ResourceId>
{
private List<Role> _roles;
private TitleVO _title;
private DescriptionVO _description;
private ModuleNameVO _moduleName;
private ResourceKey _resourceKey;
private Resource()
{
}
public Resource(TitleVO title, DescriptionVO description, ModuleNameVO moduleNames, ResourceKey resourceKey, List<Role> roles)
{
_description = description;
_title = title;
_moduleName = moduleNames;
_resourceKey = resourceKey;
_roles = roles;
}
public static Resource CreateNew(TitleVO title, DescriptionVO description, ModuleNameVO moduleNames, ResourceKey resourceKey, List<Role> roles)
=> new Resource(title, description, moduleNames, resourceKey, roles);
public TitleVO Title => _title;
public DescriptionVO Description => _description;
public ModuleNameVO ModuleName => _moduleName;
public ResourceKey ResourceKey => _resourceKey;
public IReadOnlyList<Role> Roles => _roles;
}
@@ -0,0 +1,26 @@
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Users.TypeIds;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Users.Entities;
public class Role : Entity<RoleId>
{
private TitleVO _title;
private List<RoleResource> _roleResources;
private Role()
{
}
private Role(TitleVO title, List<RoleResource> roleResources)
{
_title = title;
_roleResources = roleResources;
}
public static Role CreateNew(TitleVO title, List<RoleResource> roleResources)
=> new Role(title, roleResources);
public TitleVO Title => _title;
public IReadOnlyList<RoleResource> RoleResources => _roleResources;
}
@@ -0,0 +1,32 @@
using Vizhvizh.Shop.Domain.Users.TypeIds;
using Vizhvizh.Shop.Domain.Users.ValueObjects;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Users.Entities;
public class RoleResource : Entity<RoleResourceId>
{
private AccessLevel _accessLevel;
private User _user;
private Role _role;
private RoleResource()
{
}
private RoleResource(AccessLevel accessLevel, User user, Role role)
{
_accessLevel = accessLevel;
_user = user;
_role = role;
}
public static RoleResource CreateNew(AccessLevel accessLevel, User user, Role role)
=> new RoleResource(accessLevel, user, role);
public AccessLevel AccessLevel => _accessLevel;
public User User => _user;
public Role Role => _role;
}
@@ -0,0 +1,30 @@
using Vizhvizh.Shop.Domain.Members.TypeIds;
using Vizhvizh.Shop.Domain.Users.TypeIds;
using Vizhvizh.Shop.Domain.Users.ValueObjects;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Users.Entities;
public class User : Entity<UserId>, IAggregateRoot
{
//private UserNationalCode _nationalCode;
private MemberId _memberId;
private List<Role> _roles;
private User()
{
}
private User(MemberId memberId, List<Role> roles)
{
_memberId = memberId;
_roles = roles;
}
public static User CreateNew(MemberId memberId, List<Role> roles)
=> new User(memberId, roles);
//public UserNationalCode NationalCode => _nationalCode;
public MemberId MemberId => _memberId;
public IReadOnlyList<Role> Roles => _roles;
}
@@ -0,0 +1,11 @@
using Vizhvizh.Shop.Domain.Resource.Users;
using Vizhvizh.BuildingBlocks.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Users.Exceptions;
public class InvalidNationalCodeException : ValueObjectValidationException
{
public InvalidNationalCodeException() : base(ExceptionResources.InvalidNationalCodeException)
{
}
}
@@ -0,0 +1,11 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Users.TypeIds;
public class ResourceId : TypedIdValueBase<long>
{
public ResourceId(long value) : base(value)
{
}
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Users.TypeIds;
public class RoleId : TypedIdValueBase<int>
{
public RoleId(int value) : base(value)
{
}
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Users.TypeIds;
public class RoleResourceId : TypedIdValueBase<long>
{
public RoleResourceId(long value) : base(value)
{
}
}
@@ -0,0 +1,10 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Users.TypeIds;
public class UserId : TypedIdValueBase<long>
{
public UserId(long value) : base(value)
{
}
}
@@ -0,0 +1,25 @@
using System.ComponentModel.DataAnnotations;
using Vizhvizh.Shop.Domain.Resource.Users;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Users.ValueObjects;
public class AccessLevel : ValueObject
{
private AccessLevel(AccessLevelEnum value)
{
Value = (int)value;
}
public static AccessLevel CreateNew(AccessLevelEnum value)
=> new AccessLevel(value);
public int Value { get; init;}
}
public enum AccessLevelEnum
{
[Display(Name = nameof(ValueObjectResources.AccessLevelEnum_Write), ResourceType = typeof(ValueObjectResources))]
Write = 0,
[Display(Name = nameof(ValueObjectResources.AccessLevelEnum_Read), ResourceType = typeof(ValueObjectResources))]
Read = 1,
[Display(Name = nameof(ValueObjectResources.AccessLevelEnum_ReadWrite), ResourceType = typeof(ValueObjectResources))]
ReadWrite = 2
}
@@ -0,0 +1,20 @@
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Users.ValueObjects;
public class ResourceKey : ValueObject
{
private ResourceKey(ModuleNameVO module, TitleVO resourceTitle, params string[] parts)
{
Value = $"{module.Value}_{string.Join('.', parts)}_{resourceTitle.Value}";
}
public static ResourceKey CreateNew(string value)
{
string[] valueSplit = value.Split('_');
ModuleNamesEnum module = Enum.Parse<ModuleNamesEnum>(valueSplit[0]);
string[] paths = valueSplit[1]?.Split('.') ?? [];
return new ResourceKey(ModuleNameVO.CreateNew(module), TitleVO.CreateNew(valueSplit[2]), paths);
}
public string Value { get; init; }
}
@@ -0,0 +1,48 @@
using Vizhvizh.Shop.Domain.Users.Exceptions;
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Users.ValueObjects;
public class UserNationalCode : ValueObject
{
public static bool IsValidNationalCode(string nationalCode)
{
if (nationalCode is null || nationalCode.Length > 10)
return false;
// تبدیل به آرایه
var arr = nationalCode.ToArray().Select(n => int.Parse(n.ToString()));
//بر عکس کردن اجزا
var arrReduce = arr.Reverse().ToList();
// بدست آوردن رقم کنترل اخر کد ملی
var numberControl = arrReduce.First();
arrReduce.RemoveAt(0);
// تمام 9 رقم سمت چپ کد ملی ضرب در موقعیت خودش میشه بعد همه جمع میشن بعدش تقسیم به یازده و باقی مانده رو میگیرم
//کد ملی 0700454713
//موقیعت 07 به ترتیب 9و10 هست از اونجایی ک ما رقم کنترل رو برداشتیم پس باید ایندکس ب اضافه ی 2 شه
var remaining = decimal.Parse($"{arrReduce.Select((n, i) => n * (i + 2)).Sum() % 11}");
if (remaining <= 2.0m)
{
if (numberControl == remaining)
return true;
else
return false;
}
else if (11m - remaining == numberControl)
return true;
else
return false;
}
public UserNationalCode(string value)
{
if (!IsValidNationalCode(value))
throw new InvalidNationalCodeException();
Value = value;
}
public string Value { get; init; }
}
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Vichvich.Shared.Domain\Vizhvizh.Shared.Domain.csproj" />
<ProjectReference Include="..\VichVich.Shop.Domain.Resource\Vizhvizh.Shop.Domain.Resource.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Members\Events\" />
<Folder Include="Members\Rules\" />
<Folder Include="Members\Repositories\" />
<Folder Include="Products\Events\" />
<Folder Include="Products\Rules\" />
<Folder Include="Shops\Events\" />
<Folder Include="Shops\Exceptions\" />
<Folder Include="Shops\Rules\" />
<Folder Include="Users\Events\" />
<Folder Include="Users\Rules\" />
<Folder Include="Users\Repositories\" />
</ItemGroup>
</Project>