This commit is contained in:
2026-04-18 22:36:21 +04:30
parent 49591985ac
commit c64c3dd9be
20 changed files with 157 additions and 24 deletions
@@ -1,6 +1,6 @@
namespace Vizhvizh.BuildingBlocks.Domain; namespace Vizhvizh.BuildingBlocks.Domain;
public class DomainEventBase : IDomainEvent public abstract class DomainEventBase : IDomainEvent
{ {
public Guid Id { get; } public Guid Id { get; }
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Vizhvizh.BuildingBlocks.Infrastructure; using Vizhvizh.BuildingBlocks.Infrastructure;
using Vizhvizh.Shop.ApplicationContract.Commands;
using Vizhvizh.Shop.ApplicationContract.DTOs; using Vizhvizh.Shop.ApplicationContract.DTOs;
using Vizhvizh.Shop.ApplicationContract.Queries; using Vizhvizh.Shop.ApplicationContract.Queries;
@@ -13,6 +14,11 @@ namespace Vizhvizh.Shop.Api.Controllers
public async Task<ActionResult<ShopDTO?>> GetById([FromQuery] long shopId, CancellationToken cancellationToken) public async Task<ActionResult<ShopDTO?>> GetById([FromQuery] long shopId, CancellationToken cancellationToken)
=> Ok(await executor.Execute(new GetShopByIdQuery(shopId), cancellationToken)); => Ok(await executor.Execute(new GetShopByIdQuery(shopId), cancellationToken));
[HttpPost]
public async Task<ActionResult> Create([FromBody] CreateShopCommand request, CancellationToken cancellationToken)
{
await executor.Execute(request, cancellationToken);
return Ok();
}
} }
} }
@@ -7,18 +7,18 @@ using Vizhvizh.Shop.Domain.Shops.ValuesObjects;
namespace Vizhvizh.Shop.Application.CommandHandlers.Shops; namespace Vizhvizh.Shop.Application.CommandHandlers.Shops;
public class CreateShopCommandHandler(IShopRepository shopRepository) : ICommandHandler<CreateShopCommand, ShopId> public class CreateShopCommandHandler(IShopRepository shopRepository) : ICommandHandler<CreateShopCommand>
{ {
public async Task<ShopId> Handle(CreateShopCommand request, CancellationToken cancellationToken) public async Task Handle(CreateShopCommand request, CancellationToken cancellationToken)
{ {
var location = ShopLocation.CreateNew(request.ShopLocation.Latitude, request.ShopLocation.Longitude, var location = ShopLocation.CreateNew(request.ShopLocation.Latitude, request.ShopLocation.Longitude,
request.ShopLocation.ProvinceId, request.ShopLocation.CityId, request.ShopLocation.Address, request.ShopLocation.PostalCode); request.ShopLocation.ProvinceId, request.ShopLocation.CityId, request.ShopLocation.Address, request.ShopLocation.PostalCode);
var businessLicense = ShopBusinessLicense.CreateNew(request.ShopBusinessLicenseImage, request.ShopBusinessLicenseCode);
var shop = Domain.Shops.Entities.Shop.CreateNew(request.OwnerId, request.Title, var shop = Domain.Shops.Entities.Shop.CreateNew(request.OwnerId, request.Title,
location,TelephoneVO.CreateNew(request.Telephone), request.Description); location, TelephoneVO.CreateNew(request.Telephone), businessLicense, request.Description);
await shopRepository.AddAsync(shop, cancellationToken); await shopRepository.AddAsync(shop, cancellationToken);
return shop.Id;
} }
} }
@@ -14,4 +14,8 @@
<ProjectReference Include="..\Vichvich.Shop.ApplicationContract\Vizhvizh.Shop.ApplicationContract.csproj" /> <ProjectReference Include="..\Vichvich.Shop.ApplicationContract\Vizhvizh.Shop.ApplicationContract.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="CommandHandlers\Products\" />
</ItemGroup>
</Project> </Project>
@@ -0,0 +1,8 @@
using Vizhvizh.BuildingBlocks.Domain.Contract;
using Vizhvizh.Shop.ApplicationContract.Models.Products;
using Vizhvizh.Shop.Domain.Products.ValuesObjects;
namespace Vizhvizh.Shop.ApplicationContract.Commands;
public record CreateProductCommand(long ShopId, long CategoryId, string Title, string Description, string Image,
ProductConditionEnum ProductCondition, List<ProductSpecificationsModel> ProductSpecifications) : CommandBase;
@@ -1,9 +1,9 @@
using Vizhvizh.BuildingBlocks.Domain.Contract; using Vizhvizh.BuildingBlocks.Domain.Contract;
using Vizhvizh.Shared.Domain.ValueObjects;
using Vizhvizh.Shop.Domain.Shops.TypeIds; using Vizhvizh.Shop.Domain.Shops.TypeIds;
using Vizhvizh.Shop.Domain.Shops.ValuesObjects; using Vizhvizh.Shop.Domain.Shops.ValuesObjects;
namespace Vizhvizh.Shop.ApplicationContract.Commands; namespace Vizhvizh.Shop.ApplicationContract.Commands;
public record CreateShopCommand(long OwnerId, string Title,string Telephone, string Description, string Email, ShopLocation ShopLocation) : CommandBase<ShopId>; public record CreateShopCommand(long OwnerId, string Title,string Telephone,string ShopBusinessLicenseImage,string ShopBusinessLicenseCode,
public record SetTitleShopCommand(ShopId ShopId,TitleVO Title) : CommandBase; string Description, string Email, ShopLocation ShopLocation) : CommandBase;
public record SetTitleShopCommand(long ShopId,string Title) : CommandBase;
@@ -0,0 +1,3 @@
namespace Vizhvizh.Shop.ApplicationContract.Models.Products;
public record ProductSpecificationsModel(string Title, List<string> Values);
@@ -6,10 +6,6 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Folder Include="Models\" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup> </ItemGroup>
@@ -2,6 +2,7 @@
using Vizhvizh.Shop.Domain.Members.TypeIds; using Vizhvizh.Shop.Domain.Members.TypeIds;
using Vizhvizh.Shop.Domain.Members.ValuesObjects; using Vizhvizh.Shop.Domain.Members.ValuesObjects;
using Vizhvizh.BuildingBlocks.Domain; using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shop.Domain.Members.Events;
namespace Vizhvizh.Shop.Domain.Members.Entities; namespace Vizhvizh.Shop.Domain.Members.Entities;
@@ -10,6 +11,7 @@ public class Member : Entity<MemberId>, IAggregateRoot
private PhoneNumberVO _phoneNumber; private PhoneNumberVO _phoneNumber;
private MemberFullName _fullName; private MemberFullName _fullName;
private MemberAvatar? _avatar; private MemberAvatar? _avatar;
private MemberNationalCode? _nationalCode;
private Member() private Member()
{ {
@@ -28,4 +30,12 @@ public class Member : Entity<MemberId>, IAggregateRoot
public MemberFullName? FullName => _fullName; public MemberFullName? FullName => _fullName;
public PhoneNumberVO PhoneNumber => _phoneNumber; public PhoneNumberVO PhoneNumber => _phoneNumber;
public MemberAvatar? Avatar => _avatar; public MemberAvatar? Avatar => _avatar;
public MemberNationalCode? NationalCode => _nationalCode;
public void SetNationalCode(MemberNationalCode nationalCode)
{
_nationalCode = nationalCode;
this.AddDomainEvent(new SetNationalCodeEvent(this));
}
} }
@@ -0,0 +1,9 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shop.Domain.Members.Entities;
namespace Vizhvizh.Shop.Domain.Members.Events;
public class SetNationalCodeEvent(Member member) : DomainEventBase
{
public Member Member => member;
}
@@ -0,0 +1,17 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Members.ValuesObjects;
public class MemberNationalCode : ValueObject
{
public const short Limit = 10;
public MemberNationalCode(string value)
{
if (value.Length > Limit)
throw new CharacterLimitException(nameof(MemberNationalCode), Limit);
Value = value;
}
public string Value { get; private set; }
}
@@ -27,7 +27,7 @@ public class Specifications : Entity<SpecificationsId>
_product = product; _product = product;
} }
public static Specifications CreateNew(TitleVO title, Product product, List<string> values) internal static Specifications CreateNew(TitleVO title, Product product, List<string> values)
=> new Specifications(title, product, values); => new Specifications(title, product, values);
public TitleVO Title => _title; public TitleVO Title => _title;
+10 -1
View File
@@ -22,6 +22,8 @@ public class Shop : Entity<ShopId>, IAggregateRoot
private TelephoneVO _telephoneVO; private TelephoneVO _telephoneVO;
private ShopLogo _logo; private ShopLogo _logo;
private MemberId _ownerId; private MemberId _ownerId;
private ShopStatus _shopStatus;
private ShopBusinessLicense _businessLicense;
private Shop() private Shop()
{ {
@@ -32,6 +34,7 @@ public class Shop : Entity<ShopId>, IAggregateRoot
TitleVO title, TitleVO title,
ShopLocation location, ShopLocation location,
TelephoneVO telephone, TelephoneVO telephone,
ShopBusinessLicense businessLicense,
DescriptionVO? description = null, DescriptionVO? description = null,
EmailVO? email = null EmailVO? email = null
) )
@@ -40,18 +43,22 @@ public class Shop : Entity<ShopId>, IAggregateRoot
_title = title; _title = title;
_location = location; _location = location;
_description = description; _description = description;
_businessLicense = businessLicense;
_email = email; _email = email;
_telephoneVO = telephone; _telephoneVO = telephone;
_shopStatus = ShopStatus.CreateNew(ShopStatusEnum.PendingApproval);
} }
public static Shop CreateNew(MemberId ownerId, public static Shop CreateNew(MemberId ownerId,
TitleVO title, TitleVO title,
ShopLocation location, ShopLocation location,
TelephoneVO telephone, TelephoneVO telephone,
ShopBusinessLicense businessLicense,
DescriptionVO? description = null, DescriptionVO? description = null,
EmailVO? email = null) EmailVO? email = null)
{ {
return new Shop(ownerId, title, location, telephone, description, email); return new Shop(ownerId, title, location, telephone, businessLicense, description, email);
} }
public MemberId OwnerId => _ownerId; public MemberId OwnerId => _ownerId;
public Management Management => _management; public Management Management => _management;
@@ -61,6 +68,8 @@ public class Shop : Entity<ShopId>, IAggregateRoot
public EmailVO? Email => _email; public EmailVO? Email => _email;
public TelephoneVO Telephone => _telephoneVO; public TelephoneVO Telephone => _telephoneVO;
public ShopLogo Logo => _logo; public ShopLogo Logo => _logo;
public ShopStatus Status => _shopStatus;
public ShopBusinessLicense BusinessLicense => _businessLicense;
public IReadOnlyList<Product> Products => _products; public IReadOnlyList<Product> Products => _products;
public IReadOnlyList<ShippingMethod> ShippingMethods => _shippingMethods; public IReadOnlyList<ShippingMethod> ShippingMethods => _shippingMethods;
public IReadOnlyList<Member> Members => _members; public IReadOnlyList<Member> Members => _members;
@@ -0,0 +1,31 @@
using Vizhvizh.BuildingBlocks.Domain;
using Vizhvizh.Shared.Domain.Exceptions;
namespace Vizhvizh.Shop.Domain.Shops.ValuesObjects;
/// <summary>
/// پروانه کسب
/// </summary>
public class ShopBusinessLicense : ValueObject
{
public const short ImageLimit = 150;
public const short CodeLimit = 50;
private ShopBusinessLicense(string image, string code)
{
if (image.Length > ImageLimit)
throw new CharacterLimitException("ShopBusinessLicenseImage", ImageLimit);
if (code.Length > CodeLimit)
throw new CharacterLimitException("ShopBusinessLicenseCode", CodeLimit);
Image = image;
Code = code;
}
public string Image { get; private set; }
public string Code { get; private set; }
public static ShopBusinessLicense CreateNew(string image, string code)
=> new ShopBusinessLicense(image, code);
}
@@ -0,0 +1,22 @@
using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.Shop.Domain.Shops.ValuesObjects;
public class ShopStatus : ValueObject
{
public ShopStatus(ShopStatusEnum value)
{
Value = value;
}
public ShopStatusEnum Value { get; private set; }
public static ShopStatus CreateNew(ShopStatusEnum value)
=> new(value);
}
public enum ShopStatusEnum
{
Creating = 1,
PendingApproval,
Available,
}
@@ -12,7 +12,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Members\Events\" />
<Folder Include="Members\Rules\" /> <Folder Include="Members\Rules\" />
<Folder Include="Members\Repositories\" /> <Folder Include="Members\Repositories\" />
<Folder Include="Products\Events\" /> <Folder Include="Products\Events\" />
@@ -32,5 +32,13 @@ internal class MemberConfiguration : IEntityTypeConfiguration<Member>
.HasMaxLength(MemberAvatar.Limit) .HasMaxLength(MemberAvatar.Limit)
.HasColumnName("Avatar"); .HasColumnName("Avatar");
}); });
builder.OwnsOne(x => x.NationalCode, sa =>
{
sa.Property(x => x.Value)
.IsRequired(false)
.HasMaxLength(MemberNationalCode.Limit)
.HasColumnName("NationalCode");
});
} }
} }
@@ -31,6 +31,17 @@ public class ShopConfiguration : IEntityTypeConfiguration<Domain.Shops.Entities.
.HasMaxLength(ShopLogo.Limit) .HasMaxLength(ShopLogo.Limit)
.HasColumnName("Logo"); .HasColumnName("Logo");
}); });
builder.OwnsOne(x => x.BusinessLicense, sa =>
{
sa.Property(x => x.Image)
.HasMaxLength(ShopBusinessLicense.ImageLimit)
.HasColumnName("ShopBusinessLicenseImage");
sa.Property(x => x.Code)
.HasMaxLength(ShopBusinessLicense.CodeLimit)
.HasColumnName("ShopBusinessLicenseCode");
});
builder.OwnsOne(x => x.Location, sa => builder.OwnsOne(x => x.Location, sa =>
{ {
sa.Property(x => x.PostalCode).HasColumnName(nameof(ShopLocation.PostalCode)); sa.Property(x => x.PostalCode).HasColumnName(nameof(ShopLocation.PostalCode));
+4 -4
View File
@@ -6,21 +6,21 @@ namespace Vizhvizh.UserAccess.Domain.Entities;
public class User : Entity<UserId>, IAggregateRoot public class User : Entity<UserId>, IAggregateRoot
{ {
private UserNationalCode _nationalCode; private MemberNationalCode _nationalCode;
private MemberId _memberId; private MemberId _memberId;
private List<Role> _roles; private List<Role> _roles;
private User(UserNationalCode nationalCode,MemberId memberId,List<Role> roles) private User(MemberNationalCode nationalCode,MemberId memberId,List<Role> roles)
{ {
_nationalCode = nationalCode; _nationalCode = nationalCode;
_memberId = memberId; _memberId = memberId;
_roles = roles; _roles = roles;
} }
public static User CreateNew(UserNationalCode nationalCode, MemberId memberId, List<Role> roles) public static User CreateNew(MemberNationalCode nationalCode, MemberId memberId, List<Role> roles)
=> new User(nationalCode, memberId, roles); => new User(nationalCode, memberId, roles);
public UserNationalCode NationalCode => _nationalCode; public MemberNationalCode NationalCode => _nationalCode;
public MemberId MemberId => _memberId; public MemberId MemberId => _memberId;
public IReadOnlyList<Role> Roles => _roles; public IReadOnlyList<Role> Roles => _roles;
} }
@@ -3,7 +3,7 @@ using Vizhvizh.BuildingBlocks.Domain;
namespace Vizhvizh.UserAccess.Domain.ValueObjects; namespace Vizhvizh.UserAccess.Domain.ValueObjects;
public class UserNationalCode : ValueObject public class MemberNationalCode : ValueObject
{ {
public static bool IsValidNationalCode(string nationalCode) public static bool IsValidNationalCode(string nationalCode)
{ {
@@ -37,7 +37,7 @@ public class UserNationalCode : ValueObject
else else
return false; return false;
} }
public UserNationalCode(string value) public MemberNationalCode(string value)
{ {
if (!IsValidNationalCode(value)) if (!IsValidNationalCode(value))
throw new InvalidNationalCodeException(); throw new InvalidNationalCodeException();