Rebadge the rest of the files
This commit is contained in:
139
Imprink.sln
Normal file
139
Imprink.sln
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Imprink.WebApi", "src\Imprink.WebApi\Imprink.WebApi.csproj", "{659FA9DF-3AAF-42B0-9613-1EB79BB84053}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{06B9A385-FCDC-4052-B0AC-2B20316CC67F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Imprink.Domain", "src\Imprink.Domain\Imprink.Domain.csproj", "{45A42670-C3A2-4B21-B3C8-1AD71EE41348}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Imprink.Infrastructure", "src\Imprink.Infrastructure\Imprink.Infrastructure.csproj", "{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Imprink.Application", "src\Imprink.Application\Imprink.Application.csproj", "{379021C7-7B82-4643-A1D6-B789CEDE9BDE}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Imprink.Application.Tests", "tests\Imprink.Application.Tests\Imprink.Application.Tests.csproj", "{E858950C-69E0-426B-A679-CD1B944C2F8F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Imprink.Domain.Tests", "tests\Imprink.Domain.Tests\Imprink.Domain.Tests.csproj", "{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Imprink.Infrastructure.Tests", "tests\Imprink.Infrastructure.Tests\Imprink.Infrastructure.Tests.csproj", "{E683C824-15F9-4FD3-9947-3756E48934A4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Imprink.WebApi.Tests", "tests\Imprink.WebApi.Tests\Imprink.WebApi.Tests.csproj", "{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{659FA9DF-3AAF-42B0-9613-1EB79BB84053}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{659FA9DF-3AAF-42B0-9613-1EB79BB84053}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{659FA9DF-3AAF-42B0-9613-1EB79BB84053}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{659FA9DF-3AAF-42B0-9613-1EB79BB84053}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{659FA9DF-3AAF-42B0-9613-1EB79BB84053}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{659FA9DF-3AAF-42B0-9613-1EB79BB84053}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{659FA9DF-3AAF-42B0-9613-1EB79BB84053}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{659FA9DF-3AAF-42B0-9613-1EB79BB84053}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{659FA9DF-3AAF-42B0-9613-1EB79BB84053}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{659FA9DF-3AAF-42B0-9613-1EB79BB84053}.Release|x64.Build.0 = Release|Any CPU
|
||||
{659FA9DF-3AAF-42B0-9613-1EB79BB84053}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{659FA9DF-3AAF-42B0-9613-1EB79BB84053}.Release|x86.Build.0 = Release|Any CPU
|
||||
{45A42670-C3A2-4B21-B3C8-1AD71EE41348}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{45A42670-C3A2-4B21-B3C8-1AD71EE41348}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{45A42670-C3A2-4B21-B3C8-1AD71EE41348}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{45A42670-C3A2-4B21-B3C8-1AD71EE41348}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{45A42670-C3A2-4B21-B3C8-1AD71EE41348}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{45A42670-C3A2-4B21-B3C8-1AD71EE41348}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{45A42670-C3A2-4B21-B3C8-1AD71EE41348}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{45A42670-C3A2-4B21-B3C8-1AD71EE41348}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{45A42670-C3A2-4B21-B3C8-1AD71EE41348}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{45A42670-C3A2-4B21-B3C8-1AD71EE41348}.Release|x64.Build.0 = Release|Any CPU
|
||||
{45A42670-C3A2-4B21-B3C8-1AD71EE41348}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{45A42670-C3A2-4B21-B3C8-1AD71EE41348}.Release|x86.Build.0 = Release|Any CPU
|
||||
{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}.Release|x64.Build.0 = Release|Any CPU
|
||||
{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5566AAE7-444D-41F8-BC6D-59C341EBF6F3}.Release|x86.Build.0 = Release|Any CPU
|
||||
{379021C7-7B82-4643-A1D6-B789CEDE9BDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{379021C7-7B82-4643-A1D6-B789CEDE9BDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{379021C7-7B82-4643-A1D6-B789CEDE9BDE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{379021C7-7B82-4643-A1D6-B789CEDE9BDE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{379021C7-7B82-4643-A1D6-B789CEDE9BDE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{379021C7-7B82-4643-A1D6-B789CEDE9BDE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{379021C7-7B82-4643-A1D6-B789CEDE9BDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{379021C7-7B82-4643-A1D6-B789CEDE9BDE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{379021C7-7B82-4643-A1D6-B789CEDE9BDE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{379021C7-7B82-4643-A1D6-B789CEDE9BDE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{379021C7-7B82-4643-A1D6-B789CEDE9BDE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{379021C7-7B82-4643-A1D6-B789CEDE9BDE}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{E858950C-69E0-426B-A679-CD1B944C2F8F} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{8CB5B0C8-ED1B-486F-9A02-ED507F533D0E} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{E683C824-15F9-4FD3-9947-3756E48934A4} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{0EF1EBCE-22E2-4511-B845-EA3EC792DFE3} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
15
src/Imprink.Application/IUnitOfWork.cs
Normal file
15
src/Imprink.Application/IUnitOfWork.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Imprink.Domain.Repositories;
|
||||
|
||||
namespace Imprink.Application;
|
||||
|
||||
public interface IUnitOfWork
|
||||
{
|
||||
public IProductRepository ProductRepository { get; }
|
||||
public ICategoryRepository CategoryRepository { get; }
|
||||
public IProductVariantRepository ProductVariantRepository { get; }
|
||||
|
||||
Task SaveAsync(CancellationToken cancellationToken = default);
|
||||
Task BeginTransactionAsync(CancellationToken cancellationToken = default);
|
||||
Task CommitTransactionAsync(CancellationToken cancellationToken = default);
|
||||
Task RollbackTransactionAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
20
src/Imprink.Application/Imprink.Application.csproj
Normal file
20
src/Imprink.Application/Imprink.Application.csproj
Normal file
@@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||
<PackageReference Include="FluentValidation" Version="12.0.0-preview1" />
|
||||
<PackageReference Include="MediatR" Version="12.5.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Imprink.Domain\Imprink.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,14 @@
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Commands;
|
||||
|
||||
public class CreateCategoryCommand : IRequest<CategoryDto>
|
||||
{
|
||||
public string Name { get; set; } = null!;
|
||||
public string Description { get; set; } = null!;
|
||||
public string? ImageUrl { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
public Guid? ParentCategoryId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Commands;
|
||||
|
||||
public class CreateProductCommand : IRequest<ProductDto>
|
||||
{
|
||||
public string Name { get; set; } = null!;
|
||||
public string? Description { get; set; }
|
||||
public decimal BasePrice { get; set; }
|
||||
public bool IsCustomizable { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
public string? ImageUrl { get; set; }
|
||||
public Guid? CategoryId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Commands;
|
||||
|
||||
public class CreateProductVariantCommand : IRequest<ProductVariantDto>
|
||||
{
|
||||
public Guid ProductId { get; set; }
|
||||
public string Size { get; set; } = null!;
|
||||
public string? Color { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public string? ImageUrl { get; set; }
|
||||
public string Sku { get; set; } = null!;
|
||||
public int StockQuantity { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Commands;
|
||||
|
||||
public class DeleteCategoryCommand : IRequest<bool>
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Commands;
|
||||
|
||||
public class DeleteProductCommand : IRequest<bool>
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Commands;
|
||||
|
||||
public class DeleteProductVariantCommand : IRequest<bool>
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
14
src/Imprink.Application/Products/Dtos/CategoryDto.cs
Normal file
14
src/Imprink.Application/Products/Dtos/CategoryDto.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Imprink.Application.Products.Dtos;
|
||||
|
||||
public class CategoryDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Name { get; set; } = null!;
|
||||
public string Description { get; set; } = null!;
|
||||
public string? ImageUrl { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public Guid? ParentCategoryId { get; set; }
|
||||
public DateTime? CreatedAt { get; set; }
|
||||
public DateTime? ModifiedAt { get; set; }
|
||||
}
|
||||
12
src/Imprink.Application/Products/Dtos/PagedResultDto.cs
Normal file
12
src/Imprink.Application/Products/Dtos/PagedResultDto.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Imprink.Application.Products.Dtos;
|
||||
|
||||
public class PagedResultDto<T>
|
||||
{
|
||||
public IEnumerable<T> Items { get; set; } = new List<T>();
|
||||
public int TotalCount { get; set; }
|
||||
public int PageNumber { get; set; }
|
||||
public int PageSize { get; set; }
|
||||
public int TotalPages => (int)Math.Ceiling((double)TotalCount / PageSize);
|
||||
public bool HasPreviousPage => PageNumber > 1;
|
||||
public bool HasNextPage => PageNumber < TotalPages;
|
||||
}
|
||||
16
src/Imprink.Application/Products/Dtos/ProductDto.cs
Normal file
16
src/Imprink.Application/Products/Dtos/ProductDto.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Imprink.Application.Products.Dtos;
|
||||
|
||||
public class ProductDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Name { get; set; } = null!;
|
||||
public string? Description { get; set; }
|
||||
public decimal BasePrice { get; set; }
|
||||
public bool IsCustomizable { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public string? ImageUrl { get; set; }
|
||||
public Guid? CategoryId { get; set; }
|
||||
public CategoryDto? Category { get; set; }
|
||||
public DateTime? CreatedAt { get; set; }
|
||||
public DateTime? ModifiedAt { get; set; }
|
||||
}
|
||||
17
src/Imprink.Application/Products/Dtos/ProductVariantDto.cs
Normal file
17
src/Imprink.Application/Products/Dtos/ProductVariantDto.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Imprink.Application.Products.Dtos;
|
||||
|
||||
public class ProductVariantDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid ProductId { get; set; }
|
||||
public string Size { get; set; } = null!;
|
||||
public string? Color { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public string? ImageUrl { get; set; }
|
||||
public string Sku { get; set; } = null!;
|
||||
public int StockQuantity { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public ProductDto? Product { get; set; }
|
||||
public DateTime? CreatedAt { get; set; }
|
||||
public DateTime? ModifiedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using Imprink.Application.Products.Commands;
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using Imprink.Domain.Entities.Product;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Handlers;
|
||||
|
||||
public class CreateCategoryHandler(IUnitOfWork unitOfWork) : IRequestHandler<CreateCategoryCommand, CategoryDto>
|
||||
{
|
||||
public async Task<CategoryDto> Handle(CreateCategoryCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await unitOfWork.BeginTransactionAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
var category = new Category
|
||||
{
|
||||
Name = request.Name,
|
||||
Description = request.Description,
|
||||
ImageUrl = request.ImageUrl,
|
||||
SortOrder = request.SortOrder,
|
||||
IsActive = request.IsActive,
|
||||
ParentCategoryId = request.ParentCategoryId
|
||||
};
|
||||
|
||||
var createdCategory = await unitOfWork.CategoryRepository.AddAsync(category, cancellationToken);
|
||||
await unitOfWork.CommitTransactionAsync(cancellationToken);
|
||||
|
||||
return new CategoryDto
|
||||
{
|
||||
Id = createdCategory.Id,
|
||||
Name = createdCategory.Name,
|
||||
Description = createdCategory.Description,
|
||||
ImageUrl = createdCategory.ImageUrl,
|
||||
SortOrder = createdCategory.SortOrder,
|
||||
IsActive = createdCategory.IsActive,
|
||||
ParentCategoryId = createdCategory.ParentCategoryId,
|
||||
CreatedAt = createdCategory.CreatedAt,
|
||||
ModifiedAt = createdCategory.ModifiedAt
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync(cancellationToken);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using Imprink.Application.Products.Commands;
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using Imprink.Domain.Entities.Product;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Handlers;
|
||||
|
||||
public class CreateProductHandler(IUnitOfWork unitOfWork) : IRequestHandler<CreateProductCommand, ProductDto>
|
||||
{
|
||||
public async Task<ProductDto> Handle(CreateProductCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await unitOfWork.BeginTransactionAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
var product = new Product
|
||||
{
|
||||
Name = request.Name,
|
||||
Description = request.Description,
|
||||
BasePrice = request.BasePrice,
|
||||
IsCustomizable = request.IsCustomizable,
|
||||
IsActive = request.IsActive,
|
||||
ImageUrl = request.ImageUrl,
|
||||
CategoryId = request.CategoryId,
|
||||
Category = null!
|
||||
};
|
||||
|
||||
var createdProduct = await unitOfWork.ProductRepository.AddAsync(product, cancellationToken);
|
||||
|
||||
var categoryDto = new CategoryDto
|
||||
{
|
||||
Id = createdProduct.Category.Id,
|
||||
Name = createdProduct.Category.Name,
|
||||
Description = createdProduct.Category.Description,
|
||||
ImageUrl = createdProduct.Category.ImageUrl,
|
||||
SortOrder = createdProduct.Category.SortOrder,
|
||||
IsActive = createdProduct.Category.IsActive,
|
||||
ParentCategoryId = createdProduct.Category.ParentCategoryId,
|
||||
CreatedAt = createdProduct.Category.CreatedAt,
|
||||
ModifiedAt = createdProduct.Category.ModifiedAt
|
||||
};
|
||||
|
||||
await unitOfWork.CommitTransactionAsync(cancellationToken);
|
||||
|
||||
return new ProductDto
|
||||
{
|
||||
Id = createdProduct.Id,
|
||||
Name = createdProduct.Name,
|
||||
Description = createdProduct.Description,
|
||||
BasePrice = createdProduct.BasePrice,
|
||||
IsCustomizable = createdProduct.IsCustomizable,
|
||||
IsActive = createdProduct.IsActive,
|
||||
ImageUrl = createdProduct.ImageUrl,
|
||||
CategoryId = createdProduct.CategoryId,
|
||||
Category = categoryDto,
|
||||
CreatedAt = createdProduct.CreatedAt,
|
||||
ModifiedAt = createdProduct.ModifiedAt
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync(cancellationToken);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Imprink.Application.Products.Commands;
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using Imprink.Domain.Entities.Product;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Handlers;
|
||||
|
||||
public class CreateProductVariantHandler(IUnitOfWork unitOfWork)
|
||||
: IRequestHandler<CreateProductVariantCommand, ProductVariantDto>
|
||||
{
|
||||
public async Task<ProductVariantDto> Handle(CreateProductVariantCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await unitOfWork.BeginTransactionAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
var productVariant = new ProductVariant
|
||||
{
|
||||
ProductId = request.ProductId,
|
||||
Size = request.Size,
|
||||
Color = request.Color,
|
||||
Price = request.Price,
|
||||
ImageUrl = request.ImageUrl,
|
||||
Sku = request.Sku,
|
||||
StockQuantity = request.StockQuantity,
|
||||
IsActive = request.IsActive,
|
||||
Product = null!
|
||||
};
|
||||
|
||||
var createdVariant = await unitOfWork.ProductVariantRepository.AddAsync(productVariant, cancellationToken);
|
||||
await unitOfWork.CommitTransactionAsync(cancellationToken);
|
||||
|
||||
return new ProductVariantDto
|
||||
{
|
||||
Id = createdVariant.Id,
|
||||
ProductId = createdVariant.ProductId,
|
||||
Size = createdVariant.Size,
|
||||
Color = createdVariant.Color,
|
||||
Price = createdVariant.Price,
|
||||
ImageUrl = createdVariant.ImageUrl,
|
||||
Sku = createdVariant.Sku,
|
||||
StockQuantity = createdVariant.StockQuantity,
|
||||
IsActive = createdVariant.IsActive,
|
||||
CreatedAt = createdVariant.CreatedAt,
|
||||
ModifiedAt = createdVariant.ModifiedAt
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync(cancellationToken);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Imprink.Application.Products.Commands;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Handlers;
|
||||
|
||||
public class DeleteCategoryHandler(IUnitOfWork unitOfWork) : IRequestHandler<DeleteCategoryCommand, bool>
|
||||
{
|
||||
public async Task<bool> Handle(DeleteCategoryCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await unitOfWork.BeginTransactionAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
var exists = await unitOfWork.CategoryRepository.ExistsAsync(request.Id, cancellationToken);
|
||||
if (!exists)
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
await unitOfWork.CategoryRepository.DeleteAsync(request.Id, cancellationToken);
|
||||
await unitOfWork.CommitTransactionAsync(cancellationToken);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync(cancellationToken);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Imprink.Application.Products.Commands;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Handlers;
|
||||
|
||||
public class DeleteProductHandler(IUnitOfWork unitOfWork) : IRequestHandler<DeleteProductCommand, bool>
|
||||
{
|
||||
public async Task<bool> Handle(DeleteProductCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await unitOfWork.BeginTransactionAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
var exists = await unitOfWork.ProductRepository.ExistsAsync(request.Id, cancellationToken);
|
||||
if (!exists)
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
await unitOfWork.ProductRepository.DeleteAsync(request.Id, cancellationToken);
|
||||
await unitOfWork.CommitTransactionAsync(cancellationToken);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync(cancellationToken);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Imprink.Application.Products.Commands;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Handlers;
|
||||
|
||||
public class DeleteProductVariantHandler(IUnitOfWork unitOfWork) : IRequestHandler<DeleteProductVariantCommand, bool>
|
||||
{
|
||||
public async Task<bool> Handle(DeleteProductVariantCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await unitOfWork.BeginTransactionAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
var exists = await unitOfWork.ProductVariantRepository.ExistsAsync(request.Id, cancellationToken);
|
||||
if (!exists)
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
await unitOfWork.ProductVariantRepository.DeleteAsync(request.Id, cancellationToken);
|
||||
await unitOfWork.CommitTransactionAsync(cancellationToken);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await unitOfWork.RollbackTransactionAsync(cancellationToken);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using Imprink.Application.Products.Queries;
|
||||
using Imprink.Domain.Entities.Product;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Handlers;
|
||||
|
||||
public class GetCategoriesHandler(IUnitOfWork unitOfWork)
|
||||
: IRequestHandler<GetCategoriesQuery, IEnumerable<CategoryDto>>
|
||||
{
|
||||
public async Task<IEnumerable<CategoryDto>> Handle(GetCategoriesQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
IEnumerable<Category> categories;
|
||||
|
||||
if (request.RootCategoriesOnly)
|
||||
{
|
||||
categories = await unitOfWork.CategoryRepository.GetRootCategoriesAsync(cancellationToken);
|
||||
}
|
||||
else if (request.IsActive.HasValue && request.IsActive.Value)
|
||||
{
|
||||
categories = await unitOfWork.CategoryRepository.GetActiveAsync(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
categories = await unitOfWork.CategoryRepository.GetAllAsync(cancellationToken);
|
||||
}
|
||||
|
||||
return categories.Select(c => new CategoryDto
|
||||
{
|
||||
Id = c.Id,
|
||||
Name = c.Name,
|
||||
Description = c.Description,
|
||||
ImageUrl = c.ImageUrl,
|
||||
SortOrder = c.SortOrder,
|
||||
IsActive = c.IsActive,
|
||||
ParentCategoryId = c.ParentCategoryId,
|
||||
CreatedAt = c.CreatedAt,
|
||||
ModifiedAt = c.ModifiedAt
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using Imprink.Application.Products.Queries;
|
||||
using Imprink.Domain.Entities.Product;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Handlers;
|
||||
|
||||
public class GetProductVariantsHandler(IUnitOfWork unitOfWork)
|
||||
: IRequestHandler<GetProductVariantsQuery, IEnumerable<ProductVariantDto>>
|
||||
{
|
||||
public async Task<IEnumerable<ProductVariantDto>> Handle(GetProductVariantsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
IEnumerable<ProductVariant> variants;
|
||||
|
||||
if (request.ProductId.HasValue)
|
||||
{
|
||||
if (request.InStockOnly)
|
||||
{
|
||||
variants = await unitOfWork.ProductVariantRepository.GetInStockByProductIdAsync(request.ProductId.Value, cancellationToken);
|
||||
}
|
||||
else if (request.IsActive.HasValue && request.IsActive.Value)
|
||||
{
|
||||
variants = await unitOfWork.ProductVariantRepository.GetActiveByProductIdAsync(request.ProductId.Value, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
variants = await unitOfWork.ProductVariantRepository.GetByProductIdAsync(request.ProductId.Value, cancellationToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
variants = new List<ProductVariant>();
|
||||
}
|
||||
|
||||
return variants.Select(pv => new ProductVariantDto
|
||||
{
|
||||
Id = pv.Id,
|
||||
ProductId = pv.ProductId,
|
||||
Size = pv.Size,
|
||||
Color = pv.Color,
|
||||
Price = pv.Price,
|
||||
ImageUrl = pv.ImageUrl,
|
||||
Sku = pv.Sku,
|
||||
StockQuantity = pv.StockQuantity,
|
||||
IsActive = pv.IsActive,
|
||||
Product = new ProductDto
|
||||
{
|
||||
Id = pv.Product.Id,
|
||||
Name = pv.Product.Name,
|
||||
Description = pv.Product.Description,
|
||||
BasePrice = pv.Product.BasePrice,
|
||||
IsCustomizable = pv.Product.IsCustomizable,
|
||||
IsActive = pv.Product.IsActive,
|
||||
ImageUrl = pv.Product.ImageUrl,
|
||||
CategoryId = pv.Product.CategoryId,
|
||||
CreatedAt = pv.Product.CreatedAt,
|
||||
ModifiedAt = pv.Product.ModifiedAt
|
||||
},
|
||||
CreatedAt = pv.CreatedAt,
|
||||
ModifiedAt = pv.ModifiedAt
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using Imprink.Application.Products.Queries;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Handlers;
|
||||
|
||||
public class GetProductsHandler(IUnitOfWork unitOfWork) : IRequestHandler<GetProductsQuery, PagedResultDto<ProductDto>>
|
||||
{
|
||||
public async Task<PagedResultDto<ProductDto>> Handle(GetProductsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var pagedResult = await unitOfWork.ProductRepository.GetPagedAsync(request.FilterParameters, cancellationToken);
|
||||
|
||||
var productDtos = pagedResult.Items.Select(p => new ProductDto
|
||||
{
|
||||
Id = p.Id,
|
||||
Name = p.Name,
|
||||
Description = p.Description,
|
||||
BasePrice = p.BasePrice,
|
||||
IsCustomizable = p.IsCustomizable,
|
||||
IsActive = p.IsActive,
|
||||
ImageUrl = p.ImageUrl,
|
||||
CategoryId = p.CategoryId,
|
||||
Category = new CategoryDto
|
||||
{
|
||||
Id = p.Category.Id,
|
||||
Name = p.Category.Name,
|
||||
Description = p.Category.Description,
|
||||
ImageUrl = p.Category.ImageUrl,
|
||||
SortOrder = p.Category.SortOrder,
|
||||
IsActive = p.Category.IsActive,
|
||||
ParentCategoryId = p.Category.ParentCategoryId,
|
||||
CreatedAt = p.Category.CreatedAt,
|
||||
ModifiedAt = p.Category.ModifiedAt
|
||||
},
|
||||
CreatedAt = p.CreatedAt,
|
||||
ModifiedAt = p.ModifiedAt
|
||||
});
|
||||
|
||||
return new PagedResultDto<ProductDto>
|
||||
{
|
||||
Items = productDtos,
|
||||
TotalCount = pagedResult.TotalCount,
|
||||
PageNumber = pagedResult.PageNumber,
|
||||
PageSize = pagedResult.PageSize
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Queries;
|
||||
|
||||
public class GetCategoriesQuery : IRequest<IEnumerable<CategoryDto>>
|
||||
{
|
||||
public bool? IsActive { get; set; }
|
||||
public bool RootCategoriesOnly { get; set; } = false;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Queries;
|
||||
|
||||
public class GetProductVariantsQuery : IRequest<IEnumerable<ProductVariantDto>>
|
||||
{
|
||||
public Guid? ProductId { get; set; }
|
||||
public bool? IsActive { get; set; }
|
||||
public bool InStockOnly { get; set; } = false;
|
||||
}
|
||||
10
src/Imprink.Application/Products/Queries/GetProductsQuery.cs
Normal file
10
src/Imprink.Application/Products/Queries/GetProductsQuery.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using Imprink.Domain.Common.Models;
|
||||
using MediatR;
|
||||
|
||||
namespace Imprink.Application.Products.Queries;
|
||||
|
||||
public class GetProductsQuery : IRequest<PagedResultDto<ProductDto>>
|
||||
{
|
||||
public ProductFilterParameters FilterParameters { get; set; } = new();
|
||||
}
|
||||
12
src/Imprink.Domain/Common/Models/PagedResult.cs
Normal file
12
src/Imprink.Domain/Common/Models/PagedResult.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Imprink.Domain.Common.Models;
|
||||
|
||||
public class PagedResult<T>
|
||||
{
|
||||
public IEnumerable<T> Items { get; set; } = new List<T>();
|
||||
public int TotalCount { get; set; }
|
||||
public int PageNumber { get; set; }
|
||||
public int PageSize { get; set; }
|
||||
public int TotalPages => (int)Math.Ceiling((double)TotalCount / PageSize);
|
||||
public bool HasPreviousPage => PageNumber > 1;
|
||||
public bool HasNextPage => PageNumber < TotalPages;
|
||||
}
|
||||
15
src/Imprink.Domain/Common/Models/ProductFilterParameters.cs
Normal file
15
src/Imprink.Domain/Common/Models/ProductFilterParameters.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Imprink.Domain.Common.Models;
|
||||
|
||||
public class ProductFilterParameters
|
||||
{
|
||||
public int PageNumber { get; set; } = 1;
|
||||
public int PageSize { get; set; } = 10;
|
||||
public string? SearchTerm { get; set; }
|
||||
public Guid? CategoryId { get; set; }
|
||||
public decimal? MinPrice { get; set; }
|
||||
public decimal? MaxPrice { get; set; }
|
||||
public bool? IsActive { get; set; } = true;
|
||||
public bool? IsCustomizable { get; set; }
|
||||
public string SortBy { get; set; } = "Name";
|
||||
public string SortDirection { get; set; } = "ASC";
|
||||
}
|
||||
10
src/Imprink.Domain/Entities/EntityBase.cs
Normal file
10
src/Imprink.Domain/Entities/EntityBase.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Imprink.Domain.Entities;
|
||||
|
||||
public abstract class EntityBase
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public DateTime? CreatedAt { get; set; }
|
||||
public DateTime? ModifiedAt { get; set; }
|
||||
public string? CreatedBy { get; set; }
|
||||
public string? ModifiedBy { get; set; }
|
||||
}
|
||||
17
src/Imprink.Domain/Entities/Orders/Order.cs
Normal file
17
src/Imprink.Domain/Entities/Orders/Order.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Imprink.Domain.Entities.Orders;
|
||||
|
||||
public class Order : EntityBase
|
||||
{
|
||||
public string UserId { get; set; } = null!;
|
||||
public DateTime OrderDate { get; set; }
|
||||
public decimal TotalPrice { get; set; }
|
||||
public int OrderStatusId { get; set; }
|
||||
public int ShippingStatusId { get; set; }
|
||||
public string OrderNumber { get; set; } = null!;
|
||||
public string Notes { get; set; } = null!;
|
||||
|
||||
public OrderStatus OrderStatus { get; set; } = null!;
|
||||
public ShippingStatus ShippingStatus { get; set; } = null!;
|
||||
public OrderAddress OrderAddress { get; set; } = null!;
|
||||
public virtual ICollection<OrderItem> OrderItems { get; set; } = new List<OrderItem>();
|
||||
}
|
||||
13
src/Imprink.Domain/Entities/Orders/OrderAddress.cs
Normal file
13
src/Imprink.Domain/Entities/Orders/OrderAddress.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Imprink.Domain.Entities.Orders;
|
||||
|
||||
public class OrderAddress : EntityBase
|
||||
{
|
||||
public Guid OrderId { get; set; }
|
||||
public required string Street { get; set; }
|
||||
public required string City { get; set; }
|
||||
public required string State { get; set; }
|
||||
public required string PostalCode { get; set; }
|
||||
public required string Country { get; set; }
|
||||
|
||||
public virtual required Order Order { get; set; }
|
||||
}
|
||||
19
src/Imprink.Domain/Entities/Orders/OrderItem.cs
Normal file
19
src/Imprink.Domain/Entities/Orders/OrderItem.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Imprink.Domain.Entities.Product;
|
||||
|
||||
namespace Imprink.Domain.Entities.Orders;
|
||||
|
||||
public class OrderItem : EntityBase
|
||||
{
|
||||
public Guid OrderId { get; set; }
|
||||
public Guid ProductId { get; set; }
|
||||
public Guid? ProductVariantId { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public decimal UnitPrice { get; set; }
|
||||
public decimal TotalPrice { get; set; }
|
||||
public string CustomizationImageUrl { get; set; } = null!;
|
||||
public string CustomizationDescription { get; set; } = null!;
|
||||
|
||||
public Order Order { get; set; } = null!;
|
||||
public Product.Product Product { get; set; } = null!;
|
||||
public ProductVariant ProductVariant { get; set; } = null!;
|
||||
}
|
||||
9
src/Imprink.Domain/Entities/Orders/OrderStatus.cs
Normal file
9
src/Imprink.Domain/Entities/Orders/OrderStatus.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Imprink.Domain.Entities.Orders;
|
||||
|
||||
public class OrderStatus
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
|
||||
}
|
||||
9
src/Imprink.Domain/Entities/Orders/ShippingStatus.cs
Normal file
9
src/Imprink.Domain/Entities/Orders/ShippingStatus.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Imprink.Domain.Entities.Orders;
|
||||
|
||||
public class ShippingStatus
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
|
||||
}
|
||||
15
src/Imprink.Domain/Entities/Product/Category.cs
Normal file
15
src/Imprink.Domain/Entities/Product/Category.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Imprink.Domain.Entities.Product;
|
||||
|
||||
public class Category : EntityBase
|
||||
{
|
||||
public string Name { get; set; } = null!;
|
||||
public string Description { get; set; } = null!;
|
||||
public string? ImageUrl { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public Guid? ParentCategoryId { get; set; }
|
||||
|
||||
public virtual Category? ParentCategory { get; set; }
|
||||
public virtual ICollection<Category> SubCategories { get; set; } = new List<Category>();
|
||||
public virtual ICollection<Product> Products { get; set; } = new List<Product>();
|
||||
}
|
||||
18
src/Imprink.Domain/Entities/Product/Product.cs
Normal file
18
src/Imprink.Domain/Entities/Product/Product.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Imprink.Domain.Entities.Orders;
|
||||
|
||||
namespace Imprink.Domain.Entities.Product;
|
||||
|
||||
public class Product : EntityBase
|
||||
{
|
||||
public required string Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public required decimal BasePrice { get; set; }
|
||||
public required bool IsCustomizable { get; set; }
|
||||
public required bool IsActive { get; set; }
|
||||
public string? ImageUrl { get; set; }
|
||||
public Guid? CategoryId { get; set; }
|
||||
|
||||
public virtual required Category Category { get; set; }
|
||||
public virtual ICollection<ProductVariant> ProductVariants { get; set; } = new List<ProductVariant>();
|
||||
public virtual ICollection<OrderItem> OrderItems { get; set; } = new List<OrderItem>();
|
||||
}
|
||||
18
src/Imprink.Domain/Entities/Product/ProductVariant.cs
Normal file
18
src/Imprink.Domain/Entities/Product/ProductVariant.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Imprink.Domain.Entities.Orders;
|
||||
|
||||
namespace Imprink.Domain.Entities.Product;
|
||||
|
||||
public class ProductVariant : EntityBase
|
||||
{
|
||||
public required Guid ProductId { get; set; }
|
||||
public required string Size { get; set; }
|
||||
public string? Color { get; set; }
|
||||
public required decimal Price { get; set; }
|
||||
public string? ImageUrl { get; set; }
|
||||
public required string Sku { get; set; }
|
||||
public int StockQuantity { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
public virtual required Imprink.Domain.Entities.Product.Product Product { get; set; }
|
||||
public virtual ICollection<OrderItem> OrderItems { get; set; } = new List<OrderItem>();
|
||||
}
|
||||
14
src/Imprink.Domain/Entities/Users/Address.cs
Normal file
14
src/Imprink.Domain/Entities/Users/Address.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Imprink.Domain.Entities.Users;
|
||||
|
||||
public class Address : EntityBase
|
||||
{
|
||||
public required string UserId { get; set; }
|
||||
public required string AddressType { get; set; }
|
||||
public required string Street { get; set; }
|
||||
public required string City { get; set; }
|
||||
public required string State { get; set; }
|
||||
public required string PostalCode { get; set; }
|
||||
public required string Country { get; set; }
|
||||
public required bool IsDefault { get; set; }
|
||||
public required bool IsActive { get; set; }
|
||||
}
|
||||
16
src/Imprink.Domain/Entities/Users/ApplicationRole.cs
Normal file
16
src/Imprink.Domain/Entities/Users/ApplicationRole.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Imprink.Domain.Entities.Users;
|
||||
|
||||
public class ApplicationRole : IdentityRole
|
||||
{
|
||||
public string Description { get; set; } = null!;
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
public ApplicationRole()
|
||||
{}
|
||||
|
||||
public ApplicationRole(string roleName) : base(roleName)
|
||||
{}
|
||||
}
|
||||
18
src/Imprink.Domain/Entities/Users/ApplicationUser.cs
Normal file
18
src/Imprink.Domain/Entities/Users/ApplicationUser.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Imprink.Domain.Entities.Orders;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Imprink.Domain.Entities.Users;
|
||||
|
||||
public sealed class ApplicationUser : IdentityUser
|
||||
{
|
||||
public required string FirstName { get; set; }
|
||||
public required string LastName { get; set; }
|
||||
public DateTime? DateOfBirth { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime LastLoginAt { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public string? ProfileImageUrl { get; set; }
|
||||
|
||||
public ICollection<Address> Addresses { get; set; } = new List<Address>();
|
||||
public ICollection<Order> Orders { get; set; } = new List<Order>();
|
||||
}
|
||||
18
src/Imprink.Domain/Imprink.Domain.csproj
Normal file
18
src/Imprink.Domain/Imprink.Domain.csproj
Normal file
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Common\Enums\" />
|
||||
<Folder Include="Exceptions\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="9.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
20
src/Imprink.Domain/Repositories/ICategoryRepository.cs
Normal file
20
src/Imprink.Domain/Repositories/ICategoryRepository.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Imprink.Domain.Entities.Product;
|
||||
|
||||
namespace Imprink.Domain.Repositories;
|
||||
|
||||
public interface ICategoryRepository
|
||||
{
|
||||
Task<Category?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<Category?> GetByIdWithSubCategoriesAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<Category?> GetByIdWithProductsAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<IEnumerable<Category>> GetAllAsync(CancellationToken cancellationToken = default);
|
||||
Task<IEnumerable<Category>> GetActiveAsync(CancellationToken cancellationToken = default);
|
||||
Task<IEnumerable<Category>> GetRootCategoriesAsync(CancellationToken cancellationToken = default);
|
||||
Task<IEnumerable<Category>> GetSubCategoriesAsync(Guid parentCategoryId, CancellationToken cancellationToken = default);
|
||||
Task<Category> AddAsync(Category category, CancellationToken cancellationToken = default);
|
||||
Task<Category> UpdateAsync(Category category, CancellationToken cancellationToken = default);
|
||||
Task DeleteAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<bool> HasSubCategoriesAsync(Guid categoryId, CancellationToken cancellationToken = default);
|
||||
Task<bool> HasProductsAsync(Guid categoryId, CancellationToken cancellationToken = default);
|
||||
}
|
||||
19
src/Imprink.Domain/Repositories/IProductRepository.cs
Normal file
19
src/Imprink.Domain/Repositories/IProductRepository.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Imprink.Domain.Common.Models;
|
||||
using Imprink.Domain.Entities.Product;
|
||||
|
||||
namespace Imprink.Domain.Repositories;
|
||||
|
||||
public interface IProductRepository
|
||||
{
|
||||
Task<Product?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<Product?> GetByIdWithVariantsAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<Product?> GetByIdWithCategoryAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<Product?> GetByIdFullAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<PagedResult<Product>> GetPagedAsync(ProductFilterParameters filterParameters, CancellationToken cancellationToken = default);
|
||||
Task<IEnumerable<Product>> GetByCategoryAsync(Guid categoryId, CancellationToken cancellationToken = default);
|
||||
Task<IEnumerable<Product>> GetCustomizableAsync(CancellationToken cancellationToken = default);
|
||||
Task<Product> AddAsync(Product product, CancellationToken cancellationToken = default);
|
||||
Task<Product> UpdateAsync(Product product, CancellationToken cancellationToken = default);
|
||||
Task DeleteAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
}
|
||||
19
src/Imprink.Domain/Repositories/IProductVariantRepository.cs
Normal file
19
src/Imprink.Domain/Repositories/IProductVariantRepository.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Imprink.Domain.Entities.Product;
|
||||
|
||||
namespace Imprink.Domain.Repositories;
|
||||
|
||||
public interface IProductVariantRepository
|
||||
{
|
||||
Task<ProductVariant?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<ProductVariant?> GetByIdWithProductAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<ProductVariant?> GetBySkuAsync(string sku, CancellationToken cancellationToken = default);
|
||||
Task<IEnumerable<ProductVariant>> GetByProductIdAsync(Guid productId, CancellationToken cancellationToken = default);
|
||||
Task<IEnumerable<ProductVariant>> GetActiveByProductIdAsync(Guid productId, CancellationToken cancellationToken = default);
|
||||
Task<IEnumerable<ProductVariant>> GetInStockByProductIdAsync(Guid productId, CancellationToken cancellationToken = default);
|
||||
Task<ProductVariant> AddAsync(ProductVariant productVariant, CancellationToken cancellationToken = default);
|
||||
Task<ProductVariant> UpdateAsync(ProductVariant productVariant, CancellationToken cancellationToken = default);
|
||||
Task DeleteAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<bool> SkuExistsAsync(string sku, Guid? excludeId = null, CancellationToken cancellationToken = default);
|
||||
Task UpdateStockQuantityAsync(Guid id, int quantity, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Imprink.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Imprink.Infrastructure.Configuration;
|
||||
|
||||
public class EntityBaseConfiguration<T> : IEntityTypeConfiguration<T> where T : EntityBase
|
||||
{
|
||||
public virtual void Configure(EntityTypeBuilder<T> builder)
|
||||
{
|
||||
builder.HasKey(e => e.Id);
|
||||
|
||||
builder.Property(e => e.Id)
|
||||
.HasDefaultValueSql("NEWID()");
|
||||
|
||||
builder.Property(e => e.CreatedAt)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(e => e.ModifiedAt)
|
||||
.IsRequired()
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
builder.Property(e => e.CreatedBy)
|
||||
.IsRequired()
|
||||
.HasMaxLength(450);
|
||||
|
||||
builder.Property(e => e.ModifiedBy)
|
||||
.IsRequired()
|
||||
.HasMaxLength(450);
|
||||
|
||||
builder.HasIndex(e => e.CreatedAt)
|
||||
.HasDatabaseName($"IX_{typeof(T).Name}_CreatedAt");
|
||||
|
||||
builder.HasIndex(e => e.ModifiedAt)
|
||||
.HasDatabaseName($"IX_{typeof(T).Name}_ModifiedAt");
|
||||
|
||||
builder.HasIndex(e => e.CreatedBy)
|
||||
.HasDatabaseName($"IX_{typeof(T).Name}_CreatedBy");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Imprink.Domain.Entities.Orders;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Imprink.Infrastructure.Configuration.Orders;
|
||||
|
||||
public class OrderAddressConfiguration : EntityBaseConfiguration<OrderAddress>
|
||||
{
|
||||
public override void Configure(EntityTypeBuilder<OrderAddress> builder)
|
||||
{
|
||||
base.Configure(builder);
|
||||
|
||||
builder.Property(oa => oa.OrderId)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(oa => oa.Street)
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
builder.Property(oa => oa.City)
|
||||
.IsRequired()
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.Property(oa => oa.State)
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.Property(oa => oa.PostalCode)
|
||||
.IsRequired()
|
||||
.HasMaxLength(20);
|
||||
|
||||
builder.Property(oa => oa.Country)
|
||||
.IsRequired()
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.HasIndex(oa => oa.OrderId)
|
||||
.IsUnique()
|
||||
.HasDatabaseName("IX_OrderAddress_OrderId");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using Imprink.Domain.Entities.Orders;
|
||||
using Imprink.Domain.Entities.Users;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Imprink.Infrastructure.Configuration.Orders;
|
||||
|
||||
public class OrderConfiguration : EntityBaseConfiguration<Order>
|
||||
{
|
||||
public override void Configure(EntityTypeBuilder<Order> builder)
|
||||
{
|
||||
base.Configure(builder);
|
||||
|
||||
builder.Property(o => o.UserId)
|
||||
.IsRequired()
|
||||
.HasMaxLength(450);
|
||||
|
||||
builder.Property(o => o.OrderDate)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(o => o.TotalPrice)
|
||||
.IsRequired()
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
builder.Property(o => o.OrderStatusId)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(o => o.ShippingStatusId)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(o => o.OrderNumber)
|
||||
.IsRequired()
|
||||
.HasMaxLength(50);
|
||||
|
||||
builder.Property(o => o.Notes)
|
||||
.HasMaxLength(1000);
|
||||
|
||||
builder.HasOne<ApplicationUser>()
|
||||
.WithMany(u => u.Orders)
|
||||
.HasForeignKey(o => o.UserId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(o => o.OrderStatus)
|
||||
.WithMany(os => os.Orders)
|
||||
.HasForeignKey(o => o.OrderStatusId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(o => o.ShippingStatus)
|
||||
.WithMany(ss => ss.Orders)
|
||||
.HasForeignKey(o => o.ShippingStatusId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(o => o.OrderAddress)
|
||||
.WithOne(oa => oa.Order)
|
||||
.HasForeignKey<OrderAddress>(oa => oa.OrderId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
builder.HasIndex(o => o.UserId)
|
||||
.HasDatabaseName("IX_Order_UserId");
|
||||
|
||||
builder.HasIndex(o => o.OrderNumber)
|
||||
.IsUnique()
|
||||
.HasDatabaseName("IX_Order_OrderNumber");
|
||||
|
||||
builder.HasIndex(o => o.OrderDate)
|
||||
.HasDatabaseName("IX_Order_OrderDate");
|
||||
|
||||
builder.HasIndex(o => o.OrderStatusId)
|
||||
.HasDatabaseName("IX_Order_OrderStatusId");
|
||||
|
||||
builder.HasIndex(o => o.ShippingStatusId)
|
||||
.HasDatabaseName("IX_Order_ShippingStatusId");
|
||||
|
||||
builder.HasIndex(o => new { o.UserId, o.OrderDate })
|
||||
.HasDatabaseName("IX_Order_User_Date");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using Imprink.Domain.Entities.Orders;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Imprink.Infrastructure.Configuration.Orders;
|
||||
|
||||
public class OrderItemConfiguration : EntityBaseConfiguration<OrderItem>
|
||||
{
|
||||
public override void Configure(EntityTypeBuilder<OrderItem> builder)
|
||||
{
|
||||
base.Configure(builder);
|
||||
|
||||
builder.Property(oi => oi.OrderId)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(oi => oi.ProductId)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(oi => oi.Quantity)
|
||||
.IsRequired()
|
||||
.HasDefaultValue(1);
|
||||
|
||||
builder.Property(oi => oi.UnitPrice)
|
||||
.IsRequired()
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
builder.Property(oi => oi.TotalPrice)
|
||||
.IsRequired()
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
builder.Property(oi => oi.CustomizationImageUrl)
|
||||
.HasMaxLength(500);
|
||||
|
||||
builder.Property(oi => oi.CustomizationDescription)
|
||||
.HasMaxLength(2000);
|
||||
|
||||
builder.HasOne(oi => oi.Order)
|
||||
.WithMany(o => o.OrderItems)
|
||||
.HasForeignKey(oi => oi.OrderId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
builder.HasOne(oi => oi.Product)
|
||||
.WithMany(p => p.OrderItems)
|
||||
.HasForeignKey(oi => oi.ProductId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasOne(oi => oi.ProductVariant)
|
||||
.WithMany(pv => pv.OrderItems)
|
||||
.HasForeignKey(oi => oi.ProductVariantId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasIndex(oi => oi.OrderId)
|
||||
.HasDatabaseName("IX_OrderItem_OrderId");
|
||||
|
||||
builder.HasIndex(oi => oi.ProductId)
|
||||
.HasDatabaseName("IX_OrderItem_ProductId");
|
||||
|
||||
builder.HasIndex(oi => oi.ProductVariantId)
|
||||
.HasDatabaseName("IX_OrderItem_ProductVariantId");
|
||||
|
||||
builder.HasIndex(oi => new { oi.OrderId, oi.ProductId })
|
||||
.HasDatabaseName("IX_OrderItem_Order_Product");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Imprink.Domain.Entities.Orders;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Imprink.Infrastructure.Configuration.Orders;
|
||||
|
||||
public class OrderStatusConfiguration : IEntityTypeConfiguration<OrderStatus>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<OrderStatus> builder)
|
||||
{
|
||||
builder.HasKey(os => os.Id);
|
||||
|
||||
builder.Property(os => os.Id)
|
||||
.ValueGeneratedNever();
|
||||
|
||||
builder.Property(os => os.Name)
|
||||
.IsRequired()
|
||||
.HasMaxLength(50);
|
||||
|
||||
builder.HasIndex(os => os.Name)
|
||||
.IsUnique()
|
||||
.HasDatabaseName("IX_OrderStatus_Name");
|
||||
|
||||
builder.HasData(
|
||||
new OrderStatus { Id = 0, Name = "Pending" },
|
||||
new OrderStatus { Id = 1, Name = "Processing" },
|
||||
new OrderStatus { Id = 2, Name = "Completed" },
|
||||
new OrderStatus { Id = 3, Name = "Cancelled" }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Imprink.Domain.Entities.Orders;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Imprink.Infrastructure.Configuration.Orders;
|
||||
|
||||
public class ShippingStatusConfiguration : IEntityTypeConfiguration<ShippingStatus>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<ShippingStatus> builder)
|
||||
{
|
||||
builder.HasKey(ss => ss.Id);
|
||||
|
||||
builder.Property(ss => ss.Id)
|
||||
.ValueGeneratedNever();
|
||||
|
||||
builder.Property(ss => ss.Name)
|
||||
.IsRequired()
|
||||
.HasMaxLength(50);
|
||||
|
||||
builder.HasIndex(ss => ss.Name)
|
||||
.IsUnique()
|
||||
.HasDatabaseName("IX_ShippingStatus_Name");
|
||||
|
||||
builder.HasData(
|
||||
new ShippingStatus { Id = 0, Name = "Prepping" },
|
||||
new ShippingStatus { Id = 1, Name = "Packaging" },
|
||||
new ShippingStatus { Id = 2, Name = "Shipped" },
|
||||
new ShippingStatus { Id = 3, Name = "Delivered" }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
using Imprink.Domain.Entities.Product;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Imprink.Infrastructure.Configuration.Products;
|
||||
|
||||
public class CategoryConfiguration : EntityBaseConfiguration<Category>
|
||||
{
|
||||
public override void Configure(EntityTypeBuilder<Category> builder)
|
||||
{
|
||||
base.Configure(builder);
|
||||
|
||||
builder.Property(c => c.Name)
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
builder.Property(c => c.Description)
|
||||
.HasMaxLength(2000);
|
||||
|
||||
builder.Property(c => c.ImageUrl)
|
||||
.HasMaxLength(500);
|
||||
|
||||
builder.Property(c => c.SortOrder)
|
||||
.IsRequired()
|
||||
.HasDefaultValue(0);
|
||||
|
||||
builder.Property(c => c.IsActive)
|
||||
.IsRequired()
|
||||
.HasDefaultValue(true);
|
||||
|
||||
builder.Property(c => c.ParentCategoryId)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.Property(c => c.CreatedAt)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.Property(c => c.CreatedBy)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.Property(c => c.ModifiedAt)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.Property(c => c.ModifiedBy)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.HasOne(c => c.ParentCategory)
|
||||
.WithMany(c => c.SubCategories)
|
||||
.HasForeignKey(c => c.ParentCategoryId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasIndex(c => c.Name)
|
||||
.HasDatabaseName("IX_Category_Name");
|
||||
|
||||
builder.HasIndex(c => c.IsActive)
|
||||
.HasDatabaseName("IX_Category_IsActive");
|
||||
|
||||
builder.HasIndex(c => c.ParentCategoryId)
|
||||
.HasDatabaseName("IX_Category_ParentCategoryId");
|
||||
|
||||
builder.HasIndex(c => new { c.ParentCategoryId, c.SortOrder })
|
||||
.HasDatabaseName("IX_Category_Parent_SortOrder");
|
||||
|
||||
builder.HasIndex(c => new { c.IsActive, c.SortOrder })
|
||||
.HasDatabaseName("IX_Category_Active_SortOrder");
|
||||
|
||||
builder.HasData(
|
||||
new Category
|
||||
{
|
||||
Id = Guid.Parse("11111111-1111-1111-1111-111111111111"),
|
||||
Name = "Textile",
|
||||
Description = "Textile and fabric-based products",
|
||||
IsActive = true,
|
||||
SortOrder = 1,
|
||||
CreatedAt = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc),
|
||||
ModifiedAt = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc),
|
||||
CreatedBy = "system@printbase.com",
|
||||
ModifiedBy = "system@printbase.com"
|
||||
},
|
||||
new Category
|
||||
{
|
||||
Id = Guid.Parse("22222222-2222-2222-2222-222222222222"),
|
||||
Name = "Hard Surfaces",
|
||||
Description = "Products for hard surface printing",
|
||||
IsActive = true,
|
||||
SortOrder = 2,
|
||||
CreatedAt = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc),
|
||||
ModifiedAt = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc),
|
||||
CreatedBy = "system@printbase.com",
|
||||
ModifiedBy = "system@printbase.com"
|
||||
},
|
||||
new Category
|
||||
{
|
||||
Id = Guid.Parse("33333333-3333-3333-3333-333333333333"),
|
||||
Name = "Paper",
|
||||
Description = "Paper-based printing products",
|
||||
IsActive = true,
|
||||
SortOrder = 3,
|
||||
CreatedAt = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc),
|
||||
ModifiedAt = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc),
|
||||
CreatedBy = "system@printbase.com",
|
||||
ModifiedBy = "system@printbase.com"
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using Imprink.Domain.Entities.Product;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Imprink.Infrastructure.Configuration.Products;
|
||||
|
||||
public class ProductConfiguration : EntityBaseConfiguration<Product>
|
||||
{
|
||||
public override void Configure(EntityTypeBuilder<Product> builder)
|
||||
{
|
||||
base.Configure(builder);
|
||||
|
||||
builder.Property(p => p.Name)
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
builder.Property(p => p.Description)
|
||||
.HasMaxLength(2000);
|
||||
|
||||
builder.Property(p => p.BasePrice)
|
||||
.IsRequired()
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
builder.Property(p => p.IsCustomizable)
|
||||
.IsRequired()
|
||||
.HasDefaultValue(false);
|
||||
|
||||
builder.Property(p => p.IsActive)
|
||||
.IsRequired()
|
||||
.HasDefaultValue(true);
|
||||
|
||||
builder.Property(p => p.ImageUrl)
|
||||
.HasMaxLength(500);
|
||||
|
||||
builder.Property(p => p.CategoryId)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.Property(c => c.CreatedAt)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.Property(c => c.CreatedBy)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.Property(c => c.ModifiedAt)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.Property(c => c.ModifiedBy)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.HasOne(p => p.Category)
|
||||
.WithMany(c => c.Products)
|
||||
.HasForeignKey(p => p.CategoryId)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
builder.HasIndex(p => p.Name)
|
||||
.HasDatabaseName("IX_Product_Name");
|
||||
|
||||
builder.HasIndex(p => p.IsActive)
|
||||
.HasDatabaseName("IX_Product_IsActive");
|
||||
|
||||
builder.HasIndex(p => p.IsCustomizable)
|
||||
.HasDatabaseName("IX_Product_IsCustomizable");
|
||||
|
||||
builder.HasIndex(p => p.CategoryId)
|
||||
.HasDatabaseName("IX_Product_CategoryId");
|
||||
|
||||
builder.HasIndex(p => new { p.IsActive, p.IsCustomizable })
|
||||
.HasDatabaseName("IX_Product_Active_Customizable");
|
||||
|
||||
builder.HasIndex(p => new { p.CategoryId, p.IsActive })
|
||||
.HasDatabaseName("IX_Product_Category_Active");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using Imprink.Domain.Entities.Product;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Imprink.Infrastructure.Configuration.Products;
|
||||
|
||||
public class ProductVariantConfiguration : EntityBaseConfiguration<ProductVariant>
|
||||
{
|
||||
public override void Configure(EntityTypeBuilder<ProductVariant> builder)
|
||||
{
|
||||
base.Configure(builder);
|
||||
|
||||
builder.Property(pv => pv.ProductId)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(pv => pv.Size)
|
||||
.HasMaxLength(50);
|
||||
|
||||
builder.Property(pv => pv.Color)
|
||||
.HasMaxLength(50);
|
||||
|
||||
builder.Property(pv => pv.Price)
|
||||
.IsRequired()
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
builder.Property(pv => pv.ImageUrl)
|
||||
.HasMaxLength(500);
|
||||
|
||||
builder.Property(pv => pv.Sku)
|
||||
.IsRequired()
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.Property(pv => pv.StockQuantity)
|
||||
.IsRequired()
|
||||
.HasDefaultValue(0);
|
||||
|
||||
builder.Property(pv => pv.IsActive)
|
||||
.IsRequired()
|
||||
.HasDefaultValue(true);
|
||||
|
||||
builder.Property(c => c.CreatedAt)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.Property(c => c.CreatedBy)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.Property(c => c.ModifiedAt)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.Property(c => c.ModifiedBy)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.HasOne(pv => pv.Product)
|
||||
.WithMany(p => p.ProductVariants)
|
||||
.HasForeignKey(pv => pv.ProductId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
builder.HasIndex(pv => pv.ProductId)
|
||||
.HasDatabaseName("IX_ProductVariant_ProductId");
|
||||
|
||||
builder.HasIndex(pv => pv.Sku)
|
||||
.IsUnique()
|
||||
.HasDatabaseName("IX_ProductVariant_SKU");
|
||||
|
||||
builder.HasIndex(pv => pv.IsActive)
|
||||
.HasDatabaseName("IX_ProductVariant_IsActive");
|
||||
|
||||
builder.HasIndex(pv => new { pv.ProductId, pv.Size, pv.Color })
|
||||
.IsUnique()
|
||||
.HasDatabaseName("IX_ProductVariant_Product_Size_Color");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using Imprink.Domain.Entities.Users;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Imprink.Infrastructure.Configuration.Users;
|
||||
|
||||
public class AddressConfiguration : EntityBaseConfiguration<Address>
|
||||
{
|
||||
public override void Configure(EntityTypeBuilder<Address> builder)
|
||||
{
|
||||
base.Configure(builder);
|
||||
|
||||
builder.Property(a => a.UserId)
|
||||
.IsRequired()
|
||||
.HasMaxLength(450);
|
||||
|
||||
builder.Property(a => a.AddressType)
|
||||
.IsRequired()
|
||||
.HasMaxLength(50);
|
||||
|
||||
builder.Property(a => a.Street)
|
||||
.IsRequired()
|
||||
.HasMaxLength(200);
|
||||
|
||||
builder.Property(a => a.City)
|
||||
.IsRequired()
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.Property(a => a.State)
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.Property(a => a.PostalCode)
|
||||
.IsRequired()
|
||||
.HasMaxLength(20);
|
||||
|
||||
builder.Property(a => a.Country)
|
||||
.IsRequired()
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.Property(a => a.IsDefault)
|
||||
.IsRequired()
|
||||
.HasDefaultValue(false);
|
||||
|
||||
builder.Property(a => a.IsActive)
|
||||
.IsRequired()
|
||||
.HasDefaultValue(true);
|
||||
|
||||
builder.HasOne<ApplicationUser>()
|
||||
.WithMany(u => u.Addresses)
|
||||
.HasForeignKey(a => a.UserId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
builder.HasIndex(a => a.UserId)
|
||||
.HasDatabaseName("IX_Address_UserId");
|
||||
|
||||
builder.HasIndex(a => new { a.UserId, a.AddressType })
|
||||
.HasDatabaseName("IX_Address_User_Type");
|
||||
|
||||
builder.HasIndex(a => new { a.UserId, a.IsDefault })
|
||||
.HasDatabaseName("IX_Address_User_Default");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using Imprink.Domain.Entities.Users;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Imprink.Infrastructure.Configuration.Users;
|
||||
|
||||
public class ApplicationRoleConfiguration : IEntityTypeConfiguration<ApplicationRole>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<ApplicationRole> builder)
|
||||
{
|
||||
builder.Property(r => r.Description)
|
||||
.HasMaxLength(500);
|
||||
|
||||
builder.Property(r => r.CreatedAt)
|
||||
.IsRequired()
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
builder.Property(r => r.IsActive)
|
||||
.IsRequired()
|
||||
.HasDefaultValue(true);
|
||||
|
||||
builder.HasIndex(r => r.IsActive)
|
||||
.HasDatabaseName("IX_ApplicationRole_IsActive");
|
||||
|
||||
var seedDate = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
builder.HasData(
|
||||
new ApplicationRole
|
||||
{
|
||||
Id = "1",
|
||||
Name = "Administrator",
|
||||
NormalizedName = "ADMINISTRATOR",
|
||||
Description = "Full system access",
|
||||
CreatedAt = seedDate,
|
||||
IsActive = true
|
||||
},
|
||||
new ApplicationRole
|
||||
{
|
||||
Id = "2",
|
||||
Name = "Customer",
|
||||
NormalizedName = "CUSTOMER",
|
||||
Description = "Standard customer access",
|
||||
CreatedAt = seedDate,
|
||||
IsActive = true
|
||||
},
|
||||
new ApplicationRole
|
||||
{
|
||||
Id = "3",
|
||||
Name = "OrderManager",
|
||||
NormalizedName = "ORDERMANAGER",
|
||||
Description = "Manage orders and fulfillment",
|
||||
CreatedAt = seedDate,
|
||||
IsActive = true
|
||||
},
|
||||
new ApplicationRole
|
||||
{
|
||||
Id = "4",
|
||||
Name = "ProductManager",
|
||||
NormalizedName = "PRODUCTMANAGER",
|
||||
Description = "Manage products and inventory",
|
||||
CreatedAt = seedDate,
|
||||
IsActive = true
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Imprink.Domain.Entities.Users;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Imprink.Infrastructure.Configuration.Users;
|
||||
|
||||
public class ApplicationUserConfiguration : IEntityTypeConfiguration<ApplicationUser>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<ApplicationUser> builder)
|
||||
{
|
||||
builder.Property(u => u.FirstName)
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.Property(u => u.LastName)
|
||||
.HasMaxLength(100);
|
||||
|
||||
builder.Property(u => u.ProfileImageUrl)
|
||||
.HasMaxLength(500);
|
||||
|
||||
builder.Property(u => u.CreatedAt)
|
||||
.IsRequired()
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
builder.Property(u => u.LastLoginAt)
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
builder.Property(u => u.IsActive)
|
||||
.HasDefaultValue(true);
|
||||
}
|
||||
}
|
||||
42
src/Imprink.Infrastructure/Database/ApplicationDbContext.cs
Normal file
42
src/Imprink.Infrastructure/Database/ApplicationDbContext.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Imprink.Domain.Entities.Orders;
|
||||
using Imprink.Domain.Entities.Product;
|
||||
using Imprink.Domain.Entities.Users;
|
||||
using Imprink.Infrastructure.Configuration.Orders;
|
||||
using Imprink.Infrastructure.Configuration.Products;
|
||||
using Imprink.Infrastructure.Configuration.Users;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Imprink.Infrastructure.Database;
|
||||
|
||||
public class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
|
||||
: IdentityDbContext<ApplicationUser, ApplicationRole, string>(options)
|
||||
{
|
||||
public DbSet<Product> Products { get; set; }
|
||||
public DbSet<ProductVariant> ProductVariants { get; set; }
|
||||
public DbSet<Order> Orders { get; set; }
|
||||
public DbSet<OrderItem> OrderItems { get; set; }
|
||||
public DbSet<OrderAddress> OrderAddresses { get; set; }
|
||||
public DbSet<Address> Addresses { get; set; }
|
||||
public DbSet<OrderStatus> OrderStatuses { get; set; }
|
||||
public DbSet<ShippingStatus> ShippingStatuses { get; set; }
|
||||
public DbSet<Category> Categories { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
modelBuilder.ApplyConfiguration(new ApplicationUserConfiguration());
|
||||
modelBuilder.ApplyConfiguration(new ApplicationRoleConfiguration());
|
||||
|
||||
modelBuilder.ApplyConfiguration(new ProductConfiguration());
|
||||
modelBuilder.ApplyConfiguration(new ProductVariantConfiguration());
|
||||
modelBuilder.ApplyConfiguration(new OrderConfiguration());
|
||||
modelBuilder.ApplyConfiguration(new OrderItemConfiguration());
|
||||
modelBuilder.ApplyConfiguration(new OrderAddressConfiguration());
|
||||
modelBuilder.ApplyConfiguration(new AddressConfiguration());
|
||||
modelBuilder.ApplyConfiguration(new OrderStatusConfiguration());
|
||||
modelBuilder.ApplyConfiguration(new ShippingStatusConfiguration());
|
||||
modelBuilder.ApplyConfiguration(new CategoryConfiguration());
|
||||
}
|
||||
}
|
||||
29
src/Imprink.Infrastructure/Imprink.Infrastructure.csproj
Normal file
29
src/Imprink.Infrastructure/Imprink.Infrastructure.csproj
Normal file
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Imprink.Application\Imprink.Application.csproj" />
|
||||
<ProjectReference Include="..\Imprink.Domain\Imprink.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Migrations\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
1212
src/Imprink.Infrastructure/Migrations/20250527103204_InitialSetup.Designer.cs
generated
Normal file
1212
src/Imprink.Infrastructure/Migrations/20250527103204_InitialSetup.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,824 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace Printbase.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitialSetup : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoles",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "GETUTCDATE()"),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
|
||||
Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
NormalizedName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(type: "nvarchar(max)", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUsers",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
FirstName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
LastName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
DateOfBirth = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "GETUTCDATE()"),
|
||||
LastLoginAt = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "GETUTCDATE()"),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
|
||||
ProfileImageUrl = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
UserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
NormalizedUserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
Email = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
NormalizedEmail = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
EmailConfirmed = table.Column<bool>(type: "bit", nullable: false),
|
||||
PasswordHash = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
SecurityStamp = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
PhoneNumber = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
PhoneNumberConfirmed = table.Column<bool>(type: "bit", nullable: false),
|
||||
TwoFactorEnabled = table.Column<bool>(type: "bit", nullable: false),
|
||||
LockoutEnd = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: true),
|
||||
LockoutEnabled = table.Column<bool>(type: "bit", nullable: false),
|
||||
AccessFailedCount = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Categories",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false, defaultValueSql: "NEWID()"),
|
||||
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: false),
|
||||
ImageUrl = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
SortOrder = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
|
||||
ParentCategoryId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
ModifiedAt = table.Column<DateTime>(type: "datetime2", nullable: true, defaultValueSql: "GETUTCDATE()"),
|
||||
CreatedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: true),
|
||||
ModifiedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Categories", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Categories_Categories_ParentCategoryId",
|
||||
column: x => x.ParentCategoryId,
|
||||
principalTable: "Categories",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "OrderStatuses",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false),
|
||||
Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_OrderStatuses", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ShippingStatuses",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false),
|
||||
Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ShippingStatuses", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoleClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
RoleId = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
ClaimType = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
ClaimValue = table.Column<string>(type: "nvarchar(max)", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Addresses",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false, defaultValueSql: "NEWID()"),
|
||||
UserId = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: false),
|
||||
AddressType = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
Street = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
City = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
State = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
PostalCode = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
|
||||
Country = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
IsDefault = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ModifiedAt = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "GETUTCDATE()"),
|
||||
CreatedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: false),
|
||||
ModifiedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Addresses", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Addresses_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
ClaimType = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
ClaimValue = table.Column<string>(type: "nvarchar(max)", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserLogins",
|
||||
columns: table => new
|
||||
{
|
||||
LoginProvider = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
ProviderKey = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
ProviderDisplayName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserRoles",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
RoleId = table.Column<string>(type: "nvarchar(450)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserTokens",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
LoginProvider = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
Name = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
Value = table.Column<string>(type: "nvarchar(max)", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Products",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false, defaultValueSql: "NEWID()"),
|
||||
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
|
||||
BasePrice = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
|
||||
IsCustomizable = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
|
||||
ImageUrl = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
CategoryId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
ModifiedAt = table.Column<DateTime>(type: "datetime2", nullable: true, defaultValueSql: "GETUTCDATE()"),
|
||||
CreatedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: true),
|
||||
ModifiedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Products", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Products_Categories_CategoryId",
|
||||
column: x => x.CategoryId,
|
||||
principalTable: "Categories",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.SetNull);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Orders",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false, defaultValueSql: "NEWID()"),
|
||||
UserId = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: false),
|
||||
OrderDate = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
TotalPrice = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
|
||||
OrderStatusId = table.Column<int>(type: "int", nullable: false),
|
||||
ShippingStatusId = table.Column<int>(type: "int", nullable: false),
|
||||
OrderNumber = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
Notes = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ModifiedAt = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "GETUTCDATE()"),
|
||||
CreatedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: false),
|
||||
ModifiedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Orders", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Orders_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
table.ForeignKey(
|
||||
name: "FK_Orders_OrderStatuses_OrderStatusId",
|
||||
column: x => x.OrderStatusId,
|
||||
principalTable: "OrderStatuses",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
table.ForeignKey(
|
||||
name: "FK_Orders_ShippingStatuses_ShippingStatusId",
|
||||
column: x => x.ShippingStatusId,
|
||||
principalTable: "ShippingStatuses",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ProductVariants",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false, defaultValueSql: "NEWID()"),
|
||||
ProductId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
Size = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
Color = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
|
||||
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
|
||||
ImageUrl = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
Sku = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
StockQuantity = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
ModifiedAt = table.Column<DateTime>(type: "datetime2", nullable: true, defaultValueSql: "GETUTCDATE()"),
|
||||
CreatedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: true),
|
||||
ModifiedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ProductVariants", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_ProductVariants_Products_ProductId",
|
||||
column: x => x.ProductId,
|
||||
principalTable: "Products",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "OrderAddresses",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false, defaultValueSql: "NEWID()"),
|
||||
OrderId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
Street = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
City = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
State = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
PostalCode = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
|
||||
Country = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ModifiedAt = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "GETUTCDATE()"),
|
||||
CreatedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: false),
|
||||
ModifiedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_OrderAddresses", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_OrderAddresses_Orders_OrderId",
|
||||
column: x => x.OrderId,
|
||||
principalTable: "Orders",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "OrderItems",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false, defaultValueSql: "NEWID()"),
|
||||
OrderId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
ProductId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
ProductVariantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
Quantity = table.Column<int>(type: "int", nullable: false, defaultValue: 1),
|
||||
UnitPrice = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
|
||||
TotalPrice = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
|
||||
CustomizationImageUrl = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
|
||||
CustomizationDescription = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ModifiedAt = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "GETUTCDATE()"),
|
||||
CreatedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: false),
|
||||
ModifiedBy = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_OrderItems", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_OrderItems_Orders_OrderId",
|
||||
column: x => x.OrderId,
|
||||
principalTable: "Orders",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_OrderItems_ProductVariants_ProductVariantId",
|
||||
column: x => x.ProductVariantId,
|
||||
principalTable: "ProductVariants",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
table.ForeignKey(
|
||||
name: "FK_OrderItems_Products_ProductId",
|
||||
column: x => x.ProductId,
|
||||
principalTable: "Products",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "CreatedAt", "Description", "IsActive", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ "1", null, new DateTime(2025, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "Full system access", true, "Administrator", "ADMINISTRATOR" },
|
||||
{ "2", null, new DateTime(2025, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "Standard customer access", true, "Customer", "CUSTOMER" },
|
||||
{ "3", null, new DateTime(2025, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "Manage orders and fulfillment", true, "OrderManager", "ORDERMANAGER" },
|
||||
{ "4", null, new DateTime(2025, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "Manage products and inventory", true, "ProductManager", "PRODUCTMANAGER" }
|
||||
});
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "Categories",
|
||||
columns: new[] { "Id", "CreatedAt", "CreatedBy", "Description", "ImageUrl", "IsActive", "ModifiedAt", "ModifiedBy", "Name", "ParentCategoryId", "SortOrder" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("11111111-1111-1111-1111-111111111111"), new DateTime(2025, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "system@printbase.com", "Textile and fabric-based products", null, true, new DateTime(2025, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "system@printbase.com", "Textile", null, 1 },
|
||||
{ new Guid("22222222-2222-2222-2222-222222222222"), new DateTime(2025, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "system@printbase.com", "Products for hard surface printing", null, true, new DateTime(2025, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "system@printbase.com", "Hard Surfaces", null, 2 },
|
||||
{ new Guid("33333333-3333-3333-3333-333333333333"), new DateTime(2025, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "system@printbase.com", "Paper-based printing products", null, true, new DateTime(2025, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), "system@printbase.com", "Paper", null, 3 }
|
||||
});
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "OrderStatuses",
|
||||
columns: new[] { "Id", "Name" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ 0, "Pending" },
|
||||
{ 1, "Processing" },
|
||||
{ 2, "Completed" },
|
||||
{ 3, "Cancelled" }
|
||||
});
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "ShippingStatuses",
|
||||
columns: new[] { "Id", "Name" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ 0, "Prepping" },
|
||||
{ 1, "Packaging" },
|
||||
{ 2, "Shipped" },
|
||||
{ 3, "Delivered" }
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Address_CreatedAt",
|
||||
table: "Addresses",
|
||||
column: "CreatedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Address_CreatedBy",
|
||||
table: "Addresses",
|
||||
column: "CreatedBy");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Address_ModifiedAt",
|
||||
table: "Addresses",
|
||||
column: "ModifiedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Address_User_Default",
|
||||
table: "Addresses",
|
||||
columns: new[] { "UserId", "IsDefault" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Address_User_Type",
|
||||
table: "Addresses",
|
||||
columns: new[] { "UserId", "AddressType" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Address_UserId",
|
||||
table: "Addresses",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetRoleClaims_RoleId",
|
||||
table: "AspNetRoleClaims",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ApplicationRole_IsActive",
|
||||
table: "AspNetRoles",
|
||||
column: "IsActive");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "RoleNameIndex",
|
||||
table: "AspNetRoles",
|
||||
column: "NormalizedName",
|
||||
unique: true,
|
||||
filter: "[NormalizedName] IS NOT NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserClaims_UserId",
|
||||
table: "AspNetUserClaims",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserLogins_UserId",
|
||||
table: "AspNetUserLogins",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserRoles_RoleId",
|
||||
table: "AspNetUserRoles",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "EmailIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedEmail");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "UserNameIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedUserName",
|
||||
unique: true,
|
||||
filter: "[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Category_Active_SortOrder",
|
||||
table: "Categories",
|
||||
columns: new[] { "IsActive", "SortOrder" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Category_CreatedAt",
|
||||
table: "Categories",
|
||||
column: "CreatedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Category_CreatedBy",
|
||||
table: "Categories",
|
||||
column: "CreatedBy");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Category_IsActive",
|
||||
table: "Categories",
|
||||
column: "IsActive");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Category_ModifiedAt",
|
||||
table: "Categories",
|
||||
column: "ModifiedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Category_Name",
|
||||
table: "Categories",
|
||||
column: "Name");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Category_Parent_SortOrder",
|
||||
table: "Categories",
|
||||
columns: new[] { "ParentCategoryId", "SortOrder" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Category_ParentCategoryId",
|
||||
table: "Categories",
|
||||
column: "ParentCategoryId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrderAddress_CreatedAt",
|
||||
table: "OrderAddresses",
|
||||
column: "CreatedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrderAddress_CreatedBy",
|
||||
table: "OrderAddresses",
|
||||
column: "CreatedBy");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrderAddress_ModifiedAt",
|
||||
table: "OrderAddresses",
|
||||
column: "ModifiedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrderAddress_OrderId",
|
||||
table: "OrderAddresses",
|
||||
column: "OrderId",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrderItem_CreatedAt",
|
||||
table: "OrderItems",
|
||||
column: "CreatedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrderItem_CreatedBy",
|
||||
table: "OrderItems",
|
||||
column: "CreatedBy");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrderItem_ModifiedAt",
|
||||
table: "OrderItems",
|
||||
column: "ModifiedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrderItem_Order_Product",
|
||||
table: "OrderItems",
|
||||
columns: new[] { "OrderId", "ProductId" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrderItem_OrderId",
|
||||
table: "OrderItems",
|
||||
column: "OrderId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrderItem_ProductId",
|
||||
table: "OrderItems",
|
||||
column: "ProductId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrderItem_ProductVariantId",
|
||||
table: "OrderItems",
|
||||
column: "ProductVariantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Order_CreatedAt",
|
||||
table: "Orders",
|
||||
column: "CreatedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Order_CreatedBy",
|
||||
table: "Orders",
|
||||
column: "CreatedBy");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Order_ModifiedAt",
|
||||
table: "Orders",
|
||||
column: "ModifiedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Order_OrderDate",
|
||||
table: "Orders",
|
||||
column: "OrderDate");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Order_OrderNumber",
|
||||
table: "Orders",
|
||||
column: "OrderNumber",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Order_OrderStatusId",
|
||||
table: "Orders",
|
||||
column: "OrderStatusId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Order_ShippingStatusId",
|
||||
table: "Orders",
|
||||
column: "ShippingStatusId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Order_User_Date",
|
||||
table: "Orders",
|
||||
columns: new[] { "UserId", "OrderDate" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Order_UserId",
|
||||
table: "Orders",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrderStatus_Name",
|
||||
table: "OrderStatuses",
|
||||
column: "Name",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Product_Active_Customizable",
|
||||
table: "Products",
|
||||
columns: new[] { "IsActive", "IsCustomizable" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Product_Category_Active",
|
||||
table: "Products",
|
||||
columns: new[] { "CategoryId", "IsActive" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Product_CategoryId",
|
||||
table: "Products",
|
||||
column: "CategoryId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Product_CreatedAt",
|
||||
table: "Products",
|
||||
column: "CreatedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Product_CreatedBy",
|
||||
table: "Products",
|
||||
column: "CreatedBy");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Product_IsActive",
|
||||
table: "Products",
|
||||
column: "IsActive");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Product_IsCustomizable",
|
||||
table: "Products",
|
||||
column: "IsCustomizable");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Product_ModifiedAt",
|
||||
table: "Products",
|
||||
column: "ModifiedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Product_Name",
|
||||
table: "Products",
|
||||
column: "Name");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ProductVariant_CreatedAt",
|
||||
table: "ProductVariants",
|
||||
column: "CreatedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ProductVariant_CreatedBy",
|
||||
table: "ProductVariants",
|
||||
column: "CreatedBy");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ProductVariant_IsActive",
|
||||
table: "ProductVariants",
|
||||
column: "IsActive");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ProductVariant_ModifiedAt",
|
||||
table: "ProductVariants",
|
||||
column: "ModifiedAt");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ProductVariant_Product_Size_Color",
|
||||
table: "ProductVariants",
|
||||
columns: new[] { "ProductId", "Size", "Color" },
|
||||
unique: true,
|
||||
filter: "[Color] IS NOT NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ProductVariant_ProductId",
|
||||
table: "ProductVariants",
|
||||
column: "ProductId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ProductVariant_SKU",
|
||||
table: "ProductVariants",
|
||||
column: "Sku",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ShippingStatus_Name",
|
||||
table: "ShippingStatuses",
|
||||
column: "Name",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Addresses");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoleClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserLogins");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserTokens");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "OrderAddresses");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "OrderItems");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Orders");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ProductVariants");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUsers");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "OrderStatuses");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ShippingStatuses");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Products");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Categories");
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
111
src/Imprink.Infrastructure/Repositories/CategoryRepository.cs
Normal file
111
src/Imprink.Infrastructure/Repositories/CategoryRepository.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using Imprink.Domain.Entities.Product;
|
||||
using Imprink.Domain.Repositories;
|
||||
using Imprink.Infrastructure.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Imprink.Infrastructure.Repositories;
|
||||
|
||||
public class CategoryRepository(ApplicationDbContext context) : ICategoryRepository
|
||||
{
|
||||
public async Task<Category?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Categories
|
||||
.FirstOrDefaultAsync(c => c.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Category?> GetByIdWithSubCategoriesAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Categories
|
||||
.Include(c => c.SubCategories.Where(sc => sc.IsActive))
|
||||
.FirstOrDefaultAsync(c => c.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Category?> GetByIdWithProductsAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Categories
|
||||
.Include(c => c.Products.Where(p => p.IsActive))
|
||||
.FirstOrDefaultAsync(c => c.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Category>> GetAllAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Categories
|
||||
.OrderBy(c => c.SortOrder)
|
||||
.ThenBy(c => c.Name)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Category>> GetActiveAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Categories
|
||||
.Where(c => c.IsActive)
|
||||
.OrderBy(c => c.SortOrder)
|
||||
.ThenBy(c => c.Name)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Category>> GetRootCategoriesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Categories
|
||||
.Where(c => c.ParentCategoryId == null && c.IsActive)
|
||||
.OrderBy(c => c.SortOrder)
|
||||
.ThenBy(c => c.Name)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Category>> GetSubCategoriesAsync(Guid parentCategoryId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Categories
|
||||
.Where(c => c.ParentCategoryId == parentCategoryId && c.IsActive)
|
||||
.OrderBy(c => c.SortOrder)
|
||||
.ThenBy(c => c.Name)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Category> AddAsync(Category category, CancellationToken cancellationToken = default)
|
||||
{
|
||||
category.Id = Guid.NewGuid();
|
||||
category.CreatedAt = DateTime.UtcNow;
|
||||
category.ModifiedAt = DateTime.UtcNow;
|
||||
|
||||
context.Categories.Add(category);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
return category;
|
||||
}
|
||||
|
||||
public async Task<Category> UpdateAsync(Category category, CancellationToken cancellationToken = default)
|
||||
{
|
||||
category.ModifiedAt = DateTime.UtcNow;
|
||||
context.Categories.Update(category);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
return category;
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var category = await GetByIdAsync(id, cancellationToken);
|
||||
if (category != null)
|
||||
{
|
||||
context.Categories.Remove(category);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Categories
|
||||
.AnyAsync(c => c.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<bool> HasSubCategoriesAsync(Guid categoryId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Categories
|
||||
.AnyAsync(c => c.ParentCategoryId == categoryId, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<bool> HasProductsAsync(Guid categoryId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Products
|
||||
.AnyAsync(p => p.CategoryId == categoryId, cancellationToken);
|
||||
}
|
||||
}
|
||||
165
src/Imprink.Infrastructure/Repositories/ProductRepository.cs
Normal file
165
src/Imprink.Infrastructure/Repositories/ProductRepository.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using Imprink.Domain.Common.Models;
|
||||
using Imprink.Domain.Entities.Product;
|
||||
using Imprink.Domain.Repositories;
|
||||
using Imprink.Infrastructure.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Imprink.Infrastructure.Repositories;
|
||||
|
||||
public class ProductRepository(ApplicationDbContext context) : IProductRepository
|
||||
{
|
||||
public async Task<Product?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Products
|
||||
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Product?> GetByIdWithVariantsAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Products
|
||||
.Include(p => p.ProductVariants.Where(pv => pv.IsActive))
|
||||
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Product?> GetByIdWithCategoryAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Products
|
||||
.Include(p => p.Category)
|
||||
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Product?> GetByIdFullAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Products
|
||||
.Include(p => p.Category)
|
||||
.Include(p => p.ProductVariants.Where(pv => pv.IsActive))
|
||||
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<PagedResult<Product>> GetPagedAsync(ProductFilterParameters filterParameters, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = context.Products
|
||||
.Include(p => p.Category)
|
||||
.AsQueryable();
|
||||
|
||||
if (filterParameters.IsActive.HasValue)
|
||||
{
|
||||
query = query.Where(p => p.IsActive == filterParameters.IsActive.Value);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(filterParameters.SearchTerm))
|
||||
{
|
||||
query = query.Where(p => p.Name.Contains(filterParameters.SearchTerm) ||
|
||||
(p.Description != null && p.Description.Contains(filterParameters.SearchTerm)));
|
||||
}
|
||||
|
||||
if (filterParameters.CategoryId.HasValue)
|
||||
{
|
||||
query = query.Where(p => p.CategoryId == filterParameters.CategoryId.Value);
|
||||
}
|
||||
|
||||
if (filterParameters.MinPrice.HasValue)
|
||||
{
|
||||
query = query.Where(p => p.BasePrice >= filterParameters.MinPrice.Value);
|
||||
}
|
||||
|
||||
if (filterParameters.MaxPrice.HasValue)
|
||||
{
|
||||
query = query.Where(p => p.BasePrice <= filterParameters.MaxPrice.Value);
|
||||
}
|
||||
|
||||
if (filterParameters.IsCustomizable.HasValue)
|
||||
{
|
||||
query = query.Where(p => p.IsCustomizable == filterParameters.IsCustomizable.Value);
|
||||
}
|
||||
|
||||
query = filterParameters.SortBy.ToLower() switch
|
||||
{
|
||||
"price" => filterParameters.SortDirection.Equals("DESC"
|
||||
, StringComparison.CurrentCultureIgnoreCase)
|
||||
? query.OrderByDescending(p => p.BasePrice)
|
||||
: query.OrderBy(p => p.BasePrice),
|
||||
"name" => filterParameters.SortDirection.Equals("DESC"
|
||||
, StringComparison.CurrentCultureIgnoreCase)
|
||||
? query.OrderByDescending(p => p.Name)
|
||||
: query.OrderBy(p => p.Name),
|
||||
_ => query.OrderBy(p => p.Name)
|
||||
};
|
||||
|
||||
var totalCount = await query.CountAsync(cancellationToken);
|
||||
|
||||
var items = await query
|
||||
.Skip((filterParameters.PageNumber - 1) * filterParameters.PageSize)
|
||||
.Take(filterParameters.PageSize)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return new PagedResult<Product>
|
||||
{
|
||||
Items = items,
|
||||
TotalCount = totalCount,
|
||||
PageNumber = filterParameters.PageNumber,
|
||||
PageSize = filterParameters.PageSize
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Product>> GetByCategoryAsync(Guid categoryId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Products
|
||||
.Include(p => p.Category)
|
||||
.Where(p => p.CategoryId == categoryId && p.IsActive)
|
||||
.OrderBy(p => p.Name)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Product>> GetCustomizableAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Products
|
||||
.Include(p => p.Category)
|
||||
.Where(p => p.IsCustomizable && p.IsActive)
|
||||
.OrderBy(p => p.Name)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Product> AddAsync(Product product, CancellationToken cancellationToken = default)
|
||||
{
|
||||
product.Id = Guid.NewGuid();
|
||||
product.CreatedAt = DateTime.UtcNow;
|
||||
product.ModifiedAt = DateTime.UtcNow;
|
||||
|
||||
context.Products.Add(product);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
if (product.CategoryId.HasValue)
|
||||
{
|
||||
await context.Entry(product)
|
||||
.Reference(p => p.Category)
|
||||
.LoadAsync(cancellationToken);
|
||||
}
|
||||
|
||||
return product;
|
||||
}
|
||||
|
||||
public async Task<Product> UpdateAsync(Product product, CancellationToken cancellationToken = default)
|
||||
{
|
||||
product.ModifiedAt = DateTime.UtcNow;
|
||||
context.Products.Update(product);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
return product;
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var product = await GetByIdAsync(id, cancellationToken);
|
||||
if (product != null)
|
||||
{
|
||||
context.Products.Remove(product);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.Products
|
||||
.AnyAsync(p => p.Id == id, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
using Imprink.Domain.Entities.Product;
|
||||
using Imprink.Domain.Repositories;
|
||||
using Imprink.Infrastructure.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Imprink.Infrastructure.Repositories;
|
||||
|
||||
public class ProductVariantRepository(ApplicationDbContext context) : IProductVariantRepository
|
||||
{
|
||||
public async Task<ProductVariant?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.ProductVariants
|
||||
.FirstOrDefaultAsync(pv => pv.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<ProductVariant?> GetByIdWithProductAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.ProductVariants
|
||||
.Include(pv => pv.Product)
|
||||
.ThenInclude(p => p.Category)
|
||||
.FirstOrDefaultAsync(pv => pv.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<ProductVariant?> GetBySkuAsync(string sku, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.ProductVariants
|
||||
.Include(pv => pv.Product)
|
||||
.FirstOrDefaultAsync(pv => pv.Sku == sku, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ProductVariant>> GetByProductIdAsync(Guid productId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.ProductVariants
|
||||
.Include(pv => pv.Product)
|
||||
.Where(pv => pv.ProductId == productId)
|
||||
.OrderBy(pv => pv.Size)
|
||||
.ThenBy(pv => pv.Color)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ProductVariant>> GetActiveByProductIdAsync(Guid productId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.ProductVariants
|
||||
.Include(pv => pv.Product)
|
||||
.Where(pv => pv.ProductId == productId && pv.IsActive)
|
||||
.OrderBy(pv => pv.Size)
|
||||
.ThenBy(pv => pv.Color)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ProductVariant>> GetInStockByProductIdAsync(Guid productId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.ProductVariants
|
||||
.Include(pv => pv.Product)
|
||||
.Where(pv => pv.ProductId == productId && pv.IsActive && pv.StockQuantity > 0)
|
||||
.OrderBy(pv => pv.Size)
|
||||
.ThenBy(pv => pv.Color)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<ProductVariant> AddAsync(ProductVariant productVariant, CancellationToken cancellationToken = default)
|
||||
{
|
||||
productVariant.Id = Guid.NewGuid();
|
||||
productVariant.CreatedAt = DateTime.UtcNow;
|
||||
productVariant.ModifiedAt = DateTime.UtcNow;
|
||||
|
||||
context.ProductVariants.Add(productVariant);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
return productVariant;
|
||||
}
|
||||
|
||||
public async Task<ProductVariant> UpdateAsync(ProductVariant productVariant, CancellationToken cancellationToken = default)
|
||||
{
|
||||
productVariant.ModifiedAt = DateTime.UtcNow;
|
||||
context.ProductVariants.Update(productVariant);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
return productVariant;
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var productVariant = await GetByIdAsync(id, cancellationToken);
|
||||
if (productVariant != null)
|
||||
{
|
||||
context.ProductVariants.Remove(productVariant);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.ProductVariants
|
||||
.AnyAsync(pv => pv.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<bool> SkuExistsAsync(string sku, Guid? excludeId = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = context.ProductVariants.Where(pv => pv.Sku == sku);
|
||||
|
||||
if (excludeId.HasValue)
|
||||
{
|
||||
query = query.Where(pv => pv.Id != excludeId.Value);
|
||||
}
|
||||
|
||||
return await query.AnyAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task UpdateStockQuantityAsync(Guid id, int quantity, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var productVariant = await GetByIdAsync(id, cancellationToken);
|
||||
if (productVariant != null)
|
||||
{
|
||||
productVariant.StockQuantity = quantity;
|
||||
productVariant.ModifiedAt = DateTime.UtcNow;
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
36
src/Imprink.Infrastructure/UnitOfWork.cs
Normal file
36
src/Imprink.Infrastructure/UnitOfWork.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using Imprink.Application;
|
||||
using Imprink.Domain.Repositories;
|
||||
using Imprink.Infrastructure.Database;
|
||||
|
||||
namespace Imprink.Infrastructure;
|
||||
|
||||
public class UnitOfWork(
|
||||
ApplicationDbContext context,
|
||||
IProductRepository productRepository,
|
||||
IProductVariantRepository productVariantRepository,
|
||||
ICategoryRepository categoryRepository) : IUnitOfWork
|
||||
{
|
||||
public IProductRepository ProductRepository => productRepository;
|
||||
public IProductVariantRepository ProductVariantRepository => productVariantRepository;
|
||||
public ICategoryRepository CategoryRepository => categoryRepository;
|
||||
|
||||
public async Task SaveAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public Task BeginTransactionAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.Database.BeginTransactionAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task CommitTransactionAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await context.Database.CommitTransactionAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task RollbackTransactionAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await context.Database.RollbackTransactionAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
46
src/Imprink.WebApi/Controllers/CategoriesController.cs
Normal file
46
src/Imprink.WebApi/Controllers/CategoriesController.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using Imprink.Application.Products.Commands;
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using Imprink.Application.Products.Queries;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Imprink.WebApi.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class CategoriesController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<IEnumerable<CategoryDto>>> GetCategories(
|
||||
[FromQuery] bool? isActive = null,
|
||||
[FromQuery] bool rootCategoriesOnly = false)
|
||||
{
|
||||
var query = new GetCategoriesQuery
|
||||
{
|
||||
IsActive = isActive,
|
||||
RootCategoriesOnly = rootCategoriesOnly
|
||||
};
|
||||
|
||||
var result = await mediator.Send(query);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<CategoryDto>> CreateCategory([FromBody] CreateCategoryCommand command)
|
||||
{
|
||||
var result = await mediator.Send(command);
|
||||
return CreatedAtAction(nameof(CreateCategory), new { id = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
public async Task<ActionResult> DeleteCategory(Guid id)
|
||||
{
|
||||
var command = new DeleteCategoryCommand { Id = id };
|
||||
var result = await mediator.Send(command);
|
||||
|
||||
if (!result)
|
||||
return NotFound();
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
48
src/Imprink.WebApi/Controllers/ProductVariantsController.cs
Normal file
48
src/Imprink.WebApi/Controllers/ProductVariantsController.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Imprink.Application.Products.Commands;
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using Imprink.Application.Products.Queries;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Imprink.WebApi.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class ProductVariantsController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<IEnumerable<ProductVariantDto>>> GetProductVariants(
|
||||
[FromQuery] Guid? productId = null,
|
||||
[FromQuery] bool? isActive = null,
|
||||
[FromQuery] bool inStockOnly = false)
|
||||
{
|
||||
var query = new GetProductVariantsQuery
|
||||
{
|
||||
ProductId = productId,
|
||||
IsActive = isActive,
|
||||
InStockOnly = inStockOnly
|
||||
};
|
||||
|
||||
var result = await mediator.Send(query);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<ProductVariantDto>> CreateProductVariant([FromBody] CreateProductVariantCommand command)
|
||||
{
|
||||
var result = await mediator.Send(command);
|
||||
return CreatedAtAction(nameof(CreateProductVariant), new { id = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
public async Task<ActionResult> DeleteProductVariant(Guid id)
|
||||
{
|
||||
var command = new DeleteProductVariantCommand { Id = id };
|
||||
var result = await mediator.Send(command);
|
||||
|
||||
if (!result)
|
||||
return NotFound();
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
65
src/Imprink.WebApi/Controllers/ProductsController.cs
Normal file
65
src/Imprink.WebApi/Controllers/ProductsController.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using Imprink.Application.Products.Commands;
|
||||
using Imprink.Application.Products.Dtos;
|
||||
using Imprink.Application.Products.Queries;
|
||||
using Imprink.Domain.Common.Models;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Imprink.WebApi.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class ProductsController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<PagedResultDto<ProductDto>>> GetProducts(
|
||||
[FromQuery] int pageNumber = 1,
|
||||
[FromQuery] int pageSize = 10,
|
||||
[FromQuery] string? searchTerm = null,
|
||||
[FromQuery] Guid? categoryId = null,
|
||||
[FromQuery] decimal? minPrice = null,
|
||||
[FromQuery] decimal? maxPrice = null,
|
||||
[FromQuery] bool? isActive = true,
|
||||
[FromQuery] bool? isCustomizable = null,
|
||||
[FromQuery] string sortBy = "Name",
|
||||
[FromQuery] string sortDirection = "ASC")
|
||||
{
|
||||
var filterParameters = new ProductFilterParameters
|
||||
{
|
||||
PageNumber = pageNumber,
|
||||
PageSize = pageSize,
|
||||
SearchTerm = searchTerm,
|
||||
CategoryId = categoryId,
|
||||
MinPrice = minPrice,
|
||||
MaxPrice = maxPrice,
|
||||
IsActive = isActive,
|
||||
IsCustomizable = isCustomizable,
|
||||
SortBy = sortBy,
|
||||
SortDirection = sortDirection
|
||||
};
|
||||
|
||||
var query = new GetProductsQuery { FilterParameters = filterParameters };
|
||||
var result = await mediator.Send(query);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<ProductDto>> CreateProduct([FromBody] CreateProductCommand command)
|
||||
{
|
||||
var result = await mediator.Send(command);
|
||||
return CreatedAtAction(nameof(CreateProduct), new { id = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
public async Task<ActionResult> DeleteProduct(Guid id)
|
||||
{
|
||||
var command = new DeleteProductCommand { Id = id };
|
||||
var result = await mediator.Send(command);
|
||||
|
||||
if (!result)
|
||||
return NotFound();
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
24
src/Imprink.WebApi/Imprink.WebApi.csproj
Normal file
24
src/Imprink.WebApi/Imprink.WebApi.csproj
Normal file
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MediatR" Version="12.5.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Imprink.Application\Imprink.Application.csproj" />
|
||||
<ProjectReference Include="..\Imprink.Infrastructure\Imprink.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
11
src/Imprink.WebApi/Program.cs
Normal file
11
src/Imprink.WebApi/Program.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Imprink.WebApi;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
Startup.ConfigureServices(builder);
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
Startup.Configure(app, app.Environment);
|
||||
|
||||
app.Run();
|
||||
23
src/Imprink.WebApi/Properties/launchSettings.json
Normal file
23
src/Imprink.WebApi/Properties/launchSettings.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:5220",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "https://localhost:7277;http://localhost:5220",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
128
src/Imprink.WebApi/Startup.cs
Normal file
128
src/Imprink.WebApi/Startup.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using Imprink.Application;
|
||||
using Imprink.Application.Products.Handlers;
|
||||
using Imprink.Domain.Entities.Users;
|
||||
using Imprink.Domain.Repositories;
|
||||
using Imprink.Infrastructure;
|
||||
using Imprink.Infrastructure.Database;
|
||||
using Imprink.Infrastructure.Repositories;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Imprink.WebApi;
|
||||
|
||||
public static class Startup
|
||||
{
|
||||
public static void ConfigureServices(WebApplicationBuilder builder)
|
||||
{
|
||||
var services = builder.Services;
|
||||
|
||||
services.AddScoped<IProductRepository, ProductRepository>();
|
||||
services.AddScoped<IProductVariantRepository, ProductVariantRepository>();
|
||||
services.AddScoped<ICategoryRepository, CategoryRepository>();
|
||||
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
||||
|
||||
services.AddDbContext<ApplicationDbContext>(options =>
|
||||
options.UseSqlServer(
|
||||
builder.Configuration.GetConnectionString("DefaultConnection"),
|
||||
b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));
|
||||
|
||||
services.AddMediatR(cfg =>
|
||||
{
|
||||
cfg.RegisterServicesFromAssembly(typeof(CreateProductHandler).Assembly);
|
||||
});
|
||||
|
||||
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
|
||||
{
|
||||
options.Password.RequireDigit = true;
|
||||
options.Password.RequireLowercase = true;
|
||||
options.Password.RequireUppercase = true;
|
||||
options.Password.RequireNonAlphanumeric = true;
|
||||
options.Password.RequiredLength = 8;
|
||||
options.Password.RequiredUniqueChars = 1;
|
||||
|
||||
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
|
||||
options.Lockout.MaxFailedAccessAttempts = 5;
|
||||
options.Lockout.AllowedForNewUsers = true;
|
||||
|
||||
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
|
||||
options.User.RequireUniqueEmail = true;
|
||||
|
||||
options.SignIn.RequireConfirmedEmail = true;
|
||||
options.SignIn.RequireConfirmedPhoneNumber = false;
|
||||
})
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>()
|
||||
.AddDefaultTokenProviders();
|
||||
|
||||
services.ConfigureApplicationCookie(options =>
|
||||
{
|
||||
options.Cookie.HttpOnly = true;
|
||||
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
|
||||
options.LoginPath = "/Account/Login";
|
||||
options.AccessDeniedPath = "/Account/AccessDenied";
|
||||
options.SlidingExpiration = true;
|
||||
});
|
||||
|
||||
services.Configure<DataProtectionTokenProviderOptions>(options =>
|
||||
{
|
||||
options.TokenLifespan = TimeSpan.FromHours(24);
|
||||
});
|
||||
|
||||
services.AddAuthorizationBuilder()
|
||||
.AddPolicy("AdminPolicy", policy =>
|
||||
policy.RequireRole("Administrator"))
|
||||
.AddPolicy("OrderManagementPolicy", policy =>
|
||||
policy.RequireRole("Administrator", "OrderManager"))
|
||||
.AddPolicy("ProductManagementPolicy", policy =>
|
||||
policy.RequireRole("Administrator", "ProductManager"))
|
||||
.AddPolicy("CustomerPolicy", policy =>
|
||||
policy.RequireRole("Customer", "Administrator", "OrderManager", "ProductManager"));
|
||||
|
||||
services.AddControllers();
|
||||
services.AddSwaggerGen();
|
||||
}
|
||||
|
||||
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
if (app is WebApplication application)
|
||||
{
|
||||
using var scope = application.Services.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
||||
try
|
||||
{
|
||||
dbContext.Database.Migrate();
|
||||
Console.WriteLine("Database migrations applied successfully");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An error occurred while applying migrations: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// if (env.IsDevelopment())
|
||||
// {
|
||||
// app.UseSwagger();
|
||||
// app.UseSwaggerUI();
|
||||
// app.UseDeveloperExceptionPage();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// app.UseExceptionHandler("/Error");
|
||||
// app.UseHsts();
|
||||
// app.UseHttpsRedirection();
|
||||
// }
|
||||
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.UseDeveloperExceptionPage();
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
});
|
||||
}
|
||||
}
|
||||
15
src/Imprink.WebApi/appsettings.Development.json
Normal file
15
src/Imprink.WebApi/appsettings.Development.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Debug",
|
||||
"Microsoft.EntityFrameworkCore": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Server=localhost;Database=Printbase;Encrypt=false;Trusted_Connection=True;TrustServerCertificate=true;MultipleActiveResultSets=true;"
|
||||
},
|
||||
"DatabaseOptions": {
|
||||
"ApplyMigrationsAtStartup": true
|
||||
}
|
||||
}
|
||||
15
src/Imprink.WebApi/appsettings.json
Normal file
15
src/Imprink.WebApi/appsettings.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Debug",
|
||||
"Microsoft.EntityFrameworkCore": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Server=localhost;Database=Printbase;Encrypt=false;TrustServerCertificate=true;Trusted_Connection=True;MultipleActiveResultSets=true;"
|
||||
},
|
||||
"DatabaseOptions": {
|
||||
"ApplyMigrationsAtStartup": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Imprink.Application\Imprink.Application.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
22
tests/Imprink.Domain.Tests/Imprink.Domain.Tests.csproj
Normal file
22
tests/Imprink.Domain.Tests/Imprink.Domain.Tests.csproj
Normal file
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Imprink.Infrastructure\Imprink.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
22
tests/Imprink.WebApi.Tests/Imprink.WebApi.Tests.csproj
Normal file
22
tests/Imprink.WebApi.Tests/Imprink.WebApi.Tests.csproj
Normal file
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user