diff --git a/Netina.Api/Controllers/ProductController.cs b/Netina.Api/Controllers/ProductController.cs index 43e4e05..b0faf8c 100644 --- a/Netina.Api/Controllers/ProductController.cs +++ b/Netina.Api/Controllers/ProductController.cs @@ -28,6 +28,10 @@ public class ProductController : ICarterModule .RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManageProducts)) .HasApiVersion(1.0); + group.MapGet("{productId}/sub", GetSubProductsAsync) + .WithDisplayName("Get Sub Products") + .HasApiVersion(1.0); + group.MapPut("{productId}/displayed", ChangeDisplayedAsync) .WithDisplayName("Change Product Display") .RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManageProducts)) @@ -78,6 +82,11 @@ public class ProductController : ICarterModule CancellationToken cancellationToken) => TypedResults.Ok(await mediator.Send(request, cancellationToken)); + // PUT:Update Entity + public async Task GetSubProductsAsync(Guid productId, IMediator mediator, + CancellationToken cancellationToken) + => TypedResults.Ok(await mediator.Send(new GetSubProductsQuery(productId), cancellationToken)); + public async Task ChangeDisplayedAsync(Guid productId, [FromQuery] bool beDisplayed, [FromServices] IMediator mediator, CancellationToken cancellationToken) => TypedResults.Ok(await mediator.Send(new ChangeProductDisplayedCommand(productId, beDisplayed), cancellationToken)); diff --git a/Netina.Api/Controllers/SubProductController.cs b/Netina.Api/Controllers/SubProductController.cs new file mode 100644 index 0000000..a9a3549 --- /dev/null +++ b/Netina.Api/Controllers/SubProductController.cs @@ -0,0 +1,40 @@ +namespace Netina.Api.Controllers; + +public class SubProductController : ICarterModule +{ + + public virtual void AddRoutes(IEndpointRouteBuilder app) + { + var group = app.NewVersionedApi("SubProduct") + .MapGroup($"api/sub/product"); + + group.MapPost("", PostAsync) + .RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManageBlogs)) + .WithDisplayName("Create SubProduct") + .HasApiVersion(1.0); + + group.MapPut("", PutAsync) + .RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManageBlogs)) + .WithDisplayName("Update SubProduct") + .HasApiVersion(1.0); + + group.MapDelete("{id}", DeleteAsync) + .RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManageBlogs)) + .WithDisplayName("Delete SubProduct") + .HasApiVersion(1.0); + } + // POST:Create Entity + private async Task PostAsync([FromBody] CreateSubProductCommand request, IMediator mediator, + CancellationToken cancellationToken) + => TypedResults.Ok(await mediator.Send(request, cancellationToken)); + + // PUT:Update Entity + private async Task PutAsync([FromBody] UpdateSubProductCommand request, IMediator mediator, + CancellationToken cancellationToken) + => TypedResults.Ok(await mediator.Send(request, cancellationToken)); + + // DELETE:Delete Entity + private async Task DeleteAsync(Guid id, IMediator mediator, CancellationToken cancellationToken) + => TypedResults.Ok(await mediator.Send(new DeleteSubProductCommand(id), cancellationToken)); + +} \ No newline at end of file diff --git a/Netina.Core/BaseServices/SiteMapService.cs b/Netina.Core/BaseServices/SiteMapService.cs index d12b1f5..2cfca71 100644 --- a/Netina.Core/BaseServices/SiteMapService.cs +++ b/Netina.Core/BaseServices/SiteMapService.cs @@ -324,6 +324,7 @@ public class SiteMapService( var products = await repositoryWrapper.SetRepository() .TableNoTracking + .Where(p=>!p.IsSubProduct) .Select(ProductMapper.ProjectToSDto) .ToListAsync(); diff --git a/Netina.Domain/CommandQueries/Commands/SubProductCommands.cs b/Netina.Domain/CommandQueries/Commands/SubProductCommands.cs new file mode 100644 index 0000000..9c821b3 --- /dev/null +++ b/Netina.Domain/CommandQueries/Commands/SubProductCommands.cs @@ -0,0 +1,31 @@ +namespace Netina.Domain.CommandQueries.Commands; + + +public sealed record CreateSubProductCommand( + Guid ParentId, + ProductDiversity Diversity, + string DiversityValue, + string DiversityDescription, + string PersianName, + double Cost, + double PackingCost, + int Stock, + bool HasExpressDelivery, + int MaxOrderCount, + List Files) : IRequest; + +public sealed record UpdateSubProductCommand( + Guid Id, + Guid ParentId, + ProductDiversity Diversity, + string DiversityValue, + string DiversityDescription, + string PersianName, + double Cost, + double PackingCost, + int Stock, + bool HasExpressDelivery, + int MaxOrderCount, + List Files) : IRequest; + +public sealed record DeleteSubProductCommand(Guid Id) : IRequest; \ No newline at end of file diff --git a/Netina.Domain/CommandQueries/Queries/SubProductQueries.cs b/Netina.Domain/CommandQueries/Queries/SubProductQueries.cs new file mode 100644 index 0000000..441c57b --- /dev/null +++ b/Netina.Domain/CommandQueries/Queries/SubProductQueries.cs @@ -0,0 +1,3 @@ +namespace Netina.Domain.CommandQueries.Queries; + +public record GetSubProductsQuery(Guid ProductId) : IRequest>; \ No newline at end of file diff --git a/Netina.Domain/Dtos/SmallDtos/SubProductSDto.cs b/Netina.Domain/Dtos/SmallDtos/SubProductSDto.cs new file mode 100644 index 0000000..a753adb --- /dev/null +++ b/Netina.Domain/Dtos/SmallDtos/SubProductSDto.cs @@ -0,0 +1,15 @@ +namespace Netina.Domain.Dtos.SmallDtos; + +public class SubProductSDto : BaseDto +{ + public Guid ParentId { get; set; } + public string PersianName { get; set; } = string.Empty; + public double Cost { get; set; } + public int Stock { get; set; } + public int MaxOrderCount { get; set; } + public double PackingCost { get; set; } + public bool HasExpressDelivery { get; set; } + public ProductDiversity Diversity { get; set; } + public string DiversityValue { get; set; } = string.Empty; + public string DiversityDescription { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/Netina.Domain/Entities/Products/Product.Aggregate.cs b/Netina.Domain/Entities/Products/Product.Aggregate.cs index 96bf0ae..eca06ab 100644 --- a/Netina.Domain/Entities/Products/Product.Aggregate.cs +++ b/Netina.Domain/Entities/Products/Product.Aggregate.cs @@ -4,7 +4,12 @@ namespace Netina.Domain.Entities.Products; public partial class Product { - public static Product Create(string persianName, string englishName, string summery, string expertCheck, string tags, string warranty, + public static Product Create(string persianName, + string englishName, + string summery, + string expertCheck, + string tags, + string warranty, bool beDisplayed, double cost, double packingCost, @@ -30,6 +35,7 @@ public partial class Product hasExpressDelivery, maxOrderCount, stock > 0, + false, brandId, categoryId,authorId); } @@ -93,4 +99,53 @@ public partial class Specification { return new Specification(title, detail, value, isFeature, productId, parentId); } +} + +public partial class SubProduct +{ + public static SubProduct Create( + Guid parentId, + ProductDiversity diversity, + string diversityValue, + string diversityDescription, + string persianName, + string englishName, + string summery, + string slug, + string expertCheck, + string tags, + string warranty, + bool beDisplayed, + double cost, + double packingCost, + bool hasExpressDelivery, + int stock, + int maxOrderCount, + Guid brandId, + Guid categoryId, + Guid authorId) + { + return new SubProduct( + parentId, + diversity, + diversityValue, + diversityDescription, + persianName, + englishName, + slug, + summery, + expertCheck, + tags, + warranty, + beDisplayed, + cost, + packingCost, + stock, + hasExpressDelivery, + maxOrderCount, + stock > 0, + brandId, + categoryId, + authorId); + } } \ No newline at end of file diff --git a/Netina.Domain/Entities/Products/Product.cs b/Netina.Domain/Entities/Products/Product.cs index 4c38498..b59befa 100644 --- a/Netina.Domain/Entities/Products/Product.cs +++ b/Netina.Domain/Entities/Products/Product.cs @@ -33,6 +33,7 @@ public partial class Product : ApiEntity bool hasExpressDelivery, int maxOrderCount, bool isEnable, + bool isSubProduct, Guid brandId, Guid categoryId, Guid authorId) @@ -51,6 +52,7 @@ public partial class Product : ApiEntity HasExpressDelivery = hasExpressDelivery; MaxOrderCount = maxOrderCount; IsEnable = isEnable; + IsSubProduct = isSubProduct; BrandId = brandId; CategoryId = categoryId; AuthorId = authorId; @@ -72,7 +74,7 @@ public partial class Product : ApiEntity public int Viewed { get; internal set; } public bool HasExpressDelivery { get; internal set; } public int MaxOrderCount { get; internal set; } - + public bool IsSubProduct { get; internal set; } public Guid BrandId { get; internal set; } public Brand? Brand { get; internal set; } @@ -82,10 +84,9 @@ public partial class Product : ApiEntity public ProductCategory? Category { get; internal set; } public List Specifications { get; internal set; } = []; - public List Comments { get; internal set; } = []; - public List Files { get; internal set; } = []; - + public List SubProducts { get; internal set; } = []; public List MetaTags { get; internal set; } = []; - + public List Files { get; internal set; } = []; + public List Comments { get; internal set; } = []; public List OrderProducts { get; internal set; } = []; } \ No newline at end of file diff --git a/Netina.Domain/Entities/Products/SubProduct.cs b/Netina.Domain/Entities/Products/SubProduct.cs new file mode 100644 index 0000000..ea953b8 --- /dev/null +++ b/Netina.Domain/Entities/Products/SubProduct.cs @@ -0,0 +1,65 @@ +namespace Netina.Domain.Entities.Products; + +[AdaptTwoWays("[name]SDto", IgnoreAttributes = [typeof(AdaptIgnoreAttribute)], MapType = MapType.Map | MapType.MapToTarget)] +[GenerateMapper] + +public partial class SubProduct : Product +{ + public SubProduct() + { + + } + + public SubProduct( + Guid parentId, + ProductDiversity diversity, + string diversityValue, + string diversityDescription, + string persianName, + string englishName, + string slug, + string summery, + string expertCheck, + string tags, + string warranty, + bool beDisplayed, + double cost, + double packingCost, + int stock, + bool hasExpressDelivery, + int maxOrderCount, + bool isEnable, + Guid brandId, + Guid categoryId, + Guid authorId) : base(persianName, + englishName, + slug, + summery, + expertCheck, + tags, + warranty, + beDisplayed, + cost, + packingCost, + stock, + hasExpressDelivery, + maxOrderCount, + isEnable, + true, + brandId, + categoryId, + authorId) + { + ParentId = parentId; + Diversity = diversity; + DiversityValue = diversityValue; + DiversityDescription = diversityDescription; + } + + public Guid? ParentId { get; internal set; } + public Product? Parent { get; internal set; } + + public ProductDiversity Diversity { get; internal set; } + public string DiversityValue { get; internal set; } = string.Empty; + public string DiversityDescription { get; internal set; } = string.Empty; +} \ No newline at end of file diff --git a/Netina.Domain/Enums/ProductDiversity.cs b/Netina.Domain/Enums/ProductDiversity.cs new file mode 100644 index 0000000..81d80ec --- /dev/null +++ b/Netina.Domain/Enums/ProductDiversity.cs @@ -0,0 +1,43 @@ +namespace Netina.Domain.Enums; + +public enum ProductDiversity +{ + [Display(Name = "هیچکدام")] + None = 0, + [Display(Name = "رنگ")] + Color = 1, + [Display(Name = "گارانتی")] + Guarantee = 2, + [Display(Name = "سایز")] + Size = 3 +} + +public enum ColorDiversity +{ + [Display(Name = "سفید", Description = "#ffffff")] + White, + [Display(Name = "سیاه", Description = "#000000")] + Black, + [Display(Name = "آبی", Description = "#0000ff")] + Blue, + [Display(Name = "قرمز", Description = "#ff0000")] + Red, + [Display(Name = "زرد", Description = "#ffff00")] + Yellow, + [Display(Name = "سبز", Description = "#008000")] + Green, + [Display(Name = "نارنجی", Description = "#ffa500")] + Orange, + [Display(Name = "بنفش", Description = "#800080")] + Purple, + [Display(Name = "قهوه‌ای", Description = "#a52a2a")] + Brown, + [Display(Name = "صورتی", Description = "#ffc0cb")] + Pink, + [Display(Name = "خاکستری", Description = "#808080")] + Gray, + [Display(Name = "فیروزه‌ای", Description = "#00ffff")] + Cyan, + [Display(Name = "ارغوانی", Description = "#ff00ff")] + Magenta +} diff --git a/Netina.Domain/Mappers/ProductMapper.g.cs b/Netina.Domain/Mappers/ProductMapper.g.cs index 1f21a0a..8bb2e3e 100644 --- a/Netina.Domain/Mappers/ProductMapper.g.cs +++ b/Netina.Domain/Mappers/ProductMapper.g.cs @@ -44,8 +44,8 @@ namespace Netina.Domain.Mappers Id = p1.CategoryId }, Specifications = funcMain1(p1.Specifications), - Files = funcMain2(p1.Files), - MetaTags = funcMain3(p1.MetaTags), + MetaTags = funcMain2(p1.MetaTags), + Files = funcMain3(p1.Files), Id = p1.Id, CreatedAt = p1.CreatedAt }; @@ -79,8 +79,8 @@ namespace Netina.Domain.Mappers result.Author = funcMain5(new Never(), result.Author, p5); result.Category = funcMain6(new Never(), result.Category, p5); result.Specifications = funcMain7(p5.Specifications, result.Specifications); - result.Files = funcMain8(p5.Files, result.Files); - result.MetaTags = funcMain9(p5.MetaTags, result.MetaTags); + result.MetaTags = funcMain8(p5.MetaTags, result.MetaTags); + result.Files = funcMain9(p5.Files, result.Files); result.Id = p5.Id; result.CreatedAt = p5.CreatedAt; return result; @@ -123,24 +123,24 @@ namespace Netina.Domain.Mappers Id = p20.Id, CreatedAt = p20.CreatedAt }).ToList(), - Files = p19.Files.Select(p21 => new ProductStorageFile() + MetaTags = p19.MetaTags.Select(p21 => new ProductMetaTag() { - Name = p21.Name, - FileLocation = p21.FileLocation, - FileName = p21.FileName, - IsHeader = p21.IsHeader, - IsPrimary = p21.IsPrimary, - FileType = p21.FileType, + Type = p21.Type, + Value = p21.Value, Id = p21.Id, CreatedAt = p21.CreatedAt - }).ToList(), - MetaTags = p19.MetaTags.Select(p22 => new ProductMetaTag() + }).ToList(), + Files = p19.Files.Select(p22 => new ProductStorageFile() { - Type = p22.Type, - Value = p22.Value, + Name = p22.Name, + FileLocation = p22.FileLocation, + FileName = p22.FileName, + IsHeader = p22.IsHeader, + IsPrimary = p22.IsPrimary, + FileType = p22.FileType, Id = p22.Id, CreatedAt = p22.CreatedAt - }).ToList(), + }).ToList(), Id = p19.Id, CreatedAt = p19.CreatedAt }; @@ -472,28 +472,24 @@ namespace Netina.Domain.Mappers } - private static List funcMain2(List p3) + private static List funcMain2(List p3) { if (p3 == null) { return null; } - List result = new List(p3.Count); + List result = new List(p3.Count); int i = 0; int len = p3.Count; while (i < len) { - StorageFileSDto item = p3[i]; - result.Add(item == null ? null : new ProductStorageFile() + MetaTagSDto item = p3[i]; + result.Add(item == null ? null : new ProductMetaTag() { - Name = item.Name, - FileLocation = item.FileLocation, - FileName = item.FileName, - IsHeader = item.IsHeader, - IsPrimary = item.IsPrimary, - FileType = item.FileType, + Type = item.Type, + Value = item.Value, Id = item.Id, CreatedAt = item.CreatedAt }); @@ -503,24 +499,28 @@ namespace Netina.Domain.Mappers } - private static List funcMain3(List p4) + private static List funcMain3(List p4) { if (p4 == null) { return null; } - List result = new List(p4.Count); + List result = new List(p4.Count); int i = 0; int len = p4.Count; while (i < len) { - MetaTagSDto item = p4[i]; - result.Add(item == null ? null : new ProductMetaTag() + StorageFileSDto item = p4[i]; + result.Add(item == null ? null : new ProductStorageFile() { - Type = item.Type, - Value = item.Value, + Name = item.Name, + FileLocation = item.FileLocation, + FileName = item.FileName, + IsHeader = item.IsHeader, + IsPrimary = item.IsPrimary, + FileType = item.FileType, Id = item.Id, CreatedAt = item.CreatedAt }); @@ -589,28 +589,24 @@ namespace Netina.Domain.Mappers } - private static List funcMain8(List p15, List p16) + private static List funcMain8(List p15, List p16) { if (p15 == null) { return null; } - List result = new List(p15.Count); + List result = new List(p15.Count); int i = 0; int len = p15.Count; while (i < len) { - StorageFileSDto item = p15[i]; - result.Add(item == null ? null : new ProductStorageFile() + MetaTagSDto item = p15[i]; + result.Add(item == null ? null : new ProductMetaTag() { - Name = item.Name, - FileLocation = item.FileLocation, - FileName = item.FileName, - IsHeader = item.IsHeader, - IsPrimary = item.IsPrimary, - FileType = item.FileType, + Type = item.Type, + Value = item.Value, Id = item.Id, CreatedAt = item.CreatedAt }); @@ -620,24 +616,28 @@ namespace Netina.Domain.Mappers } - private static List funcMain9(List p17, List p18) + private static List funcMain9(List p17, List p18) { if (p17 == null) { return null; } - List result = new List(p17.Count); + List result = new List(p17.Count); int i = 0; int len = p17.Count; while (i < len) { - MetaTagSDto item = p17[i]; - result.Add(item == null ? null : new ProductMetaTag() + StorageFileSDto item = p17[i]; + result.Add(item == null ? null : new ProductStorageFile() { - Type = item.Type, - Value = item.Value, + Name = item.Name, + FileLocation = item.FileLocation, + FileName = item.FileName, + IsHeader = item.IsHeader, + IsPrimary = item.IsPrimary, + FileType = item.FileType, Id = item.Id, CreatedAt = item.CreatedAt }); diff --git a/Netina.Domain/Mappers/SubProductMapper.g.cs b/Netina.Domain/Mappers/SubProductMapper.g.cs new file mode 100644 index 0000000..4fbc901 --- /dev/null +++ b/Netina.Domain/Mappers/SubProductMapper.g.cs @@ -0,0 +1,115 @@ +using System; +using System.Linq.Expressions; +using Netina.Domain.Dtos.ResponseDtos.Torob; +using Netina.Domain.Dtos.SmallDtos; +using Netina.Domain.Entities.Products; + +namespace Netina.Domain.Mappers +{ + public static partial class SubProductMapper + { + public static SubProduct AdaptToSubProduct(this SubProductSDto p1) + { + return p1 == null ? null : new SubProduct() + { + ParentId = (Guid?)p1.ParentId, + Diversity = p1.Diversity, + DiversityValue = p1.DiversityValue, + DiversityDescription = p1.DiversityDescription, + PersianName = p1.PersianName, + Cost = p1.Cost, + PackingCost = p1.PackingCost, + Stock = p1.Stock, + HasExpressDelivery = p1.HasExpressDelivery, + MaxOrderCount = p1.MaxOrderCount, + Id = p1.Id, + CreatedAt = p1.CreatedAt + }; + } + public static SubProduct AdaptTo(this SubProductSDto p2, SubProduct p3) + { + if (p2 == null) + { + return null; + } + SubProduct result = p3 ?? new SubProduct(); + + result.ParentId = (Guid?)p2.ParentId; + result.Diversity = p2.Diversity; + result.DiversityValue = p2.DiversityValue; + result.DiversityDescription = p2.DiversityDescription; + result.PersianName = p2.PersianName; + result.Cost = p2.Cost; + result.PackingCost = p2.PackingCost; + result.Stock = p2.Stock; + result.HasExpressDelivery = p2.HasExpressDelivery; + result.MaxOrderCount = p2.MaxOrderCount; + result.Id = p2.Id; + result.CreatedAt = p2.CreatedAt; + return result; + + } + public static SubProductSDto AdaptToSDto(this SubProduct p4) + { + return p4 == null ? null : new SubProductSDto() + { + ParentId = p4.ParentId == null ? default(Guid) : (Guid)p4.ParentId, + PersianName = p4.PersianName, + Cost = p4.Cost, + Stock = p4.Stock, + MaxOrderCount = p4.MaxOrderCount, + PackingCost = p4.PackingCost, + HasExpressDelivery = p4.HasExpressDelivery, + Diversity = p4.Diversity, + DiversityValue = p4.DiversityValue, + DiversityDescription = p4.DiversityDescription, + Id = p4.Id, + CreatedAt = p4.CreatedAt + }; + } + public static SubProductSDto AdaptTo(this SubProduct p5, SubProductSDto p6) + { + if (p5 == null) + { + return null; + } + SubProductSDto result = p6 ?? new SubProductSDto(); + + result.ParentId = p5.ParentId == null ? default(Guid) : (Guid)p5.ParentId; + result.PersianName = p5.PersianName; + result.Cost = p5.Cost; + result.Stock = p5.Stock; + result.MaxOrderCount = p5.MaxOrderCount; + result.PackingCost = p5.PackingCost; + result.HasExpressDelivery = p5.HasExpressDelivery; + result.Diversity = p5.Diversity; + result.DiversityValue = p5.DiversityValue; + result.DiversityDescription = p5.DiversityDescription; + result.Id = p5.Id; + result.CreatedAt = p5.CreatedAt; + return result; + + } + public static Expression> ProjectToSDto => p7 => new SubProductSDto() + { + ParentId = p7.ParentId == null ? default(Guid) : (Guid)p7.ParentId, + PersianName = p7.PersianName, + Cost = p7.Cost, + Stock = p7.Stock, + MaxOrderCount = p7.MaxOrderCount, + PackingCost = p7.PackingCost, + HasExpressDelivery = p7.HasExpressDelivery, + Diversity = p7.Diversity, + DiversityValue = p7.DiversityValue, + DiversityDescription = p7.DiversityDescription, + Id = p7.Id, + CreatedAt = p7.CreatedAt + }; + public static Expression> ProjectToTorobProductResponseDto => p8 => new TorobProductResponseDto() + { + product_id = ((Product)p8).Id.ToString(), + price = p8.Cost, + availibility = p8.IsEnable + }; + } +} \ No newline at end of file diff --git a/Netina.Repository/Handlers/Products/CreateProductCommandHandler.cs b/Netina.Repository/Handlers/Products/CreateProductCommandHandler.cs index bf6ac99..f94dcbe 100644 --- a/Netina.Repository/Handlers/Products/CreateProductCommandHandler.cs +++ b/Netina.Repository/Handlers/Products/CreateProductCommandHandler.cs @@ -17,11 +17,17 @@ public class CreateProductCommandHandler( throw new BaseApiException(ApiResultStatusCode.UnAuthorized, "User id is wrong"); var ent = Product.Create(request.PersianName, request.EnglishName, request.Summery, request.ExpertCheck, - request.Tags, request.Warranty,request.BeDisplayed,request.Cost,request.PackingCost, + request.Tags, + request.Warranty, + request.BeDisplayed, + request.Cost, + request.PackingCost, request.HasExpressDelivery, request.Stock, request.MaxOrderCount, - request.BrandId,request.CategoryId, userId); + request.BrandId, + request.CategoryId, + userId); foreach (var specification in request.Specifications) { diff --git a/Netina.Repository/Handlers/Products/GetProductsQueryHandler.cs b/Netina.Repository/Handlers/Products/GetProductsQueryHandler.cs index 6f353f5..3c71b74 100644 --- a/Netina.Repository/Handlers/Products/GetProductsQueryHandler.cs +++ b/Netina.Repository/Handlers/Products/GetProductsQueryHandler.cs @@ -9,7 +9,7 @@ public class GetProductsQueryHandler( public async Task Handle(GetProductsQuery request, CancellationToken cancellationToken) { var response = new GetProductsResponseDto(); - var products = repositoryWrapper.SetRepository().TableNoTracking; + var products = repositoryWrapper.SetRepository().TableNoTracking.Where(s=>!s.IsSubProduct); if (currentUserService.JwtToken == null) products = products.Where(p => p.BeDisplayed); var roleClaim = currentUserService.JwtToken?.Claims.FirstOrDefault(c => c.Type == "role"); diff --git a/Netina.Repository/Handlers/Products/UpdateProductCommandHandler.cs b/Netina.Repository/Handlers/Products/UpdateProductCommandHandler.cs index dedfb97..837659a 100644 --- a/Netina.Repository/Handlers/Products/UpdateProductCommandHandler.cs +++ b/Netina.Repository/Handlers/Products/UpdateProductCommandHandler.cs @@ -13,6 +13,7 @@ public class UpdateProductCommandHandler(IRepositoryWrapper repositoryWrapper,IM throw new BaseApiException(ApiResultStatusCode.UnAuthorized, "User id is wrong"); if(!Guid.TryParse(currentUserService.UserId,out Guid userId)) throw new BaseApiException(ApiResultStatusCode.UnAuthorized, "User id is wrong"); + var newEnt = Product.Create(request.PersianName, request.EnglishName, request.Summery, request.ExpertCheck, request.Tags, request.Warranty, diff --git a/Netina.Repository/Handlers/SubProducts/CreateSubProductCommandHandler.cs b/Netina.Repository/Handlers/SubProducts/CreateSubProductCommandHandler.cs new file mode 100644 index 0000000..0acadb4 --- /dev/null +++ b/Netina.Repository/Handlers/SubProducts/CreateSubProductCommandHandler.cs @@ -0,0 +1,49 @@ +namespace Netina.Repository.Handlers.SubProducts; + +public class CreateSubProductCommandHandler(IRepositoryWrapper repositoryWrapper, + ICurrentUserService currentUserService) : IRequestHandler +{ + public async Task Handle(CreateSubProductCommand request, CancellationToken cancellationToken) + { + + if (currentUserService.UserId == null) + throw new BaseApiException(ApiResultStatusCode.UnAuthorized, "User id is wrong"); + + if (!Guid.TryParse(currentUserService.UserId, out Guid userId)) + throw new BaseApiException(ApiResultStatusCode.UnAuthorized, "User id is wrong"); + + var parent = await repositoryWrapper.SetRepository().TableNoTracking + .FirstOrDefaultAsync(p => p.Id == request.ParentId, cancellationToken); + if (parent == null) + throw new BaseApiException(ApiResultStatusCode.NotFound, "Parent product not found"); + + var subProduct = SubProduct.Create( + request.ParentId, + request.Diversity, + request.DiversityValue, + request.DiversityDescription, + $"{parent.PersianName} - {request.DiversityDescription}", + parent.EnglishName, + parent.Summery, + parent.Slug, + parent.ExpertCheck, + parent.Tags, + parent.Warranty, + parent.BeDisplayed, + request.Cost, + request.PackingCost, + request.HasExpressDelivery, + request.Stock, + request.MaxOrderCount, + parent.BrandId, + parent.CategoryId, + userId); + + foreach (var file in request.Files) + subProduct.AddFile(file.Name, file.FileLocation, file.FileName, file.IsHeader, file.IsPrimary, file.FileType); + + repositoryWrapper.SetRepository().Add(subProduct); + await repositoryWrapper.SaveChangesAsync(cancellationToken); + return subProduct.Id; + } +} \ No newline at end of file diff --git a/Netina.Repository/Handlers/SubProducts/DeleteSubProductCommandHandler.cs b/Netina.Repository/Handlers/SubProducts/DeleteSubProductCommandHandler.cs new file mode 100644 index 0000000..926fd10 --- /dev/null +++ b/Netina.Repository/Handlers/SubProducts/DeleteSubProductCommandHandler.cs @@ -0,0 +1,17 @@ +namespace Netina.Repository.Handlers.SubProducts; + +public class DeleteSubProductCommandHandler(IRepositoryWrapper repositoryWrapper) + : IRequestHandler +{ + public async Task Handle(DeleteSubProductCommand request, CancellationToken cancellationToken) + { + var ent = await repositoryWrapper.SetRepository().TableNoTracking + .FirstOrDefaultAsync(d => d.Id == request.Id, cancellationToken); + if (ent == null) + throw new AppException("Product NotFound", ApiResultStatusCode.NotFound); + + repositoryWrapper.SetRepository().Delete(ent); + await repositoryWrapper.SaveChangesAsync(cancellationToken); + return true; + } +} \ No newline at end of file diff --git a/Netina.Repository/Handlers/SubProducts/GetSubProductsQueryHandler.cs b/Netina.Repository/Handlers/SubProducts/GetSubProductsQueryHandler.cs new file mode 100644 index 0000000..3991ec2 --- /dev/null +++ b/Netina.Repository/Handlers/SubProducts/GetSubProductsQueryHandler.cs @@ -0,0 +1,17 @@ +namespace Netina.Repository.Handlers.SubProducts; + +public class GetSubProductsQueryHandler(IRepositoryWrapper repositoryWrapper) : IRequestHandler> +{ + public async Task> Handle(GetSubProductsQuery request, CancellationToken cancellationToken) + { + var product = await repositoryWrapper.SetRepository().TableNoTracking + .FirstOrDefaultAsync(p => p.Id == request.ProductId, cancellationToken); + if (product == null) + throw new AppException("Product not found"); + + return await repositoryWrapper.SetRepository().TableNoTracking + .Where(s => s.ParentId == request.ProductId) + .Select(SubProductMapper.ProjectToSDto) + .ToListAsync(cancellationToken); + } +} \ No newline at end of file diff --git a/Netina.Repository/Handlers/SubProducts/UpdateSubProductCommandHandler.cs b/Netina.Repository/Handlers/SubProducts/UpdateSubProductCommandHandler.cs new file mode 100644 index 0000000..9b45844 --- /dev/null +++ b/Netina.Repository/Handlers/SubProducts/UpdateSubProductCommandHandler.cs @@ -0,0 +1,58 @@ +namespace Netina.Repository.Handlers.SubProducts; + +public class UpdateSubProductCommandHandler(IRepositoryWrapper repositoryWrapper, + ICurrentUserService currentUserService) : IRequestHandler +{ + public async Task Handle(UpdateSubProductCommand request, CancellationToken cancellationToken) + { + + if (currentUserService.UserId == null) + throw new BaseApiException(ApiResultStatusCode.UnAuthorized, "User id is wrong"); + + if (!Guid.TryParse(currentUserService.UserId, out Guid userId)) + throw new BaseApiException(ApiResultStatusCode.UnAuthorized, "User id is wrong"); + + var parent = await repositoryWrapper.SetRepository().TableNoTracking + .FirstOrDefaultAsync(p => p.Id == request.ParentId, cancellationToken); + if (parent == null) + throw new BaseApiException(ApiResultStatusCode.NotFound, "Parent product not found"); + + var subProduct = await repositoryWrapper.SetRepository().TableNoTracking + .FirstOrDefaultAsync(p => p.Id == request.Id, cancellationToken); + if (subProduct == null) + throw new BaseApiException(ApiResultStatusCode.NotFound, "Parent product not found"); + + var newEnt = SubProduct.Create( + request.ParentId, + request.Diversity, + request.DiversityValue, + request.DiversityDescription, + $"{parent.PersianName} - {request.DiversityDescription}", + parent.EnglishName, + parent.Summery, + parent.Slug, + parent.ExpertCheck, + parent.Tags, + parent.Warranty, + parent.BeDisplayed, + request.Cost, + request.PackingCost, + request.HasExpressDelivery, + request.Stock, + request.MaxOrderCount, + parent.BrandId, + parent.CategoryId, + userId); + + newEnt.Id = subProduct.Id; + newEnt.CreatedAt = subProduct.CreatedAt; + newEnt.CreatedBy = subProduct.CreatedBy; + + foreach (var file in request.Files) + subProduct.AddFile(file.Name, file.FileLocation, file.FileName, file.IsHeader, file.IsPrimary, file.FileType); + + repositoryWrapper.SetRepository().Update(newEnt); + await repositoryWrapper.SaveChangesAsync(cancellationToken); + return subProduct.Id; + } +} \ No newline at end of file diff --git a/Netina.Repository/Migrations/20240905093846_AddAuthor.cs b/Netina.Repository/Migrations/20240905093846_AddAuthor.cs index 0155dc7..0a423de 100644 --- a/Netina.Repository/Migrations/20240905093846_AddAuthor.cs +++ b/Netina.Repository/Migrations/20240905093846_AddAuthor.cs @@ -17,7 +17,7 @@ namespace NetinaShop.Repository.Migrations table: "Products", type: "uuid", nullable: false, - defaultValue: new Guid("11c47231-4f8b-4a73-b848-d2edf3c2d9ab")); + defaultValue: new Guid("8723f1d2-e091-4812-9110-5161c9e23586")); migrationBuilder.AddColumn( name: "AuthorId", @@ -25,7 +25,7 @@ namespace NetinaShop.Repository.Migrations table: "Blogs", type: "uuid", nullable: false, - defaultValue: new Guid("11c47231-4f8b-4a73-b848-d2edf3c2d9ab")); + defaultValue: new Guid("8723f1d2-e091-4812-9110-5161c9e23586")); migrationBuilder.CreateIndex( name: "IX_Products_AuthorId", diff --git a/Netina.Repository/Migrations/20241217212716_AddSubProduct.Designer.cs b/Netina.Repository/Migrations/20241217212716_AddSubProduct.Designer.cs new file mode 100644 index 0000000..e4e5eac --- /dev/null +++ b/Netina.Repository/Migrations/20241217212716_AddSubProduct.Designer.cs @@ -0,0 +1,2313 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Netina.Repository.Models; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace NetinaShop.Repository.Migrations +{ + [DbContext(typeof(ApplicationContext))] + [Migration("20241217212716_AddSubProduct")] + partial class AddSubProduct + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("public") + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "fuzzystrmatch"); + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "pg_trgm"); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", "public"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Claims", "public"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("Logins", "public"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "public"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("Tokens", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Accounting.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("double precision"); + + b.Property("Authority") + .IsRequired() + .HasColumnType("text"); + + b.Property("CardPan") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("CustomerId") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("FactorNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("OrderId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TransactionCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.Blog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("IsSuggested") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReadingTime") + .HasColumnType("integer"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.Property("Summery") + .IsRequired() + .HasColumnType("text"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("CategoryId"); + + b.ToTable("Blogs", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsMain") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("BlogCategories", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Brands.Brand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EnglishName") + .IsRequired() + .HasColumnType("text"); + + b.Property("HasSpecialPage") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("PageUrl") + .IsRequired() + .HasColumnType("text"); + + b.Property("PersianName") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Brands", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Comments.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("character varying(21)"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("IsConfirmed") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("IsRoot") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("Rate") + .HasColumnType("real"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("UserId"); + + b.ToTable("Comments", "public"); + + b.HasDiscriminator().HasValue("Comment"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.Discount", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AmountType") + .HasColumnType("integer"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Count") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("DiscountAmount") + .HasColumnType("bigint"); + + b.Property("DiscountPercent") + .HasColumnType("integer"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("character varying(21)"); + + b.Property("ExpireDate") + .HasColumnType("timestamp without time zone"); + + b.Property("HasCode") + .HasColumnType("boolean"); + + b.Property("HasPriceCeiling") + .HasColumnType("boolean"); + + b.Property("HasPriceFloor") + .HasColumnType("boolean"); + + b.Property("Immortal") + .HasColumnType("boolean"); + + b.Property("IsForFirstPurchase") + .HasColumnType("boolean"); + + b.Property("IsForInvitation") + .HasColumnType("boolean"); + + b.Property("IsForSaleCooperation") + .HasColumnType("boolean"); + + b.Property("IsInfinity") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("IsSpecialOffer") + .HasColumnType("boolean"); + + b.Property("MarketerId") + .HasColumnType("uuid"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("PriceCeiling") + .HasColumnType("bigint"); + + b.Property("PriceFloor") + .HasColumnType("bigint"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("StartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("UseCount") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("MarketerId") + .IsUnique(); + + b.ToTable("Discounts", "public"); + + b.HasDiscriminator().HasValue("Discount"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("CustomerId") + .HasColumnType("uuid"); + + b.Property("DeliveredAt") + .HasColumnType("timestamp without time zone"); + + b.Property("DeliveryPrice") + .HasColumnType("double precision"); + + b.Property("DiscountCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("DiscountCodePrice") + .HasColumnType("double precision"); + + b.Property("DiscountId") + .HasColumnType("uuid"); + + b.Property("DiscountPrice") + .HasColumnType("double precision"); + + b.Property("DoneAt") + .HasColumnType("timestamp without time zone"); + + b.Property("FactorCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsPayed") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("OrderAt") + .HasColumnType("timestamp without time zone"); + + b.Property("OrderStatus") + .HasColumnType("integer"); + + b.Property("PackingPrice") + .HasColumnType("double precision"); + + b.Property("PayedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("PaymentMethod") + .HasColumnType("integer"); + + b.Property("PreparingMinute") + .HasColumnType("integer"); + + b.Property("ProductDiscountPrice") + .HasColumnType("double precision"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ServicePrice") + .HasColumnType("double precision"); + + b.Property("TaxesPrice") + .HasColumnType("double precision"); + + b.Property("TotalPrice") + .HasColumnType("double precision"); + + b.Property("TotalProductsPrice") + .HasColumnType("double precision"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("DiscountId"); + + b.ToTable("Orders", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.OrderDelivery", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddressId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("DeliveryCost") + .HasColumnType("double precision"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("OrderId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ShippingId") + .HasColumnType("uuid"); + + b.Property("TrackingCode") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AddressId"); + + b.HasIndex("OrderId") + .IsUnique(); + + b.HasIndex("ShippingId"); + + b.ToTable("OrderDeliveries", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.OrderProduct", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Count") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("HasDiscount") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("OrderId") + .HasColumnType("uuid"); + + b.Property("OrderProductStatus") + .HasColumnType("integer"); + + b.Property("PackingCost") + .HasColumnType("double precision"); + + b.Property("PackingFee") + .HasColumnType("double precision"); + + b.Property("ProductCategoryId") + .HasColumnType("uuid"); + + b.Property("ProductCost") + .HasColumnType("double precision"); + + b.Property("ProductFee") + .HasColumnType("double precision"); + + b.Property("ProductFeeWithDiscount") + .HasColumnType("double precision"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("ProductId"); + + b.ToTable("OrderProducts", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsMain") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("ProductCategories", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("BeDisplayed") + .HasColumnType("boolean"); + + b.Property("BrandId") + .HasColumnType("uuid"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.Property("Cost") + .HasColumnType("double precision"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(13) + .HasColumnType("character varying(13)"); + + b.Property("EnglishName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExpertCheck") + .IsRequired() + .HasColumnType("text"); + + b.Property("HasExpressDelivery") + .HasColumnType("boolean"); + + b.Property("IsEnable") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("IsSubProduct") + .HasColumnType("boolean"); + + b.Property("MaxOrderCount") + .HasColumnType("integer"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("PackingCost") + .HasColumnType("double precision"); + + b.Property("PersianName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Rate") + .HasColumnType("real"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReviewCount") + .HasColumnType("integer"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.Property("Stock") + .HasColumnType("integer"); + + b.Property("Summery") + .IsRequired() + .HasColumnType("text"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text"); + + b.Property("Viewed") + .HasColumnType("integer"); + + b.Property("Warranty") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("BrandId"); + + b.HasIndex("CategoryId"); + + b.ToTable("Products", "public"); + + b.HasDiscriminator().HasValue("Product"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.Specification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Detail") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsFeature") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("ProductId"); + + b.ToTable("Specifications", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Seo.MetaTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(34) + .HasColumnType("character varying(34)"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("MetaTags", "public"); + + b.HasDiscriminator().HasValue("MetaTag"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Netina.Domain.Entities.StorageFiles.StorageFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(34) + .HasColumnType("character varying(34)"); + + b.Property("FileLocation") + .IsRequired() + .HasColumnType("text"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("text"); + + b.Property("FileType") + .HasColumnType("integer"); + + b.Property("IsHeader") + .HasColumnType("boolean"); + + b.Property("IsPrimary") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("StorageFiles", "public"); + + b.HasDiscriminator().HasValue("StorageFile"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EnglishName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PersianName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("Roles", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.ApplicationUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("BirthDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Gender") + .HasColumnType("integer"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NationalId") + .IsRequired() + .HasColumnType("text"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("SignUpStatus") + .HasColumnType("integer"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("Users", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Customers", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Manager", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("LatestVersionUsed") + .HasColumnType("double precision"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Managers", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Marketer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("FatherName") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("LastSettlement") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Shaba") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Marketers", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.NewsletterMember", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("NewsletterMembers", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.UserAddress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Address") + .IsRequired() + .HasColumnType("text"); + + b.Property("BuildingUnit") + .IsRequired() + .HasColumnType("text"); + + b.Property("City") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("LocationLat") + .HasColumnType("real"); + + b.Property("LocationLong") + .HasColumnType("real"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Plaque") + .IsRequired() + .HasColumnType("text"); + + b.Property("PostalCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Province") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReceiverFullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReceiverPhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserAddresses", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.UserFavoriteProduct", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("UserId"); + + b.ToTable("UserFavoriteProducts", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Warehouses.Shipping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("DeliveryCost") + .HasColumnType("double precision"); + + b.Property("IsExpressShipping") + .HasColumnType("boolean"); + + b.Property("IsOriginalWarehouse") + .HasColumnType("boolean"); + + b.Property("IsRemoved") + .HasColumnType("boolean"); + + b.Property("IsShipBySeller") + .HasColumnType("boolean"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ModifiedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("RemovedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RemovedBy") + .IsRequired() + .HasColumnType("text"); + + b.Property("WarehouseName") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorkingDays") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("Shippings", "public"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogComment", b => + { + b.HasBaseType("Netina.Domain.Entities.Comments.Comment"); + + b.Property("BlogId") + .HasColumnType("uuid"); + + b.HasIndex("BlogId"); + + b.HasDiscriminator().HasValue("BlogComment"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.ProductComment", b => + { + b.HasBaseType("Netina.Domain.Entities.Comments.Comment"); + + b.Property("IsBuyer") + .HasColumnType("boolean"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.HasIndex("ProductId"); + + b.HasDiscriminator().HasValue("ProductComment"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.CategoryDiscount", b => + { + b.HasBaseType("Netina.Domain.Entities.Discounts.Discount"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.HasIndex("CategoryId"); + + b.HasDiscriminator().HasValue("CategoryDiscount"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.ProductDiscount", b => + { + b.HasBaseType("Netina.Domain.Entities.Discounts.Discount"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.HasIndex("ProductId"); + + b.HasDiscriminator().HasValue("ProductDiscount"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.SubProduct", b => + { + b.HasBaseType("Netina.Domain.Entities.Products.Product"); + + b.Property("Diversity") + .HasColumnType("integer"); + + b.Property("DiversityDescription") + .IsRequired() + .HasColumnType("text"); + + b.Property("DiversityValue") + .IsRequired() + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.HasIndex("ParentId"); + + b.HasDiscriminator().HasValue("SubProduct"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogMetaTag", b => + { + b.HasBaseType("Netina.Domain.Entities.Seo.MetaTag"); + + b.Property("BlogId") + .HasColumnType("uuid"); + + b.HasIndex("BlogId"); + + b.HasDiscriminator().HasValue("BlogMetaTag"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Brands.BrandMetaTag", b => + { + b.HasBaseType("Netina.Domain.Entities.Seo.MetaTag"); + + b.Property("BrandId") + .HasColumnType("uuid"); + + b.HasIndex("BrandId"); + + b.HasDiscriminator().HasValue("BrandMetaTag"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategoryMetaTag", b => + { + b.HasBaseType("Netina.Domain.Entities.Seo.MetaTag"); + + b.Property("ProductCategoryId") + .HasColumnType("uuid"); + + b.HasIndex("ProductCategoryId"); + + b.HasDiscriminator().HasValue("ProductCategoryMetaTag"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.ProductMetaTag", b => + { + b.HasBaseType("Netina.Domain.Entities.Seo.MetaTag"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.HasIndex("ProductId"); + + b.HasDiscriminator().HasValue("ProductMetaTag"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b => + { + b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile"); + + b.Property("BlogId") + .HasColumnType("uuid"); + + b.HasIndex("BlogId"); + + b.HasDiscriminator().HasValue("BlogStorageFile"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Brands.BrandStorageFile", b => + { + b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile"); + + b.Property("BrandId") + .HasColumnType("uuid"); + + b.HasIndex("BrandId"); + + b.HasDiscriminator().HasValue("BrandStorageFile"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategoryStorageFile", b => + { + b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.HasIndex("CategoryId"); + + b.HasDiscriminator().HasValue("ProductCategoryStorageFile"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.ProductStorageFile", b => + { + b.HasBaseType("Netina.Domain.Entities.StorageFiles.StorageFile"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.HasIndex("ProductId"); + + b.HasDiscriminator().HasValue("ProductStorageFile"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Accounting.Payment", b => + { + b.HasOne("Netina.Domain.Entities.Users.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Orders.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Customer"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.Blog", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "Author") + .WithMany() + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Blogs.BlogCategory", "Category") + .WithMany("Blogs") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Author"); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogCategory", b => + { + b.HasOne("Netina.Domain.Entities.Blogs.BlogCategory", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Comments.Comment", b => + { + b.HasOne("Netina.Domain.Entities.Comments.Comment", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId"); + + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.Discount", b => + { + b.HasOne("Netina.Domain.Entities.Users.Marketer", "Marketer") + .WithOne("Discount") + .HasForeignKey("Netina.Domain.Entities.Discounts.Discount", "MarketerId"); + + b.Navigation("Marketer"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.Order", b => + { + b.HasOne("Netina.Domain.Entities.Users.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Discounts.Discount", null) + .WithMany("Orders") + .HasForeignKey("DiscountId"); + + b.Navigation("Customer"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.OrderDelivery", b => + { + b.HasOne("Netina.Domain.Entities.Users.UserAddress", "Address") + .WithMany() + .HasForeignKey("AddressId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Orders.Order", "Order") + .WithOne("OrderDelivery") + .HasForeignKey("Netina.Domain.Entities.Orders.OrderDelivery", "OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Warehouses.Shipping", "Shipping") + .WithMany() + .HasForeignKey("ShippingId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Address"); + + b.Navigation("Order"); + + b.Navigation("Shipping"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.OrderProduct", b => + { + b.HasOne("Netina.Domain.Entities.Orders.Order", "Order") + .WithMany("OrderProducts") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany("OrderProducts") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Order"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategory", b => + { + b.HasOne("Netina.Domain.Entities.ProductCategories.ProductCategory", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.Product", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "Author") + .WithMany() + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Brands.Brand", "Brand") + .WithMany("Products") + .HasForeignKey("BrandId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.ProductCategories.ProductCategory", "Category") + .WithMany("Products") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Author"); + + b.Navigation("Brand"); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.Specification", b => + { + b.HasOne("Netina.Domain.Entities.Products.Specification", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId"); + + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany("Specifications") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Customer", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "User") + .WithOne("Customer") + .HasForeignKey("Netina.Domain.Entities.Users.Customer", "UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Manager", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "User") + .WithOne("Manager") + .HasForeignKey("Netina.Domain.Entities.Users.Manager", "UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Marketer", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "User") + .WithOne("Marketer") + .HasForeignKey("Netina.Domain.Entities.Users.Marketer", "UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.UserAddress", b => + { + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "User") + .WithMany("Addresses") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.UserFavoriteProduct", b => + { + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Netina.Domain.Entities.Users.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Product"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogComment", b => + { + b.HasOne("Netina.Domain.Entities.Blogs.Blog", "Blog") + .WithMany() + .HasForeignKey("BlogId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Blog"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.ProductComment", b => + { + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany("Comments") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.CategoryDiscount", b => + { + b.HasOne("Netina.Domain.Entities.ProductCategories.ProductCategory", "Category") + .WithMany() + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.ProductDiscount", b => + { + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.SubProduct", b => + { + b.HasOne("Netina.Domain.Entities.Products.Product", "Parent") + .WithMany("SubProducts") + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogMetaTag", b => + { + b.HasOne("Netina.Domain.Entities.Blogs.Blog", "Brand") + .WithMany("MetaTags") + .HasForeignKey("BlogId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Brand"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Brands.BrandMetaTag", b => + { + b.HasOne("Netina.Domain.Entities.Brands.Brand", "Brand") + .WithMany("MetaTags") + .HasForeignKey("BrandId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Brand"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategoryMetaTag", b => + { + b.HasOne("Netina.Domain.Entities.ProductCategories.ProductCategory", "ProductCategory") + .WithMany("MetaTags") + .HasForeignKey("ProductCategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("ProductCategory"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.ProductMetaTag", b => + { + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany("MetaTags") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogStorageFile", b => + { + b.HasOne("Netina.Domain.Entities.Blogs.Blog", "Blog") + .WithMany("Files") + .HasForeignKey("BlogId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Blog"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Brands.BrandStorageFile", b => + { + b.HasOne("Netina.Domain.Entities.Brands.Brand", "Brand") + .WithMany("Files") + .HasForeignKey("BrandId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Brand"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategoryStorageFile", b => + { + b.HasOne("Netina.Domain.Entities.ProductCategories.ProductCategory", "Category") + .WithMany("Files") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.ProductStorageFile", b => + { + b.HasOne("Netina.Domain.Entities.Products.Product", "Product") + .WithMany("Files") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.Blog", b => + { + b.Navigation("Files"); + + b.Navigation("MetaTags"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogCategory", b => + { + b.Navigation("Blogs"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Brands.Brand", b => + { + b.Navigation("Files"); + + b.Navigation("MetaTags"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Comments.Comment", b => + { + b.Navigation("Children"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Discounts.Discount", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Orders.Order", b => + { + b.Navigation("OrderDelivery"); + + b.Navigation("OrderProducts"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.ProductCategories.ProductCategory", b => + { + b.Navigation("Files"); + + b.Navigation("MetaTags"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.Product", b => + { + b.Navigation("Comments"); + + b.Navigation("Files"); + + b.Navigation("MetaTags"); + + b.Navigation("OrderProducts"); + + b.Navigation("Specifications"); + + b.Navigation("SubProducts"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Products.Specification", b => + { + b.Navigation("Children"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.ApplicationUser", b => + { + b.Navigation("Addresses"); + + b.Navigation("Customer"); + + b.Navigation("Manager"); + + b.Navigation("Marketer"); + }); + + modelBuilder.Entity("Netina.Domain.Entities.Users.Marketer", b => + { + b.Navigation("Discount"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Netina.Repository/Migrations/20241217212716_AddSubProduct.cs b/Netina.Repository/Migrations/20241217212716_AddSubProduct.cs new file mode 100644 index 0000000..f764258 --- /dev/null +++ b/Netina.Repository/Migrations/20241217212716_AddSubProduct.cs @@ -0,0 +1,119 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace NetinaShop.Repository.Migrations +{ + /// + public partial class AddSubProduct : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Discriminator", + schema: "public", + table: "Products", + type: "character varying(13)", + maxLength: 13, + nullable: false, + defaultValue: "Product"); + + migrationBuilder.AddColumn( + name: "Diversity", + schema: "public", + table: "Products", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn( + name: "DiversityDescription", + schema: "public", + table: "Products", + type: "text", + nullable: true); + + migrationBuilder.AddColumn( + name: "DiversityValue", + schema: "public", + table: "Products", + type: "text", + nullable: true); + + migrationBuilder.AddColumn( + name: "IsSubProduct", + schema: "public", + table: "Products", + type: "boolean", + nullable: false, + defaultValue: true); + + migrationBuilder.AddColumn( + name: "ParentId", + schema: "public", + table: "Products", + type: "uuid", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Products_ParentId", + schema: "public", + table: "Products", + column: "ParentId"); + + migrationBuilder.AddForeignKey( + name: "FK_Products_Products_ParentId", + schema: "public", + table: "Products", + column: "ParentId", + principalSchema: "public", + principalTable: "Products", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Products_Products_ParentId", + schema: "public", + table: "Products"); + + migrationBuilder.DropIndex( + name: "IX_Products_ParentId", + schema: "public", + table: "Products"); + + migrationBuilder.DropColumn( + name: "Discriminator", + schema: "public", + table: "Products"); + + migrationBuilder.DropColumn( + name: "Diversity", + schema: "public", + table: "Products"); + + migrationBuilder.DropColumn( + name: "DiversityDescription", + schema: "public", + table: "Products"); + + migrationBuilder.DropColumn( + name: "DiversityValue", + schema: "public", + table: "Products"); + + migrationBuilder.DropColumn( + name: "IsSubProduct", + schema: "public", + table: "Products"); + + migrationBuilder.DropColumn( + name: "ParentId", + schema: "public", + table: "Products"); + } + } +} diff --git a/Netina.Repository/Migrations/ApplicationContextModelSnapshot.cs b/Netina.Repository/Migrations/ApplicationContextModelSnapshot.cs index 6e87413..dcbdab5 100644 --- a/Netina.Repository/Migrations/ApplicationContextModelSnapshot.cs +++ b/Netina.Repository/Migrations/ApplicationContextModelSnapshot.cs @@ -892,6 +892,11 @@ namespace NetinaShop.Repository.Migrations .IsRequired() .HasColumnType("text"); + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(13) + .HasColumnType("character varying(13)"); + b.Property("EnglishName") .IsRequired() .HasColumnType("text"); @@ -909,6 +914,9 @@ namespace NetinaShop.Repository.Migrations b.Property("IsRemoved") .HasColumnType("boolean"); + b.Property("IsSubProduct") + .HasColumnType("boolean"); + b.Property("MaxOrderCount") .HasColumnType("integer"); @@ -970,6 +978,10 @@ namespace NetinaShop.Repository.Migrations b.HasIndex("CategoryId"); b.ToTable("Products", "public"); + + b.HasDiscriminator().HasValue("Product"); + + b.UseTphMappingStrategy(); }); modelBuilder.Entity("Netina.Domain.Entities.Products.Specification", b => @@ -1686,6 +1698,29 @@ namespace NetinaShop.Repository.Migrations b.HasDiscriminator().HasValue("ProductDiscount"); }); + modelBuilder.Entity("Netina.Domain.Entities.Products.SubProduct", b => + { + b.HasBaseType("Netina.Domain.Entities.Products.Product"); + + b.Property("Diversity") + .HasColumnType("integer"); + + b.Property("DiversityDescription") + .IsRequired() + .HasColumnType("text"); + + b.Property("DiversityValue") + .IsRequired() + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.HasIndex("ParentId"); + + b.HasDiscriminator().HasValue("SubProduct"); + }); + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogMetaTag", b => { b.HasBaseType("Netina.Domain.Entities.Seo.MetaTag"); @@ -2096,6 +2131,15 @@ namespace NetinaShop.Repository.Migrations b.Navigation("Product"); }); + modelBuilder.Entity("Netina.Domain.Entities.Products.SubProduct", b => + { + b.HasOne("Netina.Domain.Entities.Products.Product", "Parent") + .WithMany("SubProducts") + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + modelBuilder.Entity("Netina.Domain.Entities.Blogs.BlogMetaTag", b => { b.HasOne("Netina.Domain.Entities.Blogs.Blog", "Brand") @@ -2236,6 +2280,8 @@ namespace NetinaShop.Repository.Migrations b.Navigation("OrderProducts"); b.Navigation("Specifications"); + + b.Navigation("SubProducts"); }); modelBuilder.Entity("Netina.Domain.Entities.Products.Specification", b =>