initial commit

This commit is contained in:
2026-07-21 15:36:49 +07:00
commit 77f66132bc
2640 changed files with 850901 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
*.css linguist-vendored
*.html linguist-vendored
*.htm linguist-vendored
*.js linguist-vendored
*.php linguist-vendored
*.cshtml linguist-language=C#
*.css linguist-detectable=false
+2
View File
@@ -0,0 +1,2 @@
.vs/
obj/
+21
View File
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Domain\Domain.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.11.0" />
<PackageReference Include="MediatR" Version="12.4.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
</ItemGroup>
</Project>
@@ -0,0 +1,34 @@
using MediatR;
using Microsoft.Extensions.Logging;
namespace Application.Common.Behaviors;
public class LoggingBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull
{
private readonly ILogger<TRequest> _logger;
public LoggingBehaviour(ILogger<TRequest> logger)
{
_logger = logger;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
var requestName = typeof(TRequest).Name;
try
{
_logger.LogInformation($"Try executing {requestName} at {DateTime.UtcNow.ToString()}");
return await next();
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error executing {requestName} at {DateTime.UtcNow.ToString()}");
throw;
}
}
}
@@ -0,0 +1,37 @@
using FluentValidation;
using MediatR;
namespace Application.Common.Behaviors;
public class ValidationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehaviour(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
if (_validators.Any())
{
var context = new ValidationContext<TRequest>(request);
var validationResults = await Task.WhenAll(
_validators.Select(v =>
v.ValidateAsync(context, cancellationToken)));
var failures = validationResults
.Where(r => r.Errors.Any())
.SelectMany(r => r.Errors)
.ToList();
if (failures.Any())
throw new ValidationException(failures);
}
return await next();
}
}
@@ -0,0 +1,5 @@
namespace Application.Common.CQS.Commands;
public interface ICommandContext
{
}
@@ -0,0 +1,9 @@
using Application.Common.Repositories;
namespace Application.Common.CQS.Queries;
public interface IQueryContext : IEntityDbSet
{
IQueryable<T> Set<T>() where T : class;
}
@@ -0,0 +1,16 @@
using System.ComponentModel;
using System.Reflection;
namespace Application.Common.Extensions;
public static class EnumExtensions
{
public static string ToFriendlyName<TEnum>(this TEnum value) where TEnum : Enum
{
var memberInfo = typeof(TEnum).GetMember(value.ToString());
var descriptionAttribute = memberInfo[0]
.GetCustomAttribute<DescriptionAttribute>();
return descriptionAttribute?.Description ?? value.ToString();
}
}
@@ -0,0 +1,20 @@
using Domain.Common;
namespace Application.Common.Extensions;
public static class QueryableExtensions
{
public static IQueryable<T> IsDeletedEqualTo<T>(this IQueryable<T> query, bool isDeleted = false) where T : class
{
if (typeof(IHasIsDeleted).IsAssignableFrom(typeof(T)))
{
query = query.Where(x => (x as IHasIsDeleted)!.IsDeleted == isDeleted);
}
return query;
}
}
@@ -0,0 +1,24 @@
using Domain.Common;
namespace Application.Common.Repositories;
public interface ICommandRepository<T> where T : BaseEntity
{
Task CreateAsync(T entity, CancellationToken cancellationToken = default);
void Create(T entity);
void Update(T entity);
void Delete(T entity);
void Purge(T entity);
Task<T?> GetAsync(string id, CancellationToken cancellationToken = default);
T? Get(string id);
IQueryable<T> GetQuery();
}
@@ -0,0 +1,43 @@
using Domain.Entities;
using Microsoft.EntityFrameworkCore;
namespace Application.Common.Repositories;
public interface IEntityDbSet
{
public DbSet<Token> Token { get; set; }
public DbSet<Todo> Todo { get; set; }
public DbSet<TodoItem> TodoItem { get; set; }
public DbSet<Company> Company { get; set; }
public DbSet<FileImage> FileImage { get; set; }
public DbSet<FileDocument> FileDocument { get; set; }
public DbSet<NumberSequence> NumberSequence { get; set; }
public DbSet<CustomerGroup> CustomerGroup { get; set; }
public DbSet<CustomerCategory> CustomerCategory { get; set; }
public DbSet<VendorGroup> VendorGroup { get; set; }
public DbSet<VendorCategory> VendorCategory { get; set; }
public DbSet<Customer> Customer { get; set; }
public DbSet<Vendor> Vendor { get; set; }
public DbSet<UnitMeasure> UnitMeasure { get; set; }
public DbSet<ProductGroup> ProductGroup { get; set; }
public DbSet<Product> Product { get; set; }
public DbSet<CustomerContact> CustomerContact { get; set; }
public DbSet<VendorContact> VendorContact { get; set; }
public DbSet<Tax> Tax { get; set; }
public DbSet<SalesOrder> SalesOrder { get; set; }
public DbSet<SalesOrderItem> SalesOrderItem { get; set; }
public DbSet<PurchaseOrder> PurchaseOrder { get; set; }
public DbSet<PurchaseOrderItem> PurchaseOrderItem { get; set; }
public DbSet<Campaign> Campaign { get; set; }
public DbSet<Budget> Budget { get; set; }
public DbSet<Expense> Expense { get; set; }
public DbSet<Lead> Lead { get; set; }
public DbSet<LeadContact> LeadContact { get; set; }
public DbSet<LeadActivity> LeadActivity { get; set; }
public DbSet<SalesTeam> SalesTeam { get; set; }
public DbSet<SalesRepresentative> SalesRepresentative { get; set; }
}
@@ -0,0 +1,7 @@
namespace Application.Common.Repositories;
public interface IUnitOfWork
{
Task SaveAsync(CancellationToken cancellationToken = default);
void Save();
}
@@ -0,0 +1,7 @@
namespace Application.Common.Services.EmailManager;
public interface IEmailService
{
Task SendEmailAsync(string email, string subject, string htmlMessage);
}
@@ -0,0 +1,14 @@
namespace Application.Common.Services.FileDocumentManager;
public interface IFileDocumentService
{
Task<string> UploadAsync(
string? originalFileName,
string? docExtension,
byte[]? fileData,
long? size,
string? description = "",
string? createdById = "",
CancellationToken cancellationToken = default);
Task<byte[]> GetFileAsync(string fileName, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,13 @@
namespace Application.Common.Services.FileImageManager;
public interface IFileImageService
{
Task<string> UploadAsync(
string? originalFileName,
string? docExtension,
byte[]? fileData,
long? size,
string? description = "",
string? createdById = "",
CancellationToken cancellationToken = default);
Task<byte[]> GetFileAsync(string fileName, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,12 @@
namespace Application.Common.Services.SecurityManager;
public record CreateUserResultDto
{
public string? UserId { get; init; }
public string? Email { get; init; }
public string? FirstName { get; init; }
public string? LastName { get; init; }
public bool? EmailConfirmed { get; init; }
public bool? IsBlocked { get; init; }
public bool? IsDeleted { get; init; }
}
@@ -0,0 +1,12 @@
namespace Application.Common.Services.SecurityManager;
public record DeleteUserResultDto
{
public string? UserId { get; init; }
public string? Email { get; init; }
public string? FirstName { get; init; }
public string? LastName { get; init; }
public bool? EmailConfirmed { get; init; }
public bool? IsBlocked { get; init; }
public bool? IsDeleted { get; init; }
}
@@ -0,0 +1,9 @@
namespace Application.Common.Services.SecurityManager;
public record GetMyProfileListResultDto
{
public string? Id { get; init; }
public string? FirstName { get; init; }
public string? LastName { get; init; }
public string? CompanyName { get; init; }
}
@@ -0,0 +1,6 @@
namespace Application.Common.Services.SecurityManager;
public record GetRoleListResultDto
{
public string? Id { get; init; }
public string? Name { get; init; }
}
@@ -0,0 +1,13 @@
namespace Application.Common.Services.SecurityManager;
public record GetUserListResultDto
{
public string? Id { get; init; }
public string? FirstName { get; init; }
public string? LastName { get; init; }
public string? Email { get; init; }
public bool? EmailConfirmed { get; init; }
public bool? IsBlocked { get; init; }
public bool? IsDeleted { get; init; }
public DateTime? CreatedAt { get; init; }
}
@@ -0,0 +1,131 @@
namespace Application.Common.Services.SecurityManager;
public interface ISecurityService
{
public Task<LoginResultDto> LoginAsync(
string email,
string password,
CancellationToken cancellationToken = default
);
public Task<LogoutResultDto> LogoutAsync(
string userId,
CancellationToken cancellationToken = default
);
public Task<RegisterResultDto> RegisterAsync(
string email,
string password,
string confirmPassword,
string firstName,
string lastName,
string companyName = "",
CancellationToken cancellationToken = default
);
public Task<string> ConfirmEmailAsync(
string email,
string code,
CancellationToken cancellationToken = default
);
public Task<string> ForgotPasswordAsync(
string email,
CancellationToken cancellationToken = default
);
public Task<string> ForgotPasswordConfirmationAsync(
string email,
string tempPassword,
string code,
CancellationToken cancellationToken = default
);
public Task<RefreshTokenResultDto> RefreshTokenAsync(
string refreshToken,
CancellationToken cancellationToken
);
public Task<List<GetMyProfileListResultDto>> GetMyProfileListAsync(
string userId,
CancellationToken cancellationToken
);
public Task UpdateMyProfileAsync(
string userId,
string firstName,
string lastName,
string companyName,
CancellationToken cancellationToken
);
public Task ChangePasswordAsync(
string userId,
string oldPassword,
string newPassword,
string confirmNewPassword,
CancellationToken cancellationToken
);
public Task<List<GetRoleListResultDto>> GetRoleListAsync(
CancellationToken cancellationToken
);
public Task<List<GetUserListResultDto>> GetUserListAsync(
CancellationToken cancellationToken
);
public Task<CreateUserResultDto> CreateUserAsync(
string email,
string password,
string confirmPassword,
string firstName,
string lastName,
bool emailConfirmed = true,
bool isBlocked = false,
bool isDeleted = false,
string createdById = "",
CancellationToken cancellationToken = default
);
public Task<UpdateUserResultDto> UpdateUserAsync(
string userId,
string firstName,
string lastName,
bool emailConfirmed = true,
bool isBlocked = false,
bool isDeleted = false,
string updatedById = "",
CancellationToken cancellationToken = default
);
public Task<DeleteUserResultDto> DeleteUserAsync(
string userId,
string deletedById = "",
CancellationToken cancellationToken = default
);
public Task UpdatePasswordUserAsync(
string userId,
string newPassword,
CancellationToken cancellationToken
);
public Task<List<string>> GetUserRolesAsync(
string userId,
CancellationToken cancellationToken = default
);
public Task<List<string>> UpdateUserRoleAsync(
string userId,
string roleName,
bool accessGranted,
CancellationToken cancellationToken = default
);
public Task ChangeAvatarAsync(
string userId,
string avatar,
CancellationToken cancellationToken
);
}
@@ -0,0 +1,15 @@
namespace Application.Common.Services.SecurityManager;
public record LoginResultDto
{
public string? AccessToken { get; init; }
public string? RefreshToken { get; init; }
public string? UserId { get; init; }
public string? Email { get; init; }
public string? FirstName { get; init; }
public string? LastName { get; init; }
public string? CompanyName { get; init; }
public string? Avatar { get; init; }
public List<MenuNavigationTreeNodeDto>? MenuNavigation { get; init; }
public List<string>? Roles { get; init; }
}
@@ -0,0 +1,13 @@
namespace Application.Common.Services.SecurityManager;
public record LogoutResultDto
{
public string? AccessToken { get; init; }
public string? RefreshToken { get; init; }
public string? UserId { get; init; }
public string? Email { get; init; }
public string? FirstName { get; init; }
public string? LastName { get; init; }
public string? CompanyName { get; init; }
public List<string>? UserClaims { get; init; }
}
@@ -0,0 +1,23 @@
namespace Application.Common.Services.SecurityManager;
public class MenuNavigationTreeNodeDto
{
public string Id { get; set; }
public string Name { get; set; }
public string? Pid { get; set; }
public string? NavURL { get; set; }
public bool HasChild { get; set; }
public bool Expanded { get; set; }
public bool IsSelected { get; set; }
public MenuNavigationTreeNodeDto(string param_id, string param_name, string? param_pid = null, string? param_navURL = null, bool param_hasChild = false, bool param_expanded = false, bool param_selected = false)
{
Id = param_id;
Name = param_name;
Pid = param_pid;
NavURL = param_navURL;
HasChild = param_hasChild;
Expanded = param_expanded;
IsSelected = param_selected;
}
}
@@ -0,0 +1,15 @@
namespace Application.Common.Services.SecurityManager;
public record RefreshTokenResultDto
{
public string? AccessToken { get; init; }
public string? RefreshToken { get; init; }
public string? UserId { get; init; }
public string? Email { get; init; }
public string? FirstName { get; init; }
public string? LastName { get; init; }
public string? CompanyName { get; init; }
public string? Avatar { get; init; }
public List<MenuNavigationTreeNodeDto>? MenuNavigation { get; init; }
public List<string>? Roles { get; init; }
}
@@ -0,0 +1,10 @@
namespace Application.Common.Services.SecurityManager;
public record RegisterResultDto
{
public string? UserId { get; init; }
public string? Email { get; init; }
public string? FirstName { get; init; }
public string? LastName { get; init; }
public string? CompanyName { get; init; }
}
@@ -0,0 +1,12 @@
namespace Application.Common.Services.SecurityManager;
public record UpdateUserResultDto
{
public string? UserId { get; init; }
public string? Email { get; init; }
public string? FirstName { get; init; }
public string? LastName { get; init; }
public bool? EmailConfirmed { get; init; }
public bool? IsBlocked { get; init; }
public bool? IsDeleted { get; init; }
}
+49
View File
@@ -0,0 +1,49 @@
using Application.Common.Behaviors;
using FluentValidation;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace Application;
public static class DependencyInjection
{
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
{
//>>> AutoMapper
services.AddAutoMapper(Assembly.GetExecutingAssembly());
//>>> FluentValidation
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
//>>> MediatR
services.AddMediatR(x =>
{
x.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
x.AddBehavior(typeof(IPipelineBehavior<,>), typeof(LoggingBehaviour<,>));
x.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>));
});
//>>> Register services in Application.Features
var assembly = Assembly.GetExecutingAssembly();
var featureTypes = assembly.GetTypes()
.Where(type => type.IsClass && !type.IsAbstract)
.Where(type => type.Namespace != null && type.Namespace.StartsWith("Application.Features"));
foreach (var type in featureTypes)
{
var interfaces = type.GetInterfaces();
foreach (var serviceInterface in interfaces)
{
services.AddScoped(serviceInterface, type);
}
if (!interfaces.Any())
{
services.AddScoped(type);
}
}
return services;
}
}
@@ -0,0 +1,77 @@
using Application.Common.Repositories;
using Application.Features.NumberSequenceManager;
using Domain.Entities;
using Domain.Enums;
using FluentValidation;
using MediatR;
namespace Application.Features.BudgetManager.Commands;
public class CreateBudgetResult
{
public Budget? Data { get; set; }
}
public class CreateBudgetRequest : IRequest<CreateBudgetResult>
{
public string? Title { get; init; }
public string? Description { get; init; }
public DateTime? BudgetDate { get; init; }
public string? Status { get; init; }
public double? Amount { get; init; }
public string? CampaignId { get; init; }
public string? CreatedById { get; init; }
}
public class CreateBudgetValidator : AbstractValidator<CreateBudgetRequest>
{
public CreateBudgetValidator()
{
RuleFor(x => x.Title).NotEmpty();
RuleFor(x => x.BudgetDate).NotNull();
RuleFor(x => x.Amount).NotNull();
RuleFor(x => x.CampaignId).NotEmpty();
RuleFor(x => x.Status).NotEmpty();
}
}
public class CreateBudgetHandler : IRequestHandler<CreateBudgetRequest, CreateBudgetResult>
{
private readonly ICommandRepository<Budget> _repository;
private readonly IUnitOfWork _unitOfWork;
private readonly NumberSequenceService _numberSequenceService;
public CreateBudgetHandler(
ICommandRepository<Budget> repository,
IUnitOfWork unitOfWork,
NumberSequenceService numberSequenceService
)
{
_repository = repository;
_unitOfWork = unitOfWork;
_numberSequenceService = numberSequenceService;
}
public async Task<CreateBudgetResult> Handle(CreateBudgetRequest request, CancellationToken cancellationToken = default)
{
var entity = new Budget
{
CreatedById = request.CreatedById,
Number = _numberSequenceService.GenerateNumber(nameof(Budget), "", "BUD"),
Title = request.Title,
Description = request.Description,
BudgetDate = request.BudgetDate,
Status = (BudgetStatus)int.Parse(request.Status!),
Amount = request.Amount,
CampaignId = request.CampaignId
};
await _repository.CreateAsync(entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
return new CreateBudgetResult
{
Data = entity
};
}
}
@@ -0,0 +1,60 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.BudgetManager.Commands;
public class DeleteBudgetResult
{
public Budget? Data { get; set; }
}
public class DeleteBudgetRequest : IRequest<DeleteBudgetResult>
{
public string? Id { get; init; }
public string? DeletedById { get; init; }
}
public class DeleteBudgetValidator : AbstractValidator<DeleteBudgetRequest>
{
public DeleteBudgetValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class DeleteBudgetHandler : IRequestHandler<DeleteBudgetRequest, DeleteBudgetResult>
{
private readonly ICommandRepository<Budget> _repository;
private readonly IUnitOfWork _unitOfWork;
public DeleteBudgetHandler(
ICommandRepository<Budget> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<DeleteBudgetResult> Handle(DeleteBudgetRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.DeletedById;
_repository.Delete(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new DeleteBudgetResult
{
Data = entity
};
}
}
@@ -0,0 +1,78 @@
using Application.Common.Repositories;
using Domain.Entities;
using Domain.Enums;
using FluentValidation;
using MediatR;
namespace Application.Features.BudgetManager.Commands;
public class UpdateBudgetResult
{
public Budget? Data { get; set; }
}
public class UpdateBudgetRequest : IRequest<UpdateBudgetResult>
{
public string? Id { get; init; }
public string? Title { get; init; }
public string? Description { get; init; }
public DateTime? BudgetDate { get; init; }
public string? Status { get; init; }
public double? Amount { get; init; }
public string? CampaignId { get; init; }
public string? UpdatedById { get; init; }
}
public class UpdateBudgetValidator : AbstractValidator<UpdateBudgetRequest>
{
public UpdateBudgetValidator()
{
RuleFor(x => x.Id).NotEmpty();
RuleFor(x => x.Title).NotEmpty();
RuleFor(x => x.BudgetDate).NotNull();
RuleFor(x => x.Amount).NotNull();
RuleFor(x => x.CampaignId).NotEmpty();
RuleFor(x => x.Status).NotEmpty();
}
}
public class UpdateBudgetHandler : IRequestHandler<UpdateBudgetRequest, UpdateBudgetResult>
{
private readonly ICommandRepository<Budget> _repository;
private readonly IUnitOfWork _unitOfWork;
public UpdateBudgetHandler(
ICommandRepository<Budget> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<UpdateBudgetResult> Handle(UpdateBudgetRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.UpdatedById;
entity.Title = request.Title;
entity.Description = request.Description;
entity.BudgetDate = request.BudgetDate;
entity.Status = (BudgetStatus)int.Parse(request.Status!);
entity.Amount = request.Amount;
entity.CampaignId = request.CampaignId;
_repository.Update(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new UpdateBudgetResult
{
Data = entity
};
}
}
@@ -0,0 +1,82 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.BudgetManager.Queries;
public record GetBudgetByCampaignIdListDto
{
public string? Id { get; init; }
public string? Number { get; init; }
public string? Title { get; init; }
public string? Description { get; init; }
public DateTime? BudgetDate { get; init; }
public BudgetStatus? Status { get; init; }
public string? StatusName { get; init; }
public double? Amount { get; init; }
public string? CampaignId { get; init; }
public string? CampaignName { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetBudgetByCampaignIdListProfile : Profile
{
public GetBudgetByCampaignIdListProfile()
{
CreateMap<Budget, GetBudgetByCampaignIdListDto>()
.ForMember(
dest => dest.CampaignName,
opt => opt.MapFrom(src => src.Campaign != null ? src.Campaign.Title : string.Empty)
)
.ForMember(
dest => dest.StatusName,
opt => opt.MapFrom(src => src.Status.HasValue ? src.Status.Value.ToFriendlyName() : string.Empty)
);
}
}
public class GetBudgetByCampaignIdListResult
{
public List<GetBudgetByCampaignIdListDto>? Data { get; init; }
}
public class GetBudgetByCampaignIdListRequest : IRequest<GetBudgetByCampaignIdListResult>
{
public string? CampaignId { get; init; }
}
public class GetBudgetByCampaignIdListHandler : IRequestHandler<GetBudgetByCampaignIdListRequest, GetBudgetByCampaignIdListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetBudgetByCampaignIdListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetBudgetByCampaignIdListResult> Handle(GetBudgetByCampaignIdListRequest request, CancellationToken cancellationToken)
{
var query = _context
.Budget
.AsNoTracking()
.IsDeletedEqualTo(false)
.Include(x => x.Campaign)
.Where(x => x.CampaignId == request.CampaignId)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetBudgetByCampaignIdListDto>>(entities);
return new GetBudgetByCampaignIdListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,81 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.BudgetManager.Queries;
public record GetBudgetListDto
{
public string? Id { get; init; }
public string? Number { get; init; }
public string? Title { get; init; }
public string? Description { get; init; }
public DateTime? BudgetDate { get; init; }
public BudgetStatus? Status { get; init; }
public string? StatusName { get; init; }
public double? Amount { get; init; }
public string? CampaignId { get; init; }
public string? CampaignName { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetBudgetListProfile : Profile
{
public GetBudgetListProfile()
{
CreateMap<Budget, GetBudgetListDto>()
.ForMember(
dest => dest.CampaignName,
opt => opt.MapFrom(src => src.Campaign != null ? src.Campaign.Title : string.Empty)
)
.ForMember(
dest => dest.StatusName,
opt => opt.MapFrom(src => src.Status.HasValue ? src.Status.Value.ToFriendlyName() : string.Empty)
);
}
}
public class GetBudgetListResult
{
public List<GetBudgetListDto>? Data { get; init; }
}
public class GetBudgetListRequest : IRequest<GetBudgetListResult>
{
public bool IsDeleted { get; init; } = false;
}
public class GetBudgetListHandler : IRequestHandler<GetBudgetListRequest, GetBudgetListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetBudgetListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetBudgetListResult> Handle(GetBudgetListRequest request, CancellationToken cancellationToken)
{
var query = _context
.Budget
.AsNoTracking()
.IsDeletedEqualTo(request.IsDeleted)
.Include(x => x.Campaign)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetBudgetListDto>>(entities);
return new GetBudgetListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,62 @@
using Application.Common.CQS.Queries;
using AutoMapper;
using Domain.Entities;
using FluentValidation;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.BudgetManager.Queries;
public class GetBudgetSingleProfile : Profile
{
public GetBudgetSingleProfile()
{
}
}
public class GetBudgetSingleResult
{
public Budget? Data { get; init; }
}
public class GetBudgetSingleRequest : IRequest<GetBudgetSingleResult>
{
public string? Id { get; init; }
}
public class GetBudgetSingleValidator : AbstractValidator<GetBudgetSingleRequest>
{
public GetBudgetSingleValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class GetBudgetSingleHandler : IRequestHandler<GetBudgetSingleRequest, GetBudgetSingleResult>
{
private readonly IQueryContext _context;
public GetBudgetSingleHandler(
IQueryContext context
)
{
_context = context;
}
public async Task<GetBudgetSingleResult> Handle(GetBudgetSingleRequest request, CancellationToken cancellationToken)
{
var query = _context
.Budget
.AsNoTracking()
.Include(x => x.Campaign)
.Where(x => x.Id == request.Id)
.AsQueryable();
var entity = await query.SingleOrDefaultAsync(cancellationToken);
return new GetBudgetSingleResult
{
Data = entity
};
}
}
@@ -0,0 +1,55 @@
using Application.Common.Extensions;
using AutoMapper;
using Domain.Enums;
using MediatR;
namespace Application.Features.BudgetManager.Queries;
public record GetBudgetStatusListDto
{
public string? Id { get; init; }
public string? Name { get; init; }
}
public class GetBudgetStatusListProfile : Profile
{
public GetBudgetStatusListProfile()
{
}
}
public class GetBudgetStatusListResult
{
public List<GetBudgetStatusListDto>? Data { get; init; }
}
public class GetBudgetStatusListRequest : IRequest<GetBudgetStatusListResult>
{
}
public class GetBudgetStatusListHandler : IRequestHandler<GetBudgetStatusListRequest, GetBudgetStatusListResult>
{
public GetBudgetStatusListHandler()
{
}
public async Task<GetBudgetStatusListResult> Handle(GetBudgetStatusListRequest request, CancellationToken cancellationToken)
{
var statuses = Enum.GetValues(typeof(BudgetStatus))
.Cast<BudgetStatus>()
.Select(status => new GetBudgetStatusListDto
{
Id = ((int)status).ToString(),
Name = status.ToFriendlyName()
})
.ToList();
await Task.CompletedTask;
return new GetBudgetStatusListResult
{
Data = statuses
};
}
}
@@ -0,0 +1,79 @@
using Application.Common.Repositories;
using Application.Features.NumberSequenceManager;
using Domain.Entities;
using Domain.Enums;
using FluentValidation;
using MediatR;
namespace Application.Features.CampaignManager.Commands;
public class CreateCampaignResult
{
public Campaign? Data { get; set; }
}
public class CreateCampaignRequest : IRequest<CreateCampaignResult>
{
public string? Title { get; init; }
public string? Description { get; init; }
public double? TargetRevenueAmount { get; init; }
public DateTime? CampaignDateStart { get; init; }
public DateTime? CampaignDateFinish { get; init; }
public string? SalesTeamId { get; init; }
public string? Status { get; init; }
public string? CreatedById { get; init; }
}
public class CreateCampaignValidator : AbstractValidator<CreateCampaignRequest>
{
public CreateCampaignValidator()
{
RuleFor(x => x.Title).NotEmpty();
RuleFor(x => x.SalesTeamId).NotEmpty();
RuleFor(x => x.CampaignDateStart).NotEmpty();
RuleFor(x => x.CampaignDateFinish).NotEmpty();
RuleFor(x => x.TargetRevenueAmount).NotEmpty();
RuleFor(x => x.Status).NotEmpty();
}
}
public class CreateCampaignHandler : IRequestHandler<CreateCampaignRequest, CreateCampaignResult>
{
private readonly ICommandRepository<Campaign> _repository;
private readonly IUnitOfWork _unitOfWork;
private readonly NumberSequenceService _numberSequenceService;
public CreateCampaignHandler(
ICommandRepository<Campaign> repository,
IUnitOfWork unitOfWork,
NumberSequenceService numberSequenceService
)
{
_repository = repository;
_unitOfWork = unitOfWork;
_numberSequenceService = numberSequenceService;
}
public async Task<CreateCampaignResult> Handle(CreateCampaignRequest request, CancellationToken cancellationToken = default)
{
var entity = new Campaign();
entity.CreatedById = request.CreatedById;
entity.Number = _numberSequenceService.GenerateNumber(nameof(Campaign), "", "CAM");
entity.Title = request.Title;
entity.SalesTeamId = request.SalesTeamId;
entity.Description = request.Description;
entity.TargetRevenueAmount = request.TargetRevenueAmount;
entity.CampaignDateStart = request.CampaignDateStart;
entity.CampaignDateFinish = request.CampaignDateFinish;
entity.Status = (CampaignStatus)int.Parse(request.Status!);
await _repository.CreateAsync(entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
return new CreateCampaignResult
{
Data = entity
};
}
}
@@ -0,0 +1,60 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CampaignManager.Commands;
public class DeleteCampaignResult
{
public Campaign? Data { get; set; }
}
public class DeleteCampaignRequest : IRequest<DeleteCampaignResult>
{
public string? Id { get; init; }
public string? DeletedById { get; init; }
}
public class DeleteCampaignValidator : AbstractValidator<DeleteCampaignRequest>
{
public DeleteCampaignValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class DeleteCampaignHandler : IRequestHandler<DeleteCampaignRequest, DeleteCampaignResult>
{
private readonly ICommandRepository<Campaign> _repository;
private readonly IUnitOfWork _unitOfWork;
public DeleteCampaignHandler(
ICommandRepository<Campaign> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<DeleteCampaignResult> Handle(DeleteCampaignRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.DeletedById;
_repository.Delete(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new DeleteCampaignResult
{
Data = entity
};
}
}
@@ -0,0 +1,82 @@
using Application.Common.Repositories;
using Domain.Entities;
using Domain.Enums;
using FluentValidation;
using MediatR;
namespace Application.Features.CampaignManager.Commands;
public class UpdateCampaignResult
{
public Campaign? Data { get; set; }
}
public class UpdateCampaignRequest : IRequest<UpdateCampaignResult>
{
public string? Id { get; init; }
public string? Title { get; init; }
public string? Description { get; init; }
public double? TargetRevenueAmount { get; init; }
public DateTime? CampaignDateStart { get; init; }
public DateTime? CampaignDateFinish { get; init; }
public string? SalesTeamId { get; init; }
public string? Status { get; init; }
public string? UpdatedById { get; init; }
}
public class UpdateCampaignValidator : AbstractValidator<UpdateCampaignRequest>
{
public UpdateCampaignValidator()
{
RuleFor(x => x.Id).NotEmpty();
RuleFor(x => x.Title).NotEmpty();
RuleFor(x => x.SalesTeamId).NotEmpty();
RuleFor(x => x.CampaignDateStart).NotEmpty();
RuleFor(x => x.CampaignDateFinish).NotEmpty();
RuleFor(x => x.Status).NotEmpty();
RuleFor(x => x.Status).NotEmpty();
}
}
public class UpdateCampaignHandler : IRequestHandler<UpdateCampaignRequest, UpdateCampaignResult>
{
private readonly ICommandRepository<Campaign> _repository;
private readonly IUnitOfWork _unitOfWork;
public UpdateCampaignHandler(
ICommandRepository<Campaign> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<UpdateCampaignResult> Handle(UpdateCampaignRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.UpdatedById;
entity.Title = request.Title;
entity.SalesTeamId = request.SalesTeamId;
entity.Description = request.Description;
entity.TargetRevenueAmount = request.TargetRevenueAmount;
entity.CampaignDateStart = request.CampaignDateStart;
entity.CampaignDateFinish = request.CampaignDateFinish;
entity.Status = (CampaignStatus)int.Parse(request.Status!);
_repository.Update(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new UpdateCampaignResult
{
Data = entity
};
}
}
@@ -0,0 +1,82 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.CampaignManager.Queries;
public record GetCampaignListDto
{
public string? Id { get; init; }
public string? Number { get; init; }
public string? Title { get; init; }
public string? Description { get; init; }
public double? TargetRevenueAmount { get; init; }
public DateTime? CampaignDateStart { get; init; }
public DateTime? CampaignDateFinish { get; init; }
public CampaignStatus? Status { get; init; }
public string? StatusName { get; init; }
public string? SalesTeamId { get; init; }
public string? SalesTeamName { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetCampaignListProfile : Profile
{
public GetCampaignListProfile()
{
CreateMap<Campaign, GetCampaignListDto>()
.ForMember(
dest => dest.StatusName,
opt => opt.MapFrom(src => src.Status.HasValue ? src.Status.Value.ToFriendlyName() : string.Empty)
)
.ForMember(
dest => dest.SalesTeamName,
opt => opt.MapFrom(src => src.SalesTeam != null ? src.SalesTeam.Name : string.Empty)
);
}
}
public class GetCampaignListResult
{
public List<GetCampaignListDto>? Data { get; init; }
}
public class GetCampaignListRequest : IRequest<GetCampaignListResult>
{
public bool IsDeleted { get; init; } = false;
}
public class GetCampaignListHandler : IRequestHandler<GetCampaignListRequest, GetCampaignListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetCampaignListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetCampaignListResult> Handle(GetCampaignListRequest request, CancellationToken cancellationToken)
{
var query = _context
.Campaign
.AsNoTracking()
.IsDeletedEqualTo(request.IsDeleted)
.Include(x => x.SalesTeam)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetCampaignListDto>>(entities);
return new GetCampaignListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,64 @@
using Application.Common.CQS.Queries;
using AutoMapper;
using Domain.Entities;
using FluentValidation;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.CampaignManager.Queries;
public class GetCampaignSingleProfile : Profile
{
public GetCampaignSingleProfile()
{
}
}
public class GetCampaignSingleResult
{
public Campaign? Data { get; init; }
}
public class GetCampaignSingleRequest : IRequest<GetCampaignSingleResult>
{
public string? Id { get; init; }
}
public class GetCampaignSingleValidator : AbstractValidator<GetCampaignSingleRequest>
{
public GetCampaignSingleValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class GetCampaignSingleHandler : IRequestHandler<GetCampaignSingleRequest, GetCampaignSingleResult>
{
private readonly IQueryContext _context;
public GetCampaignSingleHandler(
IQueryContext context
)
{
_context = context;
}
public async Task<GetCampaignSingleResult> Handle(GetCampaignSingleRequest request, CancellationToken cancellationToken)
{
var query = _context
.Campaign
.AsNoTracking()
.Include(x => x.CampaignBudgetList.Where(budget => !budget.IsDeleted))
.Include(x => x.CampaignExpenseList.Where(expense => !expense.IsDeleted))
.Include(x => x.CampaignLeadList.Where(lead => !lead.IsDeleted))
.Where(x => x.Id == request.Id)
.AsQueryable();
var entity = await query.SingleOrDefaultAsync(cancellationToken);
return new GetCampaignSingleResult
{
Data = entity
};
}
}
@@ -0,0 +1,54 @@
using Application.Common.Extensions;
using AutoMapper;
using Domain.Enums;
using MediatR;
namespace Application.Features.CampaignManager.Queries;
public record GetCampaignStatusListDto
{
public string? Id { get; init; }
public string? Name { get; init; }
}
public class GetCampaignStatusListProfile : Profile
{
public GetCampaignStatusListProfile()
{
}
}
public class GetCampaignStatusListResult
{
public List<GetCampaignStatusListDto>? Data { get; init; }
}
public class GetCampaignStatusListRequest : IRequest<GetCampaignStatusListResult>
{
}
public class GetCampaignStatusListHandler : IRequestHandler<GetCampaignStatusListRequest, GetCampaignStatusListResult>
{
public GetCampaignStatusListHandler()
{
}
public async Task<GetCampaignStatusListResult> Handle(GetCampaignStatusListRequest request, CancellationToken cancellationToken)
{
var statuses = Enum.GetValues(typeof(CampaignStatus))
.Cast<CampaignStatus>()
.Select(status => new GetCampaignStatusListDto
{
Id = ((int)status).ToString(),
Name = status.ToFriendlyName()
})
.ToList();
await Task.CompletedTask;
return new GetCampaignStatusListResult
{
Data = statuses
};
}
}
@@ -0,0 +1,95 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CompanyManager.Commands;
public class UpdateCompanyResult
{
public Company? Data { get; set; }
}
public class UpdateCompanyRequest : IRequest<UpdateCompanyResult>
{
public string? Id { get; init; }
public string? Name { get; init; }
public string? Description { get; init; }
public string? Currency { get; init; }
public string? Street { get; init; }
public string? City { get; init; }
public string? State { get; init; }
public string? ZipCode { get; init; }
public string? Country { get; init; }
public string? PhoneNumber { get; init; }
public string? FaxNumber { get; init; }
public string? EmailAddress { get; init; }
public string? Website { get; init; }
public string? UpdatedById { get; init; }
}
public class UpdateCompanyValidator : AbstractValidator<UpdateCompanyRequest>
{
public UpdateCompanyValidator()
{
RuleFor(x => x.Id).NotEmpty();
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Currency).NotEmpty();
RuleFor(x => x.Street).NotEmpty();
RuleFor(x => x.City).NotEmpty();
RuleFor(x => x.State).NotEmpty();
RuleFor(x => x.ZipCode).NotEmpty();
RuleFor(x => x.PhoneNumber).NotEmpty();
RuleFor(x => x.EmailAddress).NotEmpty();
}
}
public class UpdateCompanyHandler : IRequestHandler<UpdateCompanyRequest, UpdateCompanyResult>
{
private readonly ICommandRepository<Company> _repository;
private readonly IUnitOfWork _unitOfWork;
public UpdateCompanyHandler(
ICommandRepository<Company> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<UpdateCompanyResult> Handle(UpdateCompanyRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.UpdatedById;
entity.Name = request.Name;
entity.Description = request.Description;
entity.Currency = request.Currency;
entity.Street = request.Street;
entity.City = request.City;
entity.State = request.State;
entity.ZipCode = request.ZipCode;
entity.Country = request.Country;
entity.PhoneNumber = request.PhoneNumber;
entity.FaxNumber = request.FaxNumber;
entity.EmailAddress = request.EmailAddress;
entity.Website = request.Website;
_repository.Update(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new UpdateCompanyResult
{
Data = entity
};
}
}
@@ -0,0 +1,80 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.CompanyManager.Queries;
public record GetCompanyListDto
{
public string? Id { get; init; }
public string? Name { get; init; }
public string? Description { get; init; }
public string? Currency { get; init; }
public string? Street { get; init; }
public string? City { get; init; }
public string? State { get; init; }
public string? ZipCode { get; init; }
public string? Country { get; init; }
public string? PhoneNumber { get; init; }
public string? FaxNumber { get; init; }
public string? EmailAddress { get; init; }
public string? Website { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetCompanyListProfile : Profile
{
public GetCompanyListProfile()
{
CreateMap<Company, GetCompanyListDto>();
}
}
public class GetCompanyListResult
{
public List<GetCompanyListDto>? Data { get; init; }
}
public class GetCompanyListRequest : IRequest<GetCompanyListResult>
{
public bool IsDeleted { get; init; } = false;
}
public class GetCompanyListHandler : IRequestHandler<GetCompanyListRequest, GetCompanyListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetCompanyListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetCompanyListResult> Handle(GetCompanyListRequest request, CancellationToken cancellationToken)
{
var query = _context
.Company
.AsNoTracking()
.IsDeletedEqualTo(request.IsDeleted)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetCompanyListDto>>(entities);
return new GetCompanyListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,86 @@
using Application.Common.CQS.Queries;
using AutoMapper;
using Domain.Entities;
using FluentValidation;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.CompanyManager.Queries;
public record GetCompanySingleDto
{
public string? Id { get; init; }
public string? Name { get; init; }
public string? Description { get; init; }
public string? Currency { get; init; }
public string? Street { get; init; }
public string? City { get; init; }
public string? State { get; init; }
public string? ZipCode { get; init; }
public string? Country { get; init; }
public string? PhoneNumber { get; init; }
public string? FaxNumber { get; init; }
public string? EmailAddress { get; init; }
public string? Website { get; init; }
}
public class GetCompanySingleProfile : Profile
{
public GetCompanySingleProfile()
{
CreateMap<Company, GetCompanySingleDto>();
}
}
public class GetCompanySingleResult
{
public GetCompanySingleDto? Data { get; init; }
}
public class GetCompanySingleRequest : IRequest<GetCompanySingleResult>
{
public string? Id { get; init; }
}
public class GetCompanySingleValidator : AbstractValidator<GetCompanySingleRequest>
{
public GetCompanySingleValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class GetCompanySingleHandler : IRequestHandler<GetCompanySingleRequest, GetCompanySingleResult>
{
private readonly IQueryContext _context;
private readonly IMapper _mapper;
public GetCompanySingleHandler(
IQueryContext context,
IMapper mapper
)
{
_context = context;
_mapper = mapper;
}
public async Task<GetCompanySingleResult> Handle(GetCompanySingleRequest request, CancellationToken cancellationToken)
{
var query = _context
.Company
.AsNoTracking()
.AsQueryable();
query = query
.Where(x => x.Id == request.Id);
var entity = await query.SingleOrDefaultAsync(cancellationToken);
var dto = _mapper.Map<GetCompanySingleDto>(entity);
return new GetCompanySingleResult
{
Data = dto
};
}
}
@@ -0,0 +1,58 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CustomerCategoryManager.Commands;
public class CreateCustomerCategoryResult
{
public CustomerCategory? Data { get; set; }
}
public class CreateCustomerCategoryRequest : IRequest<CreateCustomerCategoryResult>
{
public string? Name { get; init; }
public string? Description { get; init; }
public string? CreatedById { get; init; }
}
public class CreateCustomerCategoryValidator : AbstractValidator<CreateCustomerCategoryRequest>
{
public CreateCustomerCategoryValidator()
{
RuleFor(x => x.Name).NotEmpty();
}
}
public class CreateCustomerCategoryHandler : IRequestHandler<CreateCustomerCategoryRequest, CreateCustomerCategoryResult>
{
private readonly ICommandRepository<CustomerCategory> _repository;
private readonly IUnitOfWork _unitOfWork;
public CreateCustomerCategoryHandler(
ICommandRepository<CustomerCategory> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<CreateCustomerCategoryResult> Handle(CreateCustomerCategoryRequest request, CancellationToken cancellationToken = default)
{
var entity = new CustomerCategory();
entity.CreatedById = request.CreatedById;
entity.Name = request.Name;
entity.Description = request.Description;
await _repository.CreateAsync(entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
return new CreateCustomerCategoryResult
{
Data = entity
};
}
}
@@ -0,0 +1,62 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CustomerCategoryManager.Commands;
public class DeleteCustomerCategoryResult
{
public CustomerCategory? Data { get; set; }
}
public class DeleteCustomerCategoryRequest : IRequest<DeleteCustomerCategoryResult>
{
public string? Id { get; init; }
public string? DeletedById { get; init; }
}
public class DeleteCustomerCategoryValidator : AbstractValidator<DeleteCustomerCategoryRequest>
{
public DeleteCustomerCategoryValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class DeleteCustomerCategoryHandler : IRequestHandler<DeleteCustomerCategoryRequest, DeleteCustomerCategoryResult>
{
private readonly ICommandRepository<CustomerCategory> _repository;
private readonly IUnitOfWork _unitOfWork;
public DeleteCustomerCategoryHandler(
ICommandRepository<CustomerCategory> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<DeleteCustomerCategoryResult> Handle(DeleteCustomerCategoryRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.DeletedById;
_repository.Delete(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new DeleteCustomerCategoryResult
{
Data = entity
};
}
}
@@ -0,0 +1,68 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CustomerCategoryManager.Commands;
public class UpdateCustomerCategoryResult
{
public CustomerCategory? Data { get; set; }
}
public class UpdateCustomerCategoryRequest : IRequest<UpdateCustomerCategoryResult>
{
public string? Id { get; init; }
public string? Name { get; init; }
public string? Description { get; init; }
public string? UpdatedById { get; init; }
}
public class UpdateCustomerCategoryValidator : AbstractValidator<UpdateCustomerCategoryRequest>
{
public UpdateCustomerCategoryValidator()
{
RuleFor(x => x.Id).NotEmpty();
RuleFor(x => x.Name).NotEmpty();
}
}
public class UpdateCustomerCategoryHandler : IRequestHandler<UpdateCustomerCategoryRequest, UpdateCustomerCategoryResult>
{
private readonly ICommandRepository<CustomerCategory> _repository;
private readonly IUnitOfWork _unitOfWork;
public UpdateCustomerCategoryHandler(
ICommandRepository<CustomerCategory> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<UpdateCustomerCategoryResult> Handle(UpdateCustomerCategoryRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.UpdatedById;
entity.Name = request.Name;
entity.Description = request.Description;
_repository.Update(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new UpdateCustomerCategoryResult
{
Data = entity
};
}
}
@@ -0,0 +1,70 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.CustomerCategoryManager.Queries;
public record GetCustomerCategoryListDto
{
public string? Id { get; init; }
public string? Name { get; init; }
public string? Description { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetCustomerCategoryListProfile : Profile
{
public GetCustomerCategoryListProfile()
{
CreateMap<CustomerCategory, GetCustomerCategoryListDto>();
}
}
public class GetCustomerCategoryListResult
{
public List<GetCustomerCategoryListDto>? Data { get; init; }
}
public class GetCustomerCategoryListRequest : IRequest<GetCustomerCategoryListResult>
{
public bool IsDeleted { get; init; } = false;
}
public class GetCustomerCategoryListHandler : IRequestHandler<GetCustomerCategoryListRequest, GetCustomerCategoryListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetCustomerCategoryListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetCustomerCategoryListResult> Handle(GetCustomerCategoryListRequest request, CancellationToken cancellationToken)
{
var query = _context
.CustomerCategory
.AsNoTracking()
.IsDeletedEqualTo(request.IsDeleted)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetCustomerCategoryListDto>>(entities);
return new GetCustomerCategoryListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,74 @@
using Application.Common.Repositories;
using Application.Features.NumberSequenceManager;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CustomerContactManager.Commands;
public class CreateCustomerContactResult
{
public CustomerContact? Data { get; set; }
}
public class CreateCustomerContactRequest : IRequest<CreateCustomerContactResult>
{
public string? Name { get; init; }
public string? JobTitle { get; set; }
public string? PhoneNumber { get; set; }
public string? EmailAddress { get; set; }
public string? Description { get; set; }
public string? CustomerId { get; set; }
public string? CreatedById { get; init; }
}
public class CreateCustomerContactValidator : AbstractValidator<CreateCustomerContactRequest>
{
public CreateCustomerContactValidator()
{
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.JobTitle).NotEmpty();
RuleFor(x => x.PhoneNumber).NotEmpty();
RuleFor(x => x.EmailAddress).NotEmpty();
}
}
public class CreateCustomerContactHandler : IRequestHandler<CreateCustomerContactRequest, CreateCustomerContactResult>
{
private readonly ICommandRepository<CustomerContact> _repository;
private readonly IUnitOfWork _unitOfWork;
private readonly NumberSequenceService _numberSequenceService;
public CreateCustomerContactHandler(
ICommandRepository<CustomerContact> repository,
IUnitOfWork unitOfWork,
NumberSequenceService numberSequenceService
)
{
_repository = repository;
_unitOfWork = unitOfWork;
_numberSequenceService = numberSequenceService;
}
public async Task<CreateCustomerContactResult> Handle(CreateCustomerContactRequest request, CancellationToken cancellationToken = default)
{
var entity = new CustomerContact();
entity.CreatedById = request.CreatedById;
entity.Name = request.Name;
entity.Number = _numberSequenceService.GenerateNumber(nameof(CustomerContact), "", "CC");
entity.JobTitle = request.JobTitle;
entity.PhoneNumber = request.PhoneNumber;
entity.EmailAddress = request.EmailAddress;
entity.Description = request.Description;
entity.CustomerId = request.CustomerId;
await _repository.CreateAsync(entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
return new CreateCustomerContactResult
{
Data = entity
};
}
}
@@ -0,0 +1,62 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CustomerContactManager.Commands;
public class DeleteCustomerContactResult
{
public CustomerContact? Data { get; set; }
}
public class DeleteCustomerContactRequest : IRequest<DeleteCustomerContactResult>
{
public string? Id { get; init; }
public string? DeletedById { get; init; }
}
public class DeleteCustomerContactValidator : AbstractValidator<DeleteCustomerContactRequest>
{
public DeleteCustomerContactValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class DeleteCustomerContactHandler : IRequestHandler<DeleteCustomerContactRequest, DeleteCustomerContactResult>
{
private readonly ICommandRepository<CustomerContact> _repository;
private readonly IUnitOfWork _unitOfWork;
public DeleteCustomerContactHandler(
ICommandRepository<CustomerContact> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<DeleteCustomerContactResult> Handle(DeleteCustomerContactRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.DeletedById;
_repository.Delete(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new DeleteCustomerContactResult
{
Data = entity
};
}
}
@@ -0,0 +1,79 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CustomerContactManager.Commands;
public class UpdateCustomerContactResult
{
public CustomerContact? Data { get; set; }
}
public class UpdateCustomerContactRequest : IRequest<UpdateCustomerContactResult>
{
public string? Id { get; init; }
public string? Name { get; init; }
public string? JobTitle { get; set; }
public string? PhoneNumber { get; set; }
public string? EmailAddress { get; set; }
public string? Description { get; set; }
public string? CustomerId { get; set; }
public string? UpdatedById { get; init; }
}
public class UpdateCustomerContactValidator : AbstractValidator<UpdateCustomerContactRequest>
{
public UpdateCustomerContactValidator()
{
RuleFor(x => x.Id).NotEmpty();
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.JobTitle).NotEmpty();
RuleFor(x => x.PhoneNumber).NotEmpty();
RuleFor(x => x.EmailAddress).NotEmpty();
}
}
public class UpdateCustomerContactHandler : IRequestHandler<UpdateCustomerContactRequest, UpdateCustomerContactResult>
{
private readonly ICommandRepository<CustomerContact> _repository;
private readonly IUnitOfWork _unitOfWork;
public UpdateCustomerContactHandler(
ICommandRepository<CustomerContact> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<UpdateCustomerContactResult> Handle(UpdateCustomerContactRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.UpdatedById;
entity.Name = request.Name;
entity.JobTitle = request.JobTitle;
entity.PhoneNumber = request.PhoneNumber;
entity.EmailAddress = request.EmailAddress;
entity.Description = request.Description;
entity.CustomerId = request.CustomerId;
_repository.Update(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new UpdateCustomerContactResult
{
Data = entity
};
}
}
@@ -0,0 +1,83 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.CustomerContactManager.Queries;
public record GetCustomerContactByCustomerIdListDto
{
public string? Id { get; init; }
public string? Name { get; set; }
public string? Number { get; set; }
public string? JobTitle { get; set; }
public string? PhoneNumber { get; set; }
public string? EmailAddress { get; set; }
public string? Description { get; set; }
public string? CustomerId { get; set; }
public string? CustomerName { get; set; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetCustomerContactByCustomerIdListProfile : Profile
{
public GetCustomerContactByCustomerIdListProfile()
{
CreateMap<CustomerContact, GetCustomerContactByCustomerIdListDto>()
.ForMember(
dest => dest.CustomerName,
opt => opt.MapFrom(src => src.Customer != null ? src.Customer.Name : string.Empty)
);
}
}
public class GetCustomerContactByCustomerIdListResult
{
public List<GetCustomerContactByCustomerIdListDto>? Data { get; init; }
}
public class GetCustomerContactByCustomerIdListRequest : IRequest<GetCustomerContactByCustomerIdListResult>
{
public string? CustomerId { get; init; }
}
public class GetCustomerContactByCustomerIdListHandler : IRequestHandler<GetCustomerContactByCustomerIdListRequest, GetCustomerContactByCustomerIdListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetCustomerContactByCustomerIdListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetCustomerContactByCustomerIdListResult> Handle(GetCustomerContactByCustomerIdListRequest request, CancellationToken cancellationToken)
{
var query = _context
.CustomerContact
.AsNoTracking()
.IsDeletedEqualTo(false)
.Include(x => x.Customer)
.Where(x => x.CustomerId == request.CustomerId)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetCustomerContactByCustomerIdListDto>>(entities);
return new GetCustomerContactByCustomerIdListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,82 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.CustomerContactManager.Queries;
public record GetCustomerContactListDto
{
public string? Id { get; init; }
public string? Name { get; set; }
public string? Number { get; set; }
public string? JobTitle { get; set; }
public string? PhoneNumber { get; set; }
public string? EmailAddress { get; set; }
public string? Description { get; set; }
public string? CustomerId { get; set; }
public string? CustomerName { get; set; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetCustomerContactListProfile : Profile
{
public GetCustomerContactListProfile()
{
CreateMap<CustomerContact, GetCustomerContactListDto>()
.ForMember(
dest => dest.CustomerName,
opt => opt.MapFrom(src => src.Customer != null ? src.Customer.Name : string.Empty)
);
}
}
public class GetCustomerContactListResult
{
public List<GetCustomerContactListDto>? Data { get; init; }
}
public class GetCustomerContactListRequest : IRequest<GetCustomerContactListResult>
{
public bool IsDeleted { get; init; } = false;
}
public class GetCustomerContactListHandler : IRequestHandler<GetCustomerContactListRequest, GetCustomerContactListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetCustomerContactListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetCustomerContactListResult> Handle(GetCustomerContactListRequest request, CancellationToken cancellationToken)
{
var query = _context
.CustomerContact
.AsNoTracking()
.IsDeletedEqualTo(request.IsDeleted)
.Include(x => x.Customer)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetCustomerContactListDto>>(entities);
return new GetCustomerContactListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,58 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CustomerGroupManager.Commands;
public class CreateCustomerGroupResult
{
public CustomerGroup? Data { get; set; }
}
public class CreateCustomerGroupRequest : IRequest<CreateCustomerGroupResult>
{
public string? Name { get; init; }
public string? Description { get; init; }
public string? CreatedById { get; init; }
}
public class CreateCustomerGroupValidator : AbstractValidator<CreateCustomerGroupRequest>
{
public CreateCustomerGroupValidator()
{
RuleFor(x => x.Name).NotEmpty();
}
}
public class CreateCustomerGroupHandler : IRequestHandler<CreateCustomerGroupRequest, CreateCustomerGroupResult>
{
private readonly ICommandRepository<CustomerGroup> _repository;
private readonly IUnitOfWork _unitOfWork;
public CreateCustomerGroupHandler(
ICommandRepository<CustomerGroup> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<CreateCustomerGroupResult> Handle(CreateCustomerGroupRequest request, CancellationToken cancellationToken = default)
{
var entity = new CustomerGroup();
entity.CreatedById = request.CreatedById;
entity.Name = request.Name;
entity.Description = request.Description;
await _repository.CreateAsync(entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
return new CreateCustomerGroupResult
{
Data = entity
};
}
}
@@ -0,0 +1,62 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CustomerGroupManager.Commands;
public class DeleteCustomerGroupResult
{
public CustomerGroup? Data { get; set; }
}
public class DeleteCustomerGroupRequest : IRequest<DeleteCustomerGroupResult>
{
public string? Id { get; init; }
public string? DeletedById { get; init; }
}
public class DeleteCustomerGroupValidator : AbstractValidator<DeleteCustomerGroupRequest>
{
public DeleteCustomerGroupValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class DeleteCustomerGroupHandler : IRequestHandler<DeleteCustomerGroupRequest, DeleteCustomerGroupResult>
{
private readonly ICommandRepository<CustomerGroup> _repository;
private readonly IUnitOfWork _unitOfWork;
public DeleteCustomerGroupHandler(
ICommandRepository<CustomerGroup> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<DeleteCustomerGroupResult> Handle(DeleteCustomerGroupRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.DeletedById;
_repository.Delete(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new DeleteCustomerGroupResult
{
Data = entity
};
}
}
@@ -0,0 +1,68 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CustomerGroupManager.Commands;
public class UpdateCustomerGroupResult
{
public CustomerGroup? Data { get; set; }
}
public class UpdateCustomerGroupRequest : IRequest<UpdateCustomerGroupResult>
{
public string? Id { get; init; }
public string? Name { get; init; }
public string? Description { get; init; }
public string? UpdatedById { get; init; }
}
public class UpdateCustomerGroupValidator : AbstractValidator<UpdateCustomerGroupRequest>
{
public UpdateCustomerGroupValidator()
{
RuleFor(x => x.Id).NotEmpty();
RuleFor(x => x.Name).NotEmpty();
}
}
public class UpdateCustomerGroupHandler : IRequestHandler<UpdateCustomerGroupRequest, UpdateCustomerGroupResult>
{
private readonly ICommandRepository<CustomerGroup> _repository;
private readonly IUnitOfWork _unitOfWork;
public UpdateCustomerGroupHandler(
ICommandRepository<CustomerGroup> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<UpdateCustomerGroupResult> Handle(UpdateCustomerGroupRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.UpdatedById;
entity.Name = request.Name;
entity.Description = request.Description;
_repository.Update(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new UpdateCustomerGroupResult
{
Data = entity
};
}
}
@@ -0,0 +1,70 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.CustomerGroupManager.Queries;
public record GetCustomerGroupListDto
{
public string? Id { get; init; }
public string? Name { get; init; }
public string? Description { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetCustomerGroupListProfile : Profile
{
public GetCustomerGroupListProfile()
{
CreateMap<CustomerGroup, GetCustomerGroupListDto>();
}
}
public class GetCustomerGroupListResult
{
public List<GetCustomerGroupListDto>? Data { get; init; }
}
public class GetCustomerGroupListRequest : IRequest<GetCustomerGroupListResult>
{
public bool IsDeleted { get; init; } = false;
}
public class GetCustomerGroupListHandler : IRequestHandler<GetCustomerGroupListRequest, GetCustomerGroupListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetCustomerGroupListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetCustomerGroupListResult> Handle(GetCustomerGroupListRequest request, CancellationToken cancellationToken)
{
var query = _context
.CustomerGroup
.AsNoTracking()
.IsDeletedEqualTo(request.IsDeleted)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetCustomerGroupListDto>>(entities);
return new GetCustomerGroupListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,105 @@
using Application.Common.Repositories;
using Application.Features.NumberSequenceManager;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CustomerManager.Commands;
public class CreateCustomerResult
{
public Customer? Data { get; set; }
}
public class CreateCustomerRequest : IRequest<CreateCustomerResult>
{
public string? Name { get; set; }
public string? Description { get; set; }
public string? Street { get; set; }
public string? City { get; set; }
public string? State { get; set; }
public string? ZipCode { get; set; }
public string? Country { get; set; }
public string? PhoneNumber { get; set; }
public string? FaxNumber { get; set; }
public string? EmailAddress { get; set; }
public string? Website { get; set; }
public string? WhatsApp { get; set; }
public string? LinkedIn { get; set; }
public string? Facebook { get; set; }
public string? Instagram { get; set; }
public string? TwitterX { get; set; }
public string? TikTok { get; set; }
public string? CustomerGroupId { get; set; }
public string? CustomerCategoryId { get; set; }
public string? CreatedById { get; init; }
}
public class CreateCustomerValidator : AbstractValidator<CreateCustomerRequest>
{
public CreateCustomerValidator()
{
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Street).NotEmpty();
RuleFor(x => x.City).NotEmpty();
RuleFor(x => x.State).NotEmpty();
RuleFor(x => x.ZipCode).NotEmpty();
RuleFor(x => x.PhoneNumber).NotEmpty();
RuleFor(x => x.EmailAddress).NotEmpty();
RuleFor(x => x.CustomerGroupId).NotEmpty();
RuleFor(x => x.CustomerCategoryId).NotEmpty();
}
}
public class CreateCustomerHandler : IRequestHandler<CreateCustomerRequest, CreateCustomerResult>
{
private readonly ICommandRepository<Customer> _repository;
private readonly IUnitOfWork _unitOfWork;
private readonly NumberSequenceService _numberSequenceService;
public CreateCustomerHandler(
ICommandRepository<Customer> repository,
IUnitOfWork unitOfWork,
NumberSequenceService numberSequenceService
)
{
_repository = repository;
_unitOfWork = unitOfWork;
_numberSequenceService = numberSequenceService;
}
public async Task<CreateCustomerResult> Handle(CreateCustomerRequest request, CancellationToken cancellationToken = default)
{
var entity = new Customer();
entity.CreatedById = request.CreatedById;
entity.Name = request.Name;
entity.Number = _numberSequenceService.GenerateNumber(nameof(Customer), "", "CST");
entity.Description = request.Description;
entity.Street = request.Street;
entity.City = request.City;
entity.State = request.State;
entity.ZipCode = request.ZipCode;
entity.Country = request.Country;
entity.PhoneNumber = request.PhoneNumber;
entity.FaxNumber = request.FaxNumber;
entity.EmailAddress = request.EmailAddress;
entity.Website = request.Website;
entity.WhatsApp = request.WhatsApp;
entity.LinkedIn = request.LinkedIn;
entity.Facebook = request.Facebook;
entity.Instagram = request.Instagram;
entity.TwitterX = request.TwitterX;
entity.TikTok = request.TikTok;
entity.CustomerGroupId = request.CustomerGroupId;
entity.CustomerCategoryId = request.CustomerCategoryId;
await _repository.CreateAsync(entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
return new CreateCustomerResult
{
Data = entity
};
}
}
@@ -0,0 +1,62 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CustomerManager.Commands;
public class DeleteCustomerResult
{
public Customer? Data { get; set; }
}
public class DeleteCustomerRequest : IRequest<DeleteCustomerResult>
{
public string? Id { get; init; }
public string? DeletedById { get; init; }
}
public class DeleteCustomerValidator : AbstractValidator<DeleteCustomerRequest>
{
public DeleteCustomerValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class DeleteCustomerHandler : IRequestHandler<DeleteCustomerRequest, DeleteCustomerResult>
{
private readonly ICommandRepository<Customer> _repository;
private readonly IUnitOfWork _unitOfWork;
public DeleteCustomerHandler(
ICommandRepository<Customer> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<DeleteCustomerResult> Handle(DeleteCustomerRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.DeletedById;
_repository.Delete(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new DeleteCustomerResult
{
Data = entity
};
}
}
@@ -0,0 +1,111 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.CustomerManager.Commands;
public class UpdateCustomerResult
{
public Customer? Data { get; set; }
}
public class UpdateCustomerRequest : IRequest<UpdateCustomerResult>
{
public string? Id { get; init; }
public string? Name { get; set; }
public string? Description { get; set; }
public string? Street { get; set; }
public string? City { get; set; }
public string? State { get; set; }
public string? ZipCode { get; set; }
public string? Country { get; set; }
public string? PhoneNumber { get; set; }
public string? FaxNumber { get; set; }
public string? EmailAddress { get; set; }
public string? Website { get; set; }
public string? WhatsApp { get; set; }
public string? LinkedIn { get; set; }
public string? Facebook { get; set; }
public string? Instagram { get; set; }
public string? TwitterX { get; set; }
public string? TikTok { get; set; }
public string? CustomerGroupId { get; set; }
public string? CustomerCategoryId { get; set; }
public string? CreatedById { get; init; }
public string? UpdatedById { get; init; }
}
public class UpdateCustomerValidator : AbstractValidator<UpdateCustomerRequest>
{
public UpdateCustomerValidator()
{
RuleFor(x => x.Id).NotEmpty();
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Street).NotEmpty();
RuleFor(x => x.City).NotEmpty();
RuleFor(x => x.State).NotEmpty();
RuleFor(x => x.ZipCode).NotEmpty();
RuleFor(x => x.PhoneNumber).NotEmpty();
RuleFor(x => x.EmailAddress).NotEmpty();
RuleFor(x => x.CustomerGroupId).NotEmpty();
RuleFor(x => x.CustomerCategoryId).NotEmpty();
}
}
public class UpdateCustomerHandler : IRequestHandler<UpdateCustomerRequest, UpdateCustomerResult>
{
private readonly ICommandRepository<Customer> _repository;
private readonly IUnitOfWork _unitOfWork;
public UpdateCustomerHandler(
ICommandRepository<Customer> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<UpdateCustomerResult> Handle(UpdateCustomerRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.UpdatedById;
entity.Name = request.Name;
entity.Description = request.Description;
entity.Street = request.Street;
entity.City = request.City;
entity.State = request.State;
entity.ZipCode = request.ZipCode;
entity.Country = request.Country;
entity.PhoneNumber = request.PhoneNumber;
entity.FaxNumber = request.FaxNumber;
entity.EmailAddress = request.EmailAddress;
entity.Website = request.Website;
entity.WhatsApp = request.WhatsApp;
entity.LinkedIn = request.LinkedIn;
entity.Facebook = request.Facebook;
entity.Instagram = request.Instagram;
entity.TwitterX = request.TwitterX;
entity.TikTok = request.TikTok;
entity.CustomerGroupId = request.CustomerGroupId;
entity.CustomerCategoryId = request.CustomerCategoryId;
_repository.Update(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new UpdateCustomerResult
{
Data = entity
};
}
}
@@ -0,0 +1,102 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.CustomerManager.Queries;
public record GetCustomerListDto
{
public string? Id { get; init; }
public string? Name { get; set; }
public string? Number { get; set; }
public string? Description { get; set; }
public string? Street { get; set; }
public string? City { get; set; }
public string? State { get; set; }
public string? ZipCode { get; set; }
public string? Country { get; set; }
public string? PhoneNumber { get; set; }
public string? FaxNumber { get; set; }
public string? EmailAddress { get; set; }
public string? Website { get; set; }
public string? WhatsApp { get; set; }
public string? LinkedIn { get; set; }
public string? Facebook { get; set; }
public string? Instagram { get; set; }
public string? TwitterX { get; set; }
public string? TikTok { get; set; }
public string? CustomerGroupId { get; set; }
public string? CustomerGroupName { get; set; }
public string? CustomerCategoryId { get; set; }
public string? CustomerCategoryName { get; set; }
public string? CreatedById { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetCustomerListProfile : Profile
{
public GetCustomerListProfile()
{
CreateMap<Customer, GetCustomerListDto>()
.ForMember(
dest => dest.CustomerGroupName,
opt => opt.MapFrom(src => src.CustomerGroup != null ? src.CustomerGroup.Name : string.Empty)
)
.ForMember(
dest => dest.CustomerCategoryName,
opt => opt.MapFrom(src => src.CustomerCategory != null ? src.CustomerCategory.Name : string.Empty)
);
}
}
public class GetCustomerListResult
{
public List<GetCustomerListDto>? Data { get; init; }
}
public class GetCustomerListRequest : IRequest<GetCustomerListResult>
{
public bool IsDeleted { get; init; } = false;
}
public class GetCustomerListHandler : IRequestHandler<GetCustomerListRequest, GetCustomerListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetCustomerListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetCustomerListResult> Handle(GetCustomerListRequest request, CancellationToken cancellationToken)
{
var query = _context
.Customer
.AsNoTracking()
.IsDeletedEqualTo(request.IsDeleted)
.Include(x => x.CustomerGroup)
.Include(x => x.CustomerCategory)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetCustomerListDto>>(entities);
return new GetCustomerListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,8 @@
namespace Application.Features.DashboardManager.Queries;
public class AccummulationChartItem
{
public string X { get; init; } = string.Empty;
public double Y { get; init; } = 0.0;
public string Text { get; init; } = string.Empty;
}
@@ -0,0 +1,8 @@
namespace Application.Features.DashboardManager.Queries;
public class BarDataItem
{
public string X { get; set; } = string.Empty;
public int Y { get; set; }
public string TooltipMappingName { get; set; } = string.Empty;
}
@@ -0,0 +1,13 @@
namespace Application.Features.DashboardManager.Queries;
public class BarSeries
{
public string Type { get; set; } = string.Empty;
public string XName { get; set; } = string.Empty;
public int Width { get; set; }
public string YName { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public double ColumnSpacing { get; set; }
public string TooltipMappingName { get; set; } = string.Empty;
public List<BarDataItem> DataSource { get; set; } = new List<BarDataItem>();
}
@@ -0,0 +1,10 @@
namespace Application.Features.DashboardManager.Queries;
public class CRMItem
{
public double? CampaignTotalAmount { get; init; }
public double? LeadTotalAmount { get; init; }
public double? BudgetTotalAmount { get; init; }
public double? ExpenseTotalAmount { get; init; }
public double? ClosedTotalAmount { get; init; }
}
@@ -0,0 +1,13 @@
namespace Application.Features.DashboardManager.Queries;
public class CardsItem
{
public double? SalesTotal { get; init; }
public double? SalesReturnTotal { get; init; }
public double? PurchaseTotal { get; init; }
public double? PurchaseReturnTotal { get; init; }
public double? DeliveryOrderTotal { get; init; }
public double? GoodsReceiveTotal { get; init; }
public double? TransferOutTotal { get; init; }
public double? TransferInTotal { get; init; }
}
@@ -0,0 +1,83 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.DashboardManager.Queries;
public class GetCRMDashboardDto
{
public CRMItem? CRMDashboard { get; init; }
}
public class GetCRMDashboardResult
{
public GetCRMDashboardDto? Data { get; init; }
}
public class GetCRMDashboardRequest : IRequest<GetCRMDashboardResult>
{
}
public class GetCRMDashboardHandler : IRequestHandler<GetCRMDashboardRequest, GetCRMDashboardResult>
{
private readonly IQueryContext _context;
public GetCRMDashboardHandler(IQueryContext context)
{
_context = context;
}
public async Task<GetCRMDashboardResult> Handle(GetCRMDashboardRequest request, CancellationToken cancellationToken)
{
var campaignTotalAmount = await _context.Campaign
.AsNoTracking()
.IsDeletedEqualTo(false)
.SumAsync(x => (double?)x.TargetRevenueAmount, cancellationToken);
var closedTotalAmount = await _context.Lead
.AsNoTracking()
.IsDeletedEqualTo(false)
.Where(x => x.ClosingStatus == ClosingStatus.ClosedWon)
.SumAsync(x => (double?)x.AmountClosed, cancellationToken);
var leadTotalAmount = await _context.Lead
.AsNoTracking()
.IsDeletedEqualTo(false)
.SumAsync(x => (double?)x.AmountTargeted, cancellationToken);
var budgetTotalAmount = await _context.Budget
.AsNoTracking()
.IsDeletedEqualTo(false)
.SumAsync(x => (double?)x.Amount, cancellationToken);
var expenseTotalAmount = await _context.Expense
.AsNoTracking()
.IsDeletedEqualTo(false)
.SumAsync(x => (double?)x.Amount, cancellationToken);
var cardsDashboardData = new CRMItem
{
CampaignTotalAmount = campaignTotalAmount,
LeadTotalAmount = leadTotalAmount,
BudgetTotalAmount = budgetTotalAmount,
ExpenseTotalAmount = expenseTotalAmount,
ClosedTotalAmount = closedTotalAmount
};
var result = new GetCRMDashboardResult
{
Data = new GetCRMDashboardDto
{
CRMDashboard = cardsDashboardData
}
};
return result;
}
}
@@ -0,0 +1,46 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using Domain.Entities;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.DashboardManager.Queries;
public class GetCampaignByStatusResult
{
public List<AccummulationChartItem>? Data { get; init; }
}
public class GetCampaignByStatusRequest : IRequest<GetCampaignByStatusResult>
{
}
public class GetCampaignByStatusHandler : IRequestHandler<GetCampaignByStatusRequest, GetCampaignByStatusResult>
{
private readonly IQueryContext _context;
public GetCampaignByStatusHandler(IQueryContext context)
{
_context = context;
}
public async Task<GetCampaignByStatusResult> Handle(GetCampaignByStatusRequest request, CancellationToken cancellationToken)
{
var groupedCampaigns = await _context.Set<Campaign>()
.GroupBy(c => c.Status)
.Select(g => new { Status = g.Key, Count = g.Count() })
.ToListAsync(cancellationToken);
var result = groupedCampaigns.Select(g => new AccummulationChartItem
{
X = g.Status.HasValue ? ((CampaignStatus)g.Status).ToFriendlyName() : string.Empty,
Y = (double)g.Count,
Text = g.Status.HasValue
? $"{((CampaignStatus)g.Status).ToFriendlyName()} ({g.Count})"
: $"Unknown ({g.Count})"
}).ToList();
return new GetCampaignByStatusResult { Data = result };
}
}
@@ -0,0 +1,62 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.DashboardManager.Queries;
public class GetCardsDashboardDto
{
public CardsItem? CardsDashboard { get; init; }
}
public class GetCardsDashboardResult
{
public GetCardsDashboardDto? Data { get; init; }
}
public class GetCardsDashboardRequest : IRequest<GetCardsDashboardResult>
{
}
public class GetCardsDashboardHandler : IRequestHandler<GetCardsDashboardRequest, GetCardsDashboardResult>
{
private readonly IQueryContext _context;
public GetCardsDashboardHandler(IQueryContext context)
{
_context = context;
}
public async Task<GetCardsDashboardResult> Handle(GetCardsDashboardRequest request, CancellationToken cancellationToken)
{
var salesTotal = await _context.SalesOrderItem
.AsNoTracking()
.IsDeletedEqualTo(false)
.SumAsync(x => (double?)x.Quantity, cancellationToken);
var purchaseTotal = await _context.PurchaseOrderItem
.AsNoTracking()
.IsDeletedEqualTo(false)
.SumAsync(x => (double?)x.Quantity, cancellationToken);
var cardsDashboardData = new CardsItem
{
SalesTotal = salesTotal,
PurchaseTotal = purchaseTotal,
};
var result = new GetCardsDashboardResult
{
Data = new GetCardsDashboardDto
{
CardsDashboard = cardsDashboardData
}
};
return result;
}
}
@@ -0,0 +1,47 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using Domain.Entities;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.DashboardManager.Queries;
public class GetLeadActivityByTypeResult
{
public List<AccummulationChartItem>? Data { get; init; }
}
public class GetLeadActivityByTypeRequest : IRequest<GetLeadActivityByTypeResult>
{
}
public class GetLeadActivityByTypeHandler : IRequestHandler<GetLeadActivityByTypeRequest, GetLeadActivityByTypeResult>
{
private readonly IQueryContext _context;
public GetLeadActivityByTypeHandler(IQueryContext context)
{
_context = context;
}
public async Task<GetLeadActivityByTypeResult> Handle(GetLeadActivityByTypeRequest request, CancellationToken cancellationToken)
{
var groupedActivities = await _context.Set<LeadActivity>()
.GroupBy(a => a.Type)
.Select(g => new { Type = g.Key, Count = g.Count() })
.OrderBy(g => g.Count)
.ToListAsync(cancellationToken);
var result = groupedActivities.Select(g => new AccummulationChartItem
{
X = g.Type.HasValue ? ((LeadActivityType)g.Type).ToFriendlyName() : string.Empty,
Y = (double)g.Count,
Text = g.Type.HasValue
? $"{((LeadActivityType)g.Type).ToFriendlyName()} ({g.Count})"
: $"Unknown ({g.Count})"
}).ToList();
return new GetLeadActivityByTypeResult { Data = result };
}
}
@@ -0,0 +1,53 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using Domain.Entities;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.DashboardManager.Queries;
public class GetLeadPipelineFunnelResult
{
public List<AccummulationChartItem>? Data { get; init; }
}
public class GetLeadPipelineFunnelRequest : IRequest<GetLeadPipelineFunnelResult>
{
}
public class GetLeadPipelineFunnelHandler : IRequestHandler<GetLeadPipelineFunnelRequest, GetLeadPipelineFunnelResult>
{
private readonly IQueryContext _context;
public GetLeadPipelineFunnelHandler(IQueryContext context)
{
_context = context;
}
public async Task<GetLeadPipelineFunnelResult> Handle(GetLeadPipelineFunnelRequest request, CancellationToken cancellationToken)
{
var groupedLeads = await _context.Set<Lead>()
.GroupBy(l => l.PipelineStage)
.Select(g => new { Stage = g.Key, Count = g.Count() })
.ToListAsync(cancellationToken);
var result = groupedLeads.Select(g => new
{
Item = new AccummulationChartItem
{
X = g.Stage.HasValue ? ((PipelineStage)g.Stage).ToFriendlyName() : string.Empty,
Y = g.Count,
Text = g.Stage.HasValue
? $"{((PipelineStage)g.Stage).ToFriendlyName()} ({g.Count})"
: $"Unknown ({g.Count})"
},
OrderKey = g.Stage.HasValue ? ((PipelineStage)g.Stage).ToFriendlyName() : string.Empty
})
.OrderByDescending(i => i.OrderKey)
.Select(i => i.Item)
.ToList();
return new GetLeadPipelineFunnelResult { Data = result };
}
}
@@ -0,0 +1,150 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using Domain.Entities;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.DashboardManager.Queries;
public class GetPurchaseDashboardDto
{
public List<PurchaseOrderItem>? PurchaseOrderDashboard { get; init; }
public List<BarSeries>? PurchaseByVendorGroupDashboard { get; init; }
public List<BarSeries>? PurchaseByVendorCategoryDashboard { get; init; }
}
public class GetPurchaseDashboardResult
{
public GetPurchaseDashboardDto? Data { get; init; }
}
public class GetPurchaseDashboardRequest : IRequest<GetPurchaseDashboardResult>
{
}
public class GetPurchaseDashboardHandler : IRequestHandler<GetPurchaseDashboardRequest, GetPurchaseDashboardResult>
{
private readonly IQueryContext _context;
public GetPurchaseDashboardHandler(IQueryContext context)
{
_context = context;
}
public async Task<GetPurchaseDashboardResult> Handle(GetPurchaseDashboardRequest request, CancellationToken cancellationToken)
{
var purchaseOrderItemData = await _context.PurchaseOrderItem
.AsNoTracking()
.IsDeletedEqualTo(false)
.Include(x => x.PurchaseOrder)
.Include(x => x.Product)
.Where(x => x.PurchaseOrder!.OrderStatus == PurchaseOrderStatus.Confirmed)
.OrderByDescending(x => x.PurchaseOrder!.OrderDate)
.Take(30)
.ToListAsync(cancellationToken);
var purchaseByVendorGroupData = _context.PurchaseOrderItem
.AsNoTracking()
.IsDeletedEqualTo(false)
.Include(x => x.PurchaseOrder)
.ThenInclude(x => x!.Vendor)
.ThenInclude(x => x!.VendorGroup)
.Include(x => x.Product)
.Where(x => x.Product!.Physical == true)
.Select(x => new
{
Status = x.PurchaseOrder!.OrderStatus,
VendorGroupName = x.PurchaseOrder!.Vendor!.VendorGroup!.Name,
Quantity = x.Quantity
})
.GroupBy(x => new { x.Status, x.VendorGroupName })
.Select(g => new
{
Status = g.Key.Status,
VendorGroupName = g.Key.VendorGroupName,
Quantity = g.Sum(x => x.Quantity)
})
.ToList();
var purchaseByVendorCategoryDate = _context.PurchaseOrderItem
.AsNoTracking()
.IsDeletedEqualTo(false)
.Include(x => x.PurchaseOrder)
.ThenInclude(x => x!.Vendor)
.ThenInclude(x => x!.VendorCategory)
.Include(x => x.Product)
.Where(x => x.Product!.Physical == true)
.Select(x => new
{
Status = x.PurchaseOrder!.OrderStatus,
VendorCategoryName = x.PurchaseOrder!.Vendor!.VendorCategory!.Name,
Quantity = x.Quantity
})
.GroupBy(x => new { x.Status, x.VendorCategoryName })
.Select(g => new
{
Status = g.Key.Status,
VendorCategoryName = g.Key.VendorCategoryName,
Quantity = g.Sum(x => x.Quantity)
})
.ToList();
var result = new GetPurchaseDashboardResult
{
Data = new GetPurchaseDashboardDto
{
PurchaseOrderDashboard = purchaseOrderItemData,
PurchaseByVendorGroupDashboard =
Enum.GetValues(typeof(PurchaseOrderStatus))
.Cast<PurchaseOrderStatus>()
.Select(status => new BarSeries
{
Type = "Bar",
XName = "x",
Width = 2,
YName = "y",
Name = Enum.GetName(typeof(PurchaseOrderStatus), status)!,
ColumnSpacing = 0.1,
TooltipMappingName = "tooltipMappingName",
DataSource = purchaseByVendorGroupData
.Where(x => x.Status == status)
.Select(x => new BarDataItem
{
X = x.VendorGroupName ?? "",
TooltipMappingName = x.VendorGroupName ?? "",
Y = (int)x.Quantity!.Value
}).ToList()
})
.ToList(),
PurchaseByVendorCategoryDashboard =
Enum.GetValues(typeof(PurchaseOrderStatus))
.Cast<PurchaseOrderStatus>()
.Select(status => new BarSeries
{
Type = "Column",
XName = "x",
Width = 2,
YName = "y",
Name = Enum.GetName(typeof(PurchaseOrderStatus), status)!,
ColumnSpacing = 0.1,
TooltipMappingName = "tooltipMappingName",
DataSource = purchaseByVendorCategoryDate
.Where(x => x.Status == status)
.Select(x => new BarDataItem
{
X = x.VendorCategoryName ?? "",
TooltipMappingName = x.VendorCategoryName ?? "",
Y = (int)x.Quantity!.Value
}).ToList()
})
.ToList(),
}
};
return result;
}
}
@@ -0,0 +1,150 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using Domain.Entities;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.DashboardManager.Queries;
public class GetSalesDashboardDto
{
public List<SalesOrderItem>? SalesOrderDashboard { get; init; }
public List<BarSeries>? SalesByCustomerGroupDashboard { get; init; }
public List<BarSeries>? SalesByCustomerCategoryDashboard { get; init; }
}
public class GetSalesDashboardResult
{
public GetSalesDashboardDto? Data { get; init; }
}
public class GetSalesDashboardRequest : IRequest<GetSalesDashboardResult>
{
}
public class GetSalesDashboardHandler : IRequestHandler<GetSalesDashboardRequest, GetSalesDashboardResult>
{
private readonly IQueryContext _context;
public GetSalesDashboardHandler(IQueryContext context)
{
_context = context;
}
public async Task<GetSalesDashboardResult> Handle(GetSalesDashboardRequest request, CancellationToken cancellationToken)
{
var salesOrderItemData = await _context.SalesOrderItem
.AsNoTracking()
.IsDeletedEqualTo(false)
.Include(x => x.SalesOrder)
.Include(x => x.Product)
.Where(x => x.SalesOrder!.OrderStatus == SalesOrderStatus.Confirmed)
.OrderByDescending(x => x.SalesOrder!.OrderDate)
.Take(30)
.ToListAsync(cancellationToken);
var salesByCustomerGroupData = _context.SalesOrderItem
.AsNoTracking()
.IsDeletedEqualTo(false)
.Include(x => x.SalesOrder)
.ThenInclude(x => x!.Customer)
.ThenInclude(x => x!.CustomerGroup)
.Include(x => x.Product)
.Where(x => x.Product!.Physical == true)
.Select(x => new
{
Status = x.SalesOrder!.OrderStatus,
CustomerGroupName = x.SalesOrder!.Customer!.CustomerGroup!.Name,
Quantity = x.Quantity
})
.GroupBy(x => new { x.Status, x.CustomerGroupName })
.Select(g => new
{
Status = g.Key.Status,
CustomerGroupName = g.Key.CustomerGroupName,
Quantity = g.Sum(x => x.Quantity)
})
.ToList();
var salesByCustomerCategoryData = _context.SalesOrderItem
.AsNoTracking()
.IsDeletedEqualTo(false)
.Include(x => x.SalesOrder)
.ThenInclude(x => x!.Customer)
.ThenInclude(x => x!.CustomerCategory)
.Include(x => x.Product)
.Where(x => x.Product!.Physical == true)
.Select(x => new
{
Status = x.SalesOrder!.OrderStatus,
CustomerCategoryName = x.SalesOrder!.Customer!.CustomerCategory!.Name,
Quantity = x.Quantity
})
.GroupBy(x => new { x.Status, x.CustomerCategoryName })
.Select(g => new
{
Status = g.Key.Status,
CustomerCategoryName = g.Key.CustomerCategoryName,
Quantity = g.Sum(x => x.Quantity)
})
.ToList();
var result = new GetSalesDashboardResult
{
Data = new GetSalesDashboardDto
{
SalesOrderDashboard = salesOrderItemData,
SalesByCustomerGroupDashboard =
Enum.GetValues(typeof(SalesOrderStatus))
.Cast<SalesOrderStatus>()
.Select(status => new BarSeries
{
Type = "Column",
XName = "x",
Width = 2,
YName = "y",
Name = Enum.GetName(typeof(SalesOrderStatus), status)!,
ColumnSpacing = 0.1,
TooltipMappingName = "tooltipMappingName",
DataSource = salesByCustomerGroupData
.Where(x => x.Status == status)
.Select(x => new BarDataItem
{
X = x.CustomerGroupName ?? "",
TooltipMappingName = x.CustomerGroupName ?? "",
Y = (int)x.Quantity!.Value
}).ToList()
})
.ToList(),
SalesByCustomerCategoryDashboard =
Enum.GetValues(typeof(SalesOrderStatus))
.Cast<SalesOrderStatus>()
.Select(status => new BarSeries
{
Type = "Bar",
XName = "x",
Width = 2,
YName = "y",
Name = Enum.GetName(typeof(SalesOrderStatus), status)!,
ColumnSpacing = 0.1,
TooltipMappingName = "tooltipMappingName",
DataSource = salesByCustomerCategoryData
.Where(x => x.Status == status)
.Select(x => new BarDataItem
{
X = x.CustomerCategoryName ?? "",
TooltipMappingName = x.CustomerCategoryName ?? "",
Y = (int)x.Quantity!.Value
}).ToList()
})
.ToList()
}
};
return result;
}
}
@@ -0,0 +1,58 @@
using Application.Common.CQS.Queries;
using Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.DashboardManager.Queries;
public class GetSalesTeamLeadClosingResult
{
public List<AccummulationChartItem>? Data { get; init; }
}
public class GetSalesTeamLeadClosingRequest : IRequest<GetSalesTeamLeadClosingResult>
{
}
public class GetSalesTeamLeadClosingHandler : IRequestHandler<GetSalesTeamLeadClosingRequest, GetSalesTeamLeadClosingResult>
{
private readonly IQueryContext _context;
public GetSalesTeamLeadClosingHandler(IQueryContext context)
{
_context = context;
}
public async Task<GetSalesTeamLeadClosingResult> Handle(GetSalesTeamLeadClosingRequest request, CancellationToken cancellationToken)
{
var groupedLeads = await _context.Set<Lead>()
.Include(l => l.SalesTeam)
.Where(l => l.SalesTeam != null && l.AmountClosed.HasValue)
.GroupBy(l => l.SalesTeam!.Name)
.Select(g => new
{
Name = g.Key,
TotalClosed = g.Sum(l => l.AmountClosed ?? 0)
})
.ToListAsync(cancellationToken);
var totalAmountClosed = groupedLeads.Sum(g => g.TotalClosed);
var result = groupedLeads.Select(g =>
{
double percentageValue = totalAmountClosed > 0
? (double)g.TotalClosed / totalAmountClosed * 100
: 0;
var percentage = percentageValue.ToString("F2");
return new AccummulationChartItem
{
X = g.Name ?? "Unknown",
Y = Math.Round(percentageValue, 2),
Text = $"{g.Name ?? "Unknown"} ({Math.Round(percentageValue, 2)}%)"
};
}).ToList();
return new GetSalesTeamLeadClosingResult { Data = result };
}
}
@@ -0,0 +1,77 @@
using Application.Common.Repositories;
using Application.Features.NumberSequenceManager;
using Domain.Entities;
using Domain.Enums;
using FluentValidation;
using MediatR;
namespace Application.Features.ExpenseManager.Commands;
public class CreateExpenseResult
{
public Expense? Data { get; set; }
}
public class CreateExpenseRequest : IRequest<CreateExpenseResult>
{
public string? Title { get; init; }
public string? Description { get; init; }
public DateTime? ExpenseDate { get; init; }
public string? Status { get; init; }
public double? Amount { get; init; }
public string? CampaignId { get; init; }
public string? CreatedById { get; init; }
}
public class CreateExpenseValidator : AbstractValidator<CreateExpenseRequest>
{
public CreateExpenseValidator()
{
RuleFor(x => x.Title).NotEmpty();
RuleFor(x => x.ExpenseDate).NotNull();
RuleFor(x => x.Amount).NotNull();
RuleFor(x => x.CampaignId).NotEmpty();
RuleFor(x => x.Status).NotEmpty();
}
}
public class CreateExpenseHandler : IRequestHandler<CreateExpenseRequest, CreateExpenseResult>
{
private readonly ICommandRepository<Expense> _repository;
private readonly IUnitOfWork _unitOfWork;
private readonly NumberSequenceService _numberSequenceService;
public CreateExpenseHandler(
ICommandRepository<Expense> repository,
IUnitOfWork unitOfWork,
NumberSequenceService numberSequenceService
)
{
_repository = repository;
_unitOfWork = unitOfWork;
_numberSequenceService = numberSequenceService;
}
public async Task<CreateExpenseResult> Handle(CreateExpenseRequest request, CancellationToken cancellationToken = default)
{
var entity = new Expense
{
CreatedById = request.CreatedById,
Number = _numberSequenceService.GenerateNumber(nameof(Expense), "", "EXP"),
Title = request.Title,
Description = request.Description,
ExpenseDate = request.ExpenseDate,
Status = (ExpenseStatus)int.Parse(request.Status!),
Amount = request.Amount,
CampaignId = request.CampaignId
};
await _repository.CreateAsync(entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
return new CreateExpenseResult
{
Data = entity
};
}
}
@@ -0,0 +1,60 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.ExpenseManager.Commands;
public class DeleteExpenseResult
{
public Expense? Data { get; set; }
}
public class DeleteExpenseRequest : IRequest<DeleteExpenseResult>
{
public string? Id { get; init; }
public string? DeletedById { get; init; }
}
public class DeleteExpenseValidator : AbstractValidator<DeleteExpenseRequest>
{
public DeleteExpenseValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class DeleteExpenseHandler : IRequestHandler<DeleteExpenseRequest, DeleteExpenseResult>
{
private readonly ICommandRepository<Expense> _repository;
private readonly IUnitOfWork _unitOfWork;
public DeleteExpenseHandler(
ICommandRepository<Expense> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<DeleteExpenseResult> Handle(DeleteExpenseRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.DeletedById;
_repository.Delete(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new DeleteExpenseResult
{
Data = entity
};
}
}
@@ -0,0 +1,78 @@
using Application.Common.Repositories;
using Domain.Entities;
using Domain.Enums;
using FluentValidation;
using MediatR;
namespace Application.Features.ExpenseManager.Commands;
public class UpdateExpenseResult
{
public Expense? Data { get; set; }
}
public class UpdateExpenseRequest : IRequest<UpdateExpenseResult>
{
public string? Id { get; init; }
public string? Title { get; init; }
public string? Description { get; init; }
public DateTime? ExpenseDate { get; init; }
public string? Status { get; init; }
public double? Amount { get; init; }
public string? CampaignId { get; init; }
public string? UpdatedById { get; init; }
}
public class UpdateExpenseValidator : AbstractValidator<UpdateExpenseRequest>
{
public UpdateExpenseValidator()
{
RuleFor(x => x.Id).NotEmpty();
RuleFor(x => x.Title).NotEmpty();
RuleFor(x => x.ExpenseDate).NotNull();
RuleFor(x => x.Amount).NotNull();
RuleFor(x => x.CampaignId).NotEmpty();
RuleFor(x => x.Status).NotEmpty();
}
}
public class UpdateExpenseHandler : IRequestHandler<UpdateExpenseRequest, UpdateExpenseResult>
{
private readonly ICommandRepository<Expense> _repository;
private readonly IUnitOfWork _unitOfWork;
public UpdateExpenseHandler(
ICommandRepository<Expense> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<UpdateExpenseResult> Handle(UpdateExpenseRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.UpdatedById;
entity.Title = request.Title;
entity.Description = request.Description;
entity.ExpenseDate = request.ExpenseDate;
entity.Status = (ExpenseStatus)int.Parse(request.Status!);
entity.Amount = request.Amount;
entity.CampaignId = request.CampaignId;
_repository.Update(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new UpdateExpenseResult
{
Data = entity
};
}
}
@@ -0,0 +1,82 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.ExpenseManager.Queries;
public record GetExpenseByCampaignIdListDto
{
public string? Id { get; init; }
public string? Number { get; init; }
public string? Title { get; init; }
public string? Description { get; init; }
public DateTime? ExpenseDate { get; init; }
public ExpenseStatus? Status { get; init; }
public string? StatusName { get; init; }
public double? Amount { get; init; }
public string? CampaignId { get; init; }
public string? CampaignName { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetExpenseByCampaignIdListProfile : Profile
{
public GetExpenseByCampaignIdListProfile()
{
CreateMap<Expense, GetExpenseByCampaignIdListDto>()
.ForMember(
dest => dest.CampaignName,
opt => opt.MapFrom(src => src.Campaign != null ? src.Campaign.Title : string.Empty)
)
.ForMember(
dest => dest.StatusName,
opt => opt.MapFrom(src => src.Status.HasValue ? src.Status.Value.ToFriendlyName() : string.Empty)
);
}
}
public class GetExpenseByCampaignIdListResult
{
public List<GetExpenseByCampaignIdListDto>? Data { get; init; }
}
public class GetExpenseByCampaignIdListRequest : IRequest<GetExpenseByCampaignIdListResult>
{
public string? CampaignId { get; init; }
}
public class GetExpenseByCampaignIdListHandler : IRequestHandler<GetExpenseByCampaignIdListRequest, GetExpenseByCampaignIdListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetExpenseByCampaignIdListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetExpenseByCampaignIdListResult> Handle(GetExpenseByCampaignIdListRequest request, CancellationToken cancellationToken)
{
var query = _context
.Expense
.AsNoTracking()
.IsDeletedEqualTo(false)
.Include(x => x.Campaign)
.Where(x => x.CampaignId == request.CampaignId)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetExpenseByCampaignIdListDto>>(entities);
return new GetExpenseByCampaignIdListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,81 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.ExpenseManager.Queries;
public record GetExpenseListDto
{
public string? Id { get; init; }
public string? Number { get; init; }
public string? Title { get; init; }
public string? Description { get; init; }
public DateTime? ExpenseDate { get; init; }
public ExpenseStatus? Status { get; init; }
public string? StatusName { get; init; }
public double? Amount { get; init; }
public string? CampaignId { get; init; }
public string? CampaignName { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetExpenseListProfile : Profile
{
public GetExpenseListProfile()
{
CreateMap<Expense, GetExpenseListDto>()
.ForMember(
dest => dest.CampaignName,
opt => opt.MapFrom(src => src.Campaign != null ? src.Campaign.Title : string.Empty)
)
.ForMember(
dest => dest.StatusName,
opt => opt.MapFrom(src => src.Status.HasValue ? src.Status.Value.ToFriendlyName() : string.Empty)
);
}
}
public class GetExpenseListResult
{
public List<GetExpenseListDto>? Data { get; init; }
}
public class GetExpenseListRequest : IRequest<GetExpenseListResult>
{
public bool IsDeleted { get; init; } = false;
}
public class GetExpenseListHandler : IRequestHandler<GetExpenseListRequest, GetExpenseListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetExpenseListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetExpenseListResult> Handle(GetExpenseListRequest request, CancellationToken cancellationToken)
{
var query = _context
.Expense
.AsNoTracking()
.IsDeletedEqualTo(request.IsDeleted)
.Include(x => x.Campaign)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetExpenseListDto>>(entities);
return new GetExpenseListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,62 @@
using Application.Common.CQS.Queries;
using AutoMapper;
using Domain.Entities;
using FluentValidation;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.ExpenseManager.Queries;
public class GetExpenseSingleProfile : Profile
{
public GetExpenseSingleProfile()
{
}
}
public class GetExpenseSingleResult
{
public Expense? Data { get; init; }
}
public class GetExpenseSingleRequest : IRequest<GetExpenseSingleResult>
{
public string? Id { get; init; }
}
public class GetExpenseSingleValidator : AbstractValidator<GetExpenseSingleRequest>
{
public GetExpenseSingleValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class GetExpenseSingleHandler : IRequestHandler<GetExpenseSingleRequest, GetExpenseSingleResult>
{
private readonly IQueryContext _context;
public GetExpenseSingleHandler(
IQueryContext context
)
{
_context = context;
}
public async Task<GetExpenseSingleResult> Handle(GetExpenseSingleRequest request, CancellationToken cancellationToken)
{
var query = _context
.Expense
.AsNoTracking()
.Include(x => x.Campaign)
.Where(x => x.Id == request.Id)
.AsQueryable();
var entity = await query.SingleOrDefaultAsync(cancellationToken);
return new GetExpenseSingleResult
{
Data = entity
};
}
}
@@ -0,0 +1,54 @@
using Application.Common.Extensions;
using AutoMapper;
using Domain.Enums;
using MediatR;
namespace Application.Features.ExpenseManager.Queries;
public record GetExpenseStatusListDto
{
public string? Id { get; init; }
public string? Name { get; init; }
}
public class GetExpenseStatusListProfile : Profile
{
public GetExpenseStatusListProfile()
{
}
}
public class GetExpenseStatusListResult
{
public List<GetExpenseStatusListDto>? Data { get; init; }
}
public class GetExpenseStatusListRequest : IRequest<GetExpenseStatusListResult>
{
}
public class GetExpenseStatusListHandler : IRequestHandler<GetExpenseStatusListRequest, GetExpenseStatusListResult>
{
public GetExpenseStatusListHandler()
{
}
public async Task<GetExpenseStatusListResult> Handle(GetExpenseStatusListRequest request, CancellationToken cancellationToken)
{
var statuses = Enum.GetValues(typeof(ExpenseStatus))
.Cast<ExpenseStatus>()
.Select(status => new GetExpenseStatusListDto
{
Id = ((int)status).ToString(),
Name = status.ToFriendlyName()
})
.ToList();
await Task.CompletedTask;
return new GetExpenseStatusListResult
{
Data = statuses
};
}
}
@@ -0,0 +1,63 @@
using Application.Common.Services.FileDocumentManager;
using FluentValidation;
using MediatR;
namespace Application.Features.FileDocumentManager.Commands;
public class CreateDocumentResult
{
public string? DocumentName { get; init; }
}
public class CreateDocumentRequest : IRequest<CreateDocumentResult>
{
public string? OriginalFileName { get; init; }
public string? Extension { get; init; }
public byte[]? Data { get; init; }
public long? Size { get; init; }
public string? CreatedById { get; init; }
public string? Description { get; init; }
}
public class CreateDocumentValidator : AbstractValidator<CreateDocumentRequest>
{
public CreateDocumentValidator()
{
RuleFor(x => x.OriginalFileName)
.NotEmpty();
RuleFor(x => x.Extension)
.NotEmpty();
RuleFor(x => x.Data)
.NotEmpty();
RuleFor(x => x.Size)
.NotEmpty();
}
}
public class CreateDocumentHandler : IRequestHandler<CreateDocumentRequest, CreateDocumentResult>
{
private readonly IFileDocumentService _uploadDocument;
public CreateDocumentHandler(IFileDocumentService uploadDocument)
{
_uploadDocument = uploadDocument;
}
public async Task<CreateDocumentResult> Handle(CreateDocumentRequest request, CancellationToken cancellationToken)
{
var result = await _uploadDocument.UploadAsync(
request.OriginalFileName,
request.Extension,
request.Data,
request.Size,
request.Description,
request.CreatedById,
cancellationToken);
return new CreateDocumentResult { DocumentName = result };
}
}
@@ -0,0 +1,44 @@
using Application.Common.Services.FileDocumentManager;
using FluentValidation;
using MediatR;
namespace Application.Features.FileDocumentManager.Queries;
public class GetDocumentResult
{
public byte[]? Data { get; init; }
}
public class GetDocumentRequest : IRequest<GetDocumentResult>
{
public string? DocumentName { get; init; }
}
public class GetDocumentValidator : AbstractValidator<GetDocumentRequest>
{
public GetDocumentValidator()
{
RuleFor(x => x.DocumentName)
.NotEmpty();
}
}
public class GetDocumentHandler : IRequestHandler<GetDocumentRequest, GetDocumentResult>
{
private readonly IFileDocumentService _documentService;
public GetDocumentHandler(IFileDocumentService documentService)
{
_documentService = documentService;
}
public async Task<GetDocumentResult> Handle(GetDocumentRequest request, CancellationToken cancellationToken)
{
var result = await _documentService.GetFileAsync(request.DocumentName ?? "", cancellationToken);
return new GetDocumentResult { Data = result };
}
}
@@ -0,0 +1,63 @@
using Application.Common.Services.FileImageManager;
using FluentValidation;
using MediatR;
namespace Application.Features.FileImageManager.Commands;
public class CreateImageResult
{
public string? ImageName { get; init; }
}
public class CreateImageRequest : IRequest<CreateImageResult>
{
public string? OriginalFileName { get; init; }
public string? Extension { get; init; }
public byte[]? Data { get; init; }
public long? Size { get; init; }
public string? CreatedById { get; init; }
public string? Description { get; init; }
}
public class CreateImageValidator : AbstractValidator<CreateImageRequest>
{
public CreateImageValidator()
{
RuleFor(x => x.OriginalFileName)
.NotEmpty();
RuleFor(x => x.Extension)
.NotEmpty();
RuleFor(x => x.Data)
.NotEmpty();
RuleFor(x => x.Size)
.NotEmpty();
}
}
public class CreateImageHandler : IRequestHandler<CreateImageRequest, CreateImageResult>
{
private readonly IFileImageService _uploadImage;
public CreateImageHandler(IFileImageService uploadImage)
{
_uploadImage = uploadImage;
}
public async Task<CreateImageResult> Handle(CreateImageRequest request, CancellationToken cancellationToken)
{
var result = await _uploadImage.UploadAsync(
request.OriginalFileName,
request.Extension,
request.Data,
request.Size,
request.Description,
request.CreatedById,
cancellationToken);
return new CreateImageResult { ImageName = result };
}
}
@@ -0,0 +1,44 @@
using Application.Common.Services.FileImageManager;
using FluentValidation;
using MediatR;
namespace Application.Features.FileImageManager.Queries;
public class GetImageResult
{
public byte[]? Data { get; init; }
}
public class GetImageRequest : IRequest<GetImageResult>
{
public string? ImageName { get; init; }
}
public class GetImageValidator : AbstractValidator<GetImageRequest>
{
public GetImageValidator()
{
RuleFor(x => x.ImageName)
.NotEmpty();
}
}
public class GetImageHandler : IRequestHandler<GetImageRequest, GetImageResult>
{
private readonly IFileImageService _imageService;
public GetImageHandler(IFileImageService imageService)
{
_imageService = imageService;
}
public async Task<GetImageResult> Handle(GetImageRequest request, CancellationToken cancellationToken)
{
var result = await _imageService.GetFileAsync(request.ImageName ?? "", cancellationToken);
return new GetImageResult { Data = result };
}
}
@@ -0,0 +1,79 @@
using Application.Common.Repositories;
using Application.Features.NumberSequenceManager;
using Domain.Entities;
using Domain.Enums;
using FluentValidation;
using MediatR;
namespace Application.Features.LeadActivityManager.Commands;
public class CreateLeadActivityResult
{
public LeadActivity? Data { get; set; }
}
public class CreateLeadActivityRequest : IRequest<CreateLeadActivityResult>
{
public string? LeadId { get; init; }
public string? Summary { get; init; }
public string? Description { get; init; }
public DateTime? FromDate { get; init; }
public DateTime? ToDate { get; init; }
public string? Type { get; init; }
public string? AttachmentName { get; init; }
public string? CreatedById { get; init; }
}
public class CreateLeadActivityValidator : AbstractValidator<CreateLeadActivityRequest>
{
public CreateLeadActivityValidator()
{
RuleFor(x => x.LeadId).NotEmpty();
RuleFor(x => x.Summary).NotEmpty();
RuleFor(x => x.FromDate).NotNull();
RuleFor(x => x.ToDate).NotNull();
RuleFor(x => x.Type).NotEmpty();
}
}
public class CreateLeadActivityHandler : IRequestHandler<CreateLeadActivityRequest, CreateLeadActivityResult>
{
private readonly ICommandRepository<LeadActivity> _repository;
private readonly IUnitOfWork _unitOfWork;
private readonly NumberSequenceService _numberSequenceService;
public CreateLeadActivityHandler(
ICommandRepository<LeadActivity> repository,
IUnitOfWork unitOfWork,
NumberSequenceService numberSequenceService
)
{
_repository = repository;
_unitOfWork = unitOfWork;
_numberSequenceService = numberSequenceService;
}
public async Task<CreateLeadActivityResult> Handle(CreateLeadActivityRequest request, CancellationToken cancellationToken = default)
{
var entity = new LeadActivity
{
CreatedById = request.CreatedById,
LeadId = request.LeadId,
Number = _numberSequenceService.GenerateNumber(nameof(LeadActivity), "", "LA"),
Summary = request.Summary,
Description = request.Description,
FromDate = request.FromDate,
ToDate = request.ToDate,
Type = (LeadActivityType)int.Parse(request.Type!),
AttachmentName = request.AttachmentName
};
await _repository.CreateAsync(entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
return new CreateLeadActivityResult
{
Data = entity
};
}
}
@@ -0,0 +1,60 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.LeadActivityManager.Commands;
public class DeleteLeadActivityResult
{
public LeadActivity? Data { get; set; }
}
public class DeleteLeadActivityRequest : IRequest<DeleteLeadActivityResult>
{
public string? Id { get; init; }
public string? DeletedById { get; init; }
}
public class DeleteLeadActivityValidator : AbstractValidator<DeleteLeadActivityRequest>
{
public DeleteLeadActivityValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class DeleteLeadActivityHandler : IRequestHandler<DeleteLeadActivityRequest, DeleteLeadActivityResult>
{
private readonly ICommandRepository<LeadActivity> _repository;
private readonly IUnitOfWork _unitOfWork;
public DeleteLeadActivityHandler(
ICommandRepository<LeadActivity> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<DeleteLeadActivityResult> Handle(DeleteLeadActivityRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.DeletedById;
_repository.Delete(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new DeleteLeadActivityResult
{
Data = entity
};
}
}
@@ -0,0 +1,79 @@
using Application.Common.Repositories;
using Domain.Entities;
using Domain.Enums;
using FluentValidation;
using MediatR;
namespace Application.Features.LeadActivityManager.Commands;
public class UpdateLeadActivityResult
{
public LeadActivity? Data { get; set; }
}
public class UpdateLeadActivityRequest : IRequest<UpdateLeadActivityResult>
{
public string? Id { get; init; }
public string? LeadId { get; init; }
public string? Summary { get; init; }
public string? Description { get; init; }
public DateTime? FromDate { get; init; }
public DateTime? ToDate { get; init; }
public string? Type { get; init; }
public string? AttachmentName { get; init; }
public string? UpdatedById { get; init; }
}
public class UpdateLeadActivityValidator : AbstractValidator<UpdateLeadActivityRequest>
{
public UpdateLeadActivityValidator()
{
RuleFor(x => x.Id).NotEmpty();
RuleFor(x => x.Summary).NotEmpty();
RuleFor(x => x.FromDate).NotNull();
RuleFor(x => x.ToDate).NotNull();
RuleFor(x => x.Type).NotEmpty();
}
}
public class UpdateLeadActivityHandler : IRequestHandler<UpdateLeadActivityRequest, UpdateLeadActivityResult>
{
private readonly ICommandRepository<LeadActivity> _repository;
private readonly IUnitOfWork _unitOfWork;
public UpdateLeadActivityHandler(
ICommandRepository<LeadActivity> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<UpdateLeadActivityResult> Handle(UpdateLeadActivityRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.UpdatedById;
entity.LeadId = request.LeadId;
entity.Summary = request.Summary;
entity.Description = request.Description;
entity.FromDate = request.FromDate;
entity.ToDate = request.ToDate;
entity.Type = (LeadActivityType)int.Parse(request.Type!);
entity.AttachmentName = request.AttachmentName;
_repository.Update(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new UpdateLeadActivityResult
{
Data = entity
};
}
}
@@ -0,0 +1,76 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.LeadActivityManager.Queries;
public record GetLeadActivityByLeadIdListDto
{
public string? Id { get; init; }
public string? Number { get; init; }
public string? Summary { get; init; }
public string? Description { get; init; }
public DateTime? FromDate { get; init; }
public DateTime? ToDate { get; init; }
public LeadActivityType? Type { get; init; }
public string? TypeName { get; init; }
public string? AttachmentName { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetLeadActivityByLeadIdListProfile : Profile
{
public GetLeadActivityByLeadIdListProfile()
{
CreateMap<LeadActivity, GetLeadActivityByLeadIdListDto>()
.ForMember(
dest => dest.TypeName,
opt => opt.MapFrom(src => src.Type.HasValue ? src.Type.Value.ToFriendlyName() : string.Empty)
);
}
}
public class GetLeadActivityByLeadIdListResult
{
public List<GetLeadActivityByLeadIdListDto>? Data { get; init; }
}
public class GetLeadActivityByLeadIdListRequest : IRequest<GetLeadActivityByLeadIdListResult>
{
public string? LeadId { get; init; }
}
public class GetLeadActivityByLeadIdListHandler : IRequestHandler<GetLeadActivityByLeadIdListRequest, GetLeadActivityByLeadIdListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetLeadActivityByLeadIdListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetLeadActivityByLeadIdListResult> Handle(GetLeadActivityByLeadIdListRequest request, CancellationToken cancellationToken)
{
var query = _context
.LeadActivity
.AsNoTracking()
.IsDeletedEqualTo(false)
.Where(x => x.LeadId == request.LeadId)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetLeadActivityByLeadIdListDto>>(entities);
return new GetLeadActivityByLeadIdListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,82 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.LeadActivityManager.Queries;
public record GetLeadActivityListDto
{
public string? Id { get; init; }
public string? Number { get; init; }
public string? Summary { get; init; }
public string? Description { get; init; }
public DateTime? FromDate { get; init; }
public DateTime? ToDate { get; init; }
public LeadActivityType? Type { get; init; }
public string? TypeName { get; init; }
public string? AttachmentName { get; init; }
public string? LeadId { get; init; }
public string? LeadTitle { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetLeadActivityListProfile : Profile
{
public GetLeadActivityListProfile()
{
CreateMap<LeadActivity, GetLeadActivityListDto>()
.ForMember(
dest => dest.TypeName,
opt => opt.MapFrom(src => src.Type.HasValue ? src.Type.Value.ToFriendlyName() : string.Empty)
)
.ForMember(
dest => dest.LeadTitle,
opt => opt.MapFrom(src => src.Lead != null ? src.Lead.Title : string.Empty)
);
}
}
public class GetLeadActivityListResult
{
public List<GetLeadActivityListDto>? Data { get; init; }
}
public class GetLeadActivityListRequest : IRequest<GetLeadActivityListResult>
{
public bool IsDeleted { get; init; } = false;
}
public class GetLeadActivityListHandler : IRequestHandler<GetLeadActivityListRequest, GetLeadActivityListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetLeadActivityListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetLeadActivityListResult> Handle(GetLeadActivityListRequest request, CancellationToken cancellationToken)
{
var query = _context
.LeadActivity
.Include(x => x.Lead)
.AsNoTracking()
.IsDeletedEqualTo(request.IsDeleted)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetLeadActivityListDto>>(entities);
return new GetLeadActivityListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,61 @@
using Application.Common.CQS.Queries;
using AutoMapper;
using Domain.Entities;
using FluentValidation;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.LeadActivityManager.Queries;
public class GetLeadActivitySingleProfile : Profile
{
public GetLeadActivitySingleProfile()
{
}
}
public class GetLeadActivitySingleResult
{
public LeadActivity? Data { get; init; }
}
public class GetLeadActivitySingleRequest : IRequest<GetLeadActivitySingleResult>
{
public string? Id { get; init; }
}
public class GetLeadActivitySingleValidator : AbstractValidator<GetLeadActivitySingleRequest>
{
public GetLeadActivitySingleValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class GetLeadActivitySingleHandler : IRequestHandler<GetLeadActivitySingleRequest, GetLeadActivitySingleResult>
{
private readonly IQueryContext _context;
public GetLeadActivitySingleHandler(
IQueryContext context
)
{
_context = context;
}
public async Task<GetLeadActivitySingleResult> Handle(GetLeadActivitySingleRequest request, CancellationToken cancellationToken)
{
var query = _context
.LeadActivity
.AsNoTracking()
.Where(x => x.Id == request.Id)
.AsQueryable();
var entity = await query.SingleOrDefaultAsync(cancellationToken);
return new GetLeadActivitySingleResult
{
Data = entity
};
}
}
@@ -0,0 +1,61 @@
using Application.Common.Extensions;
using AutoMapper;
using Domain.Enums;
using MediatR;
namespace Application.Features.DeliveryOrderManager.Queries;
public record GetLeadActivityTypeListDto
{
public string? Id { get; init; }
public string? Name { get; init; }
}
public class GetLeadActivityTypeListProfile : Profile
{
public GetLeadActivityTypeListProfile()
{
}
}
public class GetLeadActivityTypeListResult
{
public List<GetLeadActivityTypeListDto>? Data { get; init; }
}
public class GetLeadActivityTypeListRequest : IRequest<GetLeadActivityTypeListResult>
{
}
public class GetLeadActivityTypeListHandler : IRequestHandler<GetLeadActivityTypeListRequest, GetLeadActivityTypeListResult>
{
public GetLeadActivityTypeListHandler()
{
}
public async Task<GetLeadActivityTypeListResult> Handle(GetLeadActivityTypeListRequest request, CancellationToken cancellationToken)
{
var statuses = Enum.GetValues(typeof(LeadActivityType))
.Cast<LeadActivityType>()
.Select(status => new GetLeadActivityTypeListDto
{
Id = ((int)status).ToString(),
Name = status.ToFriendlyName()
})
.ToList();
await Task.CompletedTask;
return new GetLeadActivityTypeListResult
{
Data = statuses
};
}
}
@@ -0,0 +1,82 @@
using Application.Common.Repositories;
using Application.Features.NumberSequenceManager;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.LeadContactManager.Commands;
public class CreateLeadContactResult
{
public LeadContact? Data { get; set; }
}
public class CreateLeadContactRequest : IRequest<CreateLeadContactResult>
{
public string? LeadId { get; init; }
public string? FullName { get; init; }
public string? Description { get; init; }
public string? AddressStreet { get; init; }
public string? AddressCity { get; init; }
public string? AddressState { get; init; }
public string? MobileNumber { get; init; }
public string? Email { get; init; }
public string? CreatedById { get; init; }
}
public class CreateLeadContactValidator : AbstractValidator<CreateLeadContactRequest>
{
public CreateLeadContactValidator()
{
RuleFor(x => x.LeadId).NotEmpty();
RuleFor(x => x.FullName).NotEmpty();
RuleFor(x => x.AddressStreet).NotEmpty();
RuleFor(x => x.AddressCity).NotEmpty();
RuleFor(x => x.AddressState).NotEmpty();
RuleFor(x => x.MobileNumber).NotEmpty();
RuleFor(x => x.Email).NotEmpty();
}
}
public class CreateLeadContactHandler : IRequestHandler<CreateLeadContactRequest, CreateLeadContactResult>
{
private readonly ICommandRepository<LeadContact> _repository;
private readonly IUnitOfWork _unitOfWork;
private readonly NumberSequenceService _numberSequenceService;
public CreateLeadContactHandler(
ICommandRepository<LeadContact> repository,
IUnitOfWork unitOfWork,
NumberSequenceService numberSequenceService
)
{
_repository = repository;
_unitOfWork = unitOfWork;
_numberSequenceService = numberSequenceService;
}
public async Task<CreateLeadContactResult> Handle(CreateLeadContactRequest request, CancellationToken cancellationToken = default)
{
var entity = new LeadContact
{
CreatedById = request.CreatedById,
LeadId = request.LeadId,
Number = _numberSequenceService.GenerateNumber(nameof(LeadContact), "", "LC"),
FullName = request.FullName,
Description = request.Description,
AddressStreet = request.AddressStreet,
AddressCity = request.AddressCity,
AddressState = request.AddressState,
MobileNumber = request.MobileNumber,
Email = request.Email
};
await _repository.CreateAsync(entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
return new CreateLeadContactResult
{
Data = entity
};
}
}
@@ -0,0 +1,60 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.LeadContactManager.Commands;
public class DeleteLeadContactResult
{
public LeadContact? Data { get; set; }
}
public class DeleteLeadContactRequest : IRequest<DeleteLeadContactResult>
{
public string? Id { get; init; }
public string? DeletedById { get; init; }
}
public class DeleteLeadContactValidator : AbstractValidator<DeleteLeadContactRequest>
{
public DeleteLeadContactValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class DeleteLeadContactHandler : IRequestHandler<DeleteLeadContactRequest, DeleteLeadContactResult>
{
private readonly ICommandRepository<LeadContact> _repository;
private readonly IUnitOfWork _unitOfWork;
public DeleteLeadContactHandler(
ICommandRepository<LeadContact> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<DeleteLeadContactResult> Handle(DeleteLeadContactRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.DeletedById;
_repository.Delete(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new DeleteLeadContactResult
{
Data = entity
};
}
}
@@ -0,0 +1,104 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.LeadContactManager.Commands;
public class UpdateLeadContactResult
{
public LeadContact? Data { get; set; }
}
public class UpdateLeadContactRequest : IRequest<UpdateLeadContactResult>
{
public string? Id { get; init; }
public string? LeadId { get; init; }
public string? FullName { get; init; }
public string? Description { get; init; }
public string? AddressStreet { get; init; }
public string? AddressCity { get; init; }
public string? AddressState { get; init; }
public string? AddressZipCode { get; init; }
public string? AddressCountry { get; init; }
public string? PhoneNumber { get; init; }
public string? FaxNumber { get; init; }
public string? MobileNumber { get; init; }
public string? Email { get; init; }
public string? Website { get; init; }
public string? WhatsApp { get; init; }
public string? LinkedIn { get; init; }
public string? Facebook { get; init; }
public string? Twitter { get; init; }
public string? Instagram { get; init; }
public string? AvatarName { get; init; }
public string? UpdatedById { get; init; }
}
public class UpdateLeadContactValidator : AbstractValidator<UpdateLeadContactRequest>
{
public UpdateLeadContactValidator()
{
RuleFor(x => x.Id).NotEmpty();
RuleFor(x => x.FullName).NotEmpty();
RuleFor(x => x.AddressStreet).NotEmpty();
RuleFor(x => x.AddressCity).NotEmpty();
RuleFor(x => x.AddressState).NotEmpty();
RuleFor(x => x.MobileNumber).NotEmpty();
RuleFor(x => x.Email).NotEmpty();
}
}
public class UpdateLeadContactHandler : IRequestHandler<UpdateLeadContactRequest, UpdateLeadContactResult>
{
private readonly ICommandRepository<LeadContact> _repository;
private readonly IUnitOfWork _unitOfWork;
public UpdateLeadContactHandler(
ICommandRepository<LeadContact> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<UpdateLeadContactResult> Handle(UpdateLeadContactRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.UpdatedById;
entity.LeadId = request.LeadId;
entity.FullName = request.FullName;
entity.Description = request.Description;
entity.AddressStreet = request.AddressStreet;
entity.AddressCity = request.AddressCity;
entity.AddressState = request.AddressState;
entity.AddressZipCode = request.AddressZipCode;
entity.AddressCountry = request.AddressCountry;
entity.PhoneNumber = request.PhoneNumber;
entity.FaxNumber = request.FaxNumber;
entity.MobileNumber = request.MobileNumber;
entity.Email = request.Email;
entity.Website = request.Website;
entity.WhatsApp = request.WhatsApp;
entity.LinkedIn = request.LinkedIn;
entity.Facebook = request.Facebook;
entity.Twitter = request.Twitter;
entity.Instagram = request.Instagram;
entity.AvatarName = request.AvatarName;
_repository.Update(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new UpdateLeadContactResult
{
Data = entity
};
}
}
@@ -0,0 +1,82 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.LeadContactManager.Queries;
public record GetLeadContactByLeadIdListDto
{
public string? Id { get; init; }
public string? Number { get; init; }
public string? FullName { get; init; }
public string? Description { get; init; }
public string? AddressStreet { get; init; }
public string? AddressCity { get; init; }
public string? AddressState { get; init; }
public string? AddressZipCode { get; init; }
public string? AddressCountry { get; init; }
public string? PhoneNumber { get; init; }
public string? FaxNumber { get; init; }
public string? MobileNumber { get; init; }
public string? Email { get; init; }
public string? Website { get; init; }
public string? WhatsApp { get; init; }
public string? LinkedIn { get; init; }
public string? Facebook { get; init; }
public string? Twitter { get; init; }
public string? Instagram { get; init; }
public string? AvatarName { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetLeadContactByLeadIdListProfile : Profile
{
public GetLeadContactByLeadIdListProfile()
{
CreateMap<LeadContact, GetLeadContactByLeadIdListDto>();
}
}
public class GetLeadContactByLeadIdListResult
{
public List<GetLeadContactByLeadIdListDto>? Data { get; init; }
}
public class GetLeadContactByLeadIdListRequest : IRequest<GetLeadContactByLeadIdListResult>
{
public string? LeadId { get; init; }
}
public class GetLeadContactByLeadIdListHandler : IRequestHandler<GetLeadContactByLeadIdListRequest, GetLeadContactByLeadIdListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetLeadContactByLeadIdListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetLeadContactByLeadIdListResult> Handle(GetLeadContactByLeadIdListRequest request, CancellationToken cancellationToken)
{
var query = _context
.LeadContact
.AsNoTracking()
.IsDeletedEqualTo(false) // Assuming contacts aren't soft-deleted or this method filters out deleted contacts
.Where(x => x.LeadId == request.LeadId)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetLeadContactByLeadIdListDto>>(entities);
return new GetLeadContactByLeadIdListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,88 @@
using Application.Common.CQS.Queries;
using Application.Common.Extensions;
using AutoMapper;
using Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.LeadContactManager.Queries;
public record GetLeadContactListDto
{
public string? Id { get; init; }
public string? Number { get; init; }
public string? FullName { get; init; }
public string? Description { get; init; }
public string? AddressStreet { get; init; }
public string? AddressCity { get; init; }
public string? AddressState { get; init; }
public string? AddressZipCode { get; init; }
public string? AddressCountry { get; init; }
public string? PhoneNumber { get; init; }
public string? FaxNumber { get; init; }
public string? MobileNumber { get; init; }
public string? Email { get; init; }
public string? Website { get; init; }
public string? WhatsApp { get; init; }
public string? LinkedIn { get; init; }
public string? Facebook { get; init; }
public string? Twitter { get; init; }
public string? Instagram { get; init; }
public string? AvatarName { get; init; }
public string? LeadId { get; init; }
public string? LeadTitle { get; init; }
public DateTime? CreatedAtUtc { get; init; }
}
public class GetLeadContactListProfile : Profile
{
public GetLeadContactListProfile()
{
CreateMap<LeadContact, GetLeadContactListDto>()
.ForMember(
dest => dest.LeadTitle,
opt => opt.MapFrom(src => src.Lead != null ? src.Lead.Title : string.Empty)
);
}
}
public class GetLeadContactListResult
{
public List<GetLeadContactListDto>? Data { get; init; }
}
public class GetLeadContactListRequest : IRequest<GetLeadContactListResult>
{
public bool IsDeleted { get; init; } = false;
}
public class GetLeadContactListHandler : IRequestHandler<GetLeadContactListRequest, GetLeadContactListResult>
{
private readonly IMapper _mapper;
private readonly IQueryContext _context;
public GetLeadContactListHandler(IMapper mapper, IQueryContext context)
{
_mapper = mapper;
_context = context;
}
public async Task<GetLeadContactListResult> Handle(GetLeadContactListRequest request, CancellationToken cancellationToken)
{
var query = _context
.LeadContact
.Include(x => x.Lead)
.AsNoTracking()
.IsDeletedEqualTo(request.IsDeleted)
.AsQueryable();
var entities = await query.ToListAsync(cancellationToken);
var dtos = _mapper.Map<List<GetLeadContactListDto>>(entities);
return new GetLeadContactListResult
{
Data = dtos
};
}
}
@@ -0,0 +1,61 @@
using Application.Common.CQS.Queries;
using AutoMapper;
using Domain.Entities;
using FluentValidation;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.LeadContactManager.Queries;
public class GetLeadContactSingleProfile : Profile
{
public GetLeadContactSingleProfile()
{
}
}
public class GetLeadContactSingleResult
{
public LeadContact? Data { get; init; }
}
public class GetLeadContactSingleRequest : IRequest<GetLeadContactSingleResult>
{
public string? Id { get; init; }
}
public class GetLeadContactSingleValidator : AbstractValidator<GetLeadContactSingleRequest>
{
public GetLeadContactSingleValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class GetLeadContactSingleHandler : IRequestHandler<GetLeadContactSingleRequest, GetLeadContactSingleResult>
{
private readonly IQueryContext _context;
public GetLeadContactSingleHandler(
IQueryContext context
)
{
_context = context;
}
public async Task<GetLeadContactSingleResult> Handle(GetLeadContactSingleRequest request, CancellationToken cancellationToken)
{
var query = _context
.LeadContact
.AsNoTracking()
.Where(x => x.Id == request.Id)
.AsQueryable();
var entity = await query.SingleOrDefaultAsync(cancellationToken);
return new GetLeadContactSingleResult
{
Data = entity
};
}
}
@@ -0,0 +1,124 @@
using Application.Common.Repositories;
using Application.Features.NumberSequenceManager;
using Domain.Entities;
using Domain.Enums;
using FluentValidation;
using MediatR;
namespace Application.Features.LeadManager.Commands;
public class CreateLeadResult
{
public Lead? Data { get; set; }
}
public class CreateLeadRequest : IRequest<CreateLeadResult>
{
public string? Title { get; init; }
public string? Description { get; init; }
public string? CompanyName { get; init; }
public string? CompanyAddressStreet { get; init; }
public string? CompanyAddressCity { get; init; }
public string? CompanyAddressState { get; init; }
public string? CompanyPhoneNumber { get; init; }
public string? CompanyEmail { get; init; }
public DateTime? DateProspecting { get; init; }
public DateTime? DateClosingEstimation { get; init; }
public DateTime? DateClosingActual { get; init; }
public double? AmountTargeted { get; init; }
public double? AmountClosed { get; init; }
public double? BudgetScore { get; init; }
public double? AuthorityScore { get; init; }
public double? NeedScore { get; init; }
public double? TimelineScore { get; init; }
public string? PipelineStage { get; init; }
public string? ClosingStatus { get; init; }
public string? CampaignId { get; init; }
public string? SalesTeamId { get; init; }
public string? CreatedById { get; init; }
}
public class CreateLeadValidator : AbstractValidator<CreateLeadRequest>
{
public CreateLeadValidator()
{
RuleFor(x => x.Title).NotEmpty();
RuleFor(x => x.SalesTeamId).NotEmpty();
RuleFor(x => x.CompanyName).NotEmpty();
RuleFor(x => x.CompanyAddressStreet).NotEmpty();
RuleFor(x => x.CompanyAddressCity).NotEmpty();
RuleFor(x => x.CompanyAddressState).NotEmpty();
RuleFor(x => x.CompanyPhoneNumber).NotEmpty();
RuleFor(x => x.CompanyEmail).NotEmpty();
RuleFor(x => x.DateProspecting).NotNull();
RuleFor(x => x.DateClosingEstimation).NotNull();
RuleFor(x => x.AmountTargeted).NotNull();
RuleFor(x => x.AmountClosed).NotNull();
RuleFor(x => x.BudgetScore).NotNull();
RuleFor(x => x.AuthorityScore).NotNull();
RuleFor(x => x.NeedScore).NotNull();
RuleFor(x => x.TimelineScore).NotNull();
RuleFor(x => x.PipelineStage).NotEmpty();
RuleFor(x => x.CampaignId).NotEmpty();
}
}
public class CreateLeadHandler : IRequestHandler<CreateLeadRequest, CreateLeadResult>
{
private readonly ICommandRepository<Lead> _repository;
private readonly IUnitOfWork _unitOfWork;
private readonly NumberSequenceService _numberSequenceService;
public CreateLeadHandler(
ICommandRepository<Lead> repository,
IUnitOfWork unitOfWork,
NumberSequenceService numberSequenceService
)
{
_repository = repository;
_unitOfWork = unitOfWork;
_numberSequenceService = numberSequenceService;
}
public async Task<CreateLeadResult> Handle(CreateLeadRequest request, CancellationToken cancellationToken = default)
{
var entity = new Lead
{
CreatedById = request.CreatedById,
Number = _numberSequenceService.GenerateNumber(nameof(Lead), "", "LEA"),
Title = request.Title,
SalesTeamId = request.SalesTeamId,
Description = request.Description,
CompanyName = request.CompanyName,
CompanyAddressStreet = request.CompanyAddressStreet,
CompanyAddressCity = request.CompanyAddressCity,
CompanyAddressState = request.CompanyAddressState,
CompanyPhoneNumber = request.CompanyPhoneNumber,
CompanyEmail = request.CompanyEmail,
DateProspecting = request.DateProspecting,
DateClosingEstimation = request.DateClosingEstimation,
DateClosingActual = request.DateClosingActual,
AmountTargeted = request.AmountTargeted,
AmountClosed = request.AmountClosed,
BudgetScore = request.BudgetScore,
AuthorityScore = request.AuthorityScore,
NeedScore = request.NeedScore,
TimelineScore = request.TimelineScore,
PipelineStage = (PipelineStage)int.Parse(request.PipelineStage!),
CampaignId = request.CampaignId
};
if (!string.IsNullOrEmpty(request.ClosingStatus))
{
entity.ClosingStatus = (ClosingStatus)int.Parse(request.ClosingStatus!);
}
await _repository.CreateAsync(entity, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
return new CreateLeadResult
{
Data = entity
};
}
}
@@ -0,0 +1,60 @@
using Application.Common.Repositories;
using Domain.Entities;
using FluentValidation;
using MediatR;
namespace Application.Features.LeadManager.Commands;
public class DeleteLeadResult
{
public Lead? Data { get; set; }
}
public class DeleteLeadRequest : IRequest<DeleteLeadResult>
{
public string? Id { get; init; }
public string? DeletedById { get; init; }
}
public class DeleteLeadValidator : AbstractValidator<DeleteLeadRequest>
{
public DeleteLeadValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
public class DeleteLeadHandler : IRequestHandler<DeleteLeadRequest, DeleteLeadResult>
{
private readonly ICommandRepository<Lead> _repository;
private readonly IUnitOfWork _unitOfWork;
public DeleteLeadHandler(
ICommandRepository<Lead> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public async Task<DeleteLeadResult> Handle(DeleteLeadRequest request, CancellationToken cancellationToken)
{
var entity = await _repository.GetAsync(request.Id ?? string.Empty, cancellationToken);
if (entity == null)
{
throw new Exception($"Entity not found: {request.Id}");
}
entity.UpdatedById = request.DeletedById;
_repository.Delete(entity);
await _unitOfWork.SaveAsync(cancellationToken);
return new DeleteLeadResult
{
Data = entity
};
}
}

Some files were not shown because too many files have changed in this diff Show More