Rebadge the rest of the files

This commit is contained in:
lumijiez
2025-06-03 18:24:40 +03:00
parent 1b6f69fcf9
commit 6a675ac111
77 changed files with 5931 additions and 0 deletions

View 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);
}

View 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>

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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;
}

View File

@@ -0,0 +1,8 @@
using MediatR;
namespace Imprink.Application.Products.Commands;
public class DeleteCategoryCommand : IRequest<bool>
{
public Guid Id { get; set; }
}

View File

@@ -0,0 +1,8 @@
using MediatR;
namespace Imprink.Application.Products.Commands;
public class DeleteProductCommand : IRequest<bool>
{
public Guid Id { get; set; }
}

View File

@@ -0,0 +1,8 @@
using MediatR;
namespace Imprink.Application.Products.Commands;
public class DeleteProductVariantCommand : IRequest<bool>
{
public Guid Id { get; set; }
}

View 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; }
}

View 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;
}

View 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; }
}

View 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; }
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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
});
}
}

View File

@@ -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
});
}
}

View File

@@ -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
};
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View 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();
}