diff --git a/0_Framework/0_Framework.csproj b/0_Framework/0_Framework.csproj index 54b62986..d4a5ba2f 100644 --- a/0_Framework/0_Framework.csproj +++ b/0_Framework/0_Framework.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 _0_Framework diff --git a/AccountManagement.Application.Contracts/AccountManagement.Application.Contracts.csproj b/AccountManagement.Application.Contracts/AccountManagement.Application.Contracts.csproj index 36069642..393ad8f9 100644 --- a/AccountManagement.Application.Contracts/AccountManagement.Application.Contracts.csproj +++ b/AccountManagement.Application.Contracts/AccountManagement.Application.Contracts.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 diff --git a/AccountManagement.Application/AccountManagement.Application.csproj b/AccountManagement.Application/AccountManagement.Application.csproj index 7fcb4ebe..270c0e13 100644 --- a/AccountManagement.Application/AccountManagement.Application.csproj +++ b/AccountManagement.Application/AccountManagement.Application.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 diff --git a/AccountManagement.Configuration/AccountManagement.Configuration.csproj b/AccountManagement.Configuration/AccountManagement.Configuration.csproj index 0b172228..3914494a 100644 --- a/AccountManagement.Configuration/AccountManagement.Configuration.csproj +++ b/AccountManagement.Configuration/AccountManagement.Configuration.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 diff --git a/AccountManagement.Domain/AccountManagement.Domain.csproj b/AccountManagement.Domain/AccountManagement.Domain.csproj index 031bd6e0..b0cc8442 100644 --- a/AccountManagement.Domain/AccountManagement.Domain.csproj +++ b/AccountManagement.Domain/AccountManagement.Domain.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 diff --git a/AccountMangement.Infrastructure.EFCore/AccountMangement.Infrastructure.EFCore.csproj b/AccountMangement.Infrastructure.EFCore/AccountMangement.Infrastructure.EFCore.csproj index 7899acfa..d75abbba 100644 --- a/AccountMangement.Infrastructure.EFCore/AccountMangement.Infrastructure.EFCore.csproj +++ b/AccountMangement.Infrastructure.EFCore/AccountMangement.Infrastructure.EFCore.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 diff --git a/BackgroundInstitutionContract/BackgroundInstitutionContract.Task/BackgroundInstitutionContract.Task.csproj b/BackgroundInstitutionContract/BackgroundInstitutionContract.Task/BackgroundInstitutionContract.Task.csproj index d30ce3b8..d003ac92 100644 --- a/BackgroundInstitutionContract/BackgroundInstitutionContract.Task/BackgroundInstitutionContract.Task.csproj +++ b/BackgroundInstitutionContract/BackgroundInstitutionContract.Task/BackgroundInstitutionContract.Task.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable BackgroundInstitutionContract.Task diff --git a/BackgroundJobs/BackgroundJobs.Task/BackgroundJobs.Task.csproj b/BackgroundJobs/BackgroundJobs.Task/BackgroundJobs.Task.csproj index 0ab571f8..892e6b99 100644 --- a/BackgroundJobs/BackgroundJobs.Task/BackgroundJobs.Task.csproj +++ b/BackgroundJobs/BackgroundJobs.Task/BackgroundJobs.Task.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable diff --git a/Company.Domain/Company.Domain.csproj b/Company.Domain/Company.Domain.csproj index 924cc212..cde1f022 100644 --- a/Company.Domain/Company.Domain.csproj +++ b/Company.Domain/Company.Domain.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 diff --git a/CompanyManagement.Infrastructure.Excel/CompanyManagement.Infrastructure.Excel.csproj b/CompanyManagement.Infrastructure.Excel/CompanyManagement.Infrastructure.Excel.csproj index a62b92f9..7053b025 100644 --- a/CompanyManagement.Infrastructure.Excel/CompanyManagement.Infrastructure.Excel.csproj +++ b/CompanyManagement.Infrastructure.Excel/CompanyManagement.Infrastructure.Excel.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable diff --git a/CompanyManagement.Infrastructure.Mongo/CompanyManagement.Infrastructure.Mongo.csproj b/CompanyManagement.Infrastructure.Mongo/CompanyManagement.Infrastructure.Mongo.csproj index 4c09d4ae..75b4e0f3 100644 --- a/CompanyManagement.Infrastructure.Mongo/CompanyManagement.Infrastructure.Mongo.csproj +++ b/CompanyManagement.Infrastructure.Mongo/CompanyManagement.Infrastructure.Mongo.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable diff --git a/CompanyManagment.App.Contracts/CompanyManagment.App.Contracts.csproj b/CompanyManagment.App.Contracts/CompanyManagment.App.Contracts.csproj index b2977176..07606229 100644 --- a/CompanyManagment.App.Contracts/CompanyManagment.App.Contracts.csproj +++ b/CompanyManagment.App.Contracts/CompanyManagment.App.Contracts.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 true diff --git a/CompanyManagment.Application/CompanyManagment.Application.csproj b/CompanyManagment.Application/CompanyManagment.Application.csproj index 36154b43..d6b12f2d 100644 --- a/CompanyManagment.Application/CompanyManagment.Application.csproj +++ b/CompanyManagment.Application/CompanyManagment.Application.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 diff --git a/CompanyManagment.EFCore/CompanyManagment.EFCore.csproj b/CompanyManagment.EFCore/CompanyManagment.EFCore.csproj index 7ea4c3cd..381b2623 100644 --- a/CompanyManagment.EFCore/CompanyManagment.EFCore.csproj +++ b/CompanyManagment.EFCore/CompanyManagment.EFCore.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 diff --git a/DadmehrGostar.sln b/DadmehrGostar.sln index b6cf7ab9..358d6d87 100644 --- a/DadmehrGostar.sln +++ b/DadmehrGostar.sln @@ -88,6 +88,22 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompanyManagement.Infrastru EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackgroundInstitutionContract.Task", "BackgroundInstitutionContract\BackgroundInstitutionContract.Task\BackgroundInstitutionContract.Task.csproj", "{F78FBB92-294B-88BA-168D-F0C578B0D7D6}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProgramManager", "ProgramManager", "{67AFF7B6-4C4F-464C-A90D-9BDB644D83A9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{48F6F6A5-7340-42F8-9216-BEB7A4B7D5A1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Application", "Application", "{9D85672B-D48E-40B5-9804-0CE220E0E64C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Domain", "Domain", "{D74D1E3B-3BE3-47EE-9914-785A8AD536E5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Infrastructure", "Infrastructure", "{C0AE9368-D4E7-450B-9713-929D319DE690}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GozareshgirProgramManager.Application", "ProgramManager\src\Application\GozareshgirProgramManager.Application\GozareshgirProgramManager.Application.csproj", "{B57EB542-C028-4A77-9386-9DFF1E60FDCB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GozareshgirProgramManager.Domain", "ProgramManager\src\Domain\GozareshgirProgramManager.Domain\GozareshgirProgramManager.Domain.csproj", "{D2B4F1D7-6336-4B30-910C-219F4119303F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GozareshgirProgramManager.Infrastructure", "ProgramManager\src\Infrastructure\GozareshgirProgramManager.Infrastructure\GozareshgirProgramManager.Infrastructure.csproj", "{408281FE-615F-4CBE-BD95-2E86F5ACC6C3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -198,6 +214,18 @@ Global {F78FBB92-294B-88BA-168D-F0C578B0D7D6}.Debug|Any CPU.Build.0 = Debug|Any CPU {F78FBB92-294B-88BA-168D-F0C578B0D7D6}.Release|Any CPU.ActiveCfg = Release|Any CPU {F78FBB92-294B-88BA-168D-F0C578B0D7D6}.Release|Any CPU.Build.0 = Release|Any CPU + {B57EB542-C028-4A77-9386-9DFF1E60FDCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B57EB542-C028-4A77-9386-9DFF1E60FDCB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B57EB542-C028-4A77-9386-9DFF1E60FDCB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B57EB542-C028-4A77-9386-9DFF1E60FDCB}.Release|Any CPU.Build.0 = Release|Any CPU + {D2B4F1D7-6336-4B30-910C-219F4119303F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2B4F1D7-6336-4B30-910C-219F4119303F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2B4F1D7-6336-4B30-910C-219F4119303F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2B4F1D7-6336-4B30-910C-219F4119303F}.Release|Any CPU.Build.0 = Release|Any CPU + {408281FE-615F-4CBE-BD95-2E86F5ACC6C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {408281FE-615F-4CBE-BD95-2E86F5ACC6C3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {408281FE-615F-4CBE-BD95-2E86F5ACC6C3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {408281FE-615F-4CBE-BD95-2E86F5ACC6C3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -234,6 +262,13 @@ Global {BF98173C-42AF-4897-A7CB-4CACEB2B52A2} = {86921E1B-2AFA-4B8A-9403-EE16D58B5B26} {97E148FA-3C36-40DD-B121-D90C1C0F3B47} = {C10E256D-7E7D-4C77-B416-E577A34AF924} {F78FBB92-294B-88BA-168D-F0C578B0D7D6} = {C10E256D-7E7D-4C77-B416-E577A34AF924} + {48F6F6A5-7340-42F8-9216-BEB7A4B7D5A1} = {67AFF7B6-4C4F-464C-A90D-9BDB644D83A9} + {9D85672B-D48E-40B5-9804-0CE220E0E64C} = {48F6F6A5-7340-42F8-9216-BEB7A4B7D5A1} + {D74D1E3B-3BE3-47EE-9914-785A8AD536E5} = {48F6F6A5-7340-42F8-9216-BEB7A4B7D5A1} + {C0AE9368-D4E7-450B-9713-929D319DE690} = {48F6F6A5-7340-42F8-9216-BEB7A4B7D5A1} + {B57EB542-C028-4A77-9386-9DFF1E60FDCB} = {9D85672B-D48E-40B5-9804-0CE220E0E64C} + {D2B4F1D7-6336-4B30-910C-219F4119303F} = {D74D1E3B-3BE3-47EE-9914-785A8AD536E5} + {408281FE-615F-4CBE-BD95-2E86F5ACC6C3} = {C0AE9368-D4E7-450B-9713-929D319DE690} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E6CFB3A7-A7C8-4E82-8F06-F750408F0BA9} diff --git a/PersonalContractingParty.Config/PersonalContractingParty.Config.csproj b/PersonalContractingParty.Config/PersonalContractingParty.Config.csproj index 3e55f945..9e36ff54 100644 --- a/PersonalContractingParty.Config/PersonalContractingParty.Config.csproj +++ b/PersonalContractingParty.Config/PersonalContractingParty.Config.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/DomainEventHandlers/CustomerRegisteredHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/DomainEventHandlers/CustomerRegisteredHandler.cs new file mode 100644 index 00000000..778f3104 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/DomainEventHandlers/CustomerRegisteredHandler.cs @@ -0,0 +1,33 @@ +using MediatR; +using Microsoft.Extensions.Logging; +using GozareshgirProgramManager.Domain.CustomerAgg.Events; +using GozareshgirProgramManager.Application._Common.Models; + +namespace GozareshgirProgramManager.Application.DomainEventHandlers; + +public class CustomerRegisteredHandler : INotificationHandler> +{ + private readonly ILogger _logger; + + public CustomerRegisteredHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(DomainEventNotification notification, CancellationToken cancellationToken) + { + var domainEvent = notification.DomainEvent; + + _logger.LogInformation( + "Customer registered: {CustomerId}, Name: {Name}, Email: {Email}", + domainEvent.CustomerId, + domainEvent.Name, + domainEvent.Email); + + + // اینجا می‌توانید email ارسال کنید یا کارهای دیگر انجام دهید + + return Task.CompletedTask; + } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/DomainEventHandlers/ProjectSection/TaskSectionAddedHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/DomainEventHandlers/ProjectSection/TaskSectionAddedHandler.cs new file mode 100644 index 00000000..a7538ef2 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/DomainEventHandlers/ProjectSection/TaskSectionAddedHandler.cs @@ -0,0 +1,23 @@ +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Interfaces; +using GozareshgirProgramManager.Domain.ProjectAgg.Events; +using MediatR; +using Microsoft.Extensions.Logging; + +namespace GozareshgirProgramManager.Application.DomainEventHandlers.ProjectSection; + +public class ProjectSectionAddedHandler:INotificationHandler> +{ + private readonly ILogger _logger; + + public ProjectSectionAddedHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(DomainEventNotification notification, CancellationToken cancellationToken) + { + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/DomainEventHandlers/ProjectSection/TaskSectionAssignedHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/DomainEventHandlers/ProjectSection/TaskSectionAssignedHandler.cs new file mode 100644 index 00000000..3f86a177 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/DomainEventHandlers/ProjectSection/TaskSectionAssignedHandler.cs @@ -0,0 +1,14 @@ +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain.ProjectAgg.Events; +using MediatR; + +namespace GozareshgirProgramManager.Application.DomainEventHandlers.ProjectSection; + +public class ProjectSectionAssignedHandler:INotificationHandler> +{ + public Task Handle(DomainEventNotification notification, CancellationToken cancellationToken) + { + var domainEvent = notification.DomainEvent; + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/GozareshgirProgramManager.Application.csproj b/ProgramManager/src/Application/GozareshgirProgramManager.Application/GozareshgirProgramManager.Application.csproj new file mode 100644 index 00000000..7bd51642 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/GozareshgirProgramManager.Application.csproj @@ -0,0 +1,20 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Interfaces/IBoardNotificationService.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Interfaces/IBoardNotificationService.cs new file mode 100644 index 00000000..959e7fbf --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Interfaces/IBoardNotificationService.cs @@ -0,0 +1,6 @@ +namespace GozareshgirProgramManager.Application.Interfaces; + +public interface IBoardNotificationService +{ + Task SendProjectAssignedAsync(); +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Checkouts/Commands/CreateCheckout/CreateOrEditCheckoutCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Checkouts/Commands/CreateCheckout/CreateOrEditCheckoutCommandHandler.cs new file mode 100644 index 00000000..d7704b1f --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Checkouts/Commands/CreateCheckout/CreateOrEditCheckoutCommandHandler.cs @@ -0,0 +1,266 @@ + +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Checkouts.Queries.GetUserToGropCreate; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.CheckoutAgg.Entities; +using GozareshgirProgramManager.Domain.CheckoutAgg.Enums; +using GozareshgirProgramManager.Domain.CheckoutAgg.Repositories; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.DTOs; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Enums; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Repositories; +using GozareshgirProgramManager.Domain.UserAgg.Entities; +using MediatR; +using PersianTools.Core; +using System.Runtime.InteropServices; +using Microsoft.EntityFrameworkCore; + + +namespace GozareshgirProgramManager.Application.Modules.Checkouts.Commands.CreateCheckout; + +public class CreateOrEditCheckoutCommandHandler : IBaseCommandHandler +{ + private readonly ICheckoutRepository _checkoutRepository; + private readonly ISalaryPaymentSettingRepository _salaryPaymentSettingRepository; + private readonly ITaskSectionActivityRepository _taskSectionActivityRepository; + private readonly IUnitOfWork _unitOfWork; + private readonly IGozareshgirDbContext _gozareshgirDbContext; + + + public CreateOrEditCheckoutCommandHandler(ICheckoutRepository checkoutRepository, IUnitOfWork unitOfWork, ISalaryPaymentSettingRepository salaryPaymentSettingRepository, ITaskSectionActivityRepository taskSectionActivityRepository, IGozareshgirDbContext gozareshgirDbContext) + { + _checkoutRepository = checkoutRepository; + _unitOfWork = unitOfWork; + _salaryPaymentSettingRepository = salaryPaymentSettingRepository; + _taskSectionActivityRepository = taskSectionActivityRepository; + _gozareshgirDbContext = gozareshgirDbContext; + } + + public async Task Handle(CreateOrEditCheckoutCommand request, CancellationToken cancellationToken) + { + + switch (request.TypeOfCheckoutHandler) + { + case TypeOfCheckoutHandler.CreateInGroup: + return await Create(request.Year, request.Month, request.UserIdList); + break; + case TypeOfCheckoutHandler.SingleEdit: + case TypeOfCheckoutHandler.GroupEditing: + return await GroupOrSingleEditing(request.CheckoutIdList); + break; + + } + return OperationResult.Failure("نوع متد انتخاب نشده است"); + } + + /// + /// ایجاد گروهی فیش حقوقی + /// + /// + /// + /// + /// + public async Task Create(string? Year, string? Month, List? UserIdList) + { + if (string.IsNullOrWhiteSpace(Month)) + return OperationResult.Failure("ماه خالی است"); + if (string.IsNullOrWhiteSpace(Year)) + return OperationResult.Failure("سال خالی است"); + if (UserIdList == null) + return OperationResult.Failure("هیچ موردی برای ایجاد انتخاب نشده اشت"); + if (UserIdList.Count == 0) + return OperationResult.Failure("هیچ موردی برای ایجاد انتخاب نشده اشت"); + + var startDateGr = new DateTime(); + var EndDateGr = new DateTime(); + var persianStart = new PersianDateTime(); + + int year = 0; + int month = 0; + try + { + year = Convert.ToInt32(Year); + month = Convert.ToInt32(Month); + persianStart = new PersianDateTime(year, month, 1); + var startDateFa = $"{persianStart}"; + startDateGr = startDateFa.ToGeorgianDateTime(); + + var endDateFa = startDateFa.FindeEndOfMonth(); + + EndDateGr = endDateFa.ToGeorgianDateTime(); + + + } + catch (Exception) + { + + return OperationResult.Failure( + "خطا در ورود سال و ماه"); + } + + var totalDays = Convert.ToInt32((EndDateGr - startDateGr).TotalDays + 1); + + var getAllSettings = await _salaryPaymentSettingRepository.GetAllSettings(UserIdList); + var get = await _taskSectionActivityRepository.GetTotalTimeSpentPerUserInRangeAsync(startDateGr, EndDateGr); + + foreach (var user in getAllSettings) + { + var totalWorked = get.FirstOrDefault(x => x.UserId == user.UserId); + var totalTimeTotalMinutes = (int)totalWorked.TotalTime.TotalMinutes; + var res = await ComputeSalary(user.WorkingHoursListDto, totalTimeTotalMinutes, user.MonthlySalary, startDateGr, EndDateGr, user.HolidayWorking); + var createCheckout = new Checkout(startDateGr, EndDateGr, year, month, user.FullName, user.UserId, + res.MandatoryHours, totalTimeTotalMinutes, + totalDays, res.RemainingHours, user.MonthlySalary, res.MonthlySalaryPay, res.DeductionFromSalary); + await _checkoutRepository.CreateAsync(createCheckout); + } + + await _unitOfWork.SaveChangesAsync(); + + return OperationResult.Success(); + } + + /// + /// متد ویراش گروهی و تکی + /// + /// + /// + /// + /// + public async Task GroupOrSingleEditing(List? CheckoutIdList) + { + + if (CheckoutIdList == null) + return OperationResult.Failure("هیچ موردی برای ویرایش انتخاب نشده اشت"); + if (CheckoutIdList.Count == 0) + return OperationResult.Failure("هیچ موردی برای ویرایش انتخاب نشده اشت"); + + var checkouts = await _checkoutRepository.GetCheckoutListByIds(CheckoutIdList); + if (!checkouts.Any()) + return OperationResult.Failure("هیچ موردی برای ویرایش انتخاب نشده اشت"); + var UserIdList = checkouts.Select(x => x.UserId).ToList(); + var getAllSettings = await _salaryPaymentSettingRepository.GetAllSettings(UserIdList); + if (!getAllSettings.Any()) + return OperationResult.Failure("تنظیمات ساعت و حقوق یافت نشد"); + foreach (var checkoutId in CheckoutIdList) + { + var checkout = checkouts.FirstOrDefault(x => x.Id == checkoutId); + if (checkout == null) + return OperationResult.Failure("فیش مورد نظر یافت نشد"); + + var userSetting = getAllSettings.FirstOrDefault(x => x.UserId == checkout.UserId); + + var get = await _taskSectionActivityRepository.GetTotalTimeSpentByUserInRangeAsync(checkout.UserId, checkout.CheckoutStartDate, checkout.CheckoutEndDate); + + var totalTimeTotalMinutes = (int)get.TotalMinutes; + + var totalDays = Convert.ToInt32((checkout.CheckoutEndDate - checkout.CheckoutStartDate).TotalDays + 1); + var res = await ComputeSalary(userSetting.WorkingHoursListDto, totalTimeTotalMinutes, userSetting.MonthlySalary, checkout.CheckoutStartDate, checkout.CheckoutEndDate, userSetting.HolidayWorking); + checkout.Edit(res.MandatoryHours, totalTimeTotalMinutes, totalDays, res.RemainingHours, userSetting.MonthlySalary, res.MonthlySalaryPay, res.DeductionFromSalary); + + await _unitOfWork.SaveChangesAsync(); + } + + + + return OperationResult.Success(); + } + + /// + /// محاسبه حقوق + /// + /// + public async Task ComputeSalary(List workingHoursListDto, int totalHoursWorked, double monthlySalaryDefined, DateTime start, DateTime end, bool holidayWorking) + { + var startDate = start.ToFarsi(); + var startYear = Convert.ToInt32(startDate.Substring(0, 4)); + var startMonth = Convert.ToInt32(startDate.Substring(5, 2)); + var startDay = Convert.ToInt32(startDate.Substring(8, 2)); + var persianStart = new PersianDateTime(startYear, startMonth, startDay); + var endDate = end.ToFarsi(); + var endYear = Convert.ToInt32(endDate.Substring(0, 4)); + var endMonth = Convert.ToInt32(endDate.Substring(5, 2)); + var endDay = Convert.ToInt32(endDate.Substring(8, 2)); + var persianEnd = new PersianDateTime(endYear, endMonth, endDay); + var holidays = await _gozareshgirDbContext.HolidayItems.Where(x=>x.Holidaydate >= start && x.Holidaydate <= end).ToListAsync(); + + + int mandatoryHours = 0; + for (var currentDay = persianStart; currentDay <= persianEnd; currentDay = currentDay.AddDays(1)) + { + var currentDayOfWeek = new DNTPersianUtils.Core.PersianDateTime(currentDay.Year, currentDay.Month, currentDay.Day); + var holidayDate = currentDay.ShamsiDate.ToGeorgianDateTime(); + var day = (PersianDayOfWeek)currentDayOfWeek.WeekDayNumber!; + var getDaySetting = workingHoursListDto.FirstOrDefault(x => x.PersianDayOfWeek == day); + if (getDaySetting != null) + { + if (!holidayWorking && holidays.Any(x => x.Holidaydate == holidayDate)) + { + + } + else + { + mandatoryHours += (int)getDaySetting.ShiftDuration.TotalMinutes; + Console.WriteLine((int)getDaySetting.ShiftDuration.TotalMinutes + " " + currentDay + " - " + day); + } + + + + } + + + + + } + //حقوق نهایی + var monthlySalaryPay = (totalHoursWorked * monthlySalaryDefined) / mandatoryHours; + // اگر اضافه کار داشت حقوق تعین شده به عنوان حقوق نهایی در نظر گرفته میشود + monthlySalaryPay = monthlySalaryPay > monthlySalaryDefined ? monthlySalaryDefined : monthlySalaryPay; + + //حقوق کسر شده + var deductionFromSalary = monthlySalaryDefined - monthlySalaryPay; + + //زمان باقی مانده + var remainingTime = totalHoursWorked - mandatoryHours; + + var computeResult = new ComputeResultDto + { + MandatoryHours = mandatoryHours, + MonthlySalaryPay = monthlySalaryPay, + DeductionFromSalary = deductionFromSalary, + RemainingHours = remainingTime + }; + Console.WriteLine(mandatoryHours); + return computeResult; + } + +} + + +public record CreateOrEditCheckoutCommand(TypeOfCheckoutHandler TypeOfCheckoutHandler, string? Year, string? Month, List? UserIdList, List? CheckoutIdList) : IBaseCommand; + +public record ComputeResultDto +{ + + /// + /// ساعات باقی مانده + /// کسر کار یا اضافه کار + /// + public int RemainingHours { get; set; } + + + /// + /// حقوق نهایی که به پرسنل داده می شود + /// + public double MonthlySalaryPay { get; set; } + + /// + /// کسر از حقوق + /// + public double DeductionFromSalary { get; set; } + + /// + /// ساعت موظفی + /// + public int MandatoryHours { get; set; } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Checkouts/Queries/GetCheckoutList/GetCheckoutListQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Checkouts/Queries/GetCheckoutList/GetCheckoutListQueryHandler.cs new file mode 100644 index 00000000..f2a93459 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Checkouts/Queries/GetCheckoutList/GetCheckoutListQueryHandler.cs @@ -0,0 +1,130 @@ +using GozareshgirProgramManager.Application._Common.Extensions; +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Checkouts.Queries.GetUserToGropCreate; +using GozareshgirProgramManager.Domain._Common; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Checkouts.Queries.GetCheckoutList; + +public class GetCheckoutListQueryHandler : IBasePaginationQueryHandler +{ + private readonly IProgramManagerDbContext _programManagerDbContext; + + public GetCheckoutListQueryHandler(IProgramManagerDbContext programManagerDbContext) + { + _programManagerDbContext = programManagerDbContext; + } + + public async Task>> Handle(GetCheckoutListQuery request, CancellationToken cancellationToken) + { + var query = _programManagerDbContext.Checkouts.AsQueryable(); + + if (!string.IsNullOrWhiteSpace(request.Year)) + { + var year = Convert.ToInt32(request.Year); + query = query.Where(x => x.Year == year); + + } + + if (!string.IsNullOrWhiteSpace(request.Month)) + { + var month = Convert.ToInt32(request.Month); + query = query.Where(x => x.Month == month); + } + + if (!string.IsNullOrWhiteSpace(request.FullName)) + query = query.Where(x => x.FullName.Contains(request.FullName)); + + var res =await query.Select(x => new GetCheckoutListResponse() + { + CheckoutId = x.Id, + Year = x.Year, + Month = x.PersianMonthName, + FullName = x.FullName, + MandatoryHours = x.MandatoryHours, + TotalHoursWorked = x.TotalHoursWorked, + RemainingHours = x.RemainingHours, + MonthlySalaryDefined = x.MonthlySalaryDefined.ToMoney(), + DeductionFromSalary = x.DeductionFromSalary.ToMoney(), + MonthlySalaryPay = x.MonthlySalaryPay.ToMoney() + + + }).ApplyPagination(request.PageIndex,request.PageSize).ToListAsync(cancellationToken: cancellationToken); + + var response = new PaginationResult + { + List = res, + TotalCount = query.Count(), + }; + + return OperationResult>.Success(response); + } +} + +public record GetCheckoutListQuery(string? Month, string? Year, string? FullName) : PaginationRequest, IBasePaginationQuery; + +public record GetCheckoutListResponse +{ + /// + /// آی دی فیش حقوقی + /// + public Guid CheckoutId { get; set; } + + /// + /// سال + /// + public int Year { get; set; } + + /// + /// ماه + /// + public string Month { get; set; } + + /// + /// نام کامل پرسنل + /// + public string FullName { get; set; } + + + /// + /// ساعت موظفی + /// + public int MandatoryHours { get; set; } + + /// + /// مجموع ساعات کارکرد پرسنل + /// + public int TotalHoursWorked { get; set; } + + /// + /// ساعات باقی مانده + /// کسر کار یا اضافه کار + /// + public int RemainingHours { get; set; } + + + /// + /// حقوق ماهانه + /// تعیین شده + /// + public string MonthlySalaryDefined { get; set; } + + + /// + /// کسر از حقوق + /// + public string DeductionFromSalary { get; set; } + + + /// + /// حقوق نهایی که به پرسنل داده می شود + /// + public string MonthlySalaryPay { get; set; } +} + + + + + + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Checkouts/Queries/GetUserToGropCreate/GetUserToGroupCreatingQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Checkouts/Queries/GetUserToGropCreate/GetUserToGroupCreatingQueryHandler.cs new file mode 100644 index 00000000..1b04026a --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Checkouts/Queries/GetUserToGropCreate/GetUserToGroupCreatingQueryHandler.cs @@ -0,0 +1,174 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Queries.GetUserListWhoHaveSettings; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.CheckoutAgg.Enums; +using Microsoft.EntityFrameworkCore; +using PersianTools.Core; + +namespace GozareshgirProgramManager.Application.Modules.Checkouts.Queries.GetUserToGropCreate; + +/// +/// دریافت کاربران برای ایجاد گروهی فیش حقوقی با سال و ماه +/// +public class GetUserToGroupCreatingQueryHandler : IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _context; + + public GetUserToGroupCreatingQueryHandler(IProgramManagerDbContext context) + { + _context = context; + } + + public async Task> Handle(GetUserToGroupCreatingQuery request, CancellationToken cancellationToken) + { + //سال و ماه انتخاب شده از فرانت + var selectedDate = new DateTime(); + try + { + int year = Convert.ToInt32(request.Year); + int month = Convert.ToInt32(request.Month); + selectedDate = ($"{new PersianDateTime(year,month,1)}").ToGeorgianDateTime(); + } + catch (Exception) + { + + return OperationResult.Failure( + "خطا در ورود سال و ماه"); + } + + //آخرین تاریخ مجاز برای ایجاد فیش + var lastMonth = ($"{DateTime.Now.ToFarsi().Substring(0, 8)}01").ToGeorgianDateTime().AddDays(-1); + + if (selectedDate > lastMonth) + return OperationResult.Failure( + "ایجاد فیش فقط برای ماه های گذشته امکان پذیر است"); + + + var lastMonthStart = lastMonth; + var lastMonthEnd = lastMonth; + + var query = + await (from u in _context.Users + + // LEFT JOIN + // تنظیمات حقوق + join s in _context.SalaryPaymentSettings + on u.Id equals s.UserId into sJoin + from s in sJoin.DefaultIfEmpty() + + // LEFT JOIN + //فیش + join ch in _context.Checkouts + .Where(x => x.CheckoutStartDate < lastMonthStart + && x.CheckoutEndDate >= lastMonthStart) + on u.Id equals ch.UserId into chJoin + from ch in chJoin.DefaultIfEmpty() + + group new { s, ch } by new { u.Id, u.FullName } into g + + select new GetUserWhoHaveSettingsAndCheckoutDto + { + UserId = g.Key.Id, + FullName = g.Key.FullName, + + HasSalarySettings = g.Any(x => x.s != null), + HasCheckout = g.Any(x => x.ch != null) + }) + .ToListAsync(cancellationToken); + + + + + + var responseList = query.Select(x => + { + + bool validToCreate = x.HasSalarySettings && !x.HasCheckout; + string message = "آماده تنظیم"; + CreateCheckoutStatus createCheckoutStatus = CreateCheckoutStatus.ReadyToCreate; + if (x.HasCheckout) + { + message = "موجود است"; + createCheckoutStatus = CreateCheckoutStatus.AlreadyCreated; + } + + + if (!x.HasSalarySettings) + { + message = "فاقد تنظیمات"; + createCheckoutStatus = CreateCheckoutStatus.NotSetSalaryPaymentSettings; + } + + + return new GetUserToGroupCreatingDto + { + UserId = x.UserId, + FullName = x.FullName, + IsValidToCreate = validToCreate, + StatusMessage = message, + CreateCheckoutStatus = createCheckoutStatus + + }; + + }).OrderByDescending(x=>x.IsValidToCreate).ToList(); + + var response = new GetUserToGroupCreatingResponse(responseList); + + return OperationResult.Success(response); + } +} + + +public record GetUserToGroupCreatingQuery(string Year, string Month) : IBaseQuery; + +public record GetUserToGroupCreatingResponse(List GetUserToGroupCreatingDtoList); + +public record GetUserToGroupCreatingDto +{ + /// + /// آی دی کاربر + /// + public long UserId { get; set; } + + /// + /// نام کامل پرسنل + /// + public string FullName { get; set; } + + + /// + /// پیام وضعیت ایجاد فیش + /// + public string StatusMessage { get; set; } + + /// + /// آیا مجاز به ایجاد فیش می باشد + /// + public bool IsValidToCreate { get; set; } + + public CreateCheckoutStatus CreateCheckoutStatus { get; set; } + +} + + +public record GetUserWhoHaveSettingsAndCheckoutDto +{ + /// + /// آی دی کاربر + /// + public long UserId { get; set; } + + /// + /// نام کامل پرسنل + /// + public string FullName { get; set; } + + /// + /// داشتن تنظیمات + /// + public bool HasSalarySettings { get; set; } + + + public bool HasCheckout { get; set; } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AddPhaseToProject/AddPhaseToProjectCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AddPhaseToProject/AddPhaseToProjectCommand.cs new file mode 100644 index 00000000..427904e0 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AddPhaseToProject/AddPhaseToProjectCommand.cs @@ -0,0 +1,13 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AddPhaseToProject; + +/// +/// Command to add a phase to an existing project +/// +public record AddPhaseToProjectCommand( + Guid ProjectId, + string Name, + string? Description = null, + int OrderIndex = 0 +) : IBaseCommand; diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AddPhaseToProject/AddPhaseToProjectCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AddPhaseToProject/AddPhaseToProjectCommandHandler.cs new file mode 100644 index 00000000..3eadac95 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AddPhaseToProject/AddPhaseToProjectCommandHandler.cs @@ -0,0 +1,47 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using MediatR; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AddPhaseToProject; + +public class AddPhaseToProjectCommandHandler : IRequestHandler +{ + private readonly IProjectRepository _projectRepository; + private readonly IUnitOfWork _unitOfWork; + + public AddPhaseToProjectCommandHandler( + IProjectRepository projectRepository, + IUnitOfWork unitOfWork) + { + _projectRepository = projectRepository; + _unitOfWork = unitOfWork; + } + + public async Task Handle(AddPhaseToProjectCommand request, CancellationToken cancellationToken) + { + try + { + // Get project + var project = await _projectRepository.GetByIdAsync(request.ProjectId); + if (project == null) + { + return OperationResult.NotFound("پروژه یافت نشد"); + } + + // Add phase + var phase = project.AddPhase(request.Name, request.Description); + phase.SetOrderIndex(request.OrderIndex); + + // Save changes + await _unitOfWork.SaveChangesAsync(cancellationToken); + + return OperationResult.Success(); + } + catch (Exception ex) + { + return OperationResult.Failure($"خطا در افزودن فاز: {ex.Message}"); + } + } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AddTaskToPhase/AddTaskToPhaseCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AddTaskToPhase/AddTaskToPhaseCommand.cs new file mode 100644 index 00000000..ba82f57c --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AddTaskToPhase/AddTaskToPhaseCommand.cs @@ -0,0 +1,16 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AddTaskToPhase; + +/// +/// Command to add a task to an existing phase +/// +public record AddTaskToPhaseCommand( + Guid PhaseId, + string Name, + string? Description = null, + TaskPriority Priority = TaskPriority.Medium, + int OrderIndex = 0, + DateTime? DueDate = null +) : IBaseCommand; diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AddTaskToPhase/AddTaskToPhaseCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AddTaskToPhase/AddTaskToPhaseCommandHandler.cs new file mode 100644 index 00000000..360811a7 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AddTaskToPhase/AddTaskToPhaseCommandHandler.cs @@ -0,0 +1,53 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using MediatR; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AddTaskToPhase; + +public class AddTaskToPhaseCommandHandler : IRequestHandler +{ + private readonly IProjectPhaseRepository _phaseRepository; + private readonly IUnitOfWork _unitOfWork; + + public AddTaskToPhaseCommandHandler( + IProjectPhaseRepository phaseRepository, + IUnitOfWork unitOfWork) + { + _phaseRepository = phaseRepository; + _unitOfWork = unitOfWork; + } + + public async Task Handle(AddTaskToPhaseCommand request, CancellationToken cancellationToken) + { + try + { + // Get phase + var phase = await _phaseRepository.GetByIdAsync(request.PhaseId); + if (phase == null) + { + return OperationResult.NotFound("فاز یافت نشد"); + } + + // Add task + var task = phase.AddTask(request.Name, request.Description); + task.SetPriority(request.Priority); + task.SetOrderIndex(request.OrderIndex); + + if (request.DueDate.HasValue) + { + task.SetDates(dueDate: request.DueDate); + } + + // Save changes + await _unitOfWork.SaveChangesAsync(cancellationToken); + + return OperationResult.Success(); + } + catch (Exception ex) + { + return OperationResult.Failure($"خطا در افزودن تسک: {ex.Message}"); + } + } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AssignProject/AssignProjectCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AssignProject/AssignProjectCommand.cs new file mode 100644 index 00000000..805ddb50 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AssignProject/AssignProjectCommand.cs @@ -0,0 +1,18 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AssignProject; + +public class AssignProjectCommand:IBaseCommand +{ + public List Items { get; set; } + public Guid Id { get; set; } + public ProjectHierarchyLevel Level { get; set; } + public bool CascadeToChildren { get; set; } +} + +public class AssignProjectCommandItem +{ + public long UserId { get; set; } + public Guid SkillId { get; set; } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AssignProject/AssignProjectCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AssignProject/AssignProjectCommandHandler.cs new file mode 100644 index 00000000..7dddf33e --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AssignProject/AssignProjectCommandHandler.cs @@ -0,0 +1,274 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using GozareshgirProgramManager.Domain.SkillAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AssignProject; + +public class AssignProjectCommandHandler:IBaseCommandHandler +{ + private readonly IUnitOfWork _unitOfWork; + private readonly IProjectRepository _projectRepository; + private readonly IProjectPhaseRepository _projectPhaseRepository; + private readonly IProjectTaskRepository _projectTaskRepository; + private readonly ISkillRepository _skillRepository; + private readonly IPhaseSectionRepository _phaseSectionRepository; + private readonly IProjectSectionRepository _projectSectionRepository; + private readonly ITaskSectionRepository _taskSectionRepository; + + + public AssignProjectCommandHandler( + IProjectRepository projectRepository, + IProjectPhaseRepository projectPhaseRepository, + IProjectTaskRepository projectTaskRepository, + IUnitOfWork unitOfWork, + ISkillRepository skillRepository, + IPhaseSectionRepository phaseSectionRepository, + IProjectSectionRepository projectSectionRepository, + ITaskSectionRepository taskSectionRepository) + { + _projectRepository = projectRepository; + _projectPhaseRepository = projectPhaseRepository; + _projectTaskRepository = projectTaskRepository; + _unitOfWork = unitOfWork; + _skillRepository = skillRepository; + _phaseSectionRepository = phaseSectionRepository; + _projectSectionRepository = projectSectionRepository; + _taskSectionRepository = taskSectionRepository; + } + + public async Task Handle(AssignProjectCommand request, CancellationToken cancellationToken) + { + switch (request.Level) + { + case ProjectHierarchyLevel.Project: + return await AssignProject(request); + case ProjectHierarchyLevel.Phase: + return await AssignProjectPhase(request); + case ProjectHierarchyLevel.Task: + return await AssignProjectTask(request); + default: + return OperationResult.Failure("سطح پروژه نامعتبر است"); + } + } + + private async Task AssignProject(AssignProjectCommand request) + { + var project = await _projectRepository.GetWithFullHierarchyAsync(request.Id); + if (project is null) + { + return OperationResult.NotFound("پروژه یافت نشد"); + } + + // تخصیص در سطح پروژه + foreach (var item in request.Items) + { + var skill = await _skillRepository.GetByIdAsync(item.SkillId); + if (skill is null) + { + return OperationResult.NotFound($"مهارت با شناسه {item.SkillId} یافت نشد"); + } + + // بررسی و به‌روزرسانی یا اضافه کردن ProjectSection + var existingSection = project.ProjectSections.FirstOrDefault(s => s.SkillId == item.SkillId); + if (existingSection != null) + { + // اگر وجود داشت، فقط userId را به‌روزرسانی کن + existingSection.UpdateUser(item.UserId); + } + else + { + // اگر وجود نداشت، اضافه کن + var newSection = new ProjectSection(project.Id, item.UserId, item.SkillId); + await _projectSectionRepository.CreateAsync(newSection); + } + } + + // حالا برای تمام فازها و تسک‌ها cascade کن + foreach (var phase in project.Phases) + { + // اگر CascadeToChildren true است یا فاز override ندارد + if (request.CascadeToChildren || !phase.HasAssignmentOverride) + { + // برای phase هم باید section‌ها را به‌روزرسانی کنیم + foreach (var item in request.Items) + { + var existingSection = phase.PhaseSections.FirstOrDefault(s => s.SkillId == item.SkillId); + if (existingSection != null) + { + existingSection.Update(item.UserId, item.SkillId); + } + else + { + var newPhaseSection = new PhaseSection(phase.Id, item.UserId, item.SkillId); + await _phaseSectionRepository.CreateAsync(newPhaseSection); + } + } + + foreach (var task in phase.Tasks) + { + // اگر CascadeToChildren true است یا تسک override ندارد + if (request.CascadeToChildren || !task.HasAssignmentOverride) + { + foreach (var item in request.Items) + { + var section = task.Sections.FirstOrDefault(s => s.SkillId == item.SkillId); + if (section != null) + { + // استفاده از TransferToUser + if (section.CurrentAssignedUserId != item.UserId) + { + if (section.CurrentAssignedUserId > 0) + { + section.TransferToUser(section.CurrentAssignedUserId, item.UserId); + } + else + { + section.AssignToUser(item.UserId); + } + } + } + else + { + var newTaskSection = new TaskSection(task.Id, item.SkillId, item.UserId); + await _taskSectionRepository.CreateAsync(newTaskSection); + } + } + } + } + } + } + + await _unitOfWork.SaveChangesAsync(); + return OperationResult.Success(); + } + + private async Task AssignProjectPhase(AssignProjectCommand request) + { + var phase = await _projectPhaseRepository.GetWithTasksAsync(request.Id); + if (phase is null) + { + return OperationResult.NotFound("فاز پروژه یافت نشد"); + } + + // تخصیص در سطح فاز + foreach (var item in request.Items) + { + var skill = await _skillRepository.GetByIdAsync(item.SkillId); + if (skill is null) + { + return OperationResult.NotFound($"مهارت با شناسه {item.SkillId} یافت نشد"); + } + } + + // علامت‌گذاری که این فاز نسبت به parent متمایز است + phase.MarkAsOverridden(); + + // به‌روزرسانی یا اضافه کردن PhaseSection + foreach (var item in request.Items) + { + var existingSection = phase.PhaseSections.FirstOrDefault(s => s.SkillId == item.SkillId); + if (existingSection != null) + { + // اگر وجود داشت، فقط userId را به‌روزرسانی کن + existingSection.Update(item.UserId, item.SkillId); + } + else + { + // اگر وجود نداشت، اضافه کن + var newPhaseSection = new PhaseSection(phase.Id, item.UserId, item.SkillId); + await _phaseSectionRepository.CreateAsync(newPhaseSection); + } + } + + // cascade به تمام تسک‌ها + foreach (var task in phase.Tasks) + { + // اگر CascadeToChildren true است یا تسک override ندارد + if (request.CascadeToChildren || !task.HasAssignmentOverride) + { + foreach (var item in request.Items) + { + var section = task.Sections.FirstOrDefault(s => s.SkillId == item.SkillId); + if (section != null) + { + // استفاده از TransferToUser + if (section.CurrentAssignedUserId != item.UserId) + { + if (section.CurrentAssignedUserId > 0) + { + section.TransferToUser(section.CurrentAssignedUserId, item.UserId); + } + else + { + section.AssignToUser(item.UserId); + } + } + } + else + { + var newTaskSection = new TaskSection(task.Id, item.SkillId, item.UserId); + await _taskSectionRepository.CreateAsync(newTaskSection); + } + } + } + } + + await _unitOfWork.SaveChangesAsync(); + return OperationResult.Success(); + } + + private async Task AssignProjectTask(AssignProjectCommand request) + { + var task = await _projectTaskRepository.GetWithSectionsAsync(request.Id); + if (task is null) + { + return OperationResult.NotFound("تسک یافت نشد"); + } + + foreach (var item in request.Items) + { + var skill = await _skillRepository.GetByIdAsync(item.SkillId); + if (skill is null) + { + return OperationResult.NotFound($"مهارت با شناسه {item.SkillId} یافت نشد"); + } + } + + // علامت‌گذاری که این تسک نسبت به parent متمایز است + task.MarkAsOverridden(); + + // به‌روزرسانی یا اضافه کردن TaskSection + foreach (var item in request.Items) + { + var section = task.Sections.FirstOrDefault(s => s.SkillId == item.SkillId); + if (section != null) + { + // اگر وجود داشت، از TransferToUser استفاده کن + if (section.CurrentAssignedUserId != item.UserId) + { + if (section.CurrentAssignedUserId > 0) + { + section.TransferToUser(section.CurrentAssignedUserId, item.UserId); + } + else + { + section.AssignToUser(item.UserId); + } + } + } + else + { + // اگر وجود نداشت، اضافه کن + var newTaskSection = new TaskSection(task.Id, item.SkillId, item.UserId); + await _taskSectionRepository.CreateAsync(newTaskSection); + } + } + + await _unitOfWork.SaveChangesAsync(); + return OperationResult.Success(); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AssignProject/AssignProjectCommandValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AssignProject/AssignProjectCommandValidator.cs new file mode 100644 index 00000000..6c1e80a8 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AssignProject/AssignProjectCommandValidator.cs @@ -0,0 +1,39 @@ +using FluentValidation; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AssignProject; + +public class AssignProjectCommandValidator : AbstractValidator +{ + public AssignProjectCommandValidator() + { + RuleFor(x => x.Id) + .NotEmpty() + .NotNull() + .WithMessage("شناسه پروژه نمیتواند خالی باشد"); + + RuleFor(x => x.CascadeToChildren) + .NotNull() + .WithMessage("مقدار CascadeToChildren نمیتواند خالی باشد"); + + RuleForEach(x => x.Items) + .SetValidator(new AssignProjectItemValidator()); + } +} + +public class AssignProjectItemValidator : AbstractValidator +{ + public AssignProjectItemValidator() + { + RuleFor(x => x.UserId) + .NotEmpty() + .NotNull() + .GreaterThan(0) + .WithMessage("شناسه کاربر نمیتواند خالی باشد"); + + + RuleFor(x => x.SkillId) + .NotEmpty() + .NotNull() + .WithMessage("شناسه مهارت نمیتواند خالی باشد"); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeStatusSection/ChangeStatusSectionCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeStatusSection/ChangeStatusSectionCommandHandler.cs new file mode 100644 index 00000000..9e37cdc8 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeStatusSection/ChangeStatusSectionCommandHandler.cs @@ -0,0 +1,101 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain._Common.Exceptions; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeStatusSection; + +public record ChangeStatusSectionCommand(Guid SectionId, TaskSectionStatus Status) : IBaseCommand; + +public class ChangeStatusSectionCommandHandler : IBaseCommandHandler +{ + private readonly IUnitOfWork _unitOfWork; + private readonly ITaskSectionRepository _taskSectionRepository; + private readonly IAuthHelper _authHelper; + + public ChangeStatusSectionCommandHandler(ITaskSectionRepository taskSectionRepository, + IUnitOfWork unitOfWork, IAuthHelper authHelper) + { + _taskSectionRepository = taskSectionRepository; + _unitOfWork = unitOfWork; + _authHelper = authHelper; + } + + public async Task Handle(ChangeStatusSectionCommand request, CancellationToken cancellationToken) + { + // استفاده از متد مخصوص که Activities رو load می‌کنه + var section = await _taskSectionRepository.GetByIdWithActivitiesAsync(request.SectionId, cancellationToken); + if (section == null) + return OperationResult.NotFound("بخش مورد نظر یافت نشد"); + + if (section.Status == request.Status) + return OperationResult.Success(); + + long currentUser = _authHelper.GetCurrentUserId() + ?? throw new UnAuthorizedException("کاربر احراز هویت نشده است"); + + // Validate state transitions + var validationResult = ValidateStateTransition(section.Status, request.Status); + if (!validationResult.IsSuccess) + return validationResult; + + // Handle state machine logic + if (section.Status == TaskSectionStatus.InProgress) + { + // Coming FROM InProgress: Stop the active activity + section.StopWork(currentUser, request.Status); + } + else if (request.Status == TaskSectionStatus.InProgress) + { + // Going TO InProgress: Start work and create activity + section.StartWork(currentUser); + } + else + { + // All other transitions: Just update status + section.UpdateStatus(request.Status); + } + + await _unitOfWork.SaveChangesAsync(cancellationToken); + return OperationResult.Success(); + } + + /// + /// Validates state transitions based on business rules: + /// - ReadyToStart: شروع نشده - Initial state only, cannot return to it once left + /// - InProgress: درحال انجام - Can transition from ReadyToStart, can go to Incomplete or Completed + /// - Incomplete: نیمه کاره - Can come from InProgress or other states + /// - Completed: اتمام رسیده - Can come from InProgress or other states + /// + private OperationResult ValidateStateTransition(TaskSectionStatus currentStatus, TaskSectionStatus targetStatus) + { + // Cannot transition to ReadyToStart once the section has been started + if (targetStatus == TaskSectionStatus.ReadyToStart) + return OperationResult.ValidationError("بخش نمی‌تواند به وضعیت 'آماده برای شروع' تغییر کند"); + + // From ReadyToStart, can only go to InProgress + if (currentStatus == TaskSectionStatus.ReadyToStart && targetStatus != TaskSectionStatus.InProgress) + return OperationResult.ValidationError("از وضعیت 'آماده برای شروع' فقط می‌توان به 'درحال انجام' رفت"); + + // Valid transitions matrix + var validTransitions = new Dictionary> + { + { TaskSectionStatus.ReadyToStart, new List { TaskSectionStatus.InProgress } }, + { TaskSectionStatus.InProgress, new List { TaskSectionStatus.Incomplete, TaskSectionStatus.Completed } }, + { TaskSectionStatus.Incomplete, new List { TaskSectionStatus.InProgress, TaskSectionStatus.Completed } }, + { TaskSectionStatus.Completed, new List { TaskSectionStatus.InProgress, TaskSectionStatus.Incomplete } }, // Can return to InProgress or Incomplete + { TaskSectionStatus.NotAssigned, new List { TaskSectionStatus.InProgress, TaskSectionStatus.ReadyToStart } } + }; + + if (!validTransitions.TryGetValue(currentStatus, out var allowedTargets)) + return OperationResult.ValidationError($"وضعیت فعلی '{currentStatus}' نامعتبر است"); + + if (!allowedTargets.Contains(targetStatus)) + return OperationResult.ValidationError( + $"نمی‌توان از وضعیت '{currentStatus}' به '{targetStatus}' رفت"); + + return OperationResult.Success(); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeStatusSection/ChangeStatusSectionCommandValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeStatusSection/ChangeStatusSectionCommandValidator.cs new file mode 100644 index 00000000..1de430c9 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeStatusSection/ChangeStatusSectionCommandValidator.cs @@ -0,0 +1,20 @@ +using FluentValidation; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeStatusSection; + +public class ChangeStatusSectionCommandValidator:AbstractValidator +{ + public ChangeStatusSectionCommandValidator() + { + RuleFor(c => c.SectionId) + .NotEmpty() + .NotNull() + .WithMessage("شناسه بخش نمی‌تواند خالی باشد"); + + RuleFor(c => c.Status) + .IsInEnum() + .NotEmpty() + .NotNull() + .WithMessage("وضعیت بخش نامعتبر است"); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProject/CreateProjectCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProject/CreateProjectCommand.cs new file mode 100644 index 00000000..475e7aab --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProject/CreateProjectCommand.cs @@ -0,0 +1,7 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProject; + +public record CreateProjectCommand(string Name,ProjectHierarchyLevel Level, + Guid? ParentId):IBaseCommand; \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProject/CreateProjectCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProject/CreateProjectCommandHandler.cs new file mode 100644 index 00000000..1ba61509 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProject/CreateProjectCommandHandler.cs @@ -0,0 +1,82 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain._Common.Exceptions; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProject; + +public class CreateProjectCommandHandler : IBaseCommandHandler +{ + private readonly IProjectRepository _projectRepository; + private readonly IProjectPhaseRepository _projectPhaseRepository; + private readonly IProjectTaskRepository _projectTaskRepository; + private readonly IUnitOfWork _unitOfWork; + + + public CreateProjectCommandHandler(IProjectRepository projectRepository, IUnitOfWork unitOfWork, IProjectTaskRepository projectTaskRepository, IProjectPhaseRepository projectPhaseRepository) + { + _projectRepository = projectRepository; + _unitOfWork = unitOfWork; + _projectTaskRepository = projectTaskRepository; + _projectPhaseRepository = projectPhaseRepository; + } + + public async Task Handle(CreateProjectCommand request, CancellationToken cancellationToken) + { + switch (request.Level) + { + case ProjectHierarchyLevel.Project: + await CreateProject(request); + break; + case ProjectHierarchyLevel.Phase: + await CreateProjectPhase(request); + break; + case ProjectHierarchyLevel.Task: + await CreateProjectTask(request); + break; + default: + return OperationResult.Failure("سطح پروژه نامعتبر است"); + } + + await _unitOfWork.SaveChangesAsync(cancellationToken); + return OperationResult.Success(); + } + + private async Task CreateProject(CreateProjectCommand request) + { + var project = new Project(request.Name); + await _projectRepository.CreateAsync(project); + } + + private async Task CreateProjectPhase(CreateProjectCommand request) + { + if (!request.ParentId.HasValue) + throw new BadRequestException("برای ایجاد فاز، شناسه پروژه الزامی است"); + + if(!_projectRepository.Exists(x=>x.Id == request.ParentId.Value)) + { + throw new BadRequestException("والد پروژه یافت نشد"); + } + + var projectPhase = new ProjectPhase(request.Name, request.ParentId.Value); + await _projectPhaseRepository.CreateAsync(projectPhase); + } + + private async Task CreateProjectTask(CreateProjectCommand request) + { + if (!request.ParentId.HasValue) + throw new BadRequestException("برای ایجاد تسک، شناسه فاز الزامی است"); + + if(!_projectPhaseRepository.Exists(x=>x.Id == request.ParentId.Value)) + { + throw new BadRequestException("والد پروژه یافت نشد"); + } + + var projectTask = new ProjectTask(request.Name, request.ParentId.Value); + await _projectTaskRepository.CreateAsync(projectTask); + } +} + \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProject/CreateProjectCommandValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProject/CreateProjectCommandValidator.cs new file mode 100644 index 00000000..790e1f79 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProject/CreateProjectCommandValidator.cs @@ -0,0 +1,26 @@ +using FluentValidation; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProject; + +public class CreateProjectCommandValidator:AbstractValidator +{ + public CreateProjectCommandValidator() + { + RuleFor(x => x.Name) + .NotEmpty() + .NotNull() + .WithMessage("نام نمیتواند خالی باشد"); + + RuleFor(y => y.Level) + .NotNull() + .IsInEnum(); + When(x=>x.Level>ProjectHierarchyLevel.Project,()=> + { + RuleFor(x => x.ParentId) + .NotNull() + .NotEmpty() + .WithMessage("شناسه والد نمیتواند خالی باشد"); + }); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProjectWithHierarchy/CreateProjectWithHierarchyCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProjectWithHierarchy/CreateProjectWithHierarchyCommand.cs new file mode 100644 index 00000000..385f516d --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProjectWithHierarchy/CreateProjectWithHierarchyCommand.cs @@ -0,0 +1,13 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProjectWithHierarchy; + +/// +/// Command to create a new project with the new hierarchy structure +/// +public record CreateProjectWithHierarchyCommand( + string Name, + string? Description = null, + DateTime? PlannedStartDate = null, + DateTime? PlannedEndDate = null +) : IBaseCommand; diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProjectWithHierarchy/CreateProjectWithHierarchyCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProjectWithHierarchy/CreateProjectWithHierarchyCommandHandler.cs new file mode 100644 index 00000000..0a899924 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProjectWithHierarchy/CreateProjectWithHierarchyCommandHandler.cs @@ -0,0 +1,49 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using MediatR; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProjectWithHierarchy; + +public class CreateProjectWithHierarchyCommandHandler : IRequestHandler +{ + private readonly IProjectRepository _projectRepository; + private readonly IUnitOfWork _unitOfWork; + + public CreateProjectWithHierarchyCommandHandler( + IProjectRepository projectRepository, + IUnitOfWork unitOfWork) + { + _projectRepository = projectRepository; + _unitOfWork = unitOfWork; + } + + public async Task Handle(CreateProjectWithHierarchyCommand request, CancellationToken cancellationToken) + { + try + { + // Create new project + var project = new Project(request.Name, request.Description); + + // Set planned dates if provided + if (request.PlannedStartDate.HasValue || request.PlannedEndDate.HasValue) + { + project.SetPlannedDates(request.PlannedStartDate, request.PlannedEndDate); + } + + // Add to repository + await _projectRepository.CreateAsync(project); + + // Save changes + await _unitOfWork.SaveChangesAsync(cancellationToken); + + return OperationResult.Success(); + } + catch (Exception ex) + { + return OperationResult.Failure($"خطا در ایجاد پروژه: {ex.Message}"); + } + } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProjectWithHierarchy/CreateProjectWithHierarchyCommandValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProjectWithHierarchy/CreateProjectWithHierarchyCommandValidator.cs new file mode 100644 index 00000000..2e425dc9 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/CreateProjectWithHierarchy/CreateProjectWithHierarchyCommandValidator.cs @@ -0,0 +1,21 @@ +using FluentValidation; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProjectWithHierarchy; + +public class CreateProjectWithHierarchyCommandValidator : AbstractValidator +{ + public CreateProjectWithHierarchyCommandValidator() + { + RuleFor(x => x.Name) + .NotEmpty().WithMessage("نام پروژه نمی‌تواند خالی باشد") + .MaximumLength(200).WithMessage("نام پروژه نمی‌تواند بیش از 200 کاراکتر باشد"); + + RuleFor(x => x.Description) + .MaximumLength(1000).WithMessage("توضیحات نمی‌تواند بیش از 1000 کاراکتر باشد") + .When(x => !string.IsNullOrEmpty(x.Description)); + + RuleFor(x => x) + .Must(x => x.PlannedStartDate == null || x.PlannedEndDate == null || x.PlannedStartDate <= x.PlannedEndDate) + .WithMessage("تاریخ شروع برنامه‌ریزی شده نمی‌تواند بعد از تاریخ پایان برنامه‌ریزی شده باشد"); + } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/DeleteProject/DeleteProjectCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/DeleteProject/DeleteProjectCommandHandler.cs new file mode 100644 index 00000000..57677395 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/DeleteProject/DeleteProjectCommandHandler.cs @@ -0,0 +1,91 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain._Common.Exceptions; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.DeleteProject; + +public record DeleteProjectCommand(Guid Id,ProjectHierarchyLevel Level) : IBaseCommand; + +public class DeleteProjectCommandHandler : IBaseCommandHandler +{ + private readonly IUnitOfWork _unitOfWork; + private readonly IProjectRepository _projectRepository; + private readonly IProjectPhaseRepository _projectPhaseRepository; + private readonly IProjectTaskRepository _projectTaskRepository; + + public DeleteProjectCommandHandler( + IUnitOfWork unitOfWork, + IProjectRepository projectRepository, + IProjectPhaseRepository projectPhaseRepository, + IProjectTaskRepository projectTaskRepository) + { + _unitOfWork = unitOfWork; + _projectRepository = projectRepository; + _projectPhaseRepository = projectPhaseRepository; + _projectTaskRepository = projectTaskRepository; + } + + public async Task Handle(DeleteProjectCommand request, CancellationToken cancellationToken) + { + switch (request.Level) + { + case ProjectHierarchyLevel.Project: + await DeleteProject(request.Id); + break; + case ProjectHierarchyLevel.Phase: + await DeleteProjectPhase(request.Id); + break; + case ProjectHierarchyLevel.Task: + await DeleteProjectTask(request.Id); + break; + default: + return OperationResult.Failure("سطح پروژه نامعتبر است"); + } + + await _unitOfWork.SaveChangesAsync(cancellationToken); + return OperationResult.Success(); + } + + private async Task DeleteProject(Guid projectId) + { + var projectWithPhases = await _projectRepository.GetWithFullHierarchyAsync(projectId); + + if (projectWithPhases == null) + throw new NotFoundException("پروژه یافت نشد"); + + // بررسی اینکه پروژه فاز یا زیرمجموعه دارد یا نه + if (projectWithPhases.Phases != null && projectWithPhases.Phases.Any()) + throw new BadRequestException("نمی‌توان پروژه‌ای را حذف کرد که دارای فاز است. ابتدا تمام فازها را حذف کنید."); + + _projectRepository.Remove(projectWithPhases); + } + + private async Task DeleteProjectPhase(Guid phaseId) + { + var phase = await _projectPhaseRepository.GetByIdAsync(phaseId); + + if (phase == null) + throw new NotFoundException("فاز پروژه یافت نشد"); + + // بررسی اینکه فاز تسک یا زیرمجموعه دارد یا نه + var phaseWithTasks = await _projectPhaseRepository.GetWithTasksAsync(phaseId); + if (phaseWithTasks?.Tasks != null && phaseWithTasks.Tasks.Any()) + throw new InvalidOperationException("نمی‌توان فازی را حذف کرد که دارای تسک است. ابتدا تمام تسک‌ها را حذف کنید."); + + _projectPhaseRepository.Remove(phase); + } + + private async Task DeleteProjectTask(Guid taskId) + { + var task = await _projectTaskRepository.GetByIdAsync(taskId); + + if (task == null) + throw new NotFoundException("تسک یافت نشد"); + + // حذف خود تسک + _projectTaskRepository.Remove(task); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/DeleteProject/DeleteProjectCommandValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/DeleteProject/DeleteProjectCommandValidator.cs new file mode 100644 index 00000000..47ae2eeb --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/DeleteProject/DeleteProjectCommandValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.DeleteProject; + +public class DeleteProjectCommandValidator:AbstractValidator +{ + public DeleteProjectCommandValidator() + { + RuleFor(x=>x.Id) + .NotEmpty() + .NotNull() + .WithMessage("شناسه پروژه نمی‌تواند خالی باشد."); + RuleFor(x=>x.Level) + .IsInEnum() + .NotNull() + .WithMessage("سطح حذف پروژه نامعتبر است."); + + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/EditProject/EditProjectCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/EditProject/EditProjectCommandHandler.cs new file mode 100644 index 00000000..af993664 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/EditProject/EditProjectCommandHandler.cs @@ -0,0 +1,80 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain._Common.Exceptions; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.EditProject; + +public record EditProjectCommand(string Name, Guid Id, ProjectHierarchyLevel Level): IBaseCommand; +public class EditProjectCommandHandler: IBaseCommandHandler +{ + private readonly IProjectRepository _projectRepository; + private readonly IProjectPhaseRepository _projectPhaseRepository; + private readonly IProjectTaskRepository _projectTaskRepository; + private readonly IUnitOfWork _unitOfWork; + + public EditProjectCommandHandler( + IProjectRepository projectRepository, + IProjectPhaseRepository projectPhaseRepository, + IProjectTaskRepository projectTaskRepository, + IUnitOfWork unitOfWork) + { + _projectRepository = projectRepository; + _projectPhaseRepository = projectPhaseRepository; + _projectTaskRepository = projectTaskRepository; + _unitOfWork = unitOfWork; + } + + public async Task Handle(EditProjectCommand request, CancellationToken cancellationToken) + { + switch (request.Level) + { + case ProjectHierarchyLevel.Project: + await EditProject(request); + break; + case ProjectHierarchyLevel.Phase: + await EditProjectPhase(request); + break; + case ProjectHierarchyLevel.Task: + await EditProjectTask(request); + break; + default: + return OperationResult.Failure("سطح پروژه نامعتبر است"); + } + + await _unitOfWork.SaveChangesAsync(cancellationToken); + return OperationResult.Success(); + } + + private async Task EditProject(EditProjectCommand request) + { + var project = await _projectRepository.GetByIdAsync(request.Id); + + if (project == null) + throw new NotFoundException("پروژه یافت نشد"); + + project.UpdateName(request.Name); + } + + private async Task EditProjectPhase(EditProjectCommand request) + { + var phase = await _projectPhaseRepository.GetByIdAsync(request.Id); + + if (phase == null) + throw new NotFoundException("فاز پروژه یافت نشد"); + + phase.UpdateName(request.Name); + } + + private async Task EditProjectTask(EditProjectCommand request) + { + var task = await _projectTaskRepository.GetByIdAsync(request.Id); + + if (task == null) + throw new NotFoundException("تسک یافت نشد"); + + task.UpdateName(request.Name); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/EditProject/EditProjectCommandValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/EditProject/EditProjectCommandValidator.cs new file mode 100644 index 00000000..4c50a3b1 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/EditProject/EditProjectCommandValidator.cs @@ -0,0 +1,18 @@ +using FluentValidation; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.EditProject; + +public class EditProjectCommandValidator:AbstractValidator +{ + public EditProjectCommandValidator() + { + RuleFor(x => x.Name) + .NotEmpty() + .WithMessage("نام پروژه نمی‌تواند خالی باشد."); + + RuleFor(x=>x.Id) + .NotEmpty() + .NotNull().WithMessage("شناسه پروژه نمی‌تواند خالی باشد."); + + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommand.cs new file mode 100644 index 00000000..230754b5 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommand.cs @@ -0,0 +1,13 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application.Modules.Projects.DTOs; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.SetTimeProject; + +public record SetTimeProjectCommand(List SectionItems, Guid Id, ProjectHierarchyLevel Level):IBaseCommand; + +public class SetTimeSectionTime +{ + public string Description { get; set; } + public int Hours { get; set; } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommandHandler.cs new file mode 100644 index 00000000..3b1a7b1f --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommandHandler.cs @@ -0,0 +1,164 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Projects.DTOs; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.SetTimeProject; + +public class SetTimeProjectCommandHandler:IBaseCommandHandler +{ + private readonly IProjectRepository _projectRepository; + private readonly IProjectPhaseRepository _projectPhaseRepository; + private readonly IProjectTaskRepository _projectTaskRepository; + private readonly IUnitOfWork _unitOfWork; + private readonly IAuthHelper _authHelper; + private long? _userId; + + + public SetTimeProjectCommandHandler( + IProjectRepository projectRepository, + IProjectPhaseRepository projectPhaseRepository, + IProjectTaskRepository projectTaskRepository, + IUnitOfWork unitOfWork, IAuthHelper authHelper) + { + _projectRepository = projectRepository; + _projectPhaseRepository = projectPhaseRepository; + _projectTaskRepository = projectTaskRepository; + _unitOfWork = unitOfWork; + _authHelper = authHelper; + _userId = authHelper.GetCurrentUserId(); + } + + public async Task Handle(SetTimeProjectCommand request, CancellationToken cancellationToken) + { + switch (request.Level) + { + case ProjectHierarchyLevel.Task: + return await SetTimeForProjectTask(request, cancellationToken); + default: + return OperationResult.Failure("سطح پروژه نامعتبر است"); + + } + } + + private async Task SetTimeForProject(SetTimeProjectCommand request, CancellationToken cancellationToken) + { + var project = await _projectRepository.GetWithFullHierarchyAsync(request.Id); + if (project == null) + { + return OperationResult.NotFound("پروژه یافت نشد"); + return OperationResult.NotFound("���� ���� ���"); + } + + long? addedByUserId = _userId; + + // تنظیم زمان برای تمام sections در تمام فازها و تسک‌های پروژه + foreach (var phase in project.Phases) + { + foreach (var task in phase.Tasks) + { + foreach (var section in task.Sections) + { + var sectionItem = request.SectionItems.FirstOrDefault(si => si.SectionId == section.Id); + if (sectionItem != null) + { + SetSectionTime(section, sectionItem, addedByUserId); + } + } + } + } + + await _unitOfWork.SaveChangesAsync(cancellationToken); + return OperationResult.Success(); + } + + private async Task SetTimeForProjectPhase(SetTimeProjectCommand request, CancellationToken cancellationToken) + { + var phase = await _projectPhaseRepository.GetWithTasksAsync(request.Id); + if (phase == null) + { + return OperationResult.NotFound("فاز پروژه یافت نشد"); + return OperationResult.NotFound("��� ���� ���� ���"); + } + + long? addedByUserId = _userId; + + // تنظیم زمان برای تمام sections در تمام تسک‌های این فاز + foreach (var task in phase.Tasks) + { + foreach (var section in task.Sections) + { + var sectionItem = request.SectionItems.FirstOrDefault(si => si.SectionId == section.Id); + if (sectionItem != null) + { + SetSectionTime(section, sectionItem, addedByUserId); + } + } + } + + await _unitOfWork.SaveChangesAsync(cancellationToken); + return OperationResult.Success(); + } + + private async Task SetTimeForProjectTask(SetTimeProjectCommand request, CancellationToken cancellationToken) + { + var task = await _projectTaskRepository.GetWithSectionsAsync(request.Id); + if (task == null) + { + return OperationResult.NotFound("تسک یافت نشد"); + return OperationResult.NotFound("�Ә ���� ���"); + } + + long? addedByUserId = _userId; + + // تنظیم زمان مستقیماً برای sections این تسک + foreach (var section in task.Sections) + { + var sectionItem = request.SectionItems.FirstOrDefault(si => si.SectionId == section.Id); + if (sectionItem != null) + { + SetSectionTime(section, sectionItem, addedByUserId); + } + } + + await _unitOfWork.SaveChangesAsync(cancellationToken); + return OperationResult.Success(); + } + + private void SetSectionTime(TaskSection section, SetTimeProjectSectionItem sectionItem, long? addedByUserId) + { + var initData = sectionItem.InitData; + var initialTime = TimeSpan.FromHours(initData.Hours); + + // تنظیم زمان اولیه + section.UpdateInitialEstimatedHours(initialTime, initData.Description); + + section.ClearAdditionalTimes(); + // افزودن زمان‌های اضافی + foreach (var additionalTime in sectionItem.AdditionalTime) + { + var additionalTimeSpan = TimeSpan.FromHours(additionalTime.Hours); + section.AddAdditionalTime(additionalTimeSpan, additionalTime.Description, addedByUserId); + } + } + + // private void SetSectionTime(ProjectSection section, SetTimeProjectSectionItem sectionItem, long? addedByUserId) + // { + // var initData = sectionItem.InitData; + // var initialTime = TimeSpan.FromHours(initData.Hours); + // + // // تنظیم زمان اولیه + // section.UpdateInitialEstimatedHours(initialTime, initData.Description); + // + // section.ClearAdditionalTimes(); + // // افزودن زمان‌های اضافی + // foreach (var additionalTime in sectionItem.AdditionalTime) + // { + // var additionalTimeSpan = TimeSpan.FromHours(additionalTime.Hours); + // section.AddAdditionalTime(additionalTimeSpan, additionalTime.Description, addedByUserId); + // } + // } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommandValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommandValidator.cs new file mode 100644 index 00000000..7fb182b7 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommandValidator.cs @@ -0,0 +1,50 @@ +using FluentValidation; +using GozareshgirProgramManager.Application.Modules.Projects.DTOs; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.SetTimeProject; + +public class SetTimeProjectCommandValidator:AbstractValidator +{ + public SetTimeProjectCommandValidator() + { + RuleFor(x=>x.Id) + .NotEmpty() + .NotNull() + .WithMessage("شناسه پروژه نمی‌تواند خالی باشد."); + + RuleForEach(x => x.SectionItems) + .SetValidator(command => new SetTimeProjectSectionItemValidator()); + + } +} +public class SetTimeProjectSectionItemValidator:AbstractValidator +{ + public SetTimeProjectSectionItemValidator() + { + RuleFor(x=>x.SectionId) + .NotEmpty() + .NotNull() + .WithMessage("شناسه بخش نمی‌تواند خالی باشد."); + + RuleFor(x=>x.InitData) + .SetValidator(new TimeDataValidator()); + + RuleForEach(x=>x.AdditionalTime) + .SetValidator(new TimeDataValidator()); + } +} + +public class TimeDataValidator : AbstractValidator +{ + public TimeDataValidator() + { + RuleFor(x => x.Hours) + .GreaterThanOrEqualTo(0) + .WithMessage("ساعت نمی‌تواند منفی باشد."); + + RuleFor(x=>x.Description) + .MaximumLength(500) + .WithMessage("توضیحات نمی‌تواند بیشتر از 500 کاراکتر باشد."); + + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/TransferSection/TransferSectionCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/TransferSection/TransferSectionCommand.cs new file mode 100644 index 00000000..b32f49a2 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/TransferSection/TransferSectionCommand.cs @@ -0,0 +1,12 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.TransferSection; + +public record TransferSectionCommand : IBaseCommand +{ + public Guid SectionId { get; set; } + public long FromUserId { get; set; } + public long ToUserId { get; set; } + public string? Notes { get; set; } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/TransferSection/TransferSectionCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/TransferSection/TransferSectionCommandHandler.cs new file mode 100644 index 00000000..4f27773a --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/TransferSection/TransferSectionCommandHandler.cs @@ -0,0 +1,69 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using GozareshgirProgramManager.Domain.UserAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.TransferSection; + +public class TransferSectionCommandHandler : IBaseCommandHandler +{ + private readonly IUnitOfWork _unitOfWork; + private readonly ITaskSectionRepository _taskSectionRepository; + private readonly IUserRepository _userRepository; + + public TransferSectionCommandHandler( + ITaskSectionRepository taskSectionRepository, + IUserRepository userRepository, + IUnitOfWork unitOfWork) + { + _taskSectionRepository = taskSectionRepository; + _userRepository = userRepository; + _unitOfWork = unitOfWork; + } + + public async Task Handle(TransferSectionCommand request, CancellationToken cancellationToken) + { + // دریافت section با activities + var section = await _taskSectionRepository.GetByIdWithActivitiesAsync(request.SectionId, cancellationToken); + if (section == null) + { + return OperationResult.NotFound("بخش پروژه یافت نشد"); + } + + // بررسی وجود کاربر مبدا + var fromUser = await _userRepository.GetByIdAsync(request.FromUserId); + if (fromUser == null) + { + return OperationResult.NotFound($"کاربر مبدا با شناسه {request.FromUserId} یافت نشد"); + } + + // بررسی وجود کاربر مقصد + var toUser = await _userRepository.GetByIdAsync(request.ToUserId); + if (toUser == null) + { + return OperationResult.NotFound($"کاربر مقصد با شناسه {request.ToUserId} یافت نشد"); + } + + // بررسی اینکه کاربر مبدا و مقصد یکسان نباشند + if (request.FromUserId == request.ToUserId) + { + return OperationResult.Failure("کاربر مبدا و مقصد نمی‌توانند یکسان باشند"); + } + + try + { + // انتقال به کاربر جدید + section.TransferToUser(request.FromUserId, request.ToUserId); + + await _unitOfWork.SaveChangesAsync(cancellationToken); + + return OperationResult.Success(); + } + catch (InvalidOperationException ex) + { + return OperationResult.Failure(ex.Message); + } + } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/TransferSection/TransferSectionCommandValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/TransferSection/TransferSectionCommandValidator.cs new file mode 100644 index 00000000..e7b041f3 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/TransferSection/TransferSectionCommandValidator.cs @@ -0,0 +1,28 @@ +using FluentValidation; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.TransferSection; + +public class TransferSectionCommandValidator : AbstractValidator +{ + public TransferSectionCommandValidator() + { + RuleFor(x => x.SectionId) + .NotEmpty() + .WithMessage("شناسه بخش نمیتواند خالی باشد"); + + RuleFor(x => x.FromUserId) + .NotEmpty() + .GreaterThan(0) + .WithMessage("شناسه کاربر مبدا نمیتواند خالی یا صفر باشد"); + + RuleFor(x => x.ToUserId) + .NotEmpty() + .GreaterThan(0) + .WithMessage("شناسه کاربر مقصد نمیتواند خالی یا صفر باشد"); + + RuleFor(x => x) + .Must(x => x.FromUserId != x.ToUserId) + .WithMessage("کاربر مبدا و مقصد نمی‌توانند یکسان باشند"); + } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/DTOs/ProjectHierarchyDtos.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/DTOs/ProjectHierarchyDtos.cs new file mode 100644 index 00000000..3cbc8cec --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/DTOs/ProjectHierarchyDtos.cs @@ -0,0 +1,127 @@ +namespace GozareshgirProgramManager.Application.Modules.Projects.DTOs; + +/// +/// DTO for Project entity +/// +public class ProjectDto +{ + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public DateTime CreationDate { get; set; } + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + public DateTime? PlannedStartDate { get; set; } + public DateTime? PlannedEndDate { get; set; } + public string Status { get; set; } = string.Empty; + public TimeSpan? AllocatedTime { get; set; } + public bool HasTimeOverride { get; set; } + public bool HasAssignmentOverride { get; set; } + public TimeSpan TotalTimeSpent { get; set; } + public TimeSpan TotalEstimatedTime { get; set; } + + public List Phases { get; set; } = new(); +} + +/// +/// DTO for ProjectPhase entity +/// +public class ProjectPhaseDto +{ + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public DateTime CreationDate { get; set; } + public Guid ProjectId { get; set; } + public string Status { get; set; } = string.Empty; + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + public int OrderIndex { get; set; } + public TimeSpan? AllocatedTime { get; set; } + public bool HasTimeOverride { get; set; } + public bool HasAssignmentOverride { get; set; } + public TimeSpan TotalTimeSpent { get; set; } + public TimeSpan TotalEstimatedTime { get; set; } + + public List Tasks { get; set; } = new(); +} + +/// +/// DTO for ProjectTask entity +/// +public class ProjectTaskDto +{ + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public DateTime CreationDate { get; set; } + public Guid PhaseId { get; set; } + public string Status { get; set; } = string.Empty; + public string Priority { get; set; } = string.Empty; + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + public DateTime? DueDate { get; set; } + public int OrderIndex { get; set; } + public TimeSpan? AllocatedTime { get; set; } + public bool HasTimeOverride { get; set; } + public bool HasAssignmentOverride { get; set; } + public TimeSpan TotalTimeSpent { get; set; } + public TimeSpan TotalEstimatedTime { get; set; } + + public List Sections { get; set; } = new(); +} + +/// +/// DTO for TaskSection entity +/// +public class ProjectSectionDto +{ + public Guid Id { get; set; } + public Guid TaskId { get; set; } + public Guid SkillId { get; set; } + public string SkillName { get; set; } = string.Empty; + public TimeSpan InitialEstimatedHours { get; set; } + public string? InitialDescription { get; set; } + public string Status { get; set; } = string.Empty; + public long CurrentAssignedUserId { get; set; } + public string? CurrentAssignedUserName { get; set; } + public DateTime CreationDate { get; set; } + + public TimeSpan FinalEstimatedHours { get; set; } + public TimeSpan TotalTimeSpent { get; set; } + public bool IsCompleted { get; set; } + public bool IsInProgress { get; set; } + + public List Activities { get; set; } = new(); + public List AdditionalTimes { get; set; } = new(); +} + +/// +/// DTO for ProjectSectionActivity entity +/// +public class TaskSectionActivityDto +{ + public Guid Id { get; set; } + public Guid SectionId { get; set; } + public long UserId { get; set; } + public string? UserName { get; set; } + public DateTime StartDate { get; set; } + public DateTime? EndDate { get; set; } + public string? Notes { get; set; } + public string? EndNotes { get; set; } + public bool IsActive { get; set; } + public TimeSpan TimeSpent { get; set; } +} + +/// +/// DTO for ProjectSectionAdditionalTime entity +/// +public class TaskSectionAdditionalTimeDto +{ + public Guid Id { get; set; } + public TimeSpan Hours { get; set; } + public string? Reason { get; set; } + public long? AddedByUserId { get; set; } + public string? AddedByUserName { get; set; } + public DateTime AddedAt { get; set; } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/DTOs/SetTimeProjectSectionItem.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/DTOs/SetTimeProjectSectionItem.cs new file mode 100644 index 00000000..04566e4e --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/DTOs/SetTimeProjectSectionItem.cs @@ -0,0 +1,10 @@ +using GozareshgirProgramManager.Application.Modules.Projects.Commands.SetTimeProject; + +namespace GozareshgirProgramManager.Application.Modules.Projects.DTOs; + +public class SetTimeProjectSectionItem +{ + public Guid SectionId { get; set; } + public SetTimeSectionTime InitData { get; set; } + public List AdditionalTime { get; set; } = []; +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Extensions/ProjectMappingExtensions.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Extensions/ProjectMappingExtensions.cs new file mode 100644 index 00000000..67ce006e --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Extensions/ProjectMappingExtensions.cs @@ -0,0 +1,258 @@ +using GozareshgirProgramManager.Application.Modules.Projects.DTOs; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Extensions; + +/// +/// Mapping extensions for project hierarchy entities to DTOs +/// +public static class ProjectMappingExtensions +{ + #region Project Mappings + + public static ProjectDto ToDto(this Project project) + { + return new ProjectDto + { + Id = project.Id, + Name = project.Name, + Description = project.Description, + CreationDate = project.CreationDate, + StartDate = project.StartDate, + EndDate = project.EndDate, + PlannedStartDate = project.PlannedStartDate, + PlannedEndDate = project.PlannedEndDate, + Status = project.Status.ToString(), + HasAssignmentOverride = project.HasAssignmentOverride, + TotalTimeSpent = project.GetTotalTimeSpent(), + TotalEstimatedTime = project.GetTotalEstimatedTime(), + Phases = project.Phases.Select(p => p.ToDto()).ToList() + }; + } + + public static ProjectDto ToSummaryDto(this Project project) + { + return new ProjectDto + { + Id = project.Id, + Name = project.Name, + Description = project.Description, + CreationDate = project.CreationDate, + StartDate = project.StartDate, + EndDate = project.EndDate, + PlannedStartDate = project.PlannedStartDate, + PlannedEndDate = project.PlannedEndDate, + Status = project.Status.ToString(), + HasAssignmentOverride = project.HasAssignmentOverride, + TotalTimeSpent = project.GetTotalTimeSpent(), + TotalEstimatedTime = project.GetTotalEstimatedTime() + // No phases for summary + }; + } + + #endregion + + #region Phase Mappings + + public static ProjectPhaseDto ToDto(this ProjectPhase phase) + { + return new ProjectPhaseDto + { + Id = phase.Id, + Name = phase.Name, + Description = phase.Description, + CreationDate = phase.CreationDate, + ProjectId = phase.ProjectId, + Status = phase.Status.ToString(), + StartDate = phase.StartDate, + EndDate = phase.EndDate, + OrderIndex = phase.OrderIndex, + HasAssignmentOverride = phase.HasAssignmentOverride, + TotalTimeSpent = phase.GetTotalTimeSpent(), + TotalEstimatedTime = phase.GetTotalEstimatedTime(), + Tasks = phase.Tasks.Select(t => t.ToDto()).ToList() + }; + } + + public static ProjectPhaseDto ToSummaryDto(this ProjectPhase phase) + { + return new ProjectPhaseDto + { + Id = phase.Id, + Name = phase.Name, + Description = phase.Description, + CreationDate = phase.CreationDate, + ProjectId = phase.ProjectId, + Status = phase.Status.ToString(), + StartDate = phase.StartDate, + EndDate = phase.EndDate, + OrderIndex = phase.OrderIndex, + HasAssignmentOverride = phase.HasAssignmentOverride, + TotalTimeSpent = phase.GetTotalTimeSpent(), + TotalEstimatedTime = phase.GetTotalEstimatedTime() + // No tasks for summary + }; + } + + #endregion + + #region Task Mappings + + public static ProjectTaskDto ToDto(this ProjectTask task) + { + return new ProjectTaskDto + { + Id = task.Id, + Name = task.Name, + Description = task.Description, + CreationDate = task.CreationDate, + PhaseId = task.PhaseId, + Status = task.Status.ToString(), + Priority = task.Priority.ToString(), + StartDate = task.StartDate, + EndDate = task.EndDate, + DueDate = task.DueDate, + OrderIndex = task.OrderIndex, + AllocatedTime = task.AllocatedTime, + HasTimeOverride = task.HasTimeOverride, + HasAssignmentOverride = task.HasAssignmentOverride, + TotalTimeSpent = task.GetTotalTimeSpent(), + TotalEstimatedTime = task.GetTotalEstimatedTime(), + Sections = task.Sections.Select(s => s.ToDto()).ToList() + }; + } + + public static ProjectTaskDto ToSummaryDto(this ProjectTask task) + { + return new ProjectTaskDto + { + Id = task.Id, + Name = task.Name, + Description = task.Description, + CreationDate = task.CreationDate, + PhaseId = task.PhaseId, + Status = task.Status.ToString(), + Priority = task.Priority.ToString(), + StartDate = task.StartDate, + EndDate = task.EndDate, + DueDate = task.DueDate, + OrderIndex = task.OrderIndex, + AllocatedTime = task.AllocatedTime, + HasTimeOverride = task.HasTimeOverride, + HasAssignmentOverride = task.HasAssignmentOverride, + TotalTimeSpent = task.GetTotalTimeSpent(), + TotalEstimatedTime = task.GetTotalEstimatedTime() + // No sections for summary + }; + } + + #endregion + + #region Section Mappings + + public static ProjectSectionDto ToDto(this TaskSection section) + { + return new ProjectSectionDto + { + Id = section.Id, + TaskId = section.TaskId, + SkillId = section.SkillId, + SkillName = section.Skill?.Name ?? string.Empty, + InitialEstimatedHours = section.InitialEstimatedHours, + InitialDescription = section.InitialDescription, + Status = section.Status.ToString(), + CurrentAssignedUserId = section.CurrentAssignedUserId, + CreationDate = section.CreationDate, + FinalEstimatedHours = section.FinalEstimatedHours, + TotalTimeSpent = section.GetTotalTimeSpent(), + IsCompleted = section.IsCompleted(), + IsInProgress = section.IsInProgress(), + Activities = section.Activities.Select(a => a.ToDto()).ToList(), + AdditionalTimes = section.AdditionalTimes.Select(at => at.ToDto()).ToList() + }; + } + + public static ProjectSectionDto ToSummaryDto(this TaskSection section) + { + return new ProjectSectionDto + { + Id = section.Id, + TaskId = section.TaskId, + SkillId = section.SkillId, + SkillName = section.Skill?.Name ?? string.Empty, + InitialEstimatedHours = section.InitialEstimatedHours, + InitialDescription = section.InitialDescription, + Status = section.Status.ToString(), + CurrentAssignedUserId = section.CurrentAssignedUserId, + CreationDate = section.CreationDate, + FinalEstimatedHours = section.FinalEstimatedHours, + TotalTimeSpent = section.GetTotalTimeSpent(), + IsCompleted = section.IsCompleted(), + IsInProgress = section.IsInProgress() + // No activities or additional times for summary + }; + } + + #endregion + + #region Activity Mappings + + public static TaskSectionActivityDto ToDto(this TaskSectionActivity activity) + { + return new TaskSectionActivityDto + { + Id = activity.Id, + SectionId = activity.SectionId, + UserId = activity.UserId, + StartDate = activity.StartDate, + EndDate = activity.EndDate, + Notes = activity.Notes, + EndNotes = activity.EndNotes, + IsActive = activity.IsActive, + TimeSpent = activity.GetTimeSpent() + }; + } + + #endregion + + #region Additional Time Mappings + + public static TaskSectionAdditionalTimeDto ToDto(this TaskSectionAdditionalTime additionalTime) + { + return new TaskSectionAdditionalTimeDto + { + Id = additionalTime.Id, + Hours = additionalTime.Hours, + Reason = additionalTime.Reason, + AddedByUserId = additionalTime.AddedByUserId, + AddedAt = additionalTime.AddedAt + }; + } + + #endregion + + #region Collection Mappings + + public static List ToSummaryDtos(this IEnumerable projects) + { + return projects.Select(p => p.ToSummaryDto()).ToList(); + } + + public static List ToSummaryDtos(this IEnumerable phases) + { + return phases.Select(p => p.ToSummaryDto()).ToList(); + } + + public static List ToSummaryDtos(this IEnumerable tasks) + { + return tasks.Select(t => t.ToSummaryDto()).ToList(); + } + + public static List ToSummaryDtos(this IEnumerable sections) + { + return sections.Select(s => s.ToSummaryDto()).ToList(); + } + + #endregion +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectAssignDetails/GetProjectAssignDetailsQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectAssignDetails/GetProjectAssignDetailsQueryHandler.cs new file mode 100644 index 00000000..7932fd4c --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectAssignDetails/GetProjectAssignDetailsQueryHandler.cs @@ -0,0 +1,122 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectAssignDetails; + +public record GetProjectAssignDetailsResponse(List Items); + +public record GetProjectAssignSectionDetails(string Skill,Guid SkillId,Guid? SectionId,long UserId); + +public record GetProjectAssignDetailsQuery(Guid Id,ProjectHierarchyLevel Level) : IBaseQuery; + +public class GetProjectAssignDetailsQueryHandler:IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _dbContext; + + public GetProjectAssignDetailsQueryHandler(IProgramManagerDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task> Handle(GetProjectAssignDetailsQuery request, CancellationToken cancellationToken) + { + switch (request.Level) + { + case ProjectHierarchyLevel.Project: + return await GetProjectAssignDetails(request.Id, cancellationToken); + case ProjectHierarchyLevel.Phase: + return await GetPhaseAssignDetails(request.Id, cancellationToken); + case ProjectHierarchyLevel.Task: + return await GetTaskAssignDetails(request.Id, cancellationToken); + default: + return OperationResult.Failure("سطح پروژه نامعتبر است"); + } + } + + private async Task> GetProjectAssignDetails(Guid projectId, CancellationToken cancellationToken) + { + // گرفتن تمام فازهای پروژه + + var skills = _dbContext.Skills.ToList(); + var sectionsData =await _dbContext.ProjectSections + .Where(p => p.ProjectId == projectId).ToListAsync(cancellationToken); + + if (skills.Count == 0) + { + return OperationResult.Success(new GetProjectAssignDetailsResponse(new List())); + } + var sections = skills.Select(x=> + { + var section = sectionsData.FirstOrDefault(s => s.SkillId == x.Id); + + return new GetProjectAssignSectionDetails( + x.Name, + x.Id, + section?.Id, + section?.UserId ?? 0 + ); + + }).ToList(); + var response = new GetProjectAssignDetailsResponse(sections); + return OperationResult.Success(response); + } + + private async Task> GetPhaseAssignDetails(Guid phaseId, CancellationToken cancellationToken) + { + var skills = _dbContext.Skills.ToList(); + + var sectionsData =await _dbContext.PhaseSections + .Where(p => p.PhaseId == phaseId) + .ToListAsync(cancellationToken: cancellationToken); + + if (skills.Count == 0) + { + return OperationResult.Success(new GetProjectAssignDetailsResponse(new List())); + } + + var sections = skills.Select(x=> + { + var section = sectionsData.FirstOrDefault(s => s.SkillId == x.Id); + + return new GetProjectAssignSectionDetails( + x.Name, + x.Id, + section?.Id, + section?.UserId ?? 0 + ); + + }).ToList(); + + var response = new GetProjectAssignDetailsResponse(sections); + return OperationResult.Success(response); + } + + private async Task> GetTaskAssignDetails(Guid taskId, CancellationToken cancellationToken) + { + var skills = _dbContext.Skills.ToList(); + var sectionsData =await _dbContext.TaskSections + .Where(p => p.TaskId == taskId).ToListAsync(cancellationToken); + + if (skills.Count == 0) + { + return OperationResult.Success(new GetProjectAssignDetailsResponse(new List())); + } + var sections = skills.Select(x=> + { + var section = sectionsData.FirstOrDefault(s => s.SkillId == x.Id); + + return new GetProjectAssignSectionDetails( + x.Name, + x.Id, + section?.Id, + section?.OriginalAssignedUserId ?? 0 + ); + + }).ToList(); + + var response = new GetProjectAssignDetailsResponse(sections); + return OperationResult.Success(response); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectListDto.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectListDto.cs new file mode 100644 index 00000000..74a58946 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectListDto.cs @@ -0,0 +1,18 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList; +public record GetProjectListDto +{ + public Guid Id { get; init; } + public string Name { get; init; } = string.Empty; + public int Percentage { get; init; } + public ProjectHierarchyLevel Level { get; init; } + public Guid? ParentId { get; init; } + public bool HasFront { get; set; } + public bool HasBackend { get; set; } + public bool HasDesign { get; set; } + +} + + + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQuery.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQuery.cs new file mode 100644 index 00000000..472af143 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQuery.cs @@ -0,0 +1,8 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList; + +public record GetProjectsListQuery(ProjectHierarchyLevel HierarchyLevel, + Guid? ParentId) : IBaseQuery; + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQueryHandler.cs new file mode 100644 index 00000000..523943aa --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQueryHandler.cs @@ -0,0 +1,303 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList; + +public class GetProjectsListQueryHandler : IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _context; + + public GetProjectsListQueryHandler(IProgramManagerDbContext context) + { + _context = context; + } + + public async Task> Handle(GetProjectsListQuery request, CancellationToken cancellationToken) + { + List projects; + + switch (request.HierarchyLevel) + { + case ProjectHierarchyLevel.Project: + projects = await GetProjects(request.ParentId, cancellationToken); + break; + case ProjectHierarchyLevel.Phase: + projects = await GetPhases(request.ParentId, cancellationToken); + break; + case ProjectHierarchyLevel.Task: + projects = await GetTasks(request.ParentId, cancellationToken); + break; + default: + return OperationResult.Failure("سطح سلسله مراتب نامعتبر است"); + } + await SetSkillFlags(projects, cancellationToken); + + var response = new GetProjectsListResponse(projects); + return OperationResult.Success(response); + } + + private async Task> GetProjects(Guid? parentId, CancellationToken cancellationToken) + { + var query = _context.Projects.AsQueryable(); + + // پروژه‌ها سطح بالا هستند و parentId ندارند، فقط در صورت null بودن parentId نمایش داده می‌شوند + if (parentId.HasValue) + { + return new List(); // پروژه‌ها parent ندارند + } + + var projects = await query + .OrderByDescending(p => p.CreationDate) + .ToListAsync(cancellationToken); + var result = new List(); + + foreach (var project in projects) + { + var percentage = await CalculateProjectPercentage(project, cancellationToken); + result.Add(new GetProjectListDto + { + Id = project.Id, + Name = project.Name, + Level = ProjectHierarchyLevel.Project, + ParentId = null, + Percentage = percentage + }); + } + + return result; + } + + private async Task> GetPhases(Guid? parentId, CancellationToken cancellationToken) + { + var query = _context.ProjectPhases.AsQueryable(); + + if (parentId.HasValue) + { + query = query.Where(x => x.ProjectId == parentId); + } + + var phases = await query + .OrderByDescending(p => p.CreationDate) + .ToListAsync(cancellationToken); + var result = new List(); + + foreach (var phase in phases) + { + var percentage = await CalculatePhasePercentage(phase, cancellationToken); + result.Add(new GetProjectListDto + { + Id = phase.Id, + Name = phase.Name, + Level = ProjectHierarchyLevel.Phase, + ParentId = phase.ProjectId, + Percentage = percentage + }); + } + + return result; + } + + private async Task> GetTasks(Guid? parentId, CancellationToken cancellationToken) + { + var query = _context.ProjectTasks.AsQueryable(); + + if (parentId.HasValue) + { + query = query.Where(x => x.PhaseId == parentId); + } + + var tasks = await query + .OrderByDescending(t => t.CreationDate) + .ToListAsync(cancellationToken); + var result = new List(); + + foreach (var task in tasks) + { + var percentage = await CalculateTaskPercentage(task, cancellationToken); + result.Add(new GetProjectListDto + { + Id = task.Id, + Name = task.Name, + Level = ProjectHierarchyLevel.Task, + ParentId = task.PhaseId, + Percentage = percentage + }); + } + + return result; + } + + private async Task SetSkillFlags(List projects, CancellationToken cancellationToken) + { + var projectIds = projects.Select(x => x.Id).ToList(); + + // تنها تسک‌ها sections دارند، بنابراین برای سطوح مختلف باید متفاوت عمل کنیم + List taskIds; + + switch (projects.FirstOrDefault()?.Level) + { + case ProjectHierarchyLevel.Project: + // برای پروژه‌ها، باید تمام تسک‌های زیرمجموعه را پیدا کنیم + var phaseIds = await _context.ProjectPhases + .Where(ph => projectIds.Contains(ph.ProjectId)) + .Select(ph => ph.Id) + .ToListAsync(cancellationToken); + + taskIds = await _context.ProjectTasks + .Where(t => phaseIds.Contains(t.PhaseId)) + .Select(t => t.Id) + .ToListAsync(cancellationToken); + break; + + case ProjectHierarchyLevel.Phase: + // برای فازها، تمام تسک‌های آن فازها را پیدا کنیم + taskIds = await _context.ProjectTasks + .Where(t => projectIds.Contains(t.PhaseId)) + .Select(t => t.Id) + .ToListAsync(cancellationToken); + break; + + case ProjectHierarchyLevel.Task: + // برای تسک‌ها، خود آنها taskIds هستند + taskIds = projectIds; + break; + + default: + return; + } + + if (!taskIds.Any()) + return; + + var sections = await _context.TaskSections + .Include(x => x.Skill) + .Where(x => taskIds.Contains(x.TaskId)) + .ToListAsync(cancellationToken); + + foreach (var project in projects) + { + List relevantTaskIds; + + switch (project.Level) + { + case ProjectHierarchyLevel.Project: + // برای پروژه، تمام تسک‌های زیرمجموعه + var projectPhaseIds = await _context.ProjectPhases + .Where(ph => ph.ProjectId == project.Id) + .Select(ph => ph.Id) + .ToListAsync(cancellationToken); + + relevantTaskIds = await _context.ProjectTasks + .Where(t => projectPhaseIds.Contains(t.PhaseId)) + .Select(t => t.Id) + .ToListAsync(cancellationToken); + break; + + case ProjectHierarchyLevel.Phase: + // برای فاز، تمام تسک‌های آن فاز + relevantTaskIds = await _context.ProjectTasks + .Where(t => t.PhaseId == project.Id) + .Select(t => t.Id) + .ToListAsync(cancellationToken); + break; + + case ProjectHierarchyLevel.Task: + // برای تسک، خود آن + relevantTaskIds = new List { project.Id }; + break; + + default: + continue; + } + + var projectSections = sections.Where(x => relevantTaskIds.Contains(x.TaskId)).ToList(); + project.HasBackend = projectSections.Any(x => x.Skill.Name == "Backend"); + project.HasFront = projectSections.Any(x => x.Skill.Name == "Frontend"); + project.HasDesign = projectSections.Any(x => x.Skill.Name == "UI/UX Design"); + } + } + + private async Task CalculateProjectPercentage(Project project, CancellationToken cancellationToken) + { + // گرفتن تمام فازهای پروژه + var phases = await _context.ProjectPhases + .Where(ph => ph.ProjectId == project.Id) + .ToListAsync(cancellationToken); + + if (!phases.Any()) + return 0; + + // محاسبه درصد هر فاز و میانگین‌گیری + var phasePercentages = new List(); + foreach (var phase in phases) + { + var phasePercentage = await CalculatePhasePercentage(phase, cancellationToken); + phasePercentages.Add(phasePercentage); + } + + return phasePercentages.Any() ? (int)phasePercentages.Average() : 0; + } + + private async Task CalculatePhasePercentage(ProjectPhase phase, CancellationToken cancellationToken) + { + // گرفتن تمام تسک‌های فاز + var tasks = await _context.ProjectTasks + .Where(t => t.PhaseId == phase.Id) + .ToListAsync(cancellationToken); + + if (!tasks.Any()) + return 0; + + // محاسبه درصد هر تسک و میانگین‌گیری + var taskPercentages = new List(); + foreach (var task in tasks) + { + var taskPercentage = await CalculateTaskPercentage(task, cancellationToken); + taskPercentages.Add(taskPercentage); + } + + return taskPercentages.Any() ? (int)taskPercentages.Average() : 0; + } + + private async Task CalculateTaskPercentage(ProjectTask task, CancellationToken cancellationToken) + { + // گرفتن تمام سکشن‌های تسک با activities + var sections = await _context.TaskSections + .Include(s => s.Activities) + .Where(s => s.TaskId == task.Id) + .ToListAsync(cancellationToken); + + if (!sections.Any()) + return 0; + + // محاسبه درصد هر سکشن و میانگین‌گیری + var sectionPercentages = new List(); + foreach (var section in sections) + { + var sectionPercentage = CalculateSectionPercentage(section); + sectionPercentages.Add(sectionPercentage); + } + + return sectionPercentages.Any() ? (int)sectionPercentages.Average() : 0; + } + + private static int CalculateSectionPercentage(TaskSection section) + { + // محاسبه کل زمان تخمین زده شده (اولیه + اضافی) + var totalEstimatedHours = section.FinalEstimatedHours.TotalHours; + + if (totalEstimatedHours <= 0) + return 0; + + // محاسبه کل زمان صرف شده از activities + var totalSpentHours = section.Activities.Sum(a => a.GetTimeSpent().TotalHours); + + // محاسبه درصد (حداکثر 100%) + var percentage = (totalSpentHours / totalEstimatedHours) * 100; + return Math.Min((int)Math.Round(percentage), 100); + } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQueryValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQueryValidator.cs new file mode 100644 index 00000000..33141e46 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQueryValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList; + +public class GetProjectsListQueryValidator : AbstractValidator +{ + public GetProjectsListQueryValidator() + { + RuleFor(x => x.HierarchyLevel) + .IsInEnum().WithMessage("سطح ارسال شده معتبر نمی‌باشد."); + + When(x => x.HierarchyLevel != Domain.ProjectAgg.Enums.ProjectHierarchyLevel.Project, () => + { + RuleFor(x => x.ParentId) + .NotNull().WithMessage("شناسه والد باید برای سطوح غیر از پروژه ارسال شود."); + }); + } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListResponse.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListResponse.cs new file mode 100644 index 00000000..928501dd --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListResponse.cs @@ -0,0 +1,5 @@ +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList; + +public record GetProjectsListResponse( + List Projects); + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListQuery.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListQuery.cs new file mode 100644 index 00000000..db180808 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListQuery.cs @@ -0,0 +1,10 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardList; + +public record ProjectBoardListQuery: IBaseQuery> +{ +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListQueryHandler.cs new file mode 100644 index 00000000..0edfdc0b --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListQueryHandler.cs @@ -0,0 +1,98 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardList; + +public class ProjectBoardListQueryHandler : IBaseQueryHandler> +{ + private readonly IProgramManagerDbContext _programManagerDbContext; + private readonly IAuthHelper _authHelper; + + public ProjectBoardListQueryHandler(IProgramManagerDbContext programManagerDbContext, IAuthHelper authHelper) + { + _programManagerDbContext = programManagerDbContext; + _authHelper = authHelper; + } + + public async Task>> Handle(ProjectBoardListQuery request, + CancellationToken cancellationToken) + { + var currentUserId = _authHelper.GetCurrentUserId(); + var data = await _programManagerDbContext.TaskSections.AsNoTracking() + .Where(x => x.CurrentAssignedUserId == currentUserId) + .Where(x => x.InitialEstimatedHours > TimeSpan.Zero) + .Include(x => x.Task) + .ThenInclude(x => x.Phase) + .ThenInclude(x => x.Project) + .Include(x => x.Activities) + .Include(x => x.AdditionalTimes) + .ToListAsync(cancellationToken); + + var activityUserIds = data.SelectMany(x => x.Activities).Select(a => a.UserId).Distinct().ToList(); + var users = await _programManagerDbContext.Users.AsNoTracking() + .Where(x => activityUserIds.Contains(x.Id)) + .Select(x => new { x.Id, x.FullName }) + .ToDictionaryAsync(x => x.Id, x => x.FullName, cancellationToken); + + var result = data.Select(x => + { + // محاسبه یکبار برای هر Activity و Cache کردن نتیجه + var activityTimeData = x.Activities.Select(a => + { + var timeSpent = a.GetTimeSpent(); + return new + { + Activity = a, + TimeSpent = timeSpent, + TotalSeconds = timeSpent.TotalSeconds, + FormattedTime = timeSpent.ToString(@"hh\:mm") + }; + }).ToList(); + + // ادغام پشت سر هم فعالیت‌های یک کاربر + var mergedHistories = new List(); + foreach (var activityData in activityTimeData) + { + var lastHistory = mergedHistories.LastOrDefault(); + + // اگر آخرین history برای همین کاربر باشد، زمان‌ها را جمع می‌کنیم + if (lastHistory != null && lastHistory.UserId == activityData.Activity.UserId) + { + var totalTimeSpan = lastHistory.WorkedTimeSpan + activityData.TimeSpent; + lastHistory.WorkedTimeSpan = totalTimeSpan; + lastHistory.WorkedTime = totalTimeSpan.ToString(@"hh\:mm"); + } + else + { + // در غیر این صورت، یک history جدید اضافه می‌کنیم + mergedHistories.Add(new ProjectProgressHistoryDto() + { + UserId = activityData.Activity.UserId, + IsCurrentUser = activityData.Activity.UserId == currentUserId, + Name = users.GetValueOrDefault(activityData.Activity.UserId, "ناشناس"), + WorkedTime = activityData.FormattedTime, + WorkedTimeSpan = activityData.TimeSpent, + }); + } + } + + return new ProjectBoardListResponse() + { + Id = x.Id, + PhaseName = x.Task.Phase.Name, + ProjectName = x.Task.Phase.Project.Name, + TaskName = x.Task.Name, + SectionStatus = x.Status, + Progress = new ProjectProgressDto() + { + CompleteSecond = x.FinalEstimatedHours.TotalSeconds, + CurrentSecond = activityTimeData.Sum(a => a.TotalSeconds), + Histories = mergedHistories + } + }; + }).ToList(); + + return OperationResult>.Success(result); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListResponse.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListResponse.cs new file mode 100644 index 00000000..83421e89 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListResponse.cs @@ -0,0 +1,28 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardList; + +public class ProjectBoardListResponse +{ + public Guid Id { get; set; } + public string ProjectName { get; set; } + public string PhaseName { get; set; } + public string TaskName { get; set; } + public ProjectProgressDto Progress { get; set; } + public TaskSectionStatus SectionStatus { get; set; } +} +public class ProjectProgressDto +{ + public double CurrentSecond { get; set; } + public double CompleteSecond { get; set; } + public List Histories { get; set; } +} + +public class ProjectProgressHistoryDto +{ + public string Name { get; set; } + public long UserId { get; set; } + public string WorkedTime { get; set; } + public TimeSpan WorkedTimeSpan { get; set; } + public bool IsCurrentUser { get; set; } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQuery.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQuery.cs new file mode 100644 index 00000000..4b2c08b9 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQuery.cs @@ -0,0 +1,30 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectSetTimeDetails; + +public record ProjectSetTimeDetailsQuery(Guid TaskId) + : IBaseQuery; +public record ProjectSetTimeResponse( + List SectionItems, + Guid Id, + ProjectHierarchyLevel Level); + +public record ProjectSetTimeResponseSections +{ + public string SkillName { get; init; } + public string UserName { get; init; } + public int InitialTime { get; set; } + public string InitialDescription { get; set; } + public int TotalEstimateTime { get; init; } + public int TotalAdditionalTime { get; init; } + public string InitCreationTime { get; init; } + public List AdditionalTimes { get; init; } + public Guid SectionId { get; set; } +} + +public class ProjectSetTimeResponseSectionAdditionalTime +{ + public int Time { get; init; } + public string Description { get; init; } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryHandler.cs new file mode 100644 index 00000000..f99f3370 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryHandler.cs @@ -0,0 +1,80 @@ +using DNTPersianUtils.Core; +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.SetTimeProject; +using GozareshgirProgramManager.Application.Modules.Projects.DTOs; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectSetTimeDetails; + + +public class ProjectSetTimeDetailsQueryHandler + : IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _context; + + public ProjectSetTimeDetailsQueryHandler(IProgramManagerDbContext context) + { + _context = context; + } + + public async Task> Handle(ProjectSetTimeDetailsQuery request, + CancellationToken cancellationToken) + { + var task = await _context.ProjectTasks + .Where(p => p.Id == request.TaskId) + .Include(x => x.Sections) + .ThenInclude(x => x.AdditionalTimes).AsNoTracking() + .FirstOrDefaultAsync(cancellationToken); + + if (task == null) + { + return OperationResult.NotFound("Project not found"); + } + var userIds = task.Sections.Select(x => x.OriginalAssignedUserId) + .Distinct().ToList(); + + var users = await _context.Users + .Where(x => userIds.Contains(x.Id)) + .AsNoTracking() + .ToListAsync(cancellationToken); + var skillIds = task.Sections.Select(x => x.SkillId) + .Distinct().ToList(); + + var skills = await _context.Skills + .Where(x => skillIds.Contains(x.Id)) + .AsNoTracking() + .ToListAsync(cancellationToken); + + var res = new ProjectSetTimeResponse( + task.Sections.Select(ts => + { + var user = users.FirstOrDefault(x => x.Id == ts.OriginalAssignedUserId); + var skill = skills.FirstOrDefault(x => x.Id == ts.SkillId); + return new ProjectSetTimeResponseSections + { + AdditionalTimes = ts.AdditionalTimes + .Select(x => new ProjectSetTimeResponseSectionAdditionalTime + { + Description = x.Reason ?? "", + Time = (int)x.Hours.TotalHours + }).ToList(), + InitCreationTime = ts.CreationDate.ToFarsi(), + SkillName = skill?.Name ?? "", + TotalAdditionalTime = (int)ts.GetTotalAdditionalTime().TotalHours, + TotalEstimateTime = (int)ts.FinalEstimatedHours.TotalHours, + UserName = user?.UserName ?? "", + SectionId = ts.Id, + InitialDescription = ts.InitialDescription ?? "", + InitialTime = (int)ts.InitialEstimatedHours.TotalHours + }; + }).ToList(), + task.Id, + ProjectHierarchyLevel.Task); + + + return OperationResult.Success(res); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryValidator.cs new file mode 100644 index 00000000..13952f46 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryValidator.cs @@ -0,0 +1,13 @@ +using FluentValidation; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectSetTimeDetails; + +public class ProjectSetTimeDetailsQueryValidator:AbstractValidator +{ + public ProjectSetTimeDetailsQueryValidator() + { + RuleFor(x => x.TaskId) + .NotEmpty() + .WithMessage("شناسه پروژه نمی‌تواند خالی باشد."); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Roles/Commands/CreateRole/CreateRoleCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Roles/Commands/CreateRole/CreateRoleCommandHandler.cs new file mode 100644 index 00000000..c5ef5b2c --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Roles/Commands/CreateRole/CreateRoleCommandHandler.cs @@ -0,0 +1,44 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.PermissionAgg.Entities; +using GozareshgirProgramManager.Domain.RoleAgg.Entities; +using GozareshgirProgramManager.Domain.RoleAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Roles.Commands.CreateRole; + +public class CreateRoleCommandHandler : IBaseCommandHandler +{ + private readonly IRoleRepository _roleRepository; + private readonly IUnitOfWork _unitOfWork; + + public CreateRoleCommandHandler(IRoleRepository roleRepository, IUnitOfWork unitOfWork) + { + _roleRepository = roleRepository; + _unitOfWork = unitOfWork; + } + + public async Task Handle(CreateRoleCommand request, CancellationToken cancellationToken) + { + + if(string.IsNullOrWhiteSpace(request.RoleName)) + return OperationResult.Failure("نام نقش خالی است"); + if(!request.Permissions.Any()) + return OperationResult.Failure("هیچ دسترسی داده نشده است"); + var permissions = request.Permissions.Where(x => x > 0).Select(x => new Permission(x)).ToList(); + + var role = new Role(request.RoleName, request.GozareshgirRoleId, permissions); + await _roleRepository.CreateAsync(role); + await _unitOfWork.SaveChangesAsync(); + return OperationResult.Success(); + } +} + + +public record CreateRoleCommand : IBaseCommand +{ + public string RoleName { get; set; } + public List Permissions { get; set; } + + public long? GozareshgirRoleId { get; set; } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Roles/Commands/EditRole/EditRoleCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Roles/Commands/EditRole/EditRoleCommandHandler.cs new file mode 100644 index 00000000..36e50fbb --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Roles/Commands/EditRole/EditRoleCommandHandler.cs @@ -0,0 +1,54 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.PermissionAgg.Entities; +using GozareshgirProgramManager.Domain.RoleAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Roles.Commands.EditRole; + +public class EditRoleCommandHandler : IBaseCommandHandler +{ + private readonly IRoleRepository _roleRepository; + private readonly IUnitOfWork _unitOfWork; + + public EditRoleCommandHandler(IRoleRepository roleRepository, IUnitOfWork unitOfWork) + { + _roleRepository = roleRepository; + _unitOfWork = unitOfWork; + } + + public async Task Handle(EditRoleCommand request, CancellationToken cancellationToken) + { + if (_roleRepository.Exists(x => x.RoleName == request.RoleName && x.GozareshgirRoleId != request.GozareshgirRoleId)) + return OperationResult.Failure("نام نقش تکراری است"); + + if (string.IsNullOrWhiteSpace(request.RoleName)) + return OperationResult.Failure("نام نقش خالی است"); + + if(request.GozareshgirRoleId == null || request.GozareshgirRoleId == 0) + return OperationResult.Failure("آی دی نقش از سمت گزارشگیر خالی است"); + + var permissions = request.Permissions.Where(x => x > 0).Select(x => new Permission(x)).ToList(); + + + var role =await _roleRepository.GetByGozareshgirRoleIdAsync(request.GozareshgirRoleId); + + if (role != null) + { + role?.Edit(request.RoleName, permissions); + + await _unitOfWork.SaveChangesAsync(); + } + + return OperationResult.Success(); + + } +} + +public record EditRoleCommand : IBaseCommand +{ + public string RoleName { get; set; } + public List Permissions { get; set; } + + public long? GozareshgirRoleId { get; set; } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Roles/Queries/GetRoles/GetRolesQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Roles/Queries/GetRoles/GetRolesQueryHandler.cs new file mode 100644 index 00000000..bcdb5fe1 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Roles/Queries/GetRoles/GetRolesQueryHandler.cs @@ -0,0 +1,76 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Roles.Queries.GetRoles; + +public class GetRolesQueryHandler : IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _context; + + public GetRolesQueryHandler(IProgramManagerDbContext context) + { + _context = context; + } + + public async Task> Handle(GetRolesQuery request, CancellationToken cancellationToken) + { + var query = _context.Roles.AsQueryable(); + + if (!string.IsNullOrWhiteSpace(request.RoleName)) + query = query.Where(x => x.RoleName.Contains(request.RoleName)); + if (request.GozareshgirRoleId > 0) + query = query.Where(x => x.GozareshgirRoleId == request.GozareshgirRoleId); + + var roles = await query + .Select(p => new GetRolesDto() + { + Id = p.Id, + RoleName = p.RoleName, + GozareshgirRoleId = p.GozareshgirRoleId, + Permissions = p.Permissions.Select(x=>x.Code).ToList() + + }) + .ToListAsync(cancellationToken); + if(!roles.Any()) + return OperationResult.NotFound("یافت نشد"); + + var response = new GetRolesResponse( + roles + ); + + return OperationResult.Success(response); + + } +} + + +public record GetRolesQuery(string? RoleName, long? GozareshgirRoleId) : IBaseQuery; + +public record GetRolesResponse(List Role); + +public record GetRolesDto +{ + /// + /// آی دی نقش + /// + public long Id { get; set; } + + /// + /// نام نقش + /// + public string RoleName { get; set; } + + /// + /// آی دی نقش در گزارشگیر + /// + public long? GozareshgirRoleId { get; set; } + + /// + /// لیست کدهای دسترسی + /// + public List Permissions { get; set; } + + +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/SalaryPaymentSettings/Commands/CreateSalarySettings/CreateSalarySettingsCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/SalaryPaymentSettings/Commands/CreateSalarySettings/CreateSalarySettingsCommandHandler.cs new file mode 100644 index 00000000..95e57809 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/SalaryPaymentSettings/Commands/CreateSalarySettings/CreateSalarySettingsCommandHandler.cs @@ -0,0 +1,173 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Enums; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Commands.CreateSalarySettings; + +public class CreateSalarySettingsCommandHandler : IBaseCommandHandler +{ + readonly ISalaryPaymentSettingRepository _salaryPaymentSettingRepository; + readonly IUnitOfWork _unitOfWork; + + public CreateSalarySettingsCommandHandler(ISalaryPaymentSettingRepository salaryPaymentSettingRepository, IUnitOfWork unitOfWork) + { + _salaryPaymentSettingRepository = salaryPaymentSettingRepository; + _unitOfWork = unitOfWork; + } + + public async Task Handle(CreateSalarySettingsCommand request, CancellationToken cancellationToken) + { + + if(_salaryPaymentSettingRepository.Exists(x=>x.UserId == request.UserId)) + return OperationResult.Failure(" برای این پرسنل قبلا تنظیمات ایجاد شده است"); + + + if (string.IsNullOrWhiteSpace(request.MonthlySalary)) + return OperationResult.Failure("حقوق ماهانه وارد نشده اشت"); + double monthlySalary = 0; + try + { + monthlySalary = request.MonthlySalary.MoneyToDouble(); + } + catch (Exception e) + { + return OperationResult.Failure("مبلغ حقوق به درستی وارد نشده است"); + } + + + if (monthlySalary == 0) + return OperationResult.Failure("مبلغ حقوق به درستی وارد نشده است"); + + var workingHoursList = new List(); + foreach (var workingHours in request.WorkingHoursList) + { + var startShiftOne = new TimeSpan(); + var endShiftOne = new TimeSpan(); + var startShiftTwo = new TimeSpan(); + var endShiftTwo = new TimeSpan(); + var restTime = new TimeSpan(); + workingHours.HasShiftOne = false; + workingHours.HasRestTime = false; + workingHours.HasShiftTow = false; + try + { + if (!string.IsNullOrWhiteSpace(workingHours.StartShiftOne) && !string.IsNullOrWhiteSpace(workingHours.EndShiftOne)) + { + startShiftOne = TimeSpan.ParseExact(workingHours.StartShiftOne, @"hh\:mm", null); + endShiftOne = TimeSpan.ParseExact(workingHours.EndShiftOne, @"hh\:mm", null); + + workingHours.HasShiftOne = true; + + + if (!string.IsNullOrWhiteSpace(workingHours.RestTime)) + { + try + { + restTime = TimeSpan.ParseExact(workingHours.RestTime, @"hh\:mm", null); + workingHours.HasRestTime = true; + } + catch (Exception e) + { + return OperationResult.Failure("فرمت ساعت استراحت اشتباه وارد شده است"); + } + } + + } + + if (!string.IsNullOrWhiteSpace(workingHours.StartShiftTwo) && + !string.IsNullOrWhiteSpace(workingHours.EndShiftTwo)) + { + workingHours.HasRestTime = false; + workingHours.HasShiftTow = true; + + startShiftTwo = TimeSpan.ParseExact(workingHours.StartShiftTwo, @"hh\:mm", null); + endShiftTwo = TimeSpan.ParseExact(workingHours.EndShiftTwo, @"hh\:mm", null); + } + } + catch (Exception) + { + return OperationResult.Failure("فرمت ساعت اشتباه وارد شده است"); + } + + + + + workingHoursList.Add(new WorkingHours(startShiftOne,endShiftOne,startShiftTwo, endShiftTwo,restTime,workingHours.HasShiftOne,workingHours.HasShiftTow,workingHours.HasRestTime, workingHours.PersianDayOfWeek, workingHours.IsActiveDay)); + + } + + if(workingHoursList.Count < 7) + return OperationResult.Failure("خطا در تعداد روز های ارسال شده"); + var salarySetting = new SalaryPaymentSetting(request.HolidayWorking, request.UserId,monthlySalary, workingHoursList); + await _salaryPaymentSettingRepository.CreateAsync(salarySetting); + await _unitOfWork.SaveChangesAsync(); + return OperationResult.Success(); + + } +} + + +public record CreateSalarySettingsCommand(bool HolidayWorking, long UserId, string? MonthlySalary, List WorkingHoursList) : IBaseCommand; + + +public record WorkingHoursListDto +{ + /// + /// ساعت شروع شیفت کاری + /// + public string? StartShiftOne { get; set; } + + /// + /// ساعت پایان شیفت کاری + /// + public string? EndShiftOne { get; set; } + + + /// + /// ساعت شروع شیفت دوم کاری + /// + public string? StartShiftTwo { get; set; } + + /// + /// ساعت پایان شیفت دوم کاری + /// + public string? EndShiftTwo { get; set; } + + /// + /// مدت استراحت + /// + public string? RestTime { get; set; } + + + /// + /// آیا مقطع مار اول دارد + /// + public bool HasShiftOne { get; set; } + + /// + /// آیا مقطع کار دوم دارد + /// + public bool HasShiftTow { get; set; } + + /// + /// آیا ساعت استراحت دارد + /// + public bool HasRestTime { get; set; } + + + /// + /// عدد روز از ماه + /// + public PersianDayOfWeek PersianDayOfWeek { get; set; } + + + /// + /// آیا این روز هفته + /// فعال است + /// + public bool IsActiveDay { get; set; } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/SalaryPaymentSettings/Commands/EditSalarySettings/EditSalarySettingsCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/SalaryPaymentSettings/Commands/EditSalarySettings/EditSalarySettingsCommandHandler.cs new file mode 100644 index 00000000..fe202a61 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/SalaryPaymentSettings/Commands/EditSalarySettings/EditSalarySettingsCommandHandler.cs @@ -0,0 +1,120 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Commands.CreateSalarySettings; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Commands.EditSalarySettings; + +public class EditSalarySettingsCommandHandler : IBaseCommandHandler +{ + private readonly ISalaryPaymentSettingRepository _salaryPaymentSettingRepository; + private readonly IUnitOfWork _unitOfWork; + + public EditSalarySettingsCommandHandler(ISalaryPaymentSettingRepository salaryPaymentSettingRepository, IUnitOfWork unitOfWork) + { + _salaryPaymentSettingRepository = salaryPaymentSettingRepository; + _unitOfWork = unitOfWork; + } + + public async Task Handle(EditSalarySettingsCommand request, CancellationToken cancellationToken) + { + + var getSettings =await _salaryPaymentSettingRepository.GetSalarySettingByUserId(request.UserId); + if(getSettings == null) + return OperationResult.NotFound("یافت نشد"); + + if(string.IsNullOrWhiteSpace(request.MonthlySalary)) + return OperationResult.Failure("حقوق ماهانه وارد نشده اشت"); + double monthlySalary = 0; + try + { + monthlySalary = request.MonthlySalary.MoneyToDouble(); + } + catch (Exception e) + { + return OperationResult.Failure("مبلغ حقوق به درستی وارد نشده است"); + } + + if (monthlySalary == 0) + return OperationResult.Failure("مبلغ حقوق به درستی وارد نشده است"); + + + var workingHoursList = new List(); + foreach (var workingHours in request.WorkingHoursList) + { + var startShiftOne = new TimeSpan(); + var endShiftOne = new TimeSpan(); + var startShiftTwo = new TimeSpan(); + var endShiftTwo = new TimeSpan(); + var restTime = new TimeSpan(); + workingHours.HasShiftOne = false; + workingHours.HasRestTime = false; + workingHours.HasShiftTow = false; + try + { + if (!string.IsNullOrWhiteSpace(workingHours.StartShiftOne) && !string.IsNullOrWhiteSpace(workingHours.EndShiftOne)) + { + startShiftOne = TimeSpan.ParseExact(workingHours.StartShiftOne, @"hh\:mm", null); + endShiftOne = TimeSpan.ParseExact(workingHours.EndShiftOne, @"hh\:mm", null); + + workingHours.HasShiftOne = true; + + + if (!string.IsNullOrWhiteSpace(workingHours.RestTime)) + { + try + { + restTime = TimeSpan.ParseExact(workingHours.RestTime, @"hh\:mm", null); + workingHours.HasRestTime = true; + } + catch (Exception e) + { + return OperationResult.Failure("فرمت ساعت استراحت اشتباه وارد شده است"); + } + } + } + + if (!string.IsNullOrWhiteSpace(workingHours.StartShiftTwo) && + !string.IsNullOrWhiteSpace(workingHours.EndShiftTwo)) + { + workingHours.HasRestTime = false; + workingHours.HasShiftTow = true; + + startShiftTwo = TimeSpan.ParseExact(workingHours.StartShiftTwo, @"hh\:mm", null); + endShiftTwo = TimeSpan.ParseExact(workingHours.EndShiftTwo, @"hh\:mm", null); + } + } + catch (Exception) + { + return OperationResult.Failure("فرمت ساعت اشتباه وارد شده است"); + } + + + + + workingHoursList.Add(new WorkingHours(startShiftOne, endShiftOne, startShiftTwo, endShiftTwo, restTime, workingHours.HasShiftOne, workingHours.HasShiftTow, workingHours.HasRestTime, workingHours.PersianDayOfWeek, workingHours.IsActiveDay)); + + + + } + + + getSettings.Edit(request.HolidayWorking,monthlySalary, workingHoursList); + + + await _unitOfWork.SaveChangesAsync(); + return OperationResult.Success(); + } +} + + +public record EditSalarySettingsCommand(long UserId, bool HolidayWorking,string? MonthlySalary, List WorkingHoursList) : IBaseCommand; + + + + + + + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/SalaryPaymentSettings/Queries/GetSalarySettingToEdit/GetSalarySettingToEditQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/SalaryPaymentSettings/Queries/GetSalarySettingToEdit/GetSalarySettingToEditQueryHandler.cs new file mode 100644 index 00000000..c3bd3385 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/SalaryPaymentSettings/Queries/GetSalarySettingToEdit/GetSalarySettingToEditQueryHandler.cs @@ -0,0 +1,88 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Commands.CreateSalarySettings; +using GozareshgirProgramManager.Domain._Common; +using Microsoft.EntityFrameworkCore; +using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database; + +namespace GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Queries.GetSalarySettingToEdit; + +public class GetSalarySettingToEditQueryHandler : IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _context; + + public GetSalarySettingToEditQueryHandler(IProgramManagerDbContext context) + { + _context = context; + } + + public async Task> Handle(GetSalarySettingToEditQuery request, CancellationToken cancellationToken) + { + var user =await _context.Users.FirstOrDefaultAsync(x => x.Id == request.UserId); + if(user == null) + return OperationResult.NotFound("کاربر یافت نشد"); + + var editSalarySettingsList = await _context.SalaryPaymentSettings + .Select(x => new GetSalarySettingToEdit() + { + Id = x.Id, + HolidayWorking = x.HolidayWorking, + UserId = x.UserId, + MonthlySalary = x.MonthlySalary.ToMoney(), + + WorkingHoursList = x.WorkingHoursList.Select(wh => new WorkingHoursListDto + { + StartShiftOne =wh.HasShiftOne ? wh.StartShiftOne.ToString(@"hh\:mm") : null, + EndShiftOne = wh.HasShiftOne ? wh.EndShiftOne.ToString(@"hh\:mm") : null, + StartShiftTwo = wh.HasShiftTow ? wh.StartShiftTwo.ToString(@"hh\:mm") : null, + EndShiftTwo = wh.HasShiftTow ? wh.EndShiftTwo.ToString(@"hh\:mm") :null, + RestTime = wh.HasRestTime ? wh.RestTime.ToString(@"hh\:mm") : null, + HasRestTime = wh.HasRestTime, + HasShiftOne = wh.HasShiftOne, + HasShiftTow = wh.HasShiftTow, + PersianDayOfWeek = wh.PersianDayOfWeek, + IsActiveDay = wh.IsActiveDay + }).OrderBy(wh=>wh.PersianDayOfWeek).ToList(), + + }).FirstOrDefaultAsync(x => x.UserId == request.UserId); + + var response = new GetSalarySettingToEditResponse(request.UserId,user.FullName,editSalarySettingsList); + + return OperationResult.Success(response); + + } +} + +public record GetSalarySettingToEditResponse(long UserId, string FullName, GetSalarySettingToEdit EditSalarySettingsList); + +public record GetSalarySettingToEditQuery(long UserId) :IBaseQuery; + + +public record GetSalarySettingToEdit +{ + /// + /// ای دی کاربر + /// + public long Id { get; set; } + /// + /// آی دی کاربر + /// + public long UserId { get; set; } + + /// + /// کار در تعطیلات رسمی + /// + public bool HolidayWorking { get; set; } + + /// + /// حقوق ماهانه + /// + public string MonthlySalary { get; set; } + + /// + /// لیست روزهای هفته و ساعات کاری + /// + public List WorkingHoursList { get; set; } +} + + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/SalaryPaymentSettings/Queries/GetUserListWhoHaveSettings/GetUserListWhoHaveSettingsQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/SalaryPaymentSettings/Queries/GetUserListWhoHaveSettings/GetUserListWhoHaveSettingsQueryHandler.cs new file mode 100644 index 00000000..2e9361e6 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/SalaryPaymentSettings/Queries/GetUserListWhoHaveSettings/GetUserListWhoHaveSettingsQueryHandler.cs @@ -0,0 +1,111 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; + +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Enums; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Queries.GetUserListWhoHaveSettings; + +public class GetUserListWhoHaveSettingsQueryHandler : IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _context; + + public GetUserListWhoHaveSettingsQueryHandler(IProgramManagerDbContext context) + { + _context = context; + } + + public async Task> Handle(GetUserListWhoHaveSettingsQuery request, CancellationToken cancellationToken) + { + var query = await ( + from u in _context.Users + join s in _context.SalaryPaymentSettings + on u.Id equals s.UserId into settingsGroup + select new GetUserWhoHaveSettingsDto + { + UserId = u.Id, + FullName = u.FullName, + HasSalarySettings = settingsGroup.Any(), + MontlySalary = settingsGroup.Any() ? settingsGroup.FirstOrDefault().MonthlySalary.ToMoney() : "", + WeeklyWorkingTimeAvrageInt = settingsGroup + .SelectMany(x => x.WorkingHoursList) + .Sum(w => (int?)w.ShiftDurationInMinutes) ?? 0 + } + ).ToListAsync(cancellationToken); + + + + if (!string.IsNullOrWhiteSpace(request.FullName)) + query = query.Where(x => x.FullName.Contains(request.FullName)).ToList(); + + if (request.HasSalarySettings != HasSalarySettings.Default) + { + bool hasSettings = request.HasSalarySettings == HasSalarySettings.HasSettings; + + query = query.Where(x => x.HasSalarySettings == hasSettings).ToList(); + } + + var operationQuery = query.Select(user => + { + var weeklyWorkingTimeAvrage = user.WeeklyWorkingTimeAvrageInt.ConvertIntDurationToHoursAndMinutes(); + + return new GetUserWhoHaveSettingsDto + { + UserId = user.UserId, + FullName = user.FullName, + HasSalarySettings = user.HasSalarySettings, + MontlySalary = user.MontlySalary, + WeeklyWorkingTimeAvrageInt = user.WeeklyWorkingTimeAvrageInt, + WeeklyWorkingTimeAvrage = weeklyWorkingTimeAvrage + }; + }).ToList(); + var response = new GetUserListWhoHaveSettingsResponse(operationQuery); + + return OperationResult.Success(response); + + + } +} + + +public record GetUserListWhoHaveSettingsQuery(string? FullName, HasSalarySettings HasSalarySettings) : IBaseQuery; + +public record GetUserListWhoHaveSettingsResponse(List UserList); + +public record GetUserWhoHaveSettingsDto +{ + /// + /// نام و نام خانوادگی + /// + public string FullName { get; set; } + + /// + /// آی دی کاربر + /// + public long UserId { get; set; } + + /// + /// آیا کاربر دارای تنظیمات حقوق است؟ + /// + public bool HasSalarySettings { get; set; } + + /// + /// میانگین ساعت کار + /// عددی مجموع دقایق + /// + public int WeeklyWorkingTimeAvrageInt { get; set; } + + /// + /// میانگین ساعت کار در هفته + /// رشته ساعت و دقیقه + /// + public string WeeklyWorkingTimeAvrage { get; set; } + + + /// + /// حقوق ماهانه + /// + public string MontlySalary { get; set; } + +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Skills/DTOs/SkillDto.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Skills/DTOs/SkillDto.cs new file mode 100644 index 00000000..75d052ce --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Skills/DTOs/SkillDto.cs @@ -0,0 +1,7 @@ +namespace GozareshgirProgramManager.Application.Modules.Skills.DTOs; + +public class SkillDto +{ + public Guid Id { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Skills/Queries/GetSkillList/GetSkillListCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Skills/Queries/GetSkillList/GetSkillListCommandHandler.cs new file mode 100644 index 00000000..061597c9 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Skills/Queries/GetSkillList/GetSkillListCommandHandler.cs @@ -0,0 +1,33 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Skills.DTOs; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Skills.Queries.GetSkillList; + +public record GetSkillListQuery() : IBaseQuery; +public record GetSkillListResponse(List Skills); + +public class GetSkillListCommandHandler:IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _dbContext; + + public GetSkillListCommandHandler(IProgramManagerDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task> Handle(GetSkillListQuery request, CancellationToken cancellationToken) + { + var skills =await _dbContext.Skills + .Select(s => new SkillDto + { + Id = s.Id, + Name = s.Name + }) + .ToListAsync(cancellationToken: cancellationToken); + + var response = new GetSkillListResponse(skills); + return OperationResult.Success(response); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/CreateUser/CreateUserCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/CreateUser/CreateUserCommand.cs new file mode 100644 index 00000000..4eba06a0 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/CreateUser/CreateUserCommand.cs @@ -0,0 +1,5 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; + +namespace GozareshgirProgramManager.Application.Modules.Users.Commands.CreateUser; + +public record CreateUserCommand(string FullName, string UserName, string Password, string Mobile, string? Email, long? AccountId, List Roles) : IBaseCommand; \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/CreateUser/CreateUserCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/CreateUser/CreateUserCommandHandler.cs new file mode 100644 index 00000000..535697b3 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/CreateUser/CreateUserCommandHandler.cs @@ -0,0 +1,43 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.RoleUserAgg; +using GozareshgirProgramManager.Domain.UserAgg.Entities; +using GozareshgirProgramManager.Domain.UserAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Users.Commands.CreateUser; + +public class CreateUserCommandHandler : IBaseCommandHandler +{ + private readonly IUserRepository _userRepository; + private readonly IUnitOfWork _unitOfWork; + + public CreateUserCommandHandler(IUnitOfWork unitOfWork, IUserRepository userRepository) + { + _unitOfWork = unitOfWork; + _userRepository = userRepository; + } + + public async Task Handle(CreateUserCommand request, CancellationToken cancellationToken) + { + + #region CustomValidation + if (_userRepository.Exists(x => x.FullName == request.FullName)) + return OperationResult.Failure("نام و خانوادگی تکراری است"); + if (_userRepository.Exists(x => x.UserName == request.UserName)) + return OperationResult.Failure("نام کاربری تکراری است"); + if (_userRepository.Exists(x=> !string.IsNullOrWhiteSpace(x.Mobile) && x.Mobile == request.Mobile)) + return OperationResult.ValidationError("این شماره همراه قبلا به فرد دیگری اختصاص داده شده است"); + if(request.AccountId == 0) + return OperationResult.Failure("آی دی اکانت، از سمت گزارشگیر صفر است"); + #endregion + + var userRoles = request.Roles.Where(x => x > 0).Select(x => new RoleUser(x)).ToList() ; + var create = new User(request.FullName, request.UserName, request.Password, request.Mobile, + request.Email, request?.AccountId, userRoles); + + await _userRepository.CreateAsync(create); + await _unitOfWork.SaveChangesAsync(cancellationToken); + return OperationResult.Success(); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/CreateUser/CreateUserCommandValidators.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/CreateUser/CreateUserCommandValidators.cs new file mode 100644 index 00000000..68f9f1a7 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/CreateUser/CreateUserCommandValidators.cs @@ -0,0 +1,24 @@ +using FluentValidation; + +namespace GozareshgirProgramManager.Application.Modules.Users.Commands.CreateUser; + +public class CreateUserCommandValidators : AbstractValidator +{ + public CreateUserCommandValidators() + { + RuleFor(x => x.FullName) + .NotEmpty() + .NotNull() + .WithMessage("نام و نام خانوادگی نمی تواند خالی باشد"); + + RuleFor(x => x.Mobile) + .NotNull().NotEmpty().WithMessage("شماره همراه نمی تواند خالی باشد"); + RuleFor(x=>x.Mobile) + .Length(11).WithMessage("طول شماره همراه می بایست 11 رقم باشد"); + RuleFor(x => x.UserName) + .NotEmpty().NotNull().WithMessage("نام کاربری نمیتوان خالی باشد"); + + + + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/EditUser/EditUserCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/EditUser/EditUserCommandHandler.cs new file mode 100644 index 00000000..1920f1fb --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/EditUser/EditUserCommandHandler.cs @@ -0,0 +1,34 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.RoleUserAgg; +using GozareshgirProgramManager.Domain.UserAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Users.Commands.EditUser; + +public class EditUserCommandHandler :IBaseCommandHandler +{ + private readonly IUserRepository _userRepository; + private readonly IUnitOfWork _unitOfWork; + + public EditUserCommandHandler(IUserRepository userRepository, IUnitOfWork unitOfWork) + { + _userRepository = userRepository; + _unitOfWork = unitOfWork; + } + + public async Task Handle(EditUserCommand request, CancellationToken cancellationToken) + { + var user = await _userRepository.GetByGozareshgirAccountId(request.AccountId); + if (user != null) + { + var userRoles = request.Roles.Where(x => x > 0).Select(x => new RoleUser(x)).ToList(); + user.Edit(request.FullName, request.UserName, request.Mobile, userRoles, request.IsActive); + await _unitOfWork.SaveChangesAsync(); + } + + return OperationResult.Success(); + } +} + +public record EditUserCommand(string FullName, string UserName, string Mobile,long AccountId, List Roles, bool IsActive) : IBaseCommand; \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/LoginUser/LoginUserCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/LoginUser/LoginUserCommand.cs new file mode 100644 index 00000000..80d51cb2 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/LoginUser/LoginUserCommand.cs @@ -0,0 +1,11 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using MediatR; + +namespace GozareshgirProgramManager.Application.Modules.Users.Commands.LoginUser; + +/// +/// دستور ورود کاربر به سیستم +/// +public record LoginUserCommand(long UserId) : IBaseCommand; + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/LoginUser/LoginUserCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/LoginUser/LoginUserCommandHandler.cs new file mode 100644 index 00000000..cb284fd0 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/LoginUser/LoginUserCommandHandler.cs @@ -0,0 +1,98 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.UserAgg.Entities; +using GozareshgirProgramManager.Domain.UserAgg.Repositories; +using MediatR; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Users.Commands.LoginUser; + +/// +/// Handler برای ورود کاربر به سیستم +/// +public class LoginUserCommandHandler : IRequestHandler> +{ + private readonly IUserRepository _userRepository; + private readonly IUserRefreshTokenRepository _refreshTokenRepository; + private readonly IAuthHelper _authHelper; + private readonly IUnitOfWork _unitOfWork; + + public LoginUserCommandHandler( + IUserRepository userRepository, + IAuthHelper authHelper, + IUnitOfWork unitOfWork, IUserRefreshTokenRepository refreshTokenRepository) + { + _userRepository = userRepository; + _authHelper = authHelper; + _unitOfWork = unitOfWork; + _refreshTokenRepository = refreshTokenRepository; + } + + public async Task> Handle(LoginUserCommand request, CancellationToken cancellationToken) + { + // اعتبارسنجی + if (request.UserId <= 0) + { + return OperationResult.Failure("شناسه کاربری معتبر نیست", ErrorType.BadRequest); + } + + // یافتن کاربر + var user = await _userRepository.GetUserWithRolesByIdAsync(request.UserId, cancellationToken); + + if (user == null) + { + return OperationResult.Failure("کاربر یافت نشد", ErrorType.NotFound); + } + + // بررسی فعال بودن کاربر + if (!user.IsActive) + { + return OperationResult.Failure("حساب کاربری غیرفعال است", ErrorType.Unauthorized); + } + + // تولید توکن‌ها با استفاده از AuthHelper + var roles = user.RoleUser + .Select(r => r.RoleId.ToString()).ToList(); + + var session = _authHelper.SignIn( + user.Id, + user.UserName, + user.FullName, + user.AccountId??0, + roles); + // دریافت اطلاعات درخواست با استفاده از AuthHelper + var ipAddress = _authHelper.GetClientIpAddress(); + var userAgent = _authHelper.GetUserAgent(); + + // ذخیره Refresh Token در دیتابیس + //user.AddRefreshToken(refreshToken, refreshTokenExpiration, ipAddress, userAgent); + + var refreshTokenEntity = new UserRefreshToken( + user.Id, + session.RefreshToken, + session.RefreshTokenExpiration, + ipAddress, + userAgent); + + await _refreshTokenRepository.CreateAsync(refreshTokenEntity); + + + await _unitOfWork.SaveChangesAsync(cancellationToken); + + + // ساخت پاسخ (RefreshToken به فرانت داده نمی‌شود) + var response = new LoginResponse + { + AccessToken = session.AccessToken, + ExpiresAt = session.AccessTokenExpiration, + UserId = user.Id, + FullName = user.FullName, + UserName = user.UserName, + Roles = user.RoleUser.Select(r => r.RoleId).ToList() + }; + + return OperationResult.Success(response); + } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/RefreshUserToken/RefreshUserTokenCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/RefreshUserToken/RefreshUserTokenCommand.cs new file mode 100644 index 00000000..31cf5838 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/RefreshUserToken/RefreshUserTokenCommand.cs @@ -0,0 +1,11 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using MediatR; + +namespace GozareshgirProgramManager.Application.Modules.Users.Commands.RefreshUserToken; + +/// +/// دستور تازه‌سازی توکن دسترسی کاربر +/// +public record RefreshUserTokenCommand() : IBaseCommand; + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/RefreshUserToken/RefreshUserTokenCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/RefreshUserToken/RefreshUserTokenCommandHandler.cs new file mode 100644 index 00000000..12bfb62b --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/RefreshUserToken/RefreshUserTokenCommandHandler.cs @@ -0,0 +1,86 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using Microsoft.EntityFrameworkCore; +using MediatR; + +namespace GozareshgirProgramManager.Application.Modules.Users.Commands.RefreshUserToken; + +/// +/// Handler برای تازه‌سازی توکن دسترسی +/// +public class RefreshUserTokenCommandHandler : IBaseCommandHandler +{ + private readonly IAuthHelper _authHelper; + private readonly IProgramManagerDbContext _context; + + public RefreshUserTokenCommandHandler( + IAuthHelper authHelper, + IProgramManagerDbContext context) + { + _authHelper = authHelper; + _context = context; + } + + public async Task Handle(RefreshUserTokenCommand request, CancellationToken cancellationToken) + { + + var refreshToken = _authHelper.GetRefreshTokenFromCookie(); + + // یافتن کاربر و Refresh Token فعال از دیتابیس + var user = await _context.Users + .Include(u => u.RefreshTokens) + .Include(u => u.RoleUser) + .FirstOrDefaultAsync(u => u.RefreshTokens.Any(r=>r.Token ==refreshToken), cancellationToken); + + if (user == null) + { + return OperationResult.Failure("کاربر یافت نشد", ErrorType.NotFound); + } + + // بررسی فعال بودن کاربر + if (!user.IsActive) + { + return OperationResult.Failure("حساب کاربری غیرفعال است", ErrorType.Unauthorized); + } + + // پیدا کردن Refresh Token فعال + var activeRefreshToken = user.RefreshTokens + .FirstOrDefault(rt => rt.Token == refreshToken && rt.IsActive); + + if (activeRefreshToken == null) + { + return OperationResult.Failure( + "نشست شما منقضی شده است. لطفاً دوباره وارد شوید", + ErrorType.Unauthorized); + } + + if (!activeRefreshToken.IsActive|| activeRefreshToken.IsRevoked||activeRefreshToken.IsExpired) + { + return OperationResult.Failure( + "نشست شما منقضی شده است. لطفاً دوباره وارد شوید", + ErrorType.Unauthorized); + } + + // تولید Access Token جدید با استفاده از AuthHelper + var roles = user.RoleUser.Select(r => r.RoleId.ToString()).ToList(); + var newAccessToken = _authHelper.GenerateAccessToken( + user.Id, + user.UserName, + user.FullName, + user.AccountId, + roles); + + var response = new AccessTokenResponse + { + AccessToken = newAccessToken, + ExpiresAt = DateTime.UtcNow.AddMinutes(30), + UserId = user.Id, + FullName = user.FullName, + UserName = user.UserName + }; + + return OperationResult.Success(response); + } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/SignOutUser/SignOutUserCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/SignOutUser/SignOutUserCommand.cs new file mode 100644 index 00000000..7c9c6bda --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/SignOutUser/SignOutUserCommand.cs @@ -0,0 +1,11 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using MediatR; + +namespace GozareshgirProgramManager.Application.Modules.Users.Commands.SignOutUser; + +/// +/// دستور خروج کاربر از سیستم +/// +public record SignOutUserCommand(string RefreshToken) : IBaseCommand; + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/SignOutUser/SignOutUserCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/SignOutUser/SignOutUserCommandHandler.cs new file mode 100644 index 00000000..92c69fcf --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/SignOutUser/SignOutUserCommandHandler.cs @@ -0,0 +1,68 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using MediatR; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Users.Commands.SignOutUser; + +/// +/// Handler برای خروج کاربر از سیستم +/// +public class SignOutUserCommandHandler : IBaseCommandHandler +{ + private readonly IAuthHelper _authHelper; + private readonly IProgramManagerDbContext _context; + private readonly IUnitOfWork _unitOfWork; + + public SignOutUserCommandHandler( + IAuthHelper _authHelper, + IProgramManagerDbContext context, + IUnitOfWork unitOfWork) + { + this._authHelper = _authHelper; + _context = context; + _unitOfWork = unitOfWork; + } + + public async Task Handle(SignOutUserCommand request, CancellationToken cancellationToken) + { + // دریافت UserId از Claims با استفاده از AuthHelper + var userId = _authHelper.GetCurrentUserId(); + + if (!userId.HasValue) + { + return OperationResult.Failure("کاربر احراز هویت نشده است", ErrorType.Unauthorized); + } + + if (string.IsNullOrEmpty(request.RefreshToken)) + { + return OperationResult.Failure("توکن تازه‌سازی یافت نشد", ErrorType.BadRequest); + } + + // یافتن کاربر + var user = await _context.Users + .Include(u => u.RefreshTokens) + .FirstOrDefaultAsync(u => u.Id == userId.Value, cancellationToken); + + if (user == null) + { + return OperationResult.Failure("کاربر یافت نشد", ErrorType.NotFound); + } + + try + { + // لغو Refresh Token + user.RevokeRefreshToken(request.RefreshToken); + await _unitOfWork.SaveChangesAsync(cancellationToken); + _authHelper.SignOut(); + + return OperationResult.Success(); + } + catch (InvalidOperationException ex) + { + return OperationResult.Failure(ex.Message, ErrorType.BadRequest); + } + } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/SsoLogin/SsoLoginCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/SsoLogin/SsoLoginCommand.cs new file mode 100644 index 00000000..0c6d5a33 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/SsoLogin/SsoLoginCommand.cs @@ -0,0 +1,10 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; + +namespace GozareshgirProgramManager.Application.Modules.Users.Commands.SsoLogin; + +/// +/// دستور ورود از طریق SSO با استفاده از توکن JWT +/// +public record SsoLoginCommand(string Token) : IBaseCommand; + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/SsoLogin/SsoLoginCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/SsoLogin/SsoLoginCommandHandler.cs new file mode 100644 index 00000000..3e638729 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Commands/SsoLogin/SsoLoginCommandHandler.cs @@ -0,0 +1,115 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.UserAgg.Entities; +using GozareshgirProgramManager.Domain.UserAgg.Repositories; +using MediatR; + +namespace GozareshgirProgramManager.Application.Modules.Users.Commands.SsoLogin; + +/// +/// Handler برای ورود از طریق SSO با استفاده از JWT Token +/// +public class SsoLoginCommandHandler : IRequestHandler> +{ + private readonly IUserRepository _userRepository; + private readonly IUserRefreshTokenRepository _refreshTokenRepository; + private readonly IAuthHelper _authHelper; + private readonly IUnitOfWork _unitOfWork; + + public SsoLoginCommandHandler( + IUserRepository userRepository, + IAuthHelper authHelper, + IUnitOfWork unitOfWork, + IUserRefreshTokenRepository refreshTokenRepository) + { + _userRepository = userRepository; + _authHelper = authHelper; + _unitOfWork = unitOfWork; + _refreshTokenRepository = refreshTokenRepository; + } + + public async Task> Handle(SsoLoginCommand request, CancellationToken cancellationToken) + { + // اعتبارسنجی + if (string.IsNullOrWhiteSpace(request.Token)) + { + return OperationResult.Failure("توکن SSO معتبر نیست", ErrorType.BadRequest); + } + + // اعتبارسنجی توکن و استخراج Claims + var principal = _authHelper.ValidateToken(request.Token); + if (principal == null) + { + return OperationResult.Failure("توکن SSO نامعتبر یا منقضی شده است", ErrorType.Unauthorized); + } + + // استخراج AccountId از Claims + var accountIdClaim = principal.FindFirst("AccountId")?.Value; + if (string.IsNullOrEmpty(accountIdClaim) || !long.TryParse(accountIdClaim, out var accountId)) + { + return OperationResult.Failure("AccountId در توکن یافت نشد", ErrorType.BadRequest); + } + + // یافتن کاربر بر اساس AccountId + var user = await _userRepository.GetByGozareshgirAccountId(accountId); + + if (user == null) + { + return OperationResult.Failure("کاربر با AccountId مشخص شده یافت نشد", ErrorType.NotFound); + } + + // بررسی فعال بودن کاربر + if (!user.IsActive) + { + return OperationResult.Failure("حساب کاربری غیرفعال است", ErrorType.Unauthorized); + } + + // بارگذاری نقش‌های کاربر + user = await _userRepository.GetUserWithRolesByIdAsync(user.Id, cancellationToken); + if (user == null) + { + return OperationResult.Failure("خطا در بارگذاری اطلاعات کاربر", ErrorType.InternalServerError); + } + + // تولید توکن‌های جدید برای کاربر + var roles = user.RoleUser + .Select(r => r.RoleId.ToString()).ToList(); + + var session = _authHelper.SignIn( + user.Id, + user.UserName, + user.FullName, + user.AccountId ?? 0, + roles); + + // دریافت اطلاعات درخواست + var ipAddress = _authHelper.GetClientIpAddress(); + var userAgent = _authHelper.GetUserAgent(); + + // ذخیره Refresh Token در دیتابیس + var refreshTokenEntity = new UserRefreshToken( + user.Id, + session.RefreshToken, + session.RefreshTokenExpiration, + ipAddress, + userAgent); + + await _refreshTokenRepository.CreateAsync(refreshTokenEntity); + await _unitOfWork.SaveChangesAsync(cancellationToken); + + // ساخت پاسخ + var response = new LoginResponse + { + AccessToken = session.AccessToken, + ExpiresAt = session.AccessTokenExpiration, + UserId = user.Id, + FullName = user.FullName, + UserName = user.UserName, + Roles = user.RoleUser.Select(r => r.RoleId).ToList() + }; + + return OperationResult.Success(response); + } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetSingleUser/GetSingleUserQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetSingleUser/GetSingleUserQueryHandler.cs new file mode 100644 index 00000000..2d79108e --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetSingleUser/GetSingleUserQueryHandler.cs @@ -0,0 +1,124 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Users.Queries.GetSingleUser; + +public class GetSingleUserQueryHandler : IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _context; + + public GetSingleUserQueryHandler(IProgramManagerDbContext context) + { + _context = context; + } + + public async Task> Handle(GetSingleUserQuery request, CancellationToken cancellationToken) + { + + if (!string.IsNullOrWhiteSpace(request.accountId)) + { + long accountId = 0; + try + { + accountId = Convert.ToInt64(request.accountId); + } + catch (Exception e) + { + return (OperationResult)OperationResult.Failure("فقط عدد وارد کنید"); + } + + + if (accountId > 0) + { + var user = await _context.Users + .FirstOrDefaultAsync(x => x.AccountId == accountId); + + + if(user != null) + { + List roles = user.RoleUser.Select(x => x.RoleId).ToList(); + var response = new GetSingleUserResponse + { + FullName = user.FullName, + UserName = user.UserName, + ProfilePhotoPath = user.ProfilePhotoPath, + Mobile = user.Mobile, + IsActive = user.IsActive, + AccountId = user.AccountId, + Roles = roles, + RoleListDto = await _context.Roles.Where(x => roles.Contains(x.Id)).Select(x=> new RoleListDto() + { + RoleName = x.RoleName, + RoleId = x.Id, + Permissions = x.Permissions.Select(x=>x.Code).ToList() + }).ToListAsync(), + }; + + return OperationResult.Success(response); + } + else + { + return (OperationResult)OperationResult.NotFound("کاربر یافت نشد"); + } + } + } + + return (OperationResult)OperationResult.Failure("آی دی اکانت گزارشگیر پر نشده است"); + } +} + + +public record GetSingleUserResponse +{ + /// + /// نام و نام خانوادگی + /// + public string FullName { get; set; } + + /// + /// نام کاربری + /// + public string UserName { get; set; } + + + + /// + /// مسیر عکس پروفایل + /// + public string ProfilePhotoPath { get; set; } + + /// + /// شماره موبایل + /// + public string Mobile { get; set; } + + + /// + /// فعال/غیر فعال بودن یوزر + /// + public bool IsActive { get; set; } + + /// + /// آی دی کاربر در گزارشگیر + /// + public long? AccountId { get; set; } + + /// + /// نقش ها + /// + public List Roles { get; set; } + + public List RoleListDto { get; set; } +}; + + +public record RoleListDto +{ + public string RoleName { get; set; } + public long RoleId { get; set; } + public List Permissions { get; set; } + +} + +public record GetSingleUserQuery(string? accountId) : IBaseQuery; \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetUserSelectList/GetUserSelectListQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetUserSelectList/GetUserSelectListQueryHandler.cs new file mode 100644 index 00000000..7b45273a --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetUserSelectList/GetUserSelectListQueryHandler.cs @@ -0,0 +1,48 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Users.Queries.GetSingleUser; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Users.Queries.GetUserSelectList; + +public class GetUserSelectListQueryHandler : IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _context; + + public GetUserSelectListQueryHandler(IProgramManagerDbContext context) + { + _context = context; + } + + public async Task> Handle(GetUserSelectListQuery request, CancellationToken cancellationToken) + { + + var query = await _context.Users.Select(x => new GetUserSelectListDto() + { + FullName = x.FullName, + Id = x.Id + }).ToListAsync(); + + var response = new GetUserSelectListResponse(query); + + + return OperationResult.Success(response); + } +} + + +public record GetUserSelectListResponse(List? GetUserSelectListDto); + +public record GetUserSelectListDto +{ + /// + /// نام و نام خانوادگی + /// + public string FullName { get; set; } + + /// + /// آی دی کاربر + /// + public long Id { get; set; } +} +public record GetUserSelectListQuery() : IBaseQuery; \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetUsers/GetUsersQuery.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetUsers/GetUsersQuery.cs new file mode 100644 index 00000000..9a3e15e8 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetUsers/GetUsersQuery.cs @@ -0,0 +1,5 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; + +namespace GozareshgirProgramManager.Application.Modules.Users.Queries.GetUsers; + +public record GetUsersQuery(string? FullName, string? UserName, string? Mobile) : IBaseQuery; \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetUsers/GetUsersQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetUsers/GetUsersQueryHandler.cs new file mode 100644 index 00000000..cb6467f4 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetUsers/GetUsersQueryHandler.cs @@ -0,0 +1,49 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Users.Queries.GetUsers; + +public class GetUsersQueryHandler :IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _context; + + public GetUsersQueryHandler(IProgramManagerDbContext context) + { + _context = context; + } + + public async Task> Handle(GetUsersQuery request, CancellationToken cancellationToken) + { + var query = _context.Users.AsQueryable(); + + //if (request.ParentId != null) + //{ + // query = query.Where(x => x.ParentId == request.ParentId); + //} + + var users = await query + .Select(p => new GetUserDto() + { + + FullName = p.FullName, + Mobile = p.Mobile, + UserName = p.UserName, + AccountId = p.AccountId, + IsActive = p.IsActive, + ProfilePhotoPath = p.ProfilePhotoPath, + + + }) + .ToListAsync(cancellationToken); + + var response = new GetUsersResponse( + users + ); + + return OperationResult.Success(response); + } + + + +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetUsers/GetUsersResponse.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetUsers/GetUsersResponse.cs new file mode 100644 index 00000000..e1cd043c --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Users/Queries/GetUsers/GetUsersResponse.cs @@ -0,0 +1,46 @@ +namespace GozareshgirProgramManager.Application.Modules.Users.Queries.GetUsers; + +public record GetUsersResponse(List User); + +public record GetUserDto +{ + /// + /// نام و نام خانوادگی + /// + public string FullName { get; set; } + + /// + /// نام کاربری + /// + public string UserName { get; set; } + + + + /// + /// مسیر عکس پروفایل + /// + public string ProfilePhotoPath { get; set; } + + /// + /// شماره موبایل + /// + public string Mobile { get; set; } + + + /// + /// فعال/غیر فعال بودن یوزر + /// + public bool IsActive { get; set; } + + /// + /// آی دی کاربر در گزارشگیر + /// + public long? AccountId { get; set; } + + /// + /// نقش ها + /// + public List Roles { get; set; } + +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Bootstrapper/DependencyInjection.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Bootstrapper/DependencyInjection.cs new file mode 100644 index 00000000..07aaa222 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Bootstrapper/DependencyInjection.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using GozareshgirProgramManager.Application.Interfaces; +using Microsoft.Extensions.DependencyInjection; + +namespace GozareshgirProgramManager.Application._Bootstrapper; + +public static class DependencyInjection +{ + public static IServiceCollection AddProgramManagerApplication(this IServiceCollection services) + { + services.AddMediatR(cfg => + { + cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()); + cfg.LicenseKey = + "eyJhbGciOiJSUzI1NiIsImtpZCI6Ikx1Y2t5UGVubnlTb2Z0d2FyZUxpY2Vuc2VLZXkvYmJiMTNhY2I1OTkwNGQ4OWI0Y2IxYzg1ZjA4OGNjZjkiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2x1Y2t5cGVubnlzb2Z0d2FyZS5jb20iLCJhdWQiOiJMdWNreVBlbm55U29mdHdhcmUiLCJleHAiOiIxNzk2MDgzMjAwIiwiaWF0IjoiMTc2NDU5NTE2OSIsImFjY291bnRfaWQiOiIwMTlhZGExMDA0MzA3M2Y5ODhhNWY0MmJmZDdlYTE3OCIsImN1c3RvbWVyX2lkIjoiY3RtXzAxa2JkMTJ4eXNnMHB6MjR0YnhqeXA0a2p3Iiwic3ViX2lkIjoiLSIsImVkaXRpb24iOiIwIiwidHlwZSI6IjIifQ.Gl0FB9XoQMJQgzdCh9gplRirYvmkDJYXD8tfLiWkRAeQJ2zlFdoHw7btxGrUVisI_ZfSxK2kkUB_LLty2eArbeZb5Ja1_xexgzTv3CJ4TnacT0FoVOc8eLeGCbJmmXtSt6CW89XwzvV_taiSSkcdsnATNTH0MEBLqCkKw4FMpSXqrPxCgakXB-pcyeqeTO9a0DD5XjBVITGaslUUFgnBGirsLdHRgL9AYVty3EzWTBH9WBcc4dHyZ5YUDMzsIab5elc-pmOLCXAJviamG9Afsaq4N88IMjsYvq6ihw_EAsmQH1K8WNunFMN8VjwO5csHmgKJ6wajONH7kUaMWNxRrQ"; + }); + + + return services; + } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Behaviors/CachingBehavior.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Behaviors/CachingBehavior.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Behaviors/LoggingBehavior.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Behaviors/LoggingBehavior.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Behaviors/PerformanceBehavior.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Behaviors/PerformanceBehavior.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Behaviors/TransactionBehavior.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Behaviors/TransactionBehavior.cs new file mode 100644 index 00000000..c6cd15d5 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Behaviors/TransactionBehavior.cs @@ -0,0 +1,42 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using MediatR; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application._Common.Behaviors; + +public class TransactionBehavior : IPipelineBehavior + where TRequest : IBaseCommand +{ + private readonly IProgramManagerDbContext _dbContext; + + public TransactionBehavior(IProgramManagerDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task Handle( + TRequest request, + RequestHandlerDelegate next, + CancellationToken cancellationToken) + { + // اگر تراکنش فعال است، ادامه بده + if (_dbContext is not DbContext efContext) + return await next(); + if (efContext.Database.CurrentTransaction != null) + return await next(); + + await using var transaction = await efContext.Database.BeginTransactionAsync(cancellationToken); + try + { + var response = await next(); + await _dbContext.SaveChangesAsync(cancellationToken); + await transaction.CommitAsync(cancellationToken); + return response; + } + catch + { + await transaction.RollbackAsync(cancellationToken); + throw; + } + } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Behaviors/ValidationBehavior.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Behaviors/ValidationBehavior.cs new file mode 100644 index 00000000..a1473666 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Behaviors/ValidationBehavior.cs @@ -0,0 +1,40 @@ +using FluentValidation; +using GozareshgirProgramManager.Application._Common.Interfaces; +using MediatR; + +namespace GozareshgirProgramManager.Application._Common.Behaviors; + +public class ValidationBehavior : IPipelineBehavior + where TRequest : IBaseCommand +{ + private readonly IEnumerable> _validators; + + public ValidationBehavior(IEnumerable> validators) + { + _validators = validators; + } + + public async Task Handle( + TRequest request, + RequestHandlerDelegate next, + CancellationToken cancellationToken) + { + if (!_validators.Any()) + return await next(); + + var context = new ValidationContext(request); + + var validationResults = await Task.WhenAll( + _validators.Select(v => v.ValidateAsync(context, cancellationToken))); + + var failures = validationResults + .SelectMany(r => r.Errors) + .Where(f => f != null) + .ToList(); + + if (failures.Count != 0) + throw new ValidationException(failures); + + return await next(); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Extensions/EnumExtensions.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Extensions/EnumExtensions.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Extensions/QueryableExtensions.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Extensions/QueryableExtensions.cs new file mode 100644 index 00000000..979befac --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Extensions/QueryableExtensions.cs @@ -0,0 +1,19 @@ +namespace GozareshgirProgramManager.Application._Common.Extensions; + +public static class QueryableExtensions +{ + public static IQueryable ApplyPagination(this IQueryable query, int page, int pageSize = 30) + { + if (page <= 0) page = 1; + if (pageSize <= 0) pageSize = 10; + + return query.Skip((page - 1) * pageSize).Take(pageSize); + } + public static IEnumerable ApplyPagination(this IEnumerable source, int page, int pageSize = 30) + { + if (page <= 0) page = 1; + if (pageSize <= 0) pageSize = 10; + + return source.Skip((page - 1) * pageSize).Take(pageSize); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Extensions/StringExtensions.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Extensions/StringExtensions.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IAuthHelper.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IAuthHelper.cs new file mode 100644 index 00000000..7b392d47 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IAuthHelper.cs @@ -0,0 +1,114 @@ +using System.Security.Claims; + +namespace GozareshgirProgramManager.Application._Common.Interfaces; + +/// +/// رابط کمکی برای کار با JWT و HttpContext +/// این interface فقط متدهای helper دارد و هیچ عملیات دیتابیسی ندارد +/// +public interface IAuthHelper +{ + // ==================== Token Generation ==================== + LoginSession SignIn(long userId, string userName, string fullName, long accountId, List roles); + /// + /// تولید Access Token + /// + string GenerateAccessToken(long userId, string userName, string fullName, long? accountId, List roles); + + /// + /// تولید Refresh Token + /// + string GenerateRefreshToken(); + + /// + /// دریافت تاریخ انقضای Refresh Token + /// + DateTime GetRefreshTokenExpiration(); + + // ==================== Token Validation ==================== + + /// + /// اعتبارسنجی توکن و استخراج Claims + /// + ClaimsPrincipal? ValidateToken(string token); + + /// + /// اعتبارسنجی توکن منقضی شده (بدون چک زمان انقضا) + /// + ClaimsPrincipal? ValidateExpiredToken(string token); + + /// + /// استخراج UserId از توکن (حتی اگر منقضی شده باشد) + /// + long? GetUserIdFromToken(string token); + + // ==================== HttpContext Helpers ==================== + + /// + /// دریافت IP Address کاربر جاری + /// + string? GetClientIpAddress(); + + /// + /// دریافت User Agent کاربر جاری + /// + string? GetUserAgent(); + + /// + /// دریافت Refresh Token از Cookie + /// + string? GetRefreshTokenFromCookie(); + + // ==================== Current User Claims ==================== + + /// + /// بررسی احراز هویت کاربر جاری + /// + bool IsAuthenticated(); + + /// + /// دریافت شناسه کاربر جاری از Claims + /// + long? GetCurrentUserId(); + + /// + /// دریافت نام کاربری جاری از Claims + /// + string? GetCurrentUserName(); + + /// + /// دریافت نام کامل کاربر جاری از Claims + /// + string? GetCurrentFullName(); + + /// + /// دریافت AccountId کاربر جاری از Claims + /// + long? GetCurrentAccountId(); + + /// + /// دریافت نقش‌های کاربر جاری از Claims + /// + List GetCurrentUserRoles(); + + // ==================== Role Checking ==================== + + /// + /// بررسی دسترسی کاربر به نقش خاص + /// + bool HasRole(string roleName); + + /// + /// بررسی دسترسی کاربر به یکی از نقش‌ها + /// + bool HasAnyRole(params string[] roleNames); + + void SignOut(); +} +public class LoginSession +{ + public string AccessToken { get; set; } + public string RefreshToken { get; set; } + public DateTime RefreshTokenExpiration { get; set; } + public DateTime AccessTokenExpiration { get; set; } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBaseCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBaseCommand.cs new file mode 100644 index 00000000..1b469f03 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBaseCommand.cs @@ -0,0 +1,14 @@ +using GozareshgirProgramManager.Application._Common.Models; +using MediatR; + +namespace GozareshgirProgramManager.Application._Common.Interfaces; + +public interface IBaseCommand : IRequest +{ +} + +public interface IBaseCommand : IRequest> +{ +} + + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBaseCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBaseCommandHandler.cs new file mode 100644 index 00000000..3b699cb3 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBaseCommandHandler.cs @@ -0,0 +1,13 @@ +using GozareshgirProgramManager.Application._Common.Models; +using MediatR; + +namespace GozareshgirProgramManager.Application._Common.Interfaces; + +public interface IBaseCommandHandler : IRequestHandler + where TCommand : IBaseCommand +{ +} +public interface IBaseCommandHandler : IRequestHandler> + where TCommand : IBaseCommand +{ +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBasePaginationQuery.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBasePaginationQuery.cs new file mode 100644 index 00000000..979a93f3 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBasePaginationQuery.cs @@ -0,0 +1,10 @@ +using MediatR; +using GozareshgirProgramManager.Application._Common.Models; + +namespace GozareshgirProgramManager.Application._Common.Interfaces; + +public interface IBasePaginationQuery : IRequest>> +{ + int PageIndex { get; set; } + int PageSize { get; set; } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBasePaginationQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBasePaginationQueryHandler.cs new file mode 100644 index 00000000..5d9c4bbf --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBasePaginationQueryHandler.cs @@ -0,0 +1,12 @@ +using GozareshgirProgramManager.Application._Common.Models; +using MediatR; + +namespace GozareshgirProgramManager.Application._Common.Interfaces; + +public interface IBasePaginationQueryHandler + : IRequestHandler>> + where TQuery : PaginationRequest, IBasePaginationQuery + where TResponse : class +{ + +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBaseQuery.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBaseQuery.cs new file mode 100644 index 00000000..146e2c33 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBaseQuery.cs @@ -0,0 +1,9 @@ +using MediatR; +using GozareshgirProgramManager.Application._Common.Models; + +namespace GozareshgirProgramManager.Application._Common.Interfaces; + +public interface IBaseQuery : IRequest> +{ +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBaseQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBaseQueryHandler.cs new file mode 100644 index 00000000..bd8650ba --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IBaseQueryHandler.cs @@ -0,0 +1,10 @@ +using MediatR; +using GozareshgirProgramManager.Application._Common.Models; + +namespace GozareshgirProgramManager.Application._Common.Interfaces; + +public interface IBaseQueryHandler : IRequestHandler> + where TQuery : IBaseQuery +{ +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IGozareshgirDbContext.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IGozareshgirDbContext.cs new file mode 100644 index 00000000..8baad5be --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IGozareshgirDbContext.cs @@ -0,0 +1,12 @@ +using GozareshgirProgramManager.Domain.HolidayAgg; +using GozareshgirProgramManager.Domain.HolidayItemAgg; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application._Common.Interfaces; + +public interface IGozareshgirDbContext +{ + DbSet HolidayItems { get; set; } + DbSet Holidays { get; set; } + +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IProgramManagerDbContext.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IProgramManagerDbContext.cs new file mode 100644 index 00000000..1a477bec --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Interfaces/IProgramManagerDbContext.cs @@ -0,0 +1,32 @@ +using GozareshgirProgramManager.Domain.CheckoutAgg.Entities; +using GozareshgirProgramManager.Domain.CustomerAgg; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.RoleAgg.Entities; +using GozareshgirProgramManager.Domain.RoleUserAgg; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities; +using GozareshgirProgramManager.Domain.SkillAgg.Entities; +using GozareshgirProgramManager.Domain.UserAgg.Entities; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application._Common.Interfaces; + +public interface IProgramManagerDbContext +{ + DbSet Checkouts { set; get; } + DbSet SalaryPaymentSettings { set; get; } + DbSet Roles { get; set; } + DbSet Users { get; set; } + DbSet RefreshTokens { get; set; } + DbSet Customers { get; } + DbSet Projects { get; set; } + DbSet ProjectPhases { get; set; } + DbSet TaskSections { get; set; } + DbSet ProjectSections { get; set; } + DbSet PhaseSections { get; set; } + + DbSet ProjectTasks { get; set; } + + DbSet Skills { get; set; } + Task SaveChangesAsync(CancellationToken cancellationToken = default); +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/AccessTokenResponse.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/AccessTokenResponse.cs new file mode 100644 index 00000000..3c4a68ec --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/AccessTokenResponse.cs @@ -0,0 +1,14 @@ +namespace GozareshgirProgramManager.Application._Common.Models; + +/// +/// پاسخ تازه‌سازی توکن دسترسی +/// +public class AccessTokenResponse +{ + public string AccessToken { get; set; } = string.Empty; + public DateTime ExpiresAt { get; set; } + public long UserId { get; set; } + public string FullName { get; set; } = string.Empty; + public string UserName { get; set; } = string.Empty; +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/AuthViewModel.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/AuthViewModel.cs new file mode 100644 index 00000000..64de4d90 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/AuthViewModel.cs @@ -0,0 +1,11 @@ +namespace GozareshgirProgramManager.Application._Common.Models; + +/// +/// مدل ورودی برای احراز هویت +/// +public class AuthViewModel +{ + public long UserId { get; set; } +} + + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/DomainEventNotification.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/DomainEventNotification.cs new file mode 100644 index 00000000..bf580abc --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/DomainEventNotification.cs @@ -0,0 +1,19 @@ +using GozareshgirProgramManager.Domain._Common; +using MediatR; + +namespace GozareshgirProgramManager.Application._Common.Models; + +/// +/// Wrapper to convert Domain Events to MediatR Notifications +/// +public class DomainEventNotification : INotification + where TDomainEvent : IDomainEvent +{ + public TDomainEvent DomainEvent { get; } + + public DomainEventNotification(TDomainEvent domainEvent) + { + DomainEvent = domainEvent; + } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/ErrorDetails.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/ErrorDetails.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/LoginResponse.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/LoginResponse.cs new file mode 100644 index 00000000..f4b98e4f --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/LoginResponse.cs @@ -0,0 +1,15 @@ +namespace GozareshgirProgramManager.Application._Common.Models; + +/// +/// پاسخ ورود به سیستم +/// +public class LoginResponse +{ + public string AccessToken { get; set; } = string.Empty; + public DateTime ExpiresAt { get; set; } + public long UserId { get; set; } + public string FullName { get; set; } = string.Empty; + public string UserName { get; set; } = string.Empty; + public List Roles { get; set; } = new(); +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/OperationResult.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/OperationResult.cs new file mode 100644 index 00000000..324e9895 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/OperationResult.cs @@ -0,0 +1,60 @@ +namespace GozareshgirProgramManager.Application._Common.Models; + +public enum ErrorType +{ + None, + BadRequest, + NotFound, + Unauthorized, + Validation, + InternalServerError +} + +public class OperationResult +{ + public bool IsSuccess { get; private set; } + public string? ErrorMessage { get; private set; } + public List Errors { get; private set; } + public ErrorType ErrorType { get; private set; } + + protected OperationResult(bool isSuccess, string? errorMessage = null, List? errors = null, ErrorType errorType = ErrorType.None) + { + IsSuccess = isSuccess; + ErrorMessage = errorMessage; + Errors = errors ?? new List(); + ErrorType = errorType; + } + + public static OperationResult Success() => new(true); + public static OperationResult Failure(string errorMessage, ErrorType errorType = ErrorType.BadRequest) => new(false, errorMessage, errorType: errorType); + public static OperationResult Failure(List errors, ErrorType errorType = ErrorType.BadRequest) => new(false, errors: errors, errorType: errorType); + + // Helper methods for specific error types + public static OperationResult NotFound(string errorMessage) => new(false, errorMessage, errorType: ErrorType.NotFound); + public static OperationResult Unauthorized(string errorMessage) => new(false, errorMessage, errorType: ErrorType.Unauthorized); + public static OperationResult ValidationError(string errorMessage) => new(false, errorMessage, errorType: ErrorType.Validation); + public static OperationResult ValidationError(List errors) => new(false, errors: errors, errorType: ErrorType.Validation); + public static OperationResult InternalServerError(string errorMessage) => new(false, errorMessage, errorType: ErrorType.InternalServerError); +} + +public class OperationResult : OperationResult +{ + public T? Data { get; private set; } + + private OperationResult(bool isSuccess, T? data = default, string? errorMessage = null, List? errors = null, ErrorType errorType = ErrorType.None) + : base(isSuccess, errorMessage, errors, errorType) + { + Data = data; + } + + public static OperationResult Success(T data) => new(true, data); + public static new OperationResult Failure(string errorMessage, ErrorType errorType = ErrorType.BadRequest) => new(false, default, errorMessage, errorType: errorType); + public static new OperationResult Failure(List errors, ErrorType errorType = ErrorType.BadRequest) => new(false, default, errors: errors, errorType: errorType); + + // Helper methods for specific error types + public static new OperationResult NotFound(string errorMessage) => new(false, default, errorMessage, errorType: ErrorType.NotFound); + public static new OperationResult Unauthorized(string errorMessage) => new(false, default, errorMessage, errorType: ErrorType.Unauthorized); + public static new OperationResult ValidationError(string errorMessage) => new(false, default, errorMessage, errorType: ErrorType.Validation); + public static new OperationResult ValidationError(List errors) => new(false, default, errors: errors, errorType: ErrorType.Validation); + public static new OperationResult InternalServerError(string errorMessage) => new(false, default, errorMessage, errorType: ErrorType.InternalServerError); +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/PaginationRequest.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/PaginationRequest.cs new file mode 100644 index 00000000..6c55bae2 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/PaginationRequest.cs @@ -0,0 +1,8 @@ +namespace GozareshgirProgramManager.Application._Common.Models; + +public record PaginationRequest +{ + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 30; +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/PaginationResult.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/PaginationResult.cs new file mode 100644 index 00000000..8249f241 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/PaginationResult.cs @@ -0,0 +1,11 @@ +namespace GozareshgirProgramManager.Application._Common.Models; + +public class PaginationResult +{ + public int TotalCount { get; set; } + public List List { get; set; } +} +public class PaginationResult:PaginationResult +{ + public TMeta? Meta { get; set; } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/TokenValidationResult.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/TokenValidationResult.cs new file mode 100644 index 00000000..37889e20 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/_Common/Models/TokenValidationResult.cs @@ -0,0 +1,24 @@ +namespace GozareshgirProgramManager.Application._Common.Models; + +/// +/// نتیجه اعتبارسنجی توکن +/// +public class TokenValidationResult +{ + public bool IsValid { get; set; } + public long? UserId { get; set; } + public string? ErrorMessage { get; set; } + + public static TokenValidationResult Success(long userId) => new() + { + IsValid = true, + UserId = userId + }; + + public static TokenValidationResult Failure(string errorMessage) => new() + { + IsValid = false, + ErrorMessage = errorMessage + }; +} + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Entities/Checkout.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Entities/Checkout.cs new file mode 100644 index 00000000..22e4495e --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Entities/Checkout.cs @@ -0,0 +1,134 @@ +using System.ComponentModel.DataAnnotations.Schema; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.CheckoutAgg.Enums; + +namespace GozareshgirProgramManager.Domain.CheckoutAgg.Entities; + +public class Checkout : EntityBase +{ + /// + /// ایجاد فیش + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public Checkout(DateTime checkoutStartDate, DateTime checkoutEndDate, int year, int month, string fullName, long userId, + int mandatoryHours, int totalHoursWorked, int totalDaysWorked, int remainingHours, double monthlySalaryDefined, double monthlySalaryPay, double deductionFromSalary) + { + CheckoutStartDate = checkoutStartDate; + CheckoutEndDate = checkoutEndDate; + Year = year; + Month = month; + FullName = fullName; + UserId = userId; + MandatoryHours = mandatoryHours; + TotalHoursWorked = totalHoursWorked; + TotalDaysWorked = totalDaysWorked; + RemainingHours = remainingHours; + MonthlySalaryDefined = monthlySalaryDefined; + MonthlySalaryPay = monthlySalaryPay; + DeductionFromSalary = deductionFromSalary; + + } + + /// + /// تاریخ شروع فیش حقوقی + /// + public DateTime CheckoutStartDate { get; private set; } + + /// + /// تاریخ پایان فیش حقوقی + /// + public DateTime CheckoutEndDate { get; private set; } + + /// + /// سال + /// + public int Year { get; private set; } + + /// + /// ماه + /// + public int Month { get; private set; } + + [NotMapped] + public string PersianMonthName=> Month.ToFarsiMonthByIntNumber(); + + /// + /// نام کامل کاربر + /// + public string FullName { get; private set; } + + /// + /// آی دی کاربر + /// + public long UserId { get; private set; } + + /// + /// ساعت موظفی + /// + public int MandatoryHours { get; private set; } + + /// + /// مجموع ساعات کارکرد پرسنل + /// + public int TotalHoursWorked { get; private set; } + + /// + /// مجمع روزهای کارکرد پرسنل + /// + public int TotalDaysWorked { get; private set; } + + /// + /// ساعات باقی مانده + /// کسر کار یا اضافه کار + /// + public int RemainingHours { get; private set; } + + /// + /// حقوق ماهانه + /// تعیین شده + /// + public double MonthlySalaryDefined { get; private set; } + + /// + /// حقوق نهایی که به پرسنل داده می شود + /// + public double MonthlySalaryPay { get; private set; } + + /// + /// کسر از حقوق + /// + public double DeductionFromSalary { get; private set; } + + /// + /// ویرایش فیش + /// + /// + /// + /// + /// + /// + /// + /// + public void Edit(int mandatoryHours, int totalHoursWorked, int totalDaysWorked, int remainingHours, double monthlySalaryDefined, double monthlySalaryPay, double deductionFromSalary) + { + MandatoryHours = mandatoryHours; + TotalHoursWorked = totalHoursWorked; + TotalDaysWorked = totalDaysWorked; + RemainingHours = remainingHours; + MonthlySalaryDefined = monthlySalaryDefined; + MonthlySalaryPay = monthlySalaryPay; + DeductionFromSalary = deductionFromSalary; + } +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Enums/CreateCheckoutStatus.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Enums/CreateCheckoutStatus.cs new file mode 100644 index 00000000..53b669b5 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Enums/CreateCheckoutStatus.cs @@ -0,0 +1,18 @@ +namespace GozareshgirProgramManager.Domain.CheckoutAgg.Enums; + +public enum CreateCheckoutStatus +{ + /// + /// آماده ایجاد + /// + ReadyToCreate = 1, + /// + /// قبلا ایجاد شده + /// + AlreadyCreated = 2, + /// + /// تنظیمات حقوق انجام نشده + /// + NotSetSalaryPaymentSettings = 3 + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Enums/PersianMonthName.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Enums/PersianMonthName.cs new file mode 100644 index 00000000..0890604b --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Enums/PersianMonthName.cs @@ -0,0 +1,18 @@ +namespace GozareshgirProgramManager.Domain.CheckoutAgg.Enums; + +public enum PersianMonthName +{ + فروردین = 1, + اردیبهشت = 2, + خرداد = 3, + تیر = 4, + مرداد = 5, + شهریور = 6, + مهر = 7, + آبان = 8, + آذر = 9, + دی = 10, + بهمن = 11, + اسفند = 12, + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Enums/TypeOfCheckoutHandler.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Enums/TypeOfCheckoutHandler.cs new file mode 100644 index 00000000..095562e7 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Enums/TypeOfCheckoutHandler.cs @@ -0,0 +1,22 @@ +namespace GozareshgirProgramManager.Domain.CheckoutAgg.Enums; + +/// +/// انتخاب حالت ایجاد یا ویراش تکی / گروهی +/// +public enum TypeOfCheckoutHandler +{ + /// + /// ایجاد گروهی + /// + CreateInGroup = 1, + + /// + /// ویرایش گروهی + /// + GroupEditing = 2, + + /// + /// ویرایش تکی + /// + SingleEdit = 3, +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Repositories/ICheckoutRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Repositories/ICheckoutRepository.cs new file mode 100644 index 00000000..f33b9031 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CheckoutAgg/Repositories/ICheckoutRepository.cs @@ -0,0 +1,9 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.CheckoutAgg.Entities; + +namespace GozareshgirProgramManager.Domain.CheckoutAgg.Repositories; + +public interface ICheckoutRepository : IRepository +{ + Task> GetCheckoutListByIds(List checkoutIds); +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Customer.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Customer.cs new file mode 100644 index 00000000..1126077b --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Customer.cs @@ -0,0 +1,34 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.CustomerAgg.Events; + +namespace GozareshgirProgramManager.Domain.CustomerAgg; + +public class Customer : EntityBase, IAggregateRoot +{ + public string Name { get; private set; } + public string Email { get; private set; } + public DateTime CreatedAt { get; private set; } + + private Customer() { } // For EF Core + + private Customer(Guid id, string name, string email) + { + Id = id; + Name = name; + Email = email; + CreatedAt = DateTime.UtcNow; + } + + public static Customer Create(string name, string email) + { + var customer = new Customer(Guid.NewGuid(), name, email); + customer.AddDomainEvent(new CustomerRegistered(customer.Id, customer.Name, customer.Email)); + return customer; + } + + public void UpdateName(string name) + { + Name = name; + } +} + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Entities/Address.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Entities/Address.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Entities/Customer.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Entities/Customer.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Events/CustomerRegistered.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Events/CustomerRegistered.cs new file mode 100644 index 00000000..2362f3fc --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Events/CustomerRegistered.cs @@ -0,0 +1,12 @@ +using GozareshgirProgramManager.Domain._Common; + +namespace GozareshgirProgramManager.Domain.CustomerAgg.Events; + +public record CustomerRegistered( + Guid CustomerId, + string Name, + string Email) : IDomainEvent +{ + public DateTime OccurredOn { get; } = DateTime.UtcNow; +} + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Events/CustomerRegisteredEvent.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Events/CustomerRegisteredEvent.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Exceptions/CustomerNotFoundException.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Exceptions/CustomerNotFoundException.cs new file mode 100644 index 00000000..b50831ad --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Exceptions/CustomerNotFoundException.cs @@ -0,0 +1,10 @@ +namespace GozareshgirProgramManager.Domain.CustomerAgg.Exceptions; + +public class CustomerNotFoundException : Exception +{ + public CustomerNotFoundException(Guid customerId) + : base($"Customer with ID '{customerId}' was not found.") + { + } +} + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Exceptions/DuplicateEmailException.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Exceptions/DuplicateEmailException.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Repositories/ICustomerRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Repositories/ICustomerRepository.cs new file mode 100644 index 00000000..c0b0be7a --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/Repositories/ICustomerRepository.cs @@ -0,0 +1,10 @@ +namespace GozareshgirProgramManager.Domain.CustomerAgg.Repositories; + +public interface ICustomerRepository +{ + Task GetByIdAsync(Guid id, CancellationToken cancellationToken = default); + Task AddAsync(Customer customer, CancellationToken cancellationToken = default); + void Update(Customer customer); + void Delete(Customer customer); +} + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/ValueObjects/Email.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/ValueObjects/Email.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/ValueObjects/PhoneNumber.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/CustomerAgg/ValueObjects/PhoneNumber.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/GozareshgirProgramManager.Domain.csproj b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/GozareshgirProgramManager.Domain.csproj new file mode 100644 index 00000000..9ae2365c --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/GozareshgirProgramManager.Domain.csproj @@ -0,0 +1,14 @@ + + + + net10.0 + enable + enable + + + + + + + + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/HolidayAgg/Holiday.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/HolidayAgg/Holiday.cs new file mode 100644 index 00000000..fabc5c3a --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/HolidayAgg/Holiday.cs @@ -0,0 +1,25 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.HolidayItemAgg; + +namespace GozareshgirProgramManager.Domain.HolidayAgg; + +public class Holiday : EntityBase +{ + public Holiday(string year) + { + Year = year; + + } + + public string Year { get; private set; } + public List HolidayItems { get; set; } + + public Holiday() + { + HolidayItems = new List(); + } + public void Edit(string year) + { + Year = year; + } +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/HolidayItemAgg/HolidayItem.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/HolidayItemAgg/HolidayItem.cs new file mode 100644 index 00000000..3a66bd58 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/HolidayItemAgg/HolidayItem.cs @@ -0,0 +1,28 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.HolidayAgg; + +namespace GozareshgirProgramManager.Domain.HolidayItemAgg; + +public class HolidayItem : EntityBase +{ + public HolidayItem(DateTime holidaydate, long holidayId, string holidayYear) + { + Holidaydate = holidaydate; + HolidayId = holidayId; + HolidayYear = holidayYear; + } + + public DateTime Holidaydate { get; private set; } + public long HolidayId { get; private set; } + public string HolidayYear { get; private set; } + + public Holiday Holidayss { get; set; } + + public void Edit(DateTime holidaydate, long holidayId, string holidayYear) + { + Holidaydate = holidaydate; + HolidayId = holidayId; + HolidayYear = holidayYear; + + } +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/PermissionAgg/Entities/Permission.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/PermissionAgg/Entities/Permission.cs new file mode 100644 index 00000000..49e5cdc8 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/PermissionAgg/Entities/Permission.cs @@ -0,0 +1,21 @@ +using GozareshgirProgramManager.Domain.RoleAgg.Entities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using GozareshgirProgramManager.Domain._Common; + +namespace GozareshgirProgramManager.Domain.PermissionAgg.Entities; + +public class Permission +{ + public long Id { get; private set; } + public int Code { get; private set; } + public Role Role { get; private set; } + + public Permission(int code) + { + Code = code; + } +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/PhaseSection.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/PhaseSection.cs new file mode 100644 index 00000000..33bdfcdf --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/PhaseSection.cs @@ -0,0 +1,41 @@ +using GozareshgirProgramManager.Domain._Common; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +/// +/// بخش فاز - برای ذخیره تخصیص کاربر و مهارت در سطح Phase +/// +public class PhaseSection : EntityBase +{ + private PhaseSection() { } + + public PhaseSection(Guid phaseId, long userId, Guid skillId) + { + PhaseId = phaseId; + UserId = userId; + SkillId = skillId; + } + + public Guid PhaseId { get; private set; } + public long UserId { get; private set; } + public Guid SkillId { get; private set; } + + // Navigation property + public ProjectPhase Phase { get; private set; } = null!; + + public void UpdateUser(long userId) + { + UserId = userId; + } + + public void UpdateSkill(Guid skillId) + { + SkillId = skillId; + } + public void Update(long userId, Guid skillId) + { + UserId = userId; + SkillId = skillId; + } +} + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/Project.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/Project.cs new file mode 100644 index 00000000..dc2bfa15 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/Project.cs @@ -0,0 +1,174 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Events; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +/// +/// پروژه - بالاترین سطح در سلسله مراتب و Aggregate Root +/// +public class Project : ProjectHierarchyNode +{ + private readonly List _phases; + private readonly List _projectSections; + + private Project() + { + _phases = new List(); + _projectSections = new List(); + } + + public Project(string name, string? description = null) : base(name, description) + { + _phases = new List(); + _projectSections = new List(); + AddDomainEvent(new ProjectCreatedEvent(Id, name)); + } + + + public IReadOnlyList Phases => _phases.AsReadOnly(); + public IReadOnlyList ProjectSections => _projectSections.AsReadOnly(); + + // Project-specific properties + public DateTime? StartDate { get; private set; } + public DateTime? EndDate { get; private set; } + public DateTime? PlannedStartDate { get; private set; } + public DateTime? PlannedEndDate { get; private set; } + public ProjectStatus Status { get; private set; } = ProjectStatus.Planning; + + + #region Phase Management + + public ProjectPhase AddPhase(string name, string? description = null) + { + var phase = new ProjectPhase(name, Id, description); + _phases.Add(phase); + AddDomainEvent(new PhaseAddedEvent(phase.Id, Id, name)); + return phase; + } + + public void RemovePhase(Guid phaseId) + { + var phase = _phases.FirstOrDefault(p => p.Id == phaseId); + if (phase == null) + throw new InvalidOperationException("فاز مورد نظر یافت نشد"); + + if (phase.Tasks.Any()) + throw new InvalidOperationException("نمی‌توان فازی را که شامل تسک است حذف کرد"); + + _phases.Remove(phase); + AddDomainEvent(new PhaseRemovedEvent(phaseId, Id)); + } + + #endregion + + #region ProjectSection Management + + public void AddProjectSection(long userId, Guid skillId) + { + var existingSection = _projectSections.FirstOrDefault(s => s.UserId == userId && s.SkillId == skillId); + if (existingSection == null) + { + var section = new ProjectSection(Id, userId, skillId); + _projectSections.Add(section); + } + } + + public void ClearProjectSections() + { + _projectSections.Clear(); + } + + #endregion + + #region Date Management + + public void SetDates(DateTime? startDate = null, DateTime? endDate = null) + { + if (startDate.HasValue && endDate.HasValue && startDate > endDate) + throw new ArgumentException("تاریخ شروع نمی‌تواند بعد از تاریخ پایان باشد"); + + StartDate = startDate; + EndDate = endDate; + } + + public void SetPlannedDates(DateTime? plannedStartDate = null, DateTime? plannedEndDate = null) + { + if (plannedStartDate.HasValue && plannedEndDate.HasValue && plannedStartDate > plannedEndDate) + throw new ArgumentException("تاریخ شروع برنامه‌ریزی شده نمی‌تواند بعد از تاریخ پایان برنامه‌ریزی شده باشد"); + + PlannedStartDate = plannedStartDate; + PlannedEndDate = plannedEndDate; + } + + public void UpdateStatus(ProjectStatus status) + { + Status = status; + AddDomainEvent(new ProjectStatusUpdatedEvent(Id, status)); + } + + #endregion + + #region Assignment Management + + public void AssignToUser(long userId, bool cascadeToPhases = true, bool forceOverride = false) + { + HasAssignmentOverride = true; + + if (cascadeToPhases) + { + foreach (var phase in _phases) + { + if (phase.HasAssignmentOverride && !forceOverride) + continue; + + phase.AssignToUser(userId, cascadeToTasks: true, forceOverride, markAsOverride: false); + } + } + + AddDomainEvent(new ProjectAssignedEvent(Id, userId)); + } + + public void Unassign(bool cascadeToPhases = true, bool forceOverride = false) + { + HasAssignmentOverride = true; + + if (cascadeToPhases) + { + foreach (var phase in _phases) + { + if (phase.HasAssignmentOverride && !forceOverride) + continue; + + phase.Unassign(cascadeToTasks: true, forceOverride, markAsOverride: false); + } + } + + AddDomainEvent(new ProjectUnassignedEvent(Id)); + } + + #endregion + + #region Time Calculation + + public override TimeSpan GetTotalTimeSpent() + { + return TimeSpan.FromTicks(_phases.Sum(p => p.GetTotalTimeSpent().Ticks)); + } + + public override TimeSpan GetTotalEstimatedTime() + { + return TimeSpan.FromTicks(_phases.Sum(p => p.GetTotalEstimatedTime().Ticks)); + } + + #endregion + + public void UpdateProjectSectionUser(Guid skillId, long userId) + { + var section = _projectSections.FirstOrDefault(s => s.SkillId == skillId); + if (section != null) + { + section.UpdateUser(userId); + } + } +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectHierarchyNode.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectHierarchyNode.cs new file mode 100644 index 00000000..51df2571 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectHierarchyNode.cs @@ -0,0 +1,78 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +/// +/// کلاس پایه برای تمام نودهای سلسله مراتبی پروژه +/// +public abstract class ProjectHierarchyNode : EntityBase +{ + protected ProjectHierarchyNode() + { + } + + protected ProjectHierarchyNode(string name, string? description = null) + { + Name = name; + Description = description; + } + + public string Name { get; protected set; } = string.Empty; + public string? Description { get; protected set; } + + // Time allocation properties + public bool HasAssignmentOverride { get; protected set; } + + #region Update Methods + + public virtual void UpdateName(string name) + { + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("نام نمی‌تواند خالی باشد", nameof(name)); + + Name = name; + } + + public virtual void UpdateDescription(string? description) + { + Description = description; + } + + public void MarkAsOverridden() + { + HasAssignmentOverride = true; + } + + #endregion + + // #region Time Management + // + // public virtual void SetAllocatedTime(TimeSpan time, bool markAsOverride = true) + // { + // if (time < TimeSpan.Zero) + // throw new ArgumentException("زمان تخصیص‌یافته نمی‌تواند منفی باشد", nameof(time)); + // + // AllocatedTime = time; + // if (markAsOverride) + // { + // HasTimeOverride = true; + // } + // } + // + // public virtual void ClearTimeOverride() + // { + // HasTimeOverride = false; + // AllocatedTime = null; + // } + // + // #endregion + + #region Time Calculation (Abstract) + + public abstract TimeSpan GetTotalTimeSpent(); + public abstract TimeSpan GetTotalEstimatedTime(); + + #endregion +} + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectPhase.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectPhase.cs new file mode 100644 index 00000000..539ac278 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectPhase.cs @@ -0,0 +1,199 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Events; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +/// +/// فاز پروژه - سطح میانی در سلسله مراتب +/// +public class ProjectPhase : ProjectHierarchyNode +{ + private readonly List _tasks; + private readonly List _phaseSections; + + private ProjectPhase() + { + _tasks = new List(); + _phaseSections = new List(); + } + + public ProjectPhase(string name, Guid projectId, string? description = null) : base(name, description) + { + ProjectId = projectId; + _tasks = new List(); + _phaseSections = new List(); + AddDomainEvent(new PhaseCreatedEvent(Id, projectId, name)); + } + + public Guid ProjectId { get; private set; } + public Project Project { get; private set; } = null!; + public IReadOnlyList Tasks => _tasks.AsReadOnly(); + public IReadOnlyList PhaseSections => _phaseSections.AsReadOnly(); + + // Phase-specific properties + public PhaseStatus Status { get; private set; } = PhaseStatus.Planning; + public DateTime? StartDate { get; private set; } + public DateTime? EndDate { get; private set; } + public int OrderIndex { get; private set; } + + #region Task Management + + public ProjectTask AddTask(string name, string? description = null) + { + var task = new ProjectTask(name, Id, description); + _tasks.Add(task); + AddDomainEvent(new TaskAddedEvent(task.Id, Id, name)); + return task; + } + + public void RemoveTask(Guid taskId) + { + var task = _tasks.FirstOrDefault(t => t.Id == taskId); + if (task == null) + throw new InvalidOperationException("تسک مورد نظر یافت نشد"); + + if (task.Sections.Any()) + throw new InvalidOperationException("نمی‌توان تسکی را که شامل بخش است حذف کرد"); + + _tasks.Remove(task); + AddDomainEvent(new TaskRemovedEvent(taskId, Id)); + } + + #endregion + + #region PhaseSection Management + + public void AddPhaseSection(long userId, Guid skillId) + { + var existingSection = _phaseSections.FirstOrDefault(s => s.UserId == userId && s.SkillId == skillId); + if (existingSection == null) + { + var section = new PhaseSection(Id, userId, skillId); + _phaseSections.Add(section); + } + + } + + public void RemovePhaseSection(long userId, Guid skillId) + { + var section = _phaseSections.FirstOrDefault(s => s.UserId == userId && s.SkillId == skillId); + if (section != null) + { + _phaseSections.Remove(section); + } + } + + public void ClearPhaseSections() + { + _phaseSections.Clear(); + } + + #endregion + + #region Status Management + + public void UpdateStatus(PhaseStatus status) + { + Status = status; + AddDomainEvent(new PhaseStatusUpdatedEvent(Id, status)); + } + + public void SetDates(DateTime? startDate = null, DateTime? endDate = null) + { + if (startDate.HasValue && endDate.HasValue && startDate > endDate) + throw new ArgumentException("تاریخ شروع نمی‌تواند بعد از تاریخ پایان باشد"); + + StartDate = startDate; + EndDate = endDate; + } + + public void SetOrderIndex(int orderIndex) + { + if (orderIndex < 0) + throw new ArgumentException("ترتیب نمی‌تواند منفی باشد", nameof(orderIndex)); + + OrderIndex = orderIndex; + } + + #endregion + + #region Assignment Management + + public void AssignToUser(long userId, bool cascadeToTasks = true, bool forceOverride = false, bool markAsOverride = true) + { + if (markAsOverride) + { + HasAssignmentOverride = true; + } + + if (cascadeToTasks) + { + foreach (var task in _tasks) + { + if (task.HasAssignmentOverride && !forceOverride) + continue; + + task.AssignToUser(userId, cascadeToSections: true, forceOverride, markAsOverride: false); + } + } + + AddDomainEvent(new PhaseAssignedEvent(Id, userId)); + } + + public void Unassign(bool cascadeToTasks = true, bool forceOverride = false, bool markAsOverride = true) + { + if (markAsOverride) + { + HasAssignmentOverride = true; + } + + if (cascadeToTasks) + { + foreach (var task in _tasks) + { + if (task.HasAssignmentOverride && !forceOverride) + continue; + + task.Unassign(cascadeToSections: true, forceOverride, markAsOverride: false); + } + } + + AddDomainEvent(new PhaseUnassignedEvent(Id)); + } + + #endregion + + #region Time Calculation + + public override TimeSpan GetTotalTimeSpent() + { + return TimeSpan.FromTicks(_tasks.Sum(t => t.GetTotalTimeSpent().Ticks)); + } + + public override TimeSpan GetTotalEstimatedTime() + { + return TimeSpan.FromTicks(_tasks.Sum(t => t.GetTotalEstimatedTime().Ticks)); + } + + #endregion + + #region Query Helpers + + public IEnumerable GetTasksWithTimeOverride() + { + return _tasks.Where(t => t.HasTimeOverride); + } + + public IEnumerable GetTasksWithAssignmentOverride() + { + return _tasks.Where(t => t.HasAssignmentOverride); + } + + public IEnumerable GetAllSections() + { + return _tasks.SelectMany(t => t.Sections); + } + + #endregion +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectSection.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectSection.cs new file mode 100644 index 00000000..67820d49 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectSection.cs @@ -0,0 +1,34 @@ +using GozareshgirProgramManager.Domain._Common; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +/// +/// ProjectSection: shortcut container for UserId + SkillId at Project level +/// +public class ProjectSection : EntityBase +{ + private ProjectSection() { } + + public ProjectSection(Guid projectId, long userId, Guid skillId) + { + ProjectId = projectId; + UserId = userId; + SkillId = skillId; + } + + public Guid ProjectId { get; private set; } + public long UserId { get; private set; } + public Guid SkillId { get; private set; } + + public Project Project { get; private set; } = null!; + + public void UpdateUser(long userId) + { + UserId = userId; + } + + public void UpdateSkill(Guid skillId) + { + SkillId = skillId; + } +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectTask.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectTask.cs new file mode 100644 index 00000000..863e332f --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectTask.cs @@ -0,0 +1,249 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Events; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +/// +/// تسک - پایین‌ترین سطح در سلسله مراتب که شامل بخش‌ها می‌شود +/// +public class ProjectTask : ProjectHierarchyNode +{ + private readonly List _sections; + + private ProjectTask() + { + _sections = new List(); + } + + public ProjectTask(string name, Guid phaseId, string? description = null) : base(name, description) + { + PhaseId = phaseId; + _sections = new List(); + Priority = TaskPriority.Medium; + AddDomainEvent(new TaskCreatedEvent(Id, phaseId, name)); + } + + public Guid PhaseId { get; private set; } + public ProjectPhase Phase { get; private set; } = null!; + public IReadOnlyList Sections => _sections.AsReadOnly(); + + // Task-specific properties + public Enums.TaskStatus Status { get; private set; } = Enums.TaskStatus.NotStarted; + public TaskPriority Priority { get; private set; } + public DateTime? StartDate { get; private set; } + public DateTime? EndDate { get; private set; } + public DateTime? DueDate { get; private set; } + public int OrderIndex { get; private set; } + public TimeSpan? AllocatedTime { get; protected set; } + public bool HasTimeOverride { get; protected set; } + + #region Section Management + + public void AddSection(TaskSection section, bool cascadeToChildren = false) + { + var existingSection = _sections.FirstOrDefault(s => s.SkillId == section.SkillId); + if (existingSection != null) + { + // اگر userId متفاوت است، ویرایش شود + if (existingSection.CurrentAssignedUserId != section.CurrentAssignedUserId) + { + if (existingSection.CurrentAssignedUserId > 0) + { + existingSection.TransferToUser(existingSection.CurrentAssignedUserId, section.CurrentAssignedUserId); + } + else + { + existingSection.AssignToUser(section.CurrentAssignedUserId); + } + } + } + else + { + _sections.Add(section); + AddDomainEvent(new TaskSectionAddedEvent(Id, section.Id, section.SkillId)); + } + } + + public void AddSection(Guid skillId, long assignedUserId) + { + var existingSection = _sections.FirstOrDefault(s => s.SkillId == skillId); + if (existingSection != null) + { + if (existingSection.CurrentAssignedUserId != assignedUserId) + { + if (existingSection.CurrentAssignedUserId > 0) + { + existingSection.TransferToUser(existingSection.CurrentAssignedUserId, assignedUserId); + } + else + { + existingSection.AssignToUser(assignedUserId); + } + } + return; + } + + var section = new TaskSection(Id, skillId, assignedUserId); + _sections.Add(section); + AddDomainEvent(new TaskSectionAddedEvent(Id, section.Id, skillId)); + } + + public void RemoveSection(Guid sectionId) + { + var section = _sections.FirstOrDefault(s => s.Id == sectionId); + if (section == null) + throw new InvalidOperationException("بخش مورد نظر یافت نشد"); + + _sections.Remove(section); + AddDomainEvent(new TaskSectionRemovedEvent(Id, sectionId)); + } + + public void RemoveSectionBySkill(Guid skillId) + { + var section = _sections.FirstOrDefault(s => s.SkillId == skillId); + if (section != null) + { + _sections.Remove(section); + AddDomainEvent(new TaskSectionRemovedEvent(Id, section.Id)); + } + } + + #endregion + + #region Status Management + + public void UpdateStatus(Enums.TaskStatus status) + { + Status = status; + AddDomainEvent(new TaskStatusUpdatedEvent(Id, status)); + } + + public void SetPriority(TaskPriority priority) + { + Priority = priority; + AddDomainEvent(new TaskPriorityUpdatedEvent(Id, priority)); + } + + public void SetDates(DateTime? startDate = null, DateTime? endDate = null, DateTime? dueDate = null) + { + if (startDate.HasValue && endDate.HasValue && startDate > endDate) + throw new ArgumentException("تاریخ شروع نمی‌تواند بعد از تاریخ پایان باشد"); + + if (dueDate.HasValue && endDate.HasValue && dueDate < endDate) + throw new ArgumentException("تاریخ مهلت نمی‌تواند قبل از تاریخ پایان باشد"); + + StartDate = startDate; + EndDate = endDate; + DueDate = dueDate; + } + + public void SetOrderIndex(int orderIndex) + { + if (orderIndex < 0) + throw new ArgumentException("ترتیب نمی‌تواند منفی باشد", nameof(orderIndex)); + + OrderIndex = orderIndex; + } + + #endregion + + #region Assignment Management + + public void AssignToUser(long userId, bool cascadeToSections = true, bool forceOverride = false, bool markAsOverride = true) + { + if (markAsOverride) + { + HasAssignmentOverride = true; + } + + if (cascadeToSections) + { + foreach (var section in _sections) + { + section.AssignToUser(userId); + } + } + + AddDomainEvent(new TaskAssignedEvent(Id, userId)); + } + + public void Unassign(bool cascadeToSections = true, bool forceOverride = false, bool markAsOverride = true) + { + if (markAsOverride) + { + HasAssignmentOverride = true; + } + + if (cascadeToSections) + { + foreach (var section in _sections) + { + section.Unassign(); + } + } + + AddDomainEvent(new TaskUnassignedEvent(Id)); + } + + #endregion + + #region Time Calculation + + public override TimeSpan GetTotalTimeSpent() + { + return TimeSpan.FromTicks(_sections.Sum(s => s.GetTotalTimeSpent().Ticks)); + } + + public override TimeSpan GetTotalEstimatedTime() + { + return TimeSpan.FromTicks(_sections.Sum(s => s.EstimatedHours.Ticks)); + } + + #endregion + + #region Query Helpers + + public IEnumerable GetSectionsBySkill(Guid skillId) + { + return _sections.Where(s => s.SkillId == skillId); + } + + public TaskSection? GetSectionBySkill(Guid skillId) + { + return _sections.FirstOrDefault(s => s.SkillId == skillId); + } + + public bool HasSection(Guid skillId) + { + return _sections.Any(s => s.SkillId == skillId); + } + + public IEnumerable GetAssignedSections(long userId) + { + return _sections.Where(s => s.CurrentAssignedUserId == userId); + } + + #endregion + #region Time Management + + public void SetAllocatedTime(TimeSpan time, bool markAsOverride = true) + { + if (time < TimeSpan.Zero) + throw new ArgumentException("زمان تخصیص‌یافته نمی‌تواند منفی باشد", nameof(time)); + + AllocatedTime = time; + if (markAsOverride) + { + HasTimeOverride = true; + } + } + + public void ClearTimeOverride() + { + HasTimeOverride = false; + AllocatedTime = null; + } + + #endregion +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/TaskSection.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/TaskSection.cs new file mode 100644 index 00000000..e478478d --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/TaskSection.cs @@ -0,0 +1,223 @@ +using System.Linq; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain._Common.Exceptions; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Events; +using GozareshgirProgramManager.Domain.ProjectAgg.Models; +using GozareshgirProgramManager.Domain.SkillAgg.Entities; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +/// +/// بخش تسک - برای ذخیره کار واقعی که کاربر روی یک مهارت خاص انجام می‌دهد +/// +public class TaskSection : EntityBase +{ + private readonly List _activities; + private readonly List _additionalTimes; + + private TaskSection() + { + _activities = new List(); + _additionalTimes = new List(); + } + + public TaskSection(Guid taskId, Guid skillId, long currentAssignedUserId) + { + TaskId = taskId; + SkillId = skillId; + CurrentAssignedUserId = currentAssignedUserId; + OriginalAssignedUserId = currentAssignedUserId; + InitialEstimatedHours = TimeSpan.Zero; + _activities = new List(); + _additionalTimes = new List(); + Status = TaskSectionStatus.ReadyToStart; + AddDomainEvent(new TaskSectionAddedEvent(taskId, Id, skillId)); + } + + public Guid TaskId { get; private set; } + public Guid SkillId { get; private set; } + public TimeSpan InitialEstimatedHours { get; private set; } + public string? InitialDescription { get; set; } + public TaskSectionStatus Status { get; private set; } + + // شخصی که برای اولین بار این بخش به او اختصاص داده شده (مالک اصلی) + public long OriginalAssignedUserId { get; private set; } + + // شخصی که در حال حاضر این بخش به او اختصاص داده شده + public long CurrentAssignedUserId { get; private set; } + + // Navigation to ProjectTask (must be Task level) + public ProjectTask Task { get; private set; } = null!; + public Skill? Skill { get; set; } + + public IReadOnlyList Activities => _activities.AsReadOnly(); + public IReadOnlyList AdditionalTimes => _additionalTimes.AsReadOnly(); + + // محاسبه تایم نهایی (اولیه + تمام اضافه‌ها) + public TimeSpan FinalEstimatedHours => + TimeSpan.FromTicks(InitialEstimatedHours.Ticks + _additionalTimes.Sum(at => at.Hours.Ticks)); + + // برای backward compatibility + public TimeSpan EstimatedHours => FinalEstimatedHours; + + public void AddAdditionalTime(TimeSpan additionalHours, string? reason = null, long? addedByUserId = null) + { + if (additionalHours <= TimeSpan.Zero) + throw new BadRequestException("تایم اضافی باید بزرگتر از صفر باشد", nameof(additionalHours)); + + var additionalTime = new TaskSectionAdditionalTime(additionalHours, reason, addedByUserId); + _additionalTimes.Add(additionalTime); + } + + public void UpdateInitialEstimatedHours(TimeSpan newInitialEstimate, string initialDescription) + { + if (newInitialEstimate <= TimeSpan.Zero) + throw new BadRequestException("تایم تخمینی اولیه باید بزرگتر از صفر باشد", nameof(newInitialEstimate)); + + InitialEstimatedHours = newInitialEstimate; + InitialDescription = initialDescription; + } + + public void RemoveAdditionalTime(Guid additionalTimeId) + { + var additionalTime = _additionalTimes.FirstOrDefault(at => at.Id == additionalTimeId); + if (additionalTime == null) + throw new BadRequestException("تایم اضافی مورد نظر یافت نشد"); + + _additionalTimes.Remove(additionalTime); + } + + public TimeSpan GetTotalAdditionalTime() + { + return TimeSpan.FromTicks(_additionalTimes.Sum(at => at.Hours.Ticks)); + } + + public void UnassignUser() + { + if (_activities.Any(a => a.IsActive)) + { + throw new BadRequestException("نمی‌توان کاربری را که در حال کار است حذف کرد"); + } + + CurrentAssignedUserId = 0; + UpdateStatus(TaskSectionStatus.NotAssigned); + } + + public void StartWork(long userId, string? notes = null) + { + if (CurrentAssignedUserId != userId) + { + throw new BadRequestException("کاربر مجاز به شروع این بخش نیست"); + } + + // if (Status == TaskSectionStatus.Completed) + // { + // throw new BadRequestException("این بخش قبلاً تکمیل شده است"); + // } + + if (_activities.Any(a => a.IsActive)) + { + throw new BadRequestException("یک فعالیت در حال انجام وجود دارد"); + } + + var activity = new TaskSectionActivity(Id, userId, notes); + _activities.Add(activity); + + + UpdateStatus(TaskSectionStatus.InProgress); + } + + public void StopWork(long userId, TaskSectionStatus taskSectionStatus, string? endNotes = null) + { + var activeActivity = _activities.FirstOrDefault(a => a.IsActive); + if (activeActivity == null) + { + throw new BadRequestException("هیچ فعالیت فعالی یافت نشد"); + } + + if (activeActivity.UserId != userId) + { + throw new BadRequestException("کاربر مجاز به توقف این فعالیت نیست"); + } + + UpdateStatus(taskSectionStatus); + activeActivity.StopWork(endNotes); + } + + public void CompleteSection() + { + if (_activities.Any(a => a.IsActive)) + { + throw new BadRequestException("نمی‌توان بخشی را که فعالیت فعال دارد تکمیل کرد"); + } + + UpdateStatus(TaskSectionStatus.Completed); + } + + public void UpdateStatus(TaskSectionStatus status) + { + var oldStatus = Status; + Status = status; + AddDomainEvent(new TaskSectionStatusChangedEvent(Id, oldStatus, status)); + } + + public TimeSpan GetTotalTimeSpent() + { + return TimeSpan.FromTicks(_activities.Sum(a => a.GetTimeSpent().Ticks)); + } + + public bool IsCompleted() + { + return Status == TaskSectionStatus.Completed; + } + + public bool IsInProgress() + { + return _activities.Any(a => a.IsActive); + } + + public void AssignToUser(long userId) + { + if (OriginalAssignedUserId == 0) + { + OriginalAssignedUserId = userId; + } + + CurrentAssignedUserId = userId; + + if (Status == TaskSectionStatus.NotAssigned) + { + UpdateStatus(TaskSectionStatus.ReadyToStart); + } + + AddDomainEvent(new TaskSectionAssignedEvent(Id, userId)); + } + + public void TransferToUser(long fromUserId, long toUserId) + { + if (CurrentAssignedUserId != fromUserId) + { + throw new BadRequestException("کاربر فعلی با کاربر منبع مطابقت ندارد"); + } + + if (_activities.Any(a => a.IsActive)) + { + throw new BadRequestException("نمی‌توان بخشی را که در حال انجام است انتقال داد"); + } + + OriginalAssignedUserId = toUserId; + CurrentAssignedUserId = toUserId; + AddDomainEvent(new TaskSectionTransferredEvent(Id, fromUserId, toUserId)); + } + + public void Unassign() + { + UnassignUser(); + } + + public void ClearAdditionalTimes() + { + _additionalTimes.Clear(); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/TaskSectionActivity.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/TaskSectionActivity.cs new file mode 100644 index 00000000..85e60d0d --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/TaskSectionActivity.cs @@ -0,0 +1,57 @@ +using System.Diagnostics.CodeAnalysis; +using GozareshgirProgramManager.Domain._Common; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +/// +/// فعالیت کاری روی یک بخش +/// +public class TaskSectionActivity : EntityBase +{ + private TaskSectionActivity() { } + + public TaskSectionActivity(Guid sectionId, long userId, string? notes = null) + { + SectionId = sectionId; + UserId = userId; + StartDate = DateTime.Now; + Notes = notes; + IsActive = true; + } + + public Guid SectionId { get; private set; } + public long UserId { get; private set; } + public DateTime StartDate { get; private set; } + public DateTime? EndDate { get; private set; } + public string? Notes { get; private set; } + public string? EndNotes { get; private set; } + public bool IsActive { get; private set; } + + // Navigation property + public TaskSection Section { get; private set; } = null!; + + public void StopWork(string? endNotes = null) + { + if (!IsActive) + throw new InvalidOperationException("این فعالیت قبلاً متوقف شده است."); + + EndDate = DateTime.Now; + EndNotes = endNotes; + IsActive = false; + } + + public TimeSpan GetTimeSpent() + { + if (IsActive) + { + return DateTime.Now - StartDate; + } + + return (EndDate ?? DateTime.Now) - StartDate; + } + + public void UpdateNotes(string? notes) + { + Notes = notes; + } +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/TaskSectionAdditionalTime.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/TaskSectionAdditionalTime.cs new file mode 100644 index 00000000..657f76cc --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/TaskSectionAdditionalTime.cs @@ -0,0 +1,29 @@ +using GozareshgirProgramManager.Domain._Common; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +/// +/// زمان اضافی اضافه شده بعد از تخمین اولیه +/// +public class TaskSectionAdditionalTime : EntityBase +{ + private TaskSectionAdditionalTime() { } + + public TaskSectionAdditionalTime(TimeSpan hours, string? reason = null, long? addedByUserId = null) + { + Hours = hours; + Reason = reason; + AddedByUserId = addedByUserId; + AddedAt = DateTime.UtcNow; + } + + public TimeSpan Hours { get; private set; } + public string? Reason { get; private set; } + public long? AddedByUserId { get; private set; } + public DateTime AddedAt { get; private set; } + + public void UpdateReason(string? reason) + { + Reason = reason; + } +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/UserTimeReport.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/UserTimeReport.cs new file mode 100644 index 00000000..d3525513 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/UserTimeReport.cs @@ -0,0 +1,18 @@ +namespace GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +public class UserTimeReport +{ + public long UserId { get; set; } + public string UserName { get; set; } = string.Empty; + public TimeSpan TotalTimeSpent { get; set; } + public TimeSpan EstimatedTime { get; set; } + public int ActivityCount { get; set; } + public DateTime LastActivity { get; set; } + public DateTime? FirstActivity { get; set; } + public double EfficiencyRate => EstimatedTime.TotalHours > 0 ? + (EstimatedTime.TotalHours / TotalTimeSpent.TotalHours) * 100 : 0; + + public bool IsOvertime => TotalTimeSpent > EstimatedTime; + + public TimeSpan TimeDifference => TotalTimeSpent - EstimatedTime; +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/PhaseStatus.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/PhaseStatus.cs new file mode 100644 index 00000000..a2aa534c --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/PhaseStatus.cs @@ -0,0 +1,37 @@ +namespace GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +/// +/// وضعیت فاز پروژه +/// +public enum PhaseStatus +{ + /// + /// در حال برنامه‌ریزی + /// + Planning = 0, + + /// + /// آماده شروع + /// + Ready = 1, + + /// + /// در حال اجرا + /// + InProgress = 2, + + /// + /// متوقف شده + /// + OnHold = 3, + + /// + /// تکمیل شده + /// + Completed = 4, + + /// + /// لغو شده + /// + Cancelled = 5 +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/ProjectHierarchyLevel.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/ProjectHierarchyLevel.cs new file mode 100644 index 00000000..f5a2eb28 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/ProjectHierarchyLevel.cs @@ -0,0 +1,23 @@ +namespace GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +/// +/// سطوح مختلف در سلسله مراتب پروژه +/// +public enum ProjectHierarchyLevel +{ + /// + /// سطح پروژه (بالاترین سطح) + /// + Project = 0, + + /// + /// سطح فاز پروژه + /// + Phase = 1, + + /// + /// سطح تسک + /// + Task = 2, +} + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/ProjectStatus.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/ProjectStatus.cs new file mode 100644 index 00000000..fbd58771 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/ProjectStatus.cs @@ -0,0 +1,37 @@ +namespace GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +/// +/// وضعیت پروژه +/// +public enum ProjectStatus +{ + /// + /// در حال برنامه‌ریزی + /// + Planning = 0, + + /// + /// آماده شروع + /// + Ready = 1, + + /// + /// در حال اجرا + /// + InProgress = 2, + + /// + /// متوقف شده + /// + OnHold = 3, + + /// + /// تکمیل شده + /// + Completed = 4, + + /// + /// لغو شده + /// + Cancelled = 5 +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskPriority.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskPriority.cs new file mode 100644 index 00000000..13ccd784 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskPriority.cs @@ -0,0 +1,27 @@ +namespace GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +/// +/// اولویت تسک +/// +public enum TaskPriority +{ + /// + /// پایین + /// + Low = 0, + + /// + /// متوسط + /// + Medium = 1, + + /// + /// بالا + /// + High = 2, + + /// + /// بحرانی + /// + Critical = 3 +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskSectionStatus.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskSectionStatus.cs new file mode 100644 index 00000000..d5208bfb --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskSectionStatus.cs @@ -0,0 +1,10 @@ +namespace GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +public enum TaskSectionStatus +{ + NotAssigned = 0, // تخصیص داده نشده + ReadyToStart = 1, // آماده شروع + InProgress = 2, // درحال انجام + Incomplete = 3, // ناتمام شده + Completed = 4 // تکمیل شده +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskStatus.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskStatus.cs new file mode 100644 index 00000000..fc0d3c20 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskStatus.cs @@ -0,0 +1,9 @@ +namespace GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +public enum TaskStatus +{ + NotStarted = 1, + InProgress = 2, + Completed = 3, + OnHold = 4 +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Events/ProjectEvents.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Events/ProjectEvents.cs new file mode 100644 index 00000000..e823967e --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Events/ProjectEvents.cs @@ -0,0 +1,177 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using TaskStatus = GozareshgirProgramManager.Domain.ProjectAgg.Enums.TaskStatus; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Events; + +// Project Events +public record ProjectCreatedEvent(Guid ProjectId, string Name) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record ProjectStatusUpdatedEvent(Guid ProjectId, ProjectStatus Status) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record ProjectAssignedEvent(Guid ProjectId, long UserId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record ProjectUnassignedEvent(Guid ProjectId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +// Phase Events +public record PhaseCreatedEvent(Guid PhaseId, Guid ProjectId, string Name) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record PhaseAddedEvent(Guid PhaseId, Guid ProjectId, string Name) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record PhaseRemovedEvent(Guid PhaseId, Guid ProjectId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record PhaseStatusUpdatedEvent(Guid PhaseId, PhaseStatus Status) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record PhaseAssignedEvent(Guid PhaseId, long UserId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record PhaseUnassignedEvent(Guid PhaseId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +// Task Events +public record TaskCreatedEvent(Guid TaskId, Guid PhaseId, string Name) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record TaskAddedEvent(Guid TaskId, Guid PhaseId, string Name) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record TaskRemovedEvent(Guid TaskId, Guid PhaseId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record TaskStatusUpdatedEvent(Guid TaskId, TaskStatus Status) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record TaskPriorityUpdatedEvent(Guid TaskId, TaskPriority Priority) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record TaskAssignedEvent(Guid TaskId, long UserId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record TaskUnassignedEvent(Guid TaskId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record TaskSectionAddedEvent(Guid TaskId, Guid SectionId, Guid SkillId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record TaskSectionRemovedEvent(Guid TaskId, Guid SectionId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +// TaskSection Events +public record TaskSectionStatusChangedEvent(Guid SectionId, TaskSectionStatus OldStatus, TaskSectionStatus NewStatus) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record TaskSectionAssignedEvent(Guid SectionId, long UserId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record TaskSectionTransferredEvent(Guid SectionId, long FromUserId, long ToUserId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +// Section Events (Legacy - keeping for backward compatibility) +public record ProjectPhaseAddedEvent(Guid ProjectId, Guid PhaseId, string PhaseName) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record ProjectTaskStatusChangedEvent(Guid SectionId, TaskStatus OldStatus, TaskStatus NewStatus) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record ProjectSectionAddedEvent(Guid SectionId, Guid TaskId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + + +public record ProjectSectionAssignedEvent(Guid SectionId, long UserId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record ProjectSectionTransferredEvent(Guid SectionId, long FromUserId, long ToUserId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record WorkStartedEvent(Guid SectionId, long UserId, DateTime StartTime, string? Notes) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record WorkStoppedEvent(Guid SectionId, long UserId, DateTime StartTime, DateTime EndTime, TimeSpan Duration, string? Notes) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record ProjectSectionCompletedEvent(Guid ProjectId, long UserId, TimeSpan TotalTimeSpent, string? Notes) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record AdditionalTimeAddedEvent(Guid ProjectId, Guid AdditionalTimeId, TimeSpan Hours, string? Reason, long? AddedByUserId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record AdditionalTimeRemovedEvent(Guid ProjectId, Guid AdditionalTimeId, TimeSpan RemovedHours) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record InitialEstimatedTimeUpdatedEvent(Guid ProjectId, TimeSpan OldEstimate, TimeSpan NewEstimate) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Models/UserTimeReport.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Models/UserTimeReport.cs new file mode 100644 index 00000000..c02c1a39 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Models/UserTimeReport.cs @@ -0,0 +1,12 @@ +namespace GozareshgirProgramManager.Domain.ProjectAgg.Models; + +/// +/// گزارش زمان کاربر برای یک بخش پروژه +/// +public class UserTimeReport +{ + public long UserId { get; set; } + public TimeSpan TotalTimeSpent { get; set; } + public int ActivityCount { get; set; } + public DateTime LastActivity { get; set; } +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IPhaseSectionRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IPhaseSectionRepository.cs new file mode 100644 index 00000000..db8fb7e1 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IPhaseSectionRepository.cs @@ -0,0 +1,6 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain._Common; +namespace GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +public interface IPhaseSectionRepository : IRepository +{ +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IProjectPhaseRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IProjectPhaseRepository.cs new file mode 100644 index 00000000..8a29e014 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IProjectPhaseRepository.cs @@ -0,0 +1,33 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +/// +/// Repository interface for ProjectPhase entity +/// +public interface IProjectPhaseRepository : IRepository +{ + /// + /// Get phase with all its tasks + /// + Task GetWithTasksAsync(Guid phaseId); + + /// + /// Get phases by project ID + /// + Task> GetByProjectIdAsync(Guid projectId); + + + /// + /// Get phases with assignment overrides + /// + Task> GetPhasesWithAssignmentOverridesAsync(); + + /// + /// Get phases by status + /// + Task> GetByStatusAsync(ProjectAgg.Enums.PhaseStatus status); + + void Remove(ProjectPhase phase); +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IProjectRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IProjectRepository.cs new file mode 100644 index 00000000..5514e492 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IProjectRepository.cs @@ -0,0 +1,38 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +/// +/// Repository interface for Project aggregate root +/// +public interface IProjectRepository : IRepository +{ + /// + /// Get project with all its phases and tasks + /// + Task GetWithFullHierarchyAsync(Guid projectId); + + /// + /// Get project with phases only + /// + Task GetWithPhasesAsync(Guid projectId); + + /// + /// Get projects by status + /// + Task> GetByStatusAsync(ProjectAgg.Enums.ProjectStatus status); + + + /// + /// Get projects with assignment overrides + /// + Task> GetProjectsWithAssignmentOverridesAsync(); + + /// + /// Search projects by name + /// + Task> SearchByNameAsync(string searchTerm); + + void Remove(Project project); +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IProjectSectionRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IProjectSectionRepository.cs new file mode 100644 index 00000000..2838c8d6 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IProjectSectionRepository.cs @@ -0,0 +1,9 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +public interface IProjectSectionRepository : IRepository +{ +} + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IProjectTaskRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IProjectTaskRepository.cs new file mode 100644 index 00000000..8b0ff688 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/IProjectTaskRepository.cs @@ -0,0 +1,47 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +/// +/// Repository interface for ProjectTask entity +/// +public interface IProjectTaskRepository : IRepository +{ + /// + /// Get task with all its sections + /// + Task GetWithSectionsAsync(Guid taskId); + + /// + /// Get tasks by phase ID + /// + Task> GetByPhaseIdAsync(Guid phaseId); + + /// + /// Get tasks with time overrides + /// + Task> GetTasksWithTimeOverridesAsync(); + + /// + /// Get tasks with assignment overrides + /// + Task> GetTasksWithAssignmentOverridesAsync(); + + /// + /// Get tasks by status + /// + Task> GetByStatusAsync(ProjectAgg.Enums.TaskStatus status); + + /// + /// Get tasks by priority + /// + Task> GetByPriorityAsync(ProjectAgg.Enums.TaskPriority priority); + + /// + /// Get tasks assigned to user + /// + Task> GetAssignedToUserAsync(long userId); + + void Remove(ProjectTask task); +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionActivityRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionActivityRepository.cs new file mode 100644 index 00000000..d20ef6e0 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionActivityRepository.cs @@ -0,0 +1,16 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +public interface ITaskSectionActivityRepository:IRepository +{ + Task GetByIdAsync(Guid id); + Task> GetBySectionIdAsync(Guid sectionId); + Task> GetByUserIdAsync(long userId); + Task> GetActiveByUserAsync(long userId); + Task> GetByDateRangeAsync(DateTime from, DateTime to); + Task> GetByDateRangeUserIdAsync(DateTime from, DateTime to,long userId); + Task GetTotalTimeSpentByUserInRangeAsync(long userId, DateTime from, DateTime to); + Task> GetTotalTimeSpentPerUserInRangeAsync(DateTime from, DateTime to); +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionRepository.cs new file mode 100644 index 00000000..bedf59bf --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionRepository.cs @@ -0,0 +1,12 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +public interface ITaskSectionRepository: IRepository +{ + Task GetByIdWithActivitiesAsync(Guid id, CancellationToken cancellationToken = default); + + + Task GetByIdWithFullDataAsync(Guid id, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/ValueObjects/TimeTracking.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/ValueObjects/TimeTracking.cs new file mode 100644 index 00000000..1018b220 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/ValueObjects/TimeTracking.cs @@ -0,0 +1,75 @@ +using GozareshgirProgramManager.Domain._Common; + +namespace GozareshgirProgramManager.Domain.ProjectAgg.ValueObjects; + +public class TimeRange : ValueObject +{ + public DateTime Start { get; private set; } + public DateTime? End { get; private set; } + + public TimeRange(DateTime start) + { + Start = start; + } + + public TimeRange(DateTime start, DateTime end) + { + if (start >= end) + throw new ArgumentException("Start time must be before end time"); + + Start = start; + End = end; + } + + public TimeSpan Duration => End.HasValue ? End.Value - Start : DateTime.UtcNow - Start; + public bool IsActive => !End.HasValue; + + public void Complete(DateTime endTime) + { + if (End.HasValue) + throw new InvalidOperationException("Time range is already completed"); + + if (endTime <= Start) + throw new ArgumentException("End time must be after start time"); + + End = endTime; + } + + protected override IEnumerable GetEqualityComponents() + { + yield return Start; + yield return End ?? DateTime.MinValue; + } +} + +public class WorkSession : ValueObject +{ + public long UserId { get; private set; } + public TimeRange TimeRange { get; private set; } + public string? Notes { get; private set; } + public string? EndNotes { get; private set; } + + public WorkSession(long userId, DateTime startTime, string? notes = null) + { + UserId = userId; + TimeRange = new TimeRange(startTime); + Notes = notes; + } + + public void Complete(DateTime endTime, string? endNotes = null) + { + TimeRange.Complete(endTime); + EndNotes = endNotes; + } + + public TimeSpan Duration => TimeRange.Duration; + public bool IsActive => TimeRange.IsActive; + + protected override IEnumerable GetEqualityComponents() + { + yield return UserId; + yield return TimeRange; + yield return Notes ?? string.Empty; + yield return EndNotes ?? string.Empty; + } +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/ValueObjects/UserSkillAssignment.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/ValueObjects/UserSkillAssignment.cs new file mode 100644 index 00000000..491e2000 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/ValueObjects/UserSkillAssignment.cs @@ -0,0 +1,31 @@ +namespace GozareshgirProgramManager.Domain.ProjectAgg.ValueObjects; + +/// +/// Value Object برای ذخیره تخصیص کاربر و مهارت در سطوح بالاتر (Project/Phase) +/// این اطلاعات می‌تواند به صورت shortcut در Task و Section استفاده شود +/// +public class UserSkillAssignment +{ + public UserSkillAssignment(long userId, Guid skillId) + { + UserId = userId; + SkillId = skillId; + } + + public long UserId { get; private set; } + public Guid SkillId { get; private set; } + + public override bool Equals(object? obj) + { + if (obj is not UserSkillAssignment other) + return false; + + return UserId == other.UserId && SkillId == other.SkillId; + } + + public override int GetHashCode() + { + return HashCode.Combine(UserId, SkillId); + } +} + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/RoleAgg/Entities/Role.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/RoleAgg/Entities/Role.cs new file mode 100644 index 00000000..81bb10ba --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/RoleAgg/Entities/Role.cs @@ -0,0 +1,48 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.PermissionAgg.Entities; +using System.Security.Principal; +using System.Xml.Linq; +using GozareshgirProgramManager.Domain.UserAgg.Entities; + +namespace GozareshgirProgramManager.Domain.RoleAgg.Entities; + +public class Role : EntityBase +{ + /// + /// نام نقش + /// + public string RoleName { get; private set; } + + + /// + /// لیست پرمیشن کد ها + /// + public List Permissions { get; private set; } + + /// + /// ای دی نقش در گزارشگیر + /// + public long? GozareshgirRoleId { get; private set; } + + + protected Role() + { + } + + public Role(string roleName,long? gozareshgirRolId, List permissions) + { + RoleName = roleName; + Permissions = permissions; + GozareshgirRoleId = gozareshgirRolId; + + } + + + public void Edit(string roleName, List permissions) + { + RoleName = roleName; + Permissions = permissions; + } + + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/RoleAgg/Repositories/IRoleRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/RoleAgg/Repositories/IRoleRepository.cs new file mode 100644 index 00000000..6d30ae22 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/RoleAgg/Repositories/IRoleRepository.cs @@ -0,0 +1,12 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.RoleAgg.Entities; +using GozareshgirProgramManager.Domain.UserAgg.Entities; + +namespace GozareshgirProgramManager.Domain.RoleAgg.Repositories; + +public interface IRoleRepository : IRepository +{ + Task GetByGozareshgirRoleIdAsync(long? gozareshgirRolId); + + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/RoleUserAgg/RoleUser.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/RoleUserAgg/RoleUser.cs new file mode 100644 index 00000000..b8a05dc9 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/RoleUserAgg/RoleUser.cs @@ -0,0 +1,19 @@ +using GozareshgirProgramManager.Domain.UserAgg.Entities; + +namespace GozareshgirProgramManager.Domain.RoleUserAgg; + +public class RoleUser +{ + public RoleUser(long roleId) + { + RoleId = roleId; + } + + public long Id { get; private set; } + public long RoleId { get; private set; } + + + public User User { get; set; } + + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/DTOs/UserSalarySettingDto.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/DTOs/UserSalarySettingDto.cs new file mode 100644 index 00000000..12e5f50d --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/DTOs/UserSalarySettingDto.cs @@ -0,0 +1,43 @@ +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Enums; + +namespace GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.DTOs; + +public record UserSalarySettingDto +{ + + /// + /// آی دی کاربر + /// + public long UserId { get; set; } + + /// + /// کار در تعطیلات رسمی + /// + public bool HolidayWorking { get; set; } + + /// + /// حقوق ماهانه + /// + public double MonthlySalary { get; set; } + + + public string FullName { get; set; } + + public List WorkingHoursListDto { get; set; } +} + + +public record WorkingHoursListDto +{ + /// + /// مدت زمان شیفت + /// + public TimeSpan ShiftDuration { get; set; } + /// + /// عدد روز از ماه + /// + public PersianDayOfWeek PersianDayOfWeek { get; set; } + + + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Entities/SalaryPaymentSetting.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Entities/SalaryPaymentSetting.cs new file mode 100644 index 00000000..d98e3454 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Entities/SalaryPaymentSetting.cs @@ -0,0 +1,94 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.UserAgg.Entities; + +namespace GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities; + +/// +/// تنظیمات پرداخت حقوق +/// +public class SalaryPaymentSetting : EntityBase +{ + /// + /// ایجاد تنظیمات حقوق + /// برای اولین بار + /// + /// + /// + /// + /// + public SalaryPaymentSetting(bool holidayWorking, long userId, double monthlySalary, List workingHoursList) + { + HolidayWorking = holidayWorking; + UserId = userId; + MonthlySalary = monthlySalary; + WorkingHoursList = workingHoursList; + StartSettingDate = new DateTime(2025, 3, 21); + } + /// + /// افزودن تنظیمات جدید + /// + /// + /// + /// + /// + /// + public SalaryPaymentSetting(bool holidayWorking, long userId, List workingHoursList, DateTime startSettingDate) + { + HolidayWorking = holidayWorking; + UserId = userId; + + WorkingHoursList = workingHoursList; + StartSettingDate = startSettingDate; + } + + + protected SalaryPaymentSetting() + { + + } + + /// + /// کارکردن در تعطیلات رسمی + /// + public bool HolidayWorking { get; private set; } + + + /// + /// آی دی کاربر + /// + public long UserId { get; private set; } + + /// + /// دستمزد ماهانه + /// + public double MonthlySalary { get; private set; } + + /// + /// تاریخ شروع تنظیمات + /// + public DateTime? StartSettingDate { get; private set; } + + /// + /// تاریخ پایان تنظیمات + /// + public DateTime? EndSettingDate { get; private set; } + + + public List WorkingHoursList { get; set; } + + + /// + /// ویرایش تنظیمات حقوق + /// + /// + /// + public void Edit(bool holidayWorking, double monthlySalary, List workingHoursList) + { + HolidayWorking = holidayWorking; + WorkingHoursList = workingHoursList; + MonthlySalary = monthlySalary; + } + + + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Entities/WorkingHours.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Entities/WorkingHours.cs new file mode 100644 index 00000000..0522364f --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Entities/WorkingHours.cs @@ -0,0 +1,164 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Enums; +using System.ComponentModel.DataAnnotations.Schema; + +namespace GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities; + +/// +/// تخصیص ساعت کاری به کاربر +/// +public class WorkingHours +{ + public WorkingHours(TimeSpan startShiftOne, TimeSpan endShiftOne, TimeSpan startShiftTwo, TimeSpan endShiftTwo, TimeSpan restTime, bool hasShiftOne, bool hasShiftTwo, bool hasRestTime, PersianDayOfWeek persianDayOfWeek, bool isActiveDay) + { + StartShiftOne = hasShiftOne? startShiftOne : TimeSpan.Zero; + EndShiftOne = hasShiftOne ? endShiftOne : TimeSpan.Zero; + StartShiftTwo = hasShiftTwo ? startShiftTwo : TimeSpan.Zero; + EndShiftTwo = hasShiftTwo ? endShiftTwo : TimeSpan.Zero; + RestTime = hasRestTime ? restTime : TimeSpan.Zero; + HasShiftOne = hasShiftOne; + HasShiftTow = hasShiftTwo; + HasRestTime = hasRestTime; + PersianDayOfWeek = persianDayOfWeek; + IsActiveDay = isActiveDay; + + ComputeShiftDuration(startShiftOne, endShiftOne, startShiftTwo, endShiftTwo, restTime, hasShiftOne, hasShiftTwo,hasRestTime); + } + + + private WorkingHours(bool isActiveDay) + { + IsActiveDay = isActiveDay; + } + + public long Id { get; private set; } + + /// + /// ساعت شروع شیفت کاری + /// + public TimeSpan StartShiftOne { get; private set; } + + /// + /// ساعت پایان شیفت کاری + /// + public TimeSpan EndShiftOne { get; private set; } + + + /// + /// ساعت شروع شیفت دوم کاری + /// + public TimeSpan StartShiftTwo { get; private set; } + + /// + /// ساعت پایان شیفت دوم کاری + /// + public TimeSpan EndShiftTwo { get; private set; } + + /// + /// مدت استراحت + /// + public TimeSpan RestTime { get; private set; } + + + /// + /// آیا مقطع مار اول دارد + /// + public bool HasShiftOne { get; private set; } + + /// + /// آیا مقطع کار دوم دارد + /// + public bool HasShiftTow { get; private set; } + + /// + /// آیا ساعت استراحت دارد + /// + public bool HasRestTime { get; private set; } + + /// + /// بازه زمانی شیفت + /// + public int ShiftDurationInMinutes { get; private set; } + + [NotMapped] + public TimeSpan ShiftDuration + { + get => TimeSpan.FromMinutes(ShiftDurationInMinutes); + private set => ShiftDurationInMinutes = (int)value.TotalMinutes; + } + + /// + /// عدد روز از ماه + /// + public PersianDayOfWeek PersianDayOfWeek { get; private set; } + + + + + /// + /// آیا این روز هفته + /// فعال است + /// + public bool IsActiveDay { get; private set; } + + public SalaryPaymentSetting SalaryPaymentSetting { get; set; } + + /// + /// بدست آوردن بازه زمانی شیفت + /// + /// + /// + /// + private void ComputeShiftDuration(TimeSpan startShift, TimeSpan endShift, TimeSpan startShiftTwo, TimeSpan endShiftTwo, TimeSpan restTime, bool hasShiftOne, bool hasShiftTwo, bool hasRestTime) + { + var now = DateTime.Now.Date; + + if (hasShiftOne && !hasShiftTwo) + { + DateTime startOne = new DateTime(now.Year, now.Month, now.Day, startShift.Hours, startShift.Minutes,0); + DateTime endOne = new DateTime(now.Year, now.Month, now.Day, endShift.Hours, endShift.Minutes, 0); + + + if (endOne <= startOne) + endOne = endOne.AddDays(1); + var shiftDuration = (endOne - startOne); + + ShiftDuration = hasRestTime ? (shiftDuration - restTime) : shiftDuration; + } + else if (!hasShiftOne && hasShiftTwo) + { + DateTime startTow = new DateTime(now.Year, now.Month, now.Day, startShiftTwo.Hours, startShiftTwo.Minutes, 0); + DateTime endTow = new DateTime(now.Year, now.Month, now.Day, endShiftTwo.Hours, endShiftTwo.Minutes, 0); + + if (endTow <= startTow) + endTow = endTow.AddDays(1); + + + ShiftDuration = (endTow - startTow); + } + else if (hasShiftOne && hasShiftTwo) + { + DateTime startOne = new DateTime(now.Year, now.Month, now.Day, startShift.Hours, startShift.Minutes, 0); + DateTime endOne = new DateTime(now.Year, now.Month, now.Day, endShift.Hours, endShift.Minutes, 0); + if (endOne <= startOne){} + endOne = endOne.AddDays(1); + + var shiftOneDuration = (endOne - startOne); + + DateTime startTow = new DateTime(endOne.Year, endOne.Month, endOne.Day, startShiftTwo.Hours, startShiftTwo.Minutes, 0); + DateTime endTow = new DateTime(endOne.Year, endOne.Month, endOne.Day, endShiftTwo.Hours, endShiftTwo.Minutes, 0); + + if (endTow <= startTow) + endTow = endTow.AddDays(1); + + var shiftDurationTow = (endTow - startTow); + ShiftDuration = shiftOneDuration.Add(shiftDurationTow); + } + else + { + ShiftDurationInMinutes = 0; + } + + } + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Enums/HasSalarySettings.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Enums/HasSalarySettings.cs new file mode 100644 index 00000000..589c71d1 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Enums/HasSalarySettings.cs @@ -0,0 +1,20 @@ +namespace GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Enums; + +public enum HasSalarySettings +{ + /// + /// پیش فرض هر دو حالت + /// + Default = 0, + + /// + /// تنظیمات حقوق و ساعت دارد + /// + HasSettings = 1, + /// + /// تنظیمات حقوق و ساعت ندارد + /// + DoesNotHaveSettings = 2 + + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Enums/PersianDayOfWeek.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Enums/PersianDayOfWeek.cs new file mode 100644 index 00000000..ad78b55a --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Enums/PersianDayOfWeek.cs @@ -0,0 +1,29 @@ +namespace GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Enums; + +public enum PersianDayOfWeek +{ + /// شنبه + Shanbeh = 1, + + /// یکشنبه + YekShanbeh = 2, + + /// دوشنبه + DoShanbeh = 3, + + /// سه شنبه + SeShanbeh = 4, + + /// چهارشنبه + CheharShanbeh = 5, + + /// پنجشنبه + PanjShanbeh = 6, + + /// جمعه + Jomeh = 7, + + + + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Repositories/ISalaryPaymentSettingRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Repositories/ISalaryPaymentSettingRepository.cs new file mode 100644 index 00000000..4bc45f73 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SalaryPaymentSettingAgg/Repositories/ISalaryPaymentSettingRepository.cs @@ -0,0 +1,26 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.DTOs; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities; + +namespace GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Repositories; + +public interface ISalaryPaymentSettingRepository : IRepository +{ + /// + /// دریافت لیست تنظیمات حقوق + /// + /// + /// + Task GetSalarySettingByUserId(long userId); + + + Task> GetAllSettings(List userIdList); + + /// + /// حذف گروهی تنظیمات حقوق + /// + /// + /// + void RemoveRangeSalarySettings(List removedItems); +} + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SkillAgg/Entities/Skill.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SkillAgg/Entities/Skill.cs new file mode 100644 index 00000000..662f9544 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SkillAgg/Entities/Skill.cs @@ -0,0 +1,16 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; + +namespace GozareshgirProgramManager.Domain.SkillAgg.Entities; + +public class Skill:EntityBase, IAggregateRoot +{ + public Skill(string name) + { + Name = name; + Sections = []; + } + + public string Name { get; set; } + public List Sections { get; set; } +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SkillAgg/Repositories/ISkillRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SkillAgg/Repositories/ISkillRepository.cs new file mode 100644 index 00000000..e6152c60 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/SkillAgg/Repositories/ISkillRepository.cs @@ -0,0 +1,9 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.SkillAgg.Entities; + +namespace GozareshgirProgramManager.Domain.SkillAgg.Repositories; + +public interface ISkillRepository: IRepository +{ + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Entities/User.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Entities/User.cs new file mode 100644 index 00000000..d112136d --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Entities/User.cs @@ -0,0 +1,169 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.PermissionAgg.Entities; +using GozareshgirProgramManager.Domain.RoleAgg.Entities; +using GozareshgirProgramManager.Domain.RoleUserAgg; + +namespace GozareshgirProgramManager.Domain.UserAgg.Entities; + +/// +/// کاربر +/// +public class User : EntityBase +{ + /// + /// ایجاد + /// + /// + /// + /// + /// + /// + /// + /// + public User(string fullName, string userName, string password, string mobile, string? email, long? accountId, List roles) + { + FullName = fullName; + UserName = userName; + Password = password; + Mobile = mobile; + Email = email; + IsActive = true; + AccountId = accountId; + RoleUser = roles; + } + + protected User() + { + + } + /// + /// نام و نام خانوادگی + /// + public string FullName { get; private set; } + + /// + /// نام کاربری + /// + public string UserName { get; private set; } + + /// + /// گذرواژه + /// + public string Password { get; private set; } + + /// + /// مسیر عکس پروفایل + /// + public string ProfilePhotoPath { get; private set; } + + /// + /// شماره موبایل + /// + public string Mobile { get; set; } + + /// + /// ایمیل + /// + public string? Email { get; private set; } + + /// + /// فعال/غیر فعال بودن یوزر + /// + public bool IsActive { get; private set; } + + + /// + /// کد یکبارمصرف ورود + /// + public string? VerifyCode { get; private set; } + + /// + /// آی دی کاربر در گزارشگیر + /// + public long? AccountId { get; private set; } + + + /// + /// لیست پرمیشن کد ها + /// + public List RoleUser { get; private set; } + + /// + /// لیست توکن‌های تازه‌سازی + /// + private List _refreshTokens = new(); + public IReadOnlyCollection RefreshTokens => _refreshTokens.AsReadOnly(); + + /// + /// آپدیت کاربر + /// + /// + /// + /// + /// + /// + public void Edit(string fullName, string userName, string mobile, List roles, bool isActive) + { + FullName = fullName; + UserName = userName; + Mobile = mobile; + RoleUser = roles; + IsActive = isActive; + } + + /// + /// غیرفعال سازی + /// + public void DeActive() + { + IsActive = false; + } + + /// + /// فعال سازی + /// + public void ReActive() + { + IsActive = true; + } + + /// + /// افزودن توکن تازه‌سازی + /// + public void AddRefreshToken(string token, DateTime expiresAt, string? ipAddress = null, string? userAgent = null) + { + var refreshToken = new UserRefreshToken(Id, token, expiresAt, ipAddress, userAgent); + _refreshTokens.Add(refreshToken); + } + + /// + /// لغو توکن تازه‌سازی + /// + public void RevokeRefreshToken(string token) + { + var refreshToken = _refreshTokens.FirstOrDefault(x => x.Token == token); + if (refreshToken == null) + throw new InvalidOperationException("توکن یافت نشد"); + + refreshToken.Revoke(); + } + + /// + /// لغو تمام توکن‌های فعال + /// + public void RevokeAllRefreshTokens() + { + foreach (var token in _refreshTokens.Where(x => x.IsActive)) + { + token.Revoke(); + } + } + + /// + /// پاکسازی توکن‌های منقضی شده + /// + public void RemoveExpiredRefreshTokens() + { + _refreshTokens.RemoveAll(x => !x.IsActive); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Entities/UserRefreshToken.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Entities/UserRefreshToken.cs new file mode 100644 index 00000000..b04b3615 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Entities/UserRefreshToken.cs @@ -0,0 +1,90 @@ +using GozareshgirProgramManager.Domain._Common; + +namespace GozareshgirProgramManager.Domain.UserAgg.Entities; + +/// +/// توکن تازه‌سازی برای احراز هویت +/// +public class UserRefreshToken : EntityBase +{ + /// + /// سازنده محافظت شده برای EF Core + /// + protected UserRefreshToken() + { + } + + /// + /// ایجاد توکن تازه‌سازی + /// + public UserRefreshToken(long userId, string token, DateTime expiresAt, string? ipAddress = null, string? userAgent = null) + { + UserId = userId; + Token = token; + ExpiresAt = expiresAt; + IpAddress = ipAddress; + UserAgent = userAgent; + } + + /// + /// شناسه کاربر + /// + public long UserId { get; private set; } + + /// + /// توکن تازه‌سازی + /// + public string Token { get; private set; } + + /// + /// تاریخ انقضا + /// + public DateTime ExpiresAt { get; private set; } + + /// + /// تاریخ لغو + /// + public DateTime? RevokedAt { get; private set; } + + /// + /// آی‌پی کاربر + /// + public string? IpAddress { get; private set; } + + /// + /// User Agent مرورگر + /// + public string? UserAgent { get; private set; } + + /// + /// آیا منقضی شده؟ + /// + public bool IsExpired => DateTime.Now >= ExpiresAt; + + /// + /// آیا لغو شده؟ + /// + public bool IsRevoked => RevokedAt.HasValue; + + /// + /// آیا فعال است؟ + /// + public bool IsActive => !IsRevoked && !IsExpired; + + /// + /// لغو توکن + /// + public void Revoke() + { + if (IsRevoked) + throw new InvalidOperationException("توکن قبلاً لغو شده است"); + + RevokedAt = DateTime.Now; + } + + /// + /// کاربر صاحب توکن + /// + public User User { get; private set; } +} + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Enums/ExternalAuthProvider.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Enums/ExternalAuthProvider.cs new file mode 100644 index 00000000..e02abfc9 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Enums/ExternalAuthProvider.cs @@ -0,0 +1 @@ + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Events/UserEvents.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Events/UserEvents.cs new file mode 100644 index 00000000..83b95f05 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Events/UserEvents.cs @@ -0,0 +1,47 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.UserAgg.Entities; + + +namespace GozareshgirProgramManager.Domain.UserAgg.Events; + +public record UserCreatedEvent(long UserId, string FirstName, string LastName, string Email) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record UserPersonalInfoUpdatedEvent(long UserId, string OldFirstName, string OldLastName, string NewFirstName, string NewLastName) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record UserEmailUpdatedEvent(long UserId, string OldEmail, string NewEmail) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record UserWorkInfoUpdatedEvent(long UserId, string? Department, string? Position) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + + + + + + + + +public record UserDeactivatedEvent(long UserId, string? Reason) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record UserActivatedEvent(long UserId) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} + +public record UserLoggedInEvent(long UserId, DateTime LoginTime) : IDomainEvent +{ + public DateTime OccurredOn { get; init; } = DateTime.UtcNow; +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Repositories/IUserRefreshTokenRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Repositories/IUserRefreshTokenRepository.cs new file mode 100644 index 00000000..62146e68 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Repositories/IUserRefreshTokenRepository.cs @@ -0,0 +1,9 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.UserAgg.Entities; + +namespace GozareshgirProgramManager.Domain.UserAgg.Repositories; + +public interface IUserRefreshTokenRepository : IRepository +{ + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Repositories/IUserRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Repositories/IUserRepository.cs new file mode 100644 index 00000000..5ce68190 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/UserAgg/Repositories/IUserRepository.cs @@ -0,0 +1,32 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.UserAgg.Entities; + +namespace GozareshgirProgramManager.Domain.UserAgg.Repositories; + +public interface IUserRepository: IRepository +{ + Task GetByIdAsync(long id); + + /// + /// یافتن کاربر با آی دی اکانت گزارشگیر او + /// + /// + /// + Task GetByGozareshgirAccountId(long accountId); + Task GetByEmailAsync(string email); + Task GetByMobileAsync(string mobile); + Task> GetAllAsync(); + Task> GetActiveUsersAsync(); + + Task AddAsync(User user); + void Update(User user); + void Delete(User user); + Task ExistsAsync(long id); + Task UsernameExistsAsync(string username); + Task EmailExistsAsync(string email); + Task MobileExistsAsync(string mobile); + Task GetUserWithRolesByIdAsync(long userId, CancellationToken cancellationToken); +} + + + diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/EntityBase.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/EntityBase.cs new file mode 100644 index 00000000..1710c77b --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/EntityBase.cs @@ -0,0 +1,25 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace GozareshgirProgramManager.Domain._Common; + +public abstract class EntityBase +{ + public EntityBase() + { + if (typeof(TId) == typeof(Guid)) + { + Id = (TId)(object)Guid.NewGuid(); + } + CreationDate = DateTime.Now; + } + public TId Id { get; protected set; } + public DateTime CreationDate { get; protected set; } + + private readonly List _domainEvents = new(); + [NotMapped] + public IReadOnlyCollection DomainEvents => _domainEvents.AsReadOnly(); + protected void AddDomainEvent(IDomainEvent domainEvent) => _domainEvents.Add(domainEvent); + public void ClearDomainEvents() => _domainEvents.Clear(); + + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/Exceptions/BadRequestException.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/Exceptions/BadRequestException.cs new file mode 100644 index 00000000..c33adfa0 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/Exceptions/BadRequestException.cs @@ -0,0 +1,24 @@ +namespace GozareshgirProgramManager.Domain._Common.Exceptions; + +public class BadRequestException:Exception +{ + public BadRequestException(string message):base(message) + { + + } + + public BadRequestException(string message, string details) : base(message) + { + Details = details; + } + + public BadRequestException(string message, Dictionary extra) : + base(message) + { + Extra = extra; + } + + public string Details { get; } + public Dictionary Extra { get; set; } + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/Exceptions/NotFoundException.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/Exceptions/NotFoundException.cs new file mode 100644 index 00000000..3b0f1796 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/Exceptions/NotFoundException.cs @@ -0,0 +1,13 @@ +namespace GozareshgirProgramManager.Domain._Common.Exceptions; + +public class NotFoundException:Exception +{ + public NotFoundException(string message) : base(message) + { + } + + public NotFoundException(string name, object key) : base($"Entity \"{name}\" ({key}) was not found.") + { + } + +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/Exceptions/UnAuthorizedException.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/Exceptions/UnAuthorizedException.cs new file mode 100644 index 00000000..67f0befb --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/Exceptions/UnAuthorizedException.cs @@ -0,0 +1,8 @@ +namespace GozareshgirProgramManager.Domain._Common.Exceptions; + +public class UnAuthorizedException:Exception +{ + public UnAuthorizedException(string message) : base(message) + { + } +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IAggregateRoot.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IAggregateRoot.cs new file mode 100644 index 00000000..b11ee26d --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IAggregateRoot.cs @@ -0,0 +1,8 @@ +namespace GozareshgirProgramManager.Domain._Common; + +/// +/// Marker interface for Aggregate Roots +/// +public interface IAggregateRoot +{ +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IDomainEvent.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IDomainEvent.cs new file mode 100644 index 00000000..6ab51876 --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IDomainEvent.cs @@ -0,0 +1,6 @@ +namespace GozareshgirProgramManager.Domain._Common; + +public interface IDomainEvent +{ + DateTime OccurredOn { get; } +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IRepository.cs new file mode 100644 index 00000000..cd8a9dcc --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IRepository.cs @@ -0,0 +1,17 @@ +using System.Linq.Expressions; + +namespace GozareshgirProgramManager.Domain._Common; + +public interface IRepository where T:class +{ + T Get(TKey id); + Task GetByIdAsync(TKey id); + List Get(); + IQueryable GetQueryable(); + void Create(T entity); + Task CreateAsync(T entity); + bool ExistsIgnoreQueryFilter(Expression> expression); + bool Exists(Expression> expression); + //void SaveChanges(); + //Task SaveChangesAsync(); +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IUnitOfWork.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IUnitOfWork.cs new file mode 100644 index 00000000..1ecce3ef --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IUnitOfWork.cs @@ -0,0 +1,9 @@ + namespace GozareshgirProgramManager.Domain._Common; + +/// +/// Unit of Work pattern interface +/// +public interface IUnitOfWork +{ + Task SaveChangesAsync(CancellationToken cancellationToken = default); +} diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/Tools.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/Tools.cs new file mode 100644 index 00000000..0f1ed2da --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/Tools.cs @@ -0,0 +1,2089 @@ +using System.Globalization; +using System.Text.RegularExpressions; +using PersianTools.Core; + + +namespace GozareshgirProgramManager.Domain._Common; + +public static class Tools +{ + + public static string[] MonthNames = + {"فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند"}; + + public static string[] DayNames = { "شنبه", "یکشنبه", "دو شنبه", "سه شنبه", "چهار شنبه", "پنج شنبه", "جمعه" }; + public static string[] DayNamesG = { "یکشنبه", "دو شنبه", "سه شنبه", "چهار شنبه", "پنج شنبه", "جمعه", "شنبه" }; + + + public static bool IsMobileValid(this string mobileNo) + { + if (mobileNo.Length < 11) + return false; + return Regex.IsMatch(mobileNo, "^((09))(\\d{9})$"); + } + + /// + /// تاریخ شروع و تعداد ماه را میگیرد و تاریخ پایان قراردا را بر میگرداند + /// + /// + /// + /// + public static (DateTime endDateGr, string endDateFa) FindEndOfContract(string startDate, string monthPlus) + { + + int startYear = Convert.ToInt32(startDate.Substring(0, 4)); + int startMonth = Convert.ToInt32(startDate.Substring(5, 2)); + int startDay = Convert.ToInt32(startDate.Substring(8, 2)); + var start = new PersianDateTime(startYear, startMonth, startDay); + var end = (start.AddMonths(Convert.ToInt32(monthPlus))).AddDays(-1); + return ($"{end}".ToGeorgianDateTime(), $"{end}"); + + } + + /// + /// دریافت روزهای کارکرد پرسنل در لیست بیمه ماه مشخص شده + /// با کمک شروع بکار و ترک کار + /// + /// + /// + /// + /// + /// + /// + public static (int countWorkingDays, DateTime startWork, DateTime endWork, bool hasStartWorkInMonth, bool hasLeftWorkInMonth) GetEmployeeInsuranceWorkingDays(DateTime startWork, DateTime? leftWork, DateTime startDate, + DateTime endDate, long employeeId) + { + DateTime start = startDate; + DateTime end = endDate; + bool startWorkInMonth = false; + bool endWorkInMonth = false; + + //اگر شروع بکار پرسنل در ماه مشخص شده لیست بیمه بود + if (startWork >= startDate) + { + start = startWork; + startWorkInMonth = true; + } + + if (leftWork == null) + leftWork = DateTime.MinValue; + //اگر ترک کار پرسنل در ماه مشخص شده لیست بیمه بود + if (leftWork != DateTime.MinValue && leftWork.Value < endDate) + { + end = leftWork.Value; + endWorkInMonth = true; + } + + int countDays = (int)(end - start).TotalDays + 1; + + + //روزهای کارکرد پرسنل با آی دی های زیر دستی تعریف شد + switch (employeeId) + { + + //case 3812://ثابت- کسری حاجی پور + // countWorkingDays = 15; + // break; + case 40463://ثابت + countDays = 10; + break; + case 40469://ثابت + countDays = 7; + break; + //case 9950://ثابت + // countDays = 15; + //break; + case 9640://ثابت + countDays = 15; + break; + case 40998://ثابت + countDays = 15; + break; + case 6219://ثابت + countDays = 15; + break; + //case 7897://ثابت + // countWorkingDays = 15; + } + + + return (countDays, start, end, startWorkInMonth, endWorkInMonth); + } + /// + /// محاسبه سن + /// + /// + /// + /// + public static (int yearCount, int monthCount, int dayCount) GetAge(DateTime startDate, DateTime endDate) + { + + var startFa = startDate.ToFarsi(); + int startYear = Convert.ToInt32(startFa.Substring(0, 4)); + int startMonth = Convert.ToInt32(startFa.Substring(5, 2)); + int startDay = Convert.ToInt32(startFa.Substring(8, 2)); + var start = new PersianDateTime(startYear, startMonth, startDay); + + + var endFa = endDate.ToFarsi(); + int endYear = Convert.ToInt32(endFa.Substring(0, 4)); + int endMonth = Convert.ToInt32(endFa.Substring(5, 2)); + int endDay = Convert.ToInt32(endFa.Substring(8, 2)); + var end = new PersianDateTime(endYear, endMonth, endDay); + int months = 0; + int days = 0; + int years = 0; + + var firstYearCounter = start.AddYears(1); + //اگر سنش هنوز به یک سال نرسیده بود + if (firstYearCounter > end) + { + start = start.AddYears(-1); + + var endMonthCounter = new PersianDateTime(end.Year, end.Month, start.Day); + + for (var monthCounter = start; monthCounter <= end; monthCounter = monthCounter.AddMonths(1)) + { + if (monthCounter <= end) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine("month : " + monthCounter); + months++; + } + + if (monthCounter.Month == end.Month) + { + var firstDayCounter = monthCounter.AddDays(1); + for (var dayCounter = firstDayCounter; dayCounter <= end; dayCounter = dayCounter.AddDays(1)) + { + if (dayCounter <= end) + { + days++; + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("day : " + dayCounter); + + } + + } + months = months > 0 ? months - 1 : 0; + break; + } + + + + } + + + } + else + { + for (var yearCouner = firstYearCounter; yearCouner <= end; yearCouner = yearCouner.AddYears(1)) + { + + if (yearCouner.Year <= end.Year) + { + years++; + Console.ForegroundColor = ConsoleColor.DarkMagenta; + Console.WriteLine("year : " + yearCouner); + } + + + if (yearCouner.Year == end.Year) + { + + var endMonthCounter = new PersianDateTime(end.Year, end.Month, (yearCouner.Day > end.Day ? end.Day : yearCouner.Day)); + + if (yearCouner.Day <= end.Day) + { + endMonthCounter = end; + + } + for (var monthCounter = yearCouner; monthCounter <= endMonthCounter; monthCounter = monthCounter.AddMonths(1)) + { + if (monthCounter < end) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine("month : " + monthCounter); + months++; + } + + if (monthCounter.Month == end.Month) + { + var firstDayCounter = monthCounter.AddDays(1); + if (yearCouner.Day > end.Day) + { + + firstDayCounter = firstDayCounter.AddMonths(-1); + } + for (var dayCounter = firstDayCounter; dayCounter <= end; dayCounter = dayCounter.AddDays(1)) + { + if (dayCounter <= end) + { + days++; + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("day : " + dayCounter); + + } + + } + + months = months > 0 ? months - 1 : 0; + break; + } + + + } + + } + + } + } + + + Console.ResetColor(); + Console.WriteLine($"old: [{years} year] ، [{months} month] ، [{days} day]"); + return (years, months, days); + } + + public static string ToFarsi(this DateTime? date) + { + try + { + if (date != null) return date.Value.ToFarsi(); + } + catch (Exception) + { + return ""; + } + + return ""; + } + + public static string ToFarsi(this DateTime date) + { + if (date == new DateTime()) return ""; + var pc = new PersianCalendar(); + return $"{pc.GetYear(date)}/{pc.GetMonth(date):00}/{pc.GetDayOfMonth(date):00}"; + } + public static string ToFarsiMonth(this DateTime date) + { + if (date == new DateTime()) return ""; + var pc = new PersianCalendar(); + return $"{pc.GetMonth(date)}"; + } + + /// + /// دریافت عدد ماه شمسی + /// از تاریخ میلادی + /// + /// + /// + public static string GetShamsiMonthNumber(this DateTime date) + { + if (date == new DateTime()) return ""; + var pc = new PersianCalendar(); + return $"{pc.GetMonth(date):00}"; + } + /// + /// دریافت ساتل شمسی + /// از تاریخ میلادی + /// + /// + /// + public static string GetShamsiYearNumber(this DateTime date) + { + if (date == new DateTime()) return ""; + var pc = new PersianCalendar(); + return $"{pc.GetYear(date)}"; + } + /// + /// این متد تاریخ میلادی را گرفته و ماه 31 یا 30 روزه را تشخیص میدهد، ماه اسفند 30 روزه برمگیردد + /// + /// + /// + public static int CountMonthDays(this DateTime date) + { + if (date == new DateTime()) return 0; + var pc = new PersianCalendar(); + + return pc.GetMonth(date) switch + { + 1 => 31, + 2 => 31, + 3 => 31, + 4 => 31, + 5 => 31, + 6 => 31, + + 7 => 30, + 8 => 30, + 9 => 30, + 10 => 30, + 11 => 30, + 12 => 30, + _ => 0, + + }; + } + + public static string ToFarsiYear2(this DateTime date) + { + if (date == new DateTime()) return ""; + var pc = new PersianCalendar(); + var year = pc.GetYear(date).ToString(); + string y1 = string.Empty; + string y2 = string.Empty; + string sum = string.Empty; + for (int i = 0; i < year.Length; i++) + { + + if (year[i] == 2) + { + y1 += year[i]; + } + + if (year[i] == 3) + { + y2 += year[i]; + } + + } + + sum = y1 + y2; + return sum; + } + public static string ToFarsiYear(this DateTime date) + { + if (date == new DateTime()) return ""; + var pc = new PersianCalendar(); + + return $"{pc.GetYear(date)}"; + } + public static string ToDiscountFormat(this DateTime date) + { + if (date == new DateTime()) return ""; + return $"{date.Year}/{date.Month}/{date.Day}"; + } + + public static string GetTime(this DateTime date) + { + return $"_{date.Hour:00}_{date.Minute:00}_{date.Second:00}"; + } + + public static string ToFarsiFull(this DateTime date) + { + var pc = new PersianCalendar(); + return + $"{pc.GetYear(date)}/{pc.GetMonth(date):00}/{pc.GetDayOfMonth(date):00} {date.Hour:00}:{date.Minute:00}:{date.Second:00}"; + } + + private static readonly string[] Pn = { "۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹" }; + private static readonly string[] En = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + + public static string ToEnglishNumber(this string strNum) + { + var cash = strNum; + for (var i = 0; i < 10; i++) + cash = cash.Replace(Pn[i], En[i]); + return cash; + } + + public static string ToPersianNumber(this int intNum) + { + var chash = intNum.ToString(); + for (var i = 0; i < 10; i++) + chash = chash.Replace(En[i], Pn[i]); + return chash; + } + + public static DateTime? FromFarsiDate(this string InDate) + { + if (string.IsNullOrEmpty(InDate)) + return null; + + var spited = InDate.Split('/'); + if (spited.Length < 3) + return null; + + if (!int.TryParse(spited[0].ToEnglishNumber(), out var year)) + return null; + + if (!int.TryParse(spited[1].ToEnglishNumber(), out var month)) + return null; + + if (!int.TryParse(spited[2].ToEnglishNumber(), out var day)) + return null; + var c = new PersianCalendar(); + return c.ToDateTime(year, month, day, 0, 0, 0, 0); + } + + + public static DateTime ToGeorgianDateTime(this string persianDate) + { + try + { + persianDate = persianDate.ToEnglishNumber(); + var year = Convert.ToInt32(persianDate.Substring(0, 4)); + var month = Convert.ToInt32(persianDate.Substring(5, 2)); + var day = Convert.ToInt32(persianDate.Substring(8, 2)); + + return new DateTime(year, month, day, new PersianCalendar()); + + + } + catch (Exception e) + { + return new DateTime(3000, 12, 20, new PersianCalendar()); + } + + } + + public static DateTime ToGeorgian(this string persianDate) + { + persianDate = persianDate.ToEnglishNumber(); + var year = Convert.ToInt32(persianDate.Substring(0, 4)); + var month = 01; + var day = 01; + return new DateTime(year, month, day, new PersianCalendar()); + } + public static string ToMoney(this double myMoney) + { + + return myMoney.ToString("N0", CultureInfo.CreateSpecificCulture("fa-ir")); + } + public static string ToMoneyNullable(this double? myMoney) + { + + return myMoney?.ToString("N0", CultureInfo.CreateSpecificCulture("fa-ir")); + } + public static string ToDoubleMoney(this string myMoney) + { + string bb = string.Empty; + + for (int x = 0; x < myMoney.Length; x++) + { + if (char.IsDigit(myMoney[x])) + bb += myMoney[x]; + } + + if (bb.Length > 0) + { + return bb; + } + else + { + return "0"; + } + + + + } + public static double MoneyToDouble(this string myMoney) + { + string bb = string.Empty; + bool isNegative = false; + + try + { + if (!string.IsNullOrWhiteSpace(myMoney)) + { + for (int x = 0; x < myMoney.Length; x++) + { + if (char.IsDigit(myMoney[x])) + { + bb += myMoney[x]; + } + else if (myMoney[x] == '-' && bb.Length == 0) + { + // اگر علامت منفی قبل از اولین عدد آمد، در نظر بگیر + isNegative = true; + } + } + + if (bb.Length > 0) + { + double res = double.Parse(bb); + return isNegative ? -res : res; + } + else + { + return 0; + } + } + else + { + return 0; + } + + } + catch (Exception) + { + + return 0; + } + } + public static string ToFileName(this DateTime date) + { + return $"{date.Year:0000}-{date.Month:00}-{date.Day:00}-{date.Hour:00}-{date.Minute:00}-{date.Second:00}"; + } + + public static string FindeEndOfMonth(this string date) + { + string y2 = string.Empty; + var year = Convert.ToInt32(date.Substring(0, 4)); + var month = Convert.ToInt32(date.Substring(5, 2)); + var YearD = date.Substring(0, 4); + var MonthD = date.Substring(5, 2); + if (month <= 6) + { + y2 = $"{YearD}/{MonthD}/31"; + } + else if (month > 6 && month < 12) + { + y2 = $"{YearD}/{MonthD}/30"; + } + else if (month == 12) + { + switch (year) + { + case 1346: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1350: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1354: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1358: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1362: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1366: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1370: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1375: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1379: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1383: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1387: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1391: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1395: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1399: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1403: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1408: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1412: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1416: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1420: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1424: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1428: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1432: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1436: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1441: + y2 = $"{YearD}/{MonthD}/30"; + break; + case 1445: + y2 = $"{YearD}/{MonthD}/30"; + break; + + default: + y2 = $"{YearD}/{MonthD}/29"; + break; + + } + } + + return y2; + } + + + /// + /// تعداد روزهای سال را برمیگرداند + /// اگر کبیسهد بود سال 366 روزه برمیگرداند + /// اگر کبیسهد نبود سال 365 روزه برمیگرداند + /// + /// + /// + public static int YearTotalDays(this string date) + { + int y2 = 366; + var year = Convert.ToInt32(date.Substring(0, 4)); + + + switch (year) + { + case 1346: + y2 = 367; + break; + case 1350: + y2 = 367; + break; + case 1354: + y2 = 367; + break; + case 1358: + y2 = 367; + break; + case 1362: + y2 = 367; + break; + case 1366: + y2 = 367; + break; + case 1370: + y2 = 367; + break; + case 1375: + y2 = 367; + break; + case 1379: + y2 = 367; + break; + case 1383: + y2 = 367; + break; + case 1387: + y2 = 367; + break; + case 1391: + y2 = 367; + break; + case 1395: + y2 = 367; + break; + case 1399: + y2 = 367; + break; + case 1403: + y2 = 367; + break; + case 1408: + y2 = 367; + break; + case 1412: + y2 = 367; + break; + case 1416: + y2 = 367; + break; + case 1420: + y2 = 367; + break; + case 1424: + y2 = 367; + break; + case 1428: + y2 = 367; + break; + case 1432: + y2 = 367; + break; + case 1436: + y2 = 367; + break; + case 1441: + y2 = 367; + break; + case 1445: + y2 = 367; + break; + + default: + y2 = 366; + break; + + } + + + return y2; + } + + public static int BetweenDateGeorgianToDay(DateTime dateStart, DateTime? dateEnd) + { + DateTime end = DateTime.Now; + if (dateEnd != null) + { + end = (DateTime)dateEnd; + } + return (int)(end - dateStart).TotalDays; + } + + public static string GetMonthByNumber(this string value) + { + + if (value == "01") + { + return "فروردین"; + } + else if (value == "02") + { + return "اردیبهشت"; + } + else if (value == "03") + { + return "خرداد"; + } + else if (value == "04") + { + return "تیر"; + } + else if (value == "05") + { + return "مرداد"; + } + else if (value == "06") + { + return "شهریور"; + } + else if (value == "07") + { + return "مهر"; + } + else if (value == "08") + { + return "آبان"; + } + else if (value == "09") + { + return "آذر"; + } + else if (value == "10") + { + return "دی"; + } + else if (value == "11") + { + return "بهمن"; + } + else + return "اسفند"; + + } + + public static string RestTimeSplit(this string restTime) + { + string result = string.Empty; + + if (restTime?.Length >= 2) + { + result = restTime.Substring(0, 2); + if (result == "00") + result = "0"; + } + else + { + result = "0"; + } + + + return result; + } + + public static string NationalCodeValid(this string nationalCode) + { + try + { + char[] chArray = nationalCode.ToCharArray(); + int[] numArray = new int[chArray.Length]; + var cunt = chArray.Length; + for (int i = 0; i < chArray.Length; i++) + { + numArray[i] = (int)char.GetNumericValue(chArray[i]); + } + + int num2 = numArray[9]; + switch (nationalCode) + { + case "0000000000": + case "1111111111": + case "2222222222": + case "3333333333": + case "4444444444": + case "5555555555": + case "6666666666": + case "7777777777": + case "8888888888": + case "9999999999": + + return "incorrect"; + } + + int num3 = + ((((((((numArray[0] * 10) + (numArray[1] * 9)) + (numArray[2] * 8)) + (numArray[3] * 7)) + + (numArray[4] * 6)) + (numArray[5] * 5)) + (numArray[6] * 4)) + (numArray[7] * 3)) + + (numArray[8] * 2); + int num4 = num3 - ((num3 / 11) * 11); + if ((((num4 == 0) && (num2 == num4)) || ((num4 == 1) && (num2 == 1))) || + ((num4 > 1) && (num2 == Math.Abs((int)(num4 - 11)))) && cunt <= 10) + { + return "valid"; + } + else + { + return "invalid"; + } + } + catch (Exception) + { + return "lessThan10"; + + } + + } + public static string RestTimeMinSplit(this string restTime) + { + string result = string.Empty; + + if (restTime?.Length > 2) + { + result = restTime.Substring(3, 2); + if (result == "00") + result = "0"; + + } + else + { + result = "0"; + } + + + return result; + } + + public static List ExtractNumbers(this string input) + { + List numbers = new List(); + string pattern = @"\d+"; // Matches one or more digits + + MatchCollection matches = Regex.Matches(input, pattern); + + foreach (Match match in matches) + { + if (long.TryParse(match.Value, out long number)) + { + numbers.Add(number); + } + } + + return numbers; + } + public static int ExtractIntNumbers(this string input) + { + int numbers = 0; + string num = ""; + string pattern = @"\d+"; // Matches one or more digits + + MatchCollection matches = Regex.Matches(input, pattern); + + foreach (Match match in matches) + { + if (int.TryParse(match.Value, out int number)) + { + num += $"{number}"; + } + } + + try + { + numbers = Convert.ToInt32(num); + } + catch (Exception e) + { + return 0; + } + + return numbers; + } + public static string ToFarsiMonthByNumber(this string value) + { + if (value == "") return ""; + string result = ""; + switch (value) + { + case "1": + case "01": + result = "فروردین"; + break; + case "2": + case "02": + result = "اردیبهشت"; + break; + case "3": + case "03": + result = "خرداد"; + break; + case "4": + case "04": + result = "تیر"; + break; + case "5": + case "05": + result = "مرداد"; + break; + case "6": + case "06": + result = "شهریور"; + break; + case "7": + case "07": + result = "مهر"; + break; + case "8": + case "08": + result = "آبان"; + break; + case "9": + case "09": + result = "آذر"; + break; + case "10": + result = "دی"; + break; + case "11": + result = "بهمن"; + break; + case "12": + result = "اسفند"; + break; + default: + result = ""; + break; + } + + return result; + } + public static string ToFarsiMonthByIntNumber(this int value) + { + if (value == 0) return ""; + string result = ""; + switch (value) + { + case 1: + result = "فروردین"; + break; + case 2: + result = "اردیبهشت"; + break; + case 3: + result = "خرداد"; + break; + case 4: + result = "تیر"; + break; + case 5: + result = "مرداد"; + break; + case 6: + result = "شهریور"; + break; + case 7: + result = "مهر"; + break; + case 8: + result = "آبان"; + break; + case 9: + result = "آذر"; + break; + case 10: + result = "دی"; + break; + case 11: + result = "بهمن"; + break; + case 12: + result = "اسفند"; + break; + default: + result = ""; + break; + } + + return result; + } + + #region Vafa + public static string ToFarsiWithoutYear(this DateTime date) + { + if (date == new DateTime()) return ""; + var pc = new PersianCalendar(); + return $"{pc.GetMonth(date):00}/{pc.GetDayOfMonth(date):00}"; + } + public static int ToMonthByStringValue(this string value) + { + if (value == "") return 0; + int result = 0; + switch (value) + { + case "فروردین": + result = 1; + break; + case "اردیبهشت": + result = 2; + break; + case "خرداد": + result = 3; + break; + case "تیر": + result = 4; + break; + case "مرداد": + result = 5; + break; + case "شهریور": + result = 6; + break; + case "مهر": + result = 7; + break; + case "آبان": + result = 8; + break; + case "آذر": + result = 9; + break; + case "دی": + result = 10; + break; + case "بهمن": + result = 11; + break; + case "اسفند": + result = 12; + break; + default: + result = 0; + break; + } + + return result; + } + + public static string ColorPercent(this int value) + { + string color = ""; + + var redDark = "#B91C1C"; + var redLight = "#EF4444"; + + var orangeDark = "#F59E0B"; + var orangeLight = "#FBBF24"; + + var limeDark = "#81CB0F"; + var limeLight = "#A3E635"; + + switch (value) + { + case <= 16: + color = redDark; + break; + case <= 33: + color = redLight; + break; + case <= 49: + color = orangeDark; + break; + case <= 66: + color = orangeLight; + break; + case <= 83: + color = limeLight; + break; + case <= 100: + color = limeDark; + break; + default: + color = ""; + break; + } + return color; + } + + public static double RoundMoney(this double value) + { + var valueLength = (((int)value).ToString()).Length; + var checkZero = (((int)value).ToString()).Substring(1, 1); + int digitValue = 0; + int digitLentgh = 0; + int d = 0; + if ((int)value == 10499677) + { + Console.WriteLine(90); + } + switch (valueLength) + { + case 6: + digitValue = 5000; + digitLentgh = 100000; + d = 1000; + break; + case 7: + digitValue = 50000; + digitLentgh = 1000000; + d = 10000; + break; + case 8: + digitValue = checkZero == "0" ? 50000 : 500000; + digitLentgh = checkZero == "0" ? 100000 : 10000000; + d = 100000; + break; + + } + + int result = 0; + int rightDigits = (int)(value % digitLentgh); + + + //if (rightDigits < digitValue) + //{ + // result = (int)(value / d) * d; + //} + //else + //{ + // result = (int)(value / d + 1) * d; + //} + result = (int)(value / d + 1) * d; + return result; + } + + public static string ToMoneyToman(this double myMoney) + { + myMoney = myMoney / 10; + return myMoney.ToString("N0", CultureInfo.CreateSpecificCulture("fa-ir")); + } + + public static PersianDateTime ToPersianDateTime(this DateTime date) + { + var persianDate = date.ToFarsi(); + var year = Convert.ToInt32(persianDate.Substring(0, 4)); + var month = Convert.ToInt32(persianDate.Substring(5, 2)); + var day = Convert.ToInt32(persianDate.Substring(8, 2)); + return new PersianDateTime(year, month, day); + } + + //public static string ResizeImage(string imagePath, int width, int height) + //{ + // using (var srcImage = Image.FromFile(imagePath)) + // { + // var newImage = new Bitmap(width, height); + // using (var graphics = Graphics.FromImage(newImage)) + // { + // graphics.CompositingQuality = CompositingQuality.HighSpeed; + // graphics.InterpolationMode = InterpolationMode.Bicubic; + // graphics.SmoothingMode = SmoothingMode.HighSpeed; + // graphics.DrawImage(srcImage, 0, 0, width, height); + // } + + // using (var memoryStream = new MemoryStream()) + // { + // newImage.Save(memoryStream, ImageFormat.Jpeg); + // return Convert.ToBase64String(memoryStream.ToArray()); + // } + // } + //} + + public static PersianDateTime ToFirstDayOfNextMonth(this DateTime date) + { + var pc = new PersianCalendar(); + var year = pc.GetYear(date); + var month = pc.GetMonth(date); + + if (month == 12) + { + year += 1; + month = 1; + } + else + { + month += 1; + } + + return new PersianDateTime(year, month, 1); + + } + #endregion + + #region Safa + + public static string GetContentTypeImage(string extension) + { + if (!extension.StartsWith(".")) + { + extension = "." + extension; + } + + return extension.ToLower() switch + { + ".jpg" => "image/jpeg", + ".jpeg" => "image/jpeg", + ".png" => "image/png", + ".gif" => "image/gif", + ".bmp" => "image/bmp", + ".svg" => "image/svg+xml", + ".ico" => "image/x-icon", + _ => "", + }; + } + + public static string GetContentType(string extension) + { + + // Ensure the extension starts with a dot + if (!extension.StartsWith(".")) + { + extension = "." + extension; + } + + // Use switch expression to return the appropriate content type + return extension.ToLower() switch + { + ".txt" => "text/plain", + ".htm" => "text/html", + ".html" => "text/html", + ".css" => "text/css", + ".js" => "application/javascript", + ".json" => "application/json", + ".xml" => "application/xml", + ".pdf" => "application/pdf", + ".zip" => "application/zip", + ".rar" => "application/x-rar-compressed", + ".tar" => "application/x-tar", + ".mp3" => "audio/mpeg", + ".wav" => "audio/wav", + ".mp4" => "video/mp4", + ".avi" => "video/x-msvideo", + ".doc" => "application/msword", + ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ".xls" => "application/vnd.ms-excel", + ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ".ppt" => "application/vnd.ms-powerpoint", + ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", + _ => "application/octet-stream", + }; + } + + #endregion + public static string ConvertToEnglish(this string value) + { + if (string.IsNullOrEmpty(value)) + return value; + + string EnglishNumbers = ""; + for (int i = 0; i < value.Length; i++) + { + if (Char.IsDigit(value[i])) + { + EnglishNumbers += char.GetNumericValue(value, i); + } + else + { + EnglishNumbers += value[i].ToString(); + } + } + return EnglishNumbers; + } + + public static DateTime ExtractTimeFromDbbackup(this string value) + { + DateTime dateTime = new DateTime(); + var parts = value.Split('-'); + if (parts.Length >= 4 && parts[1].Length == 4 && parts[2].Length == 2 && parts[3].Length == 2 && parts[4].Length == 2 && parts[5].Length >= 2) + { + var part5 = parts[5].Substring(0, 2); + + + try + { + PersianCalendar pc = new PersianCalendar(); + dateTime = pc.ToDateTime(int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]), int.Parse(parts[4]), int.Parse(part5), 0, 0, 0); + + } + catch (Exception e) + { + + + } + + } + //var year = value.Substring(10, 4); + //var month = value.Substring(15, 2); + //var day = value.Substring(18, 2); + //var persianDate = year + "/" + month + "/" + day; + //var georgianDate = persianDate.ToGeorgianDateTime(); + //var hourString = value.Substring(21, 2); + //int hour = hourString.ExtractIntNumbers(); + + //var result = new DateTime(georgianDate.Year, georgianDate.Month, georgianDate.Day, hour, 1, 1); + return dateTime; + } + + public static DateTime ExtractTimeFromInsurancebackup(this string value) + { + var year = value.Substring(14, 4); + var month = value.Substring(19, 2); + var day = value.Substring(22, 2); + var persianDate = year + "/" + month + "/" + day; + var georgianDate = persianDate.ToGeorgianDateTime(); + var hourString = value.Substring(25, 2); + int hour = hourString.ExtractIntNumbers(); + + var result = new DateTime(georgianDate.Year, georgianDate.Month, georgianDate.Day, hour, 1, 1); + return result; + } + + public static string FindeEndOfYear(this string date) + { + var year = Convert.ToInt32(date.Substring(0, 4)); + var month = Convert.ToInt32(date.Substring(5, 2)); + var day = Convert.ToInt32(date.Substring(8, 2)); + + var start = new PersianDateTime(year, month, day); + var startAddYear = start.AddMonths(11); + var monthStr = $"{startAddYear.Month}"; + if (monthStr.Length < 2) + monthStr = $"0{monthStr}"; + var lastMonth = $"{startAddYear.Year}/{monthStr}/01"; + var end = lastMonth.FindeEndOfMonth(); + return end; + + } + + public static string CalculateLeaveHoursAndDays(string paidLeaveType, string leaveHourses) + { + string leaveHoursResult = ""; + if (paidLeaveType == "ساعتی") + { + var leaveH = TimeSpan.Parse(leaveHourses); + var hours = (int)leaveH.TotalHours; + var minutes = (int)leaveH.TotalMinutes % 60; + if (hours > 0 && minutes > 0) + { + leaveHoursResult = hours + " ساعت و " + minutes + " دقیقه"; + } + else if (hours > 0 && minutes == 0) + { + leaveHoursResult = hours + " ساعت"; + } + else if (hours == 0 && minutes > 0) + { + leaveHoursResult = minutes + " دقیقه"; + } + } + else + { + leaveHoursResult = leaveHourses + " روز"; + } + + return leaveHoursResult; + } + + public static string ComputationOfHoursAndMinutes(double data) + { + int hours = (int)Math.Floor(data); + double remaining = data - hours; + int minutes = (int)(remaining * 60); + + string result; + if (minutes == 0) + { + result = hours + " س"; + } + else + { + result = hours + " س " + minutes + " د"; + } + + return result; + } + + public static bool CheckValidHm(string input) + { + if (string.IsNullOrWhiteSpace(input)) + return true; + string pattern = @"^([2][0-3]|[1][0-9]|[0-9]|[0][0-9])([:][0-5][0-9])$"; + + var match = Regex.Match(input, pattern); + if (!match.Success) + return false; + return true; + } + + /// + /// چک میکند که در دو شیفت استاتیک تداخل زمانی وجود دارد یا خیر + /// چک میکند که آیا ساعات وارد شده ولید هستند یا خیر + /// + /// + /// + /// + /// + /// + public static bool InterferenceTime(string start1, string end1, string start2, string end2) + { + if (!CheckValidHm(start1)) + return true; + + if (!CheckValidHm(end1)) + return true; + + if (!CheckValidHm(start2)) + return true; + + if (!CheckValidHm(end2)) + return true; + + //اگه دو شیفت نبود + if (string.IsNullOrWhiteSpace(start1) || string.IsNullOrWhiteSpace(start2)) + return false; + + + try + { + var start1Gr = Convert.ToDateTime(start1); + var end1Gr = Convert.ToDateTime(end1); + + if (end1Gr < start1Gr) + end1Gr = end1Gr.AddDays(1); + + var start2Gr = Convert.ToDateTime(start2); + var end2Gr = Convert.ToDateTime(end2); + + + start2Gr = new DateTime(end1Gr.Year, end1Gr.Month, end1Gr.Day, start2Gr.Hour, start2Gr.Minute, + start2Gr.Second); + + + end2Gr = new DateTime(end1Gr.Year, end1Gr.Month, end1Gr.Day, end2Gr.Hour, end2Gr.Minute, + end2Gr.Second); + if (end2Gr < start2Gr) + end2Gr = end2Gr.AddDays(1); + + var diff = (end1Gr - start1Gr).Add((end2Gr - start2Gr)); + if (diff > new TimeSpan(24,0,0)) + return true; + + if (start2Gr <= end1Gr) + return true; + + return false; + } + catch (Exception) + { + + return true; + } + + + } + public static DateTime FindFirstDayOfMonthGr(this DateTime date) + { + var pc = new PersianCalendar(); + return ($"{pc.GetYear(date)}/{pc.GetMonth(date):00}/01").ToGeorgianDateTime(); + } + #region Mahan + + + public static bool IsvalidIban(this string iban) + { + return Regex.IsMatch(iban, @"^IR[0-9]{24}$"); + } + public static bool IsValidCardNumber(this string cardNumber) + { + return Regex.IsMatch(cardNumber, @"^[0-9]{16}$"); + } + /// + /// این متد حروف عربی را به فارسی در میاورد. مثال: علي را به علی تبدیل میکند + /// + /// + /// + public static string ToPersian(this string text) + { + var res = ""; + foreach (var @char in text) + { + + if (@char == char.Parse("ي")) + res += "ی"; + else if (@char == char.Parse("ك")) + res += "ک"; + else + res += @char; + } + return res; + } + + /// + /// این متد سعی میکند رشته را به تاریخ برگرداند و یک بول و دیت تایم برمیگرداند + /// + /// تاریخ شمسی + /// تاریخ + /// + public static bool TryToGeorgianDateTime(this string persianDate, out DateTime georgianDateTime) + { + if (string.IsNullOrWhiteSpace(persianDate)) + { + georgianDateTime = new DateTime(3000, 12, 20, new PersianCalendar()); + return false; + } + persianDate = persianDate.ToEnglishNumber(); + try + { + var year = Convert.ToInt32(persianDate.Substring(0, 4)); + var month = Convert.ToInt32(persianDate.Substring(5, 2)); + var day = Convert.ToInt32(persianDate.Substring(8, 2)); + + georgianDateTime = new DateTime(year, month, day, new PersianCalendar()); + return true; + } + catch + { + georgianDateTime = new DateTime(3000, 12, 20, new PersianCalendar()); + return false; + } + } + + public static string FindFirstDayOfMonth(this DateTime date) + { + var pc = new PersianCalendar(); + return $"{pc.GetYear(date)}/{pc.GetMonth(date):00}/01"; + } + public static string ToFarsiDuration(this string date) + { + var today = DateTime.Now.ToFarsi(); + var year = Convert.ToInt32(today.Substring(0, 4)); + var month = Convert.ToInt32(today.Substring(5, 2)); + var day = Convert.ToInt32(today.Substring(8, 2)); + var todayPersianDate = new PersianDateTime(year, month, day); + + var planYear = Convert.ToInt32(date.Substring(0, 4)); + var planMonth = Convert.ToInt32(date.Substring(5, 2)); + var planDay = Convert.ToInt32(date.Substring(8, 2)); + var planPersianDate = new PersianDateTime(planYear, planMonth, planDay); + + if (planPersianDate > todayPersianDate) + { + var countDay = 0; + var counMonth = 0; + var nextMonth = new PersianDateTime(todayPersianDate).AddMonths(1); + for (var start = todayPersianDate; start <= planPersianDate; start = start.AddDays(1)) + { + countDay++; + if (start == nextMonth) + { + counMonth++; + nextMonth = new PersianDateTime(start).AddMonths(1); + countDay = 0; + } + } + + if (counMonth > 0) + { + if (countDay == 0) + { + return $"{counMonth} ماه"; + } + return $"{counMonth}ماه و {countDay} روز"; + } + else + { + return $"{countDay}روز"; + } + } + else + { + return ""; + } + } + + public static string ToFarsiDuration2(this string date) + { + var persianCalendar = new System.Globalization.PersianCalendar(); + var today = DateTime.Now; + + // Convert today's Gregorian date to Persian date + var todayYear = persianCalendar.GetYear(today); + var todayMonth = persianCalendar.GetMonth(today); + var todayDay = persianCalendar.GetDayOfMonth(today); + + var todayPersianDate = new DateTime(todayYear, todayMonth, todayDay, persianCalendar); + + // Parse the target Persian date from the input string + var planYear = int.Parse(date.Substring(0, 4)); + var planMonth = int.Parse(date.Substring(5, 2)); + var planDay = int.Parse(date.Substring(8, 2)); + + var planPersianDate = new DateTime(planYear, planMonth, planDay, persianCalendar); + + if (planPersianDate > todayPersianDate) + { + // Calculate the exact difference in years, months, and days + int yearDifference = planYear - todayYear; + int monthDifference = planMonth - todayMonth; + int dayDifference = planDay - todayDay; + + if (dayDifference < 0) + { + monthDifference--; + dayDifference += persianCalendar.GetDaysInMonth(todayYear, todayMonth); + } + + if (monthDifference < 0) + { + yearDifference--; + monthDifference += 12; + } + + // Construct the duration string + var duration = ""; + if (yearDifference > 0) + { + duration += $"{yearDifference} سال "; + } + + if (monthDifference > 0) + { + duration += $"{monthDifference} ماه "; + } + + if (dayDifference > 0) + { + duration += $"{dayDifference} روز"; + } + + return duration.Trim(); + } + else + { + return ""; + } + } + //public static string SerializeToBson(object obj) + //{ + // using var memoryStream = new MemoryStream(); + // using (BsonDataWriter bsonWriter = new BsonDataWriter(memoryStream)) + // { + // JsonSerializer serializer = new JsonSerializer(); + // serializer.Serialize(bsonWriter, obj); + // } + // byte[] bsonData = memoryStream.ToArray(); + // return Convert.ToBase64String(bsonData); + //} + ////بیسان هایی که بصورت لیست بودند استخراج میشود + //public static List DeserializeFromBsonList(string base64Data) + //{ + // byte[] data = Convert.FromBase64String(base64Data); + + // using MemoryStream memoryStream = new MemoryStream(data); + // using BsonDataReader reader = new BsonDataReader(memoryStream); + // reader.ReadRootValueAsArray = true; + // JsonSerializer serializer = new JsonSerializer(); + // return serializer.Deserialize>(reader); + //} + ////بیسان هایی که بصورت تکی بودند استخراج میشود + //public static T DeserializeFromBson(string base64Data) + //{ + // byte[] bsonData = Convert.FromBase64String(base64Data); + // using MemoryStream memoryStream = new MemoryStream(bsonData); + // using BsonDataReader bsonReader = new BsonDataReader(memoryStream); + // JsonSerializer serializer = new JsonSerializer(); + // return serializer.Deserialize(bsonReader); + //} + + //public static TimeOnly CalculateOffset(ICollection shiftDetailsRegularShifts) + //{ + // if (!shiftDetailsRegularShifts.Any()) + // { + // return TimeOnly.MinValue; + // } + // var date = new DateOnly(); + // var firstStartShift = new DateTime(date, shiftDetailsRegularShifts.MinBy(x => x.Placement).StartTime); + // var lastEndShift = new DateTime(date, shiftDetailsRegularShifts.MaxBy(x => x.Placement).EndTime); + // if (lastEndShift > firstStartShift) + // firstStartShift = firstStartShift.AddDays(1); + // var offSet = (firstStartShift - lastEndShift).Divide(2); + // return TimeOnly.FromDateTime(lastEndShift.Add(offSet)); + //} + public static DateTime GetNextDayOfWeek(this DateTime date, DayOfWeek dayOfWeek) + { + int numberOfNextDayOfWeek = ((int)dayOfWeek - (int)date.DayOfWeek + 7) % 7; + return date.AddDays(numberOfNextDayOfWeek == 0 ? 7 : numberOfNextDayOfWeek); + } + + + //این متد آخر همان روز را به صورت دیت تایم برمیگرداند + public static DateTime ToEndDayOfGeorgianDateTime(this string persianDate) + { + persianDate = persianDate.ToEnglishNumber(); + try + { + var year = Convert.ToInt32(persianDate.Substring(0, 4)); + var month = Convert.ToInt32(persianDate.Substring(5, 2)); + var day = Convert.ToInt32(persianDate.Substring(8, 2)); + + var res = new DateTime(year, month, day, new PersianCalendar()); + res = res.AddHours(23); + res = res.AddMinutes(59); + res = res.AddSeconds(59); + + return res; + + } + catch (Exception e) + { + return new DateTime(3000, 12, 20, new PersianCalendar()); + } + + } + //تبدیل به تاریخ با ساعت + public static DateTime ToGeorgianDateWithTime(this string persianDate, string persianTime) + { + persianDate = persianDate.ToEnglishNumber(); + try + { + var year = Convert.ToInt32(persianDate.Substring(0, 4)); + var month = Convert.ToInt32(persianDate.Substring(5, 2)); + var day = Convert.ToInt32(persianDate.Substring(8, 2)); + + + + var hour = int.Parse(persianTime.Substring(0, 2)); + var minute = int.Parse(persianTime.Substring(3, 2)); + + var res = new DateTime(year, month, day, new PersianCalendar()); + res = res.AddHours(hour); + res = res.AddMinutes(minute); + return res; + + } + catch (Exception e) + { + return new DateTime(3000, 12, 20, new PersianCalendar()); + } + + } + + public static string DayOfWeeKToPersian(this DayOfWeek dayOfWeek) + { + return dayOfWeek switch + { + DayOfWeek.Friday => "جمعه", + DayOfWeek.Monday => "دوشنبه", + DayOfWeek.Saturday => "شنبه", + DayOfWeek.Sunday => "یکشنبه", + DayOfWeek.Thursday => "پنجشنبه", + DayOfWeek.Tuesday => "سه شنبه", + DayOfWeek.Wednesday => "چهارشنبه", + _ => "" + }; + } + + public static bool IsInvalidDateTime(this DateTime date) + { + return date == new DateTime(3000, 12, 20, new PersianCalendar()); + + } + + + + + + #endregion + + #region Pooya + /// + /// محاسبه روز های هر ماه شمسی + /// + /// تاریخ روزی از ماه + public static int CountPersianMonthDays(this DateTime date) + { + DateTime currentMonthDate, nextMonthDate; + currentMonthDate = date.FindFirstDayOfMonth().ToGeorgianDateTime(); + FindFirstDayOfNextMonth(date, out nextMonthDate); + + return ((int)(nextMonthDate.Date - currentMonthDate.Date).TotalDays); + } + + public static string FindFirstDayOfNextMonth(this DateTime date, out DateTime nextMonthDate) + { + var dateFa = date.ToFarsi(); + int year = Convert.ToInt32(dateFa.Substring(0, 4)); + int month = Convert.ToInt32(dateFa.Substring(5, 2)); + int nextMonth; + int nextMonthYear; + if (month == 12) + { + nextMonthYear = year + 1; + nextMonth = 1; + } + else + { + nextMonthYear = year; + nextMonth = month + 1; + } + nextMonthDate = new DateTime(nextMonthYear, nextMonth, 1, new PersianCalendar()); + return $"{nextMonthYear:0000}/{nextMonth:00}/01"; + } + + + /// + /// اضافه یا کم کردن ماه، توجه داشته باشید خروجی متد همیشه یکم ماه می باشد + /// + public static string AddMonthsFa(this DateTime date, int count, out DateTime result) + { + var dateFa = date.ToFarsi(); + int year = Convert.ToInt32(dateFa.Substring(0, 4)); + int month = Convert.ToInt32(dateFa.Substring(5, 2)); + + int newMonth; + int newYear; + + //add operation + if (count >= 0) + { + newYear = year; + while (month + count > 12) + { + newYear += 1; + count -= 12; + } + newMonth = month + count; + + } + + //subtract operation + else + { + newYear = year; + while (month + count < 1) + { + newYear -= 1; + count += 12; + } + newMonth = month + count; + } + result = new DateTime(newYear, newMonth, 1, new PersianCalendar()); + return $"{newYear:0000}/{newMonth:00}/01"; + + } + + + public static DateTime GetUndefinedDateTime() + { + return new DateTime(2121, 03, 21); + } + + public static bool IsDateUndefined(this DateTime date) + { + return date == new DateTime(2121, 03, 21); + } + public static string ToFarsiHoursAndMinutes(int hours, int minutes, string emptyValue = "") + { + + string message = emptyValue; + if (hours > 0 && minutes > 0) + { + + message = hours + " " + "ساعت و" + " " + minutes + " " + "دقیقه"; + } + else if (hours > 0 && minutes == 0) + { + + message = hours + " " + "ساعت "; + } + else if (hours == 0 && minutes > 0) + { + + message = minutes + " " + "دقیقه"; + } + + return message; + } + /// + /// تبدیل بازه زمانی اینتیجر به متن ساعت و دقسقه + /// + /// + /// + /// + public static string ConvertIntDurationToHoursAndMinutes(this int duration, string emptyValue = "") + { + var minutes = duration % 60; + var hours = duration / 60; + + string message = emptyValue; + if (hours > 0 && minutes > 0) + { + + message = hours + " " + "ساعت و" + " " + minutes + " " + "دقیقه"; + } + else if (hours > 0 && minutes == 0) + { + + message = hours + " " + "ساعت "; + } + else if (hours == 0 && minutes > 0) + { + + message = minutes + " " + "دقیقه"; + } + + return message; + } + + public static string ToFarsiHoursAndMinutes(this TimeSpan timeSpan, string emptyValue = "") + { + var hours = (int)timeSpan.TotalHours; + var minutes = timeSpan.Minutes; + string message = emptyValue; + if (hours > 0 && minutes > 0) + { + + message = hours + " " + "ساعت و" + " " + minutes + " " + "دقیقه"; + } + else if (hours > 0 && minutes == 0) + { + + message = hours + " " + "ساعت "; + } + else if (hours == 0 && minutes > 0) + { + + message = minutes + " " + "دقیقه"; + } + + return message; + } + public static string ToFarsiDaysAndHoursAndMinutes(this TimeSpan timeSpan, string emptyValue = "") + { + var hours = (int)timeSpan.TotalHours; + var minutes = timeSpan.Minutes; + var days = hours / 24; + hours = hours % 24; + string message = ""; + + if (days > 0) + message += days + " " + "روز"; + if (hours > 0) + if (message == "") + message += hours + " " + "ساعت"; + else + message += " و " + hours + " " + "ساعت"; + if (minutes > 0) + if (message == "") + message += minutes + " " + "دقیقه"; + else + message += " و " + minutes + " " + "دقیقه"; + + if (message == "") + message = emptyValue; + return message; + } + + public static bool ArePropertiesEqual(this T obj1, T obj2) + { + // If either object is null, they can't be equal + if (obj1 == null || obj2 == null) + return false; + + // Get the type of the objects + var type = typeof(T); + + // Iterate through each property + foreach (var property in type.GetProperties()) + { + // Get the values of the current property for both objects + var value1 = property.GetValue(obj1); + var value2 = property.GetValue(obj2); + + // If both values are null, they are considered equal + if (value1 == null && value2 == null) + continue; + + // If one value is null, but the other isn't, they are not equal + if (value1 == null || value2 == null) + return false; + + // If values are not equal, return false + if (!value1.Equals(value2)) + return false; + } + + // If all properties are equal, return true + return true; + } + + #endregion + + #region Davoodi + + //public static List GetDaysBetweenDateGeorgian(DateTime startDate, DateTime? endDate) + //{ + // var days = new List(); + + // if (endDate == null) + // endDate = DateTime.Now; + + // var persianStartDate = new MD.PersianDateTime.Standard.PersianDateTime(startDate); + // var persianEndDate = new MD.PersianDateTime.Standard.PersianDateTime(endDate); + + + // while (persianEndDate - persianStartDate >= TimeSpan.FromDays(0)) + // { + // days.Add(persianStartDate.ToShortDateString()); + // persianStartDate = persianStartDate.AddDays(1); + // } + + // return days; + //} + + public static int GetWorkingDaysDifference(DateTime? fromDate, DateTime? toDate) + { + //var workingDays = PersianDateExtensions.GetWorkingDays(new PersianDateTime(fromDate.ToFarsi()), new PersianDateTime(toDate.ToFarsi()), true); + var workingDays = PersianDateExtensions.GetWorkingDays((DateTime)fromDate, (DateTime)toDate, true); + + + if (fromDate > toDate) + workingDays *= -1; + + + return workingDays; + } + + + + #endregion +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/ValueObject.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/ValueObject.cs new file mode 100644 index 00000000..9a486daa --- /dev/null +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/ValueObject.cs @@ -0,0 +1,38 @@ +namespace GozareshgirProgramManager.Domain._Common; + +public abstract class ValueObject +{ + protected abstract IEnumerable GetEqualityComponents(); + + public override bool Equals(object? obj) + { + if (obj == null || obj.GetType() != GetType()) + return false; + + var other = (ValueObject)obj; + return GetEqualityComponents().SequenceEqual(other.GetEqualityComponents()); + } + + public override int GetHashCode() + { + return GetEqualityComponents() + .Select(x => x?.GetHashCode() ?? 0) + .Aggregate((x, y) => x ^ y); + } + + public static bool operator ==(ValueObject? left, ValueObject? right) + { + if (left is null && right is null) + return true; + + if (left is null || right is null) + return false; + + return left.Equals(right); + } + + public static bool operator !=(ValueObject? left, ValueObject? right) + { + return !(left == right); + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/DependencyInjection.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/DependencyInjection.cs new file mode 100644 index 00000000..a17403b0 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/DependencyInjection.cs @@ -0,0 +1,105 @@ + + + +using GozareshgirProgramManager.Application._Common.Behaviors; +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.CustomerAgg.Repositories; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using GozareshgirProgramManager.Domain.RoleAgg.Repositories; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Repositories; +using GozareshgirProgramManager.Domain.SkillAgg.Repositories; +using GozareshgirProgramManager.Domain.UserAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using GozareshgirProgramManager.Infrastructure.Persistence.Repositories; +using GozareshgirProgramManager.Infrastructure.Services.Authentication; +using MediatR; +using FluentValidation; +using GozareshgirProgramManager.Domain.CheckoutAgg.Repositories; +using GozareshgirProgramManager.Domain.RoleAgg.Repositories; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Repositories; +using GozareshgirProgramManager.Domain.SkillAgg.Repositories; + +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace GozareshgirProgramManager.Infrastructure; + +public static class DependencyInjection +{ + public static IServiceCollection AddProgramManagerInfrastructure( + this IServiceCollection services, + IConfiguration configuration) + { + // DbContext + services.AddDbContext(options => + options.UseSqlServer( + configuration.GetConnectionString("ProgramManagerDb"), + b => b.MigrationsAssembly(typeof(ProgramManagerDbContext).Assembly.FullName))); + + // Register IAppDbContext + services.AddScoped(provider => + provider.GetRequiredService()); + + + + #region GozareshgirDbContext + + services.AddDbContext(x => x.UseSqlServer(configuration.GetConnectionString("GozareshgirDb"))); + + services.AddScoped(provider => + provider.GetRequiredService()); + #endregion + + // Unit of Work + services.AddScoped(); + + //Users + services.AddScoped(); + + //Roles + services.AddScoped(); + + //WorkingHours + services.AddScoped(); + + //Checkout + services.AddScoped(); + + // Repositories + services.AddScoped(); + + // Legacy Project repositories + services.AddScoped(); + + // New Hierarchy repositories + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + services.AddScoped(); + + services.AddScoped(); + + // JWT Settings + services.Configure(configuration.GetSection("JwtSettings")); + + // Authentication Services + services.AddScoped(); + services.AddScoped(); + + + + + // MediatR Validation Behavior + services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>)); + + + return services; + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/GozareshgirProgramManager.Infrastructure.csproj b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/GozareshgirProgramManager.Infrastructure.csproj new file mode 100644 index 00000000..57ba7bdb --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/GozareshgirProgramManager.Infrastructure.csproj @@ -0,0 +1,22 @@ + + + + net10.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251119114157_Initial.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251119114157_Initial.Designer.cs new file mode 100644 index 00000000..45ff290c --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251119114157_Initial.Designer.cs @@ -0,0 +1,393 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251119114157_Initial")] + partial class Initial + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.22") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.AdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Reason") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("TaskSectionId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TaskSectionId"); + + b.ToTable("AdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Projects", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("AssignedUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("HasAssignmentOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("HasTimeOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("Level") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Level"); + + b.HasIndex("ParentId"); + + b.HasIndex("Level", "AssignedUserId"); + + b.ToTable("ProjectNodes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectPhases", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("ProjectTasks", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialEstimatedHours") + .HasColumnType("time"); + + b.Property("ProjectTaskId") + .HasColumnType("uniqueidentifier"); + + b.Property("SectionType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskNodeId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ProjectTaskId"); + + b.HasIndex("TaskNodeId"); + + b.ToTable("TaskSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.AdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("TaskSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("Phases") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "ProjectPhase") + .WithMany("Tasks") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectPhase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", null) + .WithMany("Sections") + .HasForeignKey("ProjectTaskId"); + + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "TaskNode") + .WithMany("Sections") + .HasForeignKey("TaskNodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TaskNode"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Navigation("Phases"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Navigation("Children"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251119114157_Initial.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251119114157_Initial.cs new file mode 100644 index 00000000..546082b6 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251119114157_Initial.cs @@ -0,0 +1,262 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class Initial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Customers", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), + Email = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Customers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ProjectNodes", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + Level = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + ParentId = table.Column(type: "uniqueidentifier", nullable: true), + AllocatedTime = table.Column(type: "time", nullable: true), + AssignedUserId = table.Column(type: "bigint", nullable: true), + HasTimeOverride = table.Column(type: "bit", nullable: false, defaultValue: false), + HasAssignmentOverride = table.Column(type: "bit", nullable: false, defaultValue: false), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectNodes", x => x.Id); + table.ForeignKey( + name: "FK_ProjectNodes_ProjectNodes_ParentId", + column: x => x.ParentId, + principalTable: "ProjectNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Projects", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Projects", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ProjectPhases", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + ProjectId = table.Column(type: "uniqueidentifier", nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectPhases", x => x.Id); + table.ForeignKey( + name: "FK_ProjectPhases_Projects_ProjectId", + column: x => x.ProjectId, + principalTable: "Projects", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ProjectTasks", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + PhaseId = table.Column(type: "uniqueidentifier", nullable: false), + Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectTasks", x => x.Id); + table.ForeignKey( + name: "FK_ProjectTasks_ProjectPhases_PhaseId", + column: x => x.PhaseId, + principalTable: "ProjectPhases", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TaskSections", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TaskNodeId = table.Column(type: "uniqueidentifier", nullable: false), + SectionType = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + InitialEstimatedHours = table.Column(type: "time", nullable: false), + Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + CurrentAssignedUserId = table.Column(type: "bigint", nullable: true), + AllocatedTime = table.Column(type: "time", nullable: true), + ProjectTaskId = table.Column(type: "uniqueidentifier", nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TaskSections", x => x.Id); + table.ForeignKey( + name: "FK_TaskSections_ProjectNodes_TaskNodeId", + column: x => x.TaskNodeId, + principalTable: "ProjectNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_TaskSections_ProjectTasks_ProjectTaskId", + column: x => x.ProjectTaskId, + principalTable: "ProjectTasks", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "AdditionalTimes", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Hours = table.Column(type: "nvarchar(30)", maxLength: 30, nullable: false), + Reason = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + AddedByUserId = table.Column(type: "bigint", nullable: true), + AddedAt = table.Column(type: "datetime2", nullable: false), + TaskSectionId = table.Column(type: "uniqueidentifier", nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AdditionalTimes", x => x.Id); + table.ForeignKey( + name: "FK_AdditionalTimes_TaskSections_TaskSectionId", + column: x => x.TaskSectionId, + principalTable: "TaskSections", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "TaskSectionActivities", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + SectionId = table.Column(type: "uniqueidentifier", nullable: false), + UserId = table.Column(type: "bigint", nullable: false), + StartDate = table.Column(type: "datetime2", nullable: false), + EndDate = table.Column(type: "datetime2", nullable: true), + Notes = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + EndNotes = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TaskSectionActivities", x => x.Id); + table.ForeignKey( + name: "FK_TaskSectionActivities_TaskSections_SectionId", + column: x => x.SectionId, + principalTable: "TaskSections", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AdditionalTimes_TaskSectionId", + table: "AdditionalTimes", + column: "TaskSectionId"); + + migrationBuilder.CreateIndex( + name: "IX_ProjectNodes_Level", + table: "ProjectNodes", + column: "Level"); + + migrationBuilder.CreateIndex( + name: "IX_ProjectNodes_Level_AssignedUserId", + table: "ProjectNodes", + columns: new[] { "Level", "AssignedUserId" }); + + migrationBuilder.CreateIndex( + name: "IX_ProjectNodes_ParentId", + table: "ProjectNodes", + column: "ParentId"); + + migrationBuilder.CreateIndex( + name: "IX_ProjectPhases_ProjectId", + table: "ProjectPhases", + column: "ProjectId"); + + migrationBuilder.CreateIndex( + name: "IX_ProjectTasks_PhaseId", + table: "ProjectTasks", + column: "PhaseId"); + + migrationBuilder.CreateIndex( + name: "IX_TaskSectionActivities_SectionId", + table: "TaskSectionActivities", + column: "SectionId"); + + migrationBuilder.CreateIndex( + name: "IX_TaskSections_ProjectTaskId", + table: "TaskSections", + column: "ProjectTaskId"); + + migrationBuilder.CreateIndex( + name: "IX_TaskSections_TaskNodeId", + table: "TaskSections", + column: "TaskNodeId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AdditionalTimes"); + + migrationBuilder.DropTable( + name: "Customers"); + + migrationBuilder.DropTable( + name: "TaskSectionActivities"); + + migrationBuilder.DropTable( + name: "TaskSections"); + + migrationBuilder.DropTable( + name: "ProjectNodes"); + + migrationBuilder.DropTable( + name: "ProjectTasks"); + + migrationBuilder.DropTable( + name: "ProjectPhases"); + + migrationBuilder.DropTable( + name: "Projects"); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251119152314_ChangeUsertable.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251119152314_ChangeUsertable.Designer.cs new file mode 100644 index 00000000..e78e8c7c --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251119152314_ChangeUsertable.Designer.cs @@ -0,0 +1,320 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251119152314_ChangeUsertable")] + partial class ChangeUsertable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.22") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("AssignedUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("HasAssignmentOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("HasTimeOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("Level") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Level"); + + b.HasIndex("ParentId"); + + b.HasIndex("Level", "AssignedUserId"); + + b.ToTable("ProjectNodes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialEstimatedHours") + .HasColumnType("time"); + + b.Property("SectionType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskNodeId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TaskNodeId"); + + b.ToTable("TaskSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("AdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "TaskNode") + .WithMany("Sections") + .HasForeignKey("TaskNodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TaskNode"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Navigation("Children"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251119152314_ChangeUsertable.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251119152314_ChangeUsertable.cs new file mode 100644 index 00000000..334e7d78 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251119152314_ChangeUsertable.cs @@ -0,0 +1,192 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class ChangeUsertable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_AdditionalTimes_TaskSections_TaskSectionId", + table: "AdditionalTimes"); + + migrationBuilder.DropForeignKey( + name: "FK_TaskSections_ProjectTasks_ProjectTaskId", + table: "TaskSections"); + + migrationBuilder.DropTable( + name: "ProjectTasks"); + + migrationBuilder.DropTable( + name: "ProjectPhases"); + + migrationBuilder.DropTable( + name: "Projects"); + + migrationBuilder.DropIndex( + name: "IX_TaskSections_ProjectTaskId", + table: "TaskSections"); + + migrationBuilder.DropColumn( + name: "ProjectTaskId", + table: "TaskSections"); + + migrationBuilder.RenameColumn( + name: "TaskSectionId", + table: "AdditionalTimes", + newName: "ProjectSectionId"); + + migrationBuilder.RenameIndex( + name: "IX_AdditionalTimes_TaskSectionId", + table: "AdditionalTimes", + newName: "IX_AdditionalTimes_ProjectSectionId"); + + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + FullName = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), + UserName = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), + Password = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: false), + ProfilePhotoPath = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true), + Mobile = table.Column(type: "nvarchar(20)", maxLength: 20, nullable: false), + Email = table.Column(type: "nvarchar(150)", maxLength: 150, nullable: true), + IsActive = table.Column(type: "bit", nullable: false), + VerifyCode = table.Column(type: "nvarchar(10)", maxLength: 10, nullable: true), + AccountId = table.Column(type: "bigint", nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.Id); + }); + + migrationBuilder.AddForeignKey( + name: "FK_AdditionalTimes_TaskSections_ProjectSectionId", + table: "AdditionalTimes", + column: "ProjectSectionId", + principalTable: "TaskSections", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_AdditionalTimes_TaskSections_ProjectSectionId", + table: "AdditionalTimes"); + + migrationBuilder.DropTable( + name: "Users"); + + migrationBuilder.RenameColumn( + name: "ProjectSectionId", + table: "AdditionalTimes", + newName: "TaskSectionId"); + + migrationBuilder.RenameIndex( + name: "IX_AdditionalTimes_ProjectSectionId", + table: "AdditionalTimes", + newName: "IX_AdditionalTimes_TaskSectionId"); + + migrationBuilder.AddColumn( + name: "ProjectTaskId", + table: "TaskSections", + type: "uniqueidentifier", + nullable: true); + + migrationBuilder.CreateTable( + name: "Projects", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Projects", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ProjectPhases", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ProjectId = table.Column(type: "uniqueidentifier", nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectPhases", x => x.Id); + table.ForeignKey( + name: "FK_ProjectPhases_Projects_ProjectId", + column: x => x.ProjectId, + principalTable: "Projects", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ProjectTasks", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + PhaseId = table.Column(type: "uniqueidentifier", nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), + Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectTasks", x => x.Id); + table.ForeignKey( + name: "FK_ProjectTasks_ProjectPhases_PhaseId", + column: x => x.PhaseId, + principalTable: "ProjectPhases", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_TaskSections_ProjectTaskId", + table: "TaskSections", + column: "ProjectTaskId"); + + migrationBuilder.CreateIndex( + name: "IX_ProjectPhases_ProjectId", + table: "ProjectPhases", + column: "ProjectId"); + + migrationBuilder.CreateIndex( + name: "IX_ProjectTasks_PhaseId", + table: "ProjectTasks", + column: "PhaseId"); + + migrationBuilder.AddForeignKey( + name: "FK_AdditionalTimes_TaskSections_TaskSectionId", + table: "AdditionalTimes", + column: "TaskSectionId", + principalTable: "TaskSections", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_TaskSections_ProjectTasks_ProjectTaskId", + table: "TaskSections", + column: "ProjectTaskId", + principalTable: "ProjectTasks", + principalColumn: "Id"); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251123123226_RoleInit.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251123123226_RoleInit.Designer.cs new file mode 100644 index 00000000..2ac5aede --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251123123226_RoleInit.Designer.cs @@ -0,0 +1,372 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251123123226_RoleInit")] + partial class RoleInit + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.22") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("AssignedUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("HasAssignmentOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("HasTimeOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("Level") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Level"); + + b.HasIndex("ParentId"); + + b.HasIndex("Level", "AssignedUserId"); + + b.ToTable("ProjectNodes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialEstimatedHours") + .HasColumnType("time"); + + b.Property("SectionType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskNodeId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TaskNodeId"); + + b.ToTable("TaskSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("AdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "TaskNode") + .WithMany("Sections") + .HasForeignKey("TaskNodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TaskNode"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("RolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Navigation("Children"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251123123226_RoleInit.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251123123226_RoleInit.cs new file mode 100644 index 00000000..bea52da9 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251123123226_RoleInit.cs @@ -0,0 +1,64 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class RoleInit : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Roles", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + RoleName = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Roles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "RolePermissions", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Code = table.Column(type: "int", nullable: false), + RoleId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RolePermissions", x => x.Id); + table.ForeignKey( + name: "FK_RolePermissions_Roles_RoleId", + column: x => x.RoleId, + principalTable: "Roles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_RolePermissions_RoleId", + table: "RolePermissions", + column: "RoleId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RolePermissions"); + + migrationBuilder.DropTable( + name: "Roles"); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251123135308_RoleUpdate.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251123135308_RoleUpdate.Designer.cs new file mode 100644 index 00000000..f8e22836 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251123135308_RoleUpdate.Designer.cs @@ -0,0 +1,375 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251123135308_RoleUpdate")] + partial class RoleUpdate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.22") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("AssignedUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("HasAssignmentOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("HasTimeOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("Level") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Level"); + + b.HasIndex("ParentId"); + + b.HasIndex("Level", "AssignedUserId"); + + b.ToTable("ProjectNodes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialEstimatedHours") + .HasColumnType("time"); + + b.Property("SectionType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskNodeId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TaskNodeId"); + + b.ToTable("TaskSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("AdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("GozareshgirRoleId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "TaskNode") + .WithMany("Sections") + .HasForeignKey("TaskNodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TaskNode"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("RolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Navigation("Children"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251123135308_RoleUpdate.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251123135308_RoleUpdate.cs new file mode 100644 index 00000000..16b9be9c --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251123135308_RoleUpdate.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class RoleUpdate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "GozareshgirRoleId", + table: "Roles", + type: "bigint", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "GozareshgirRoleId", + table: "Roles"); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125111142_add skills to entity.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125111142_add skills to entity.Designer.cs new file mode 100644 index 00000000..827e389f --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125111142_add skills to entity.Designer.cs @@ -0,0 +1,346 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251125111142_add skills to entity")] + partial class addskillstoentity + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.22") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("HasAssignmentOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("HasTimeOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("Level") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Level"); + + b.HasIndex("ParentId"); + + b.ToTable("ProjectNodes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialEstimatedHours") + .HasColumnType("time"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskNodeId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("TaskNodeId"); + + b.ToTable("ProjectSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("AdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "TaskNode") + .WithMany("Sections") + .HasForeignKey("TaskNodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("TaskNode"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Navigation("Children"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125111142_add skills to entity.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125111142_add skills to entity.cs new file mode 100644 index 00000000..944ad923 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125111142_add skills to entity.cs @@ -0,0 +1,222 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class addskillstoentity : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_AdditionalTimes_TaskSections_ProjectSectionId", + table: "AdditionalTimes"); + + migrationBuilder.DropForeignKey( + name: "FK_TaskSectionActivities_TaskSections_SectionId", + table: "TaskSectionActivities"); + + migrationBuilder.DropForeignKey( + name: "FK_TaskSections_ProjectNodes_TaskNodeId", + table: "TaskSections"); + + migrationBuilder.DropIndex( + name: "IX_ProjectNodes_Level_AssignedUserId", + table: "ProjectNodes"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TaskSections", + table: "TaskSections"); + + migrationBuilder.DropColumn( + name: "AssignedUserId", + table: "ProjectNodes"); + + migrationBuilder.DropColumn( + name: "SectionType", + table: "TaskSections"); + + migrationBuilder.RenameTable( + name: "TaskSections", + newName: "ProjectSections"); + + migrationBuilder.RenameIndex( + name: "IX_TaskSections_TaskNodeId", + table: "ProjectSections", + newName: "IX_ProjectSections_TaskNodeId"); + + migrationBuilder.AlterColumn( + name: "CurrentAssignedUserId", + table: "ProjectSections", + type: "bigint", + nullable: false, + defaultValue: 0L, + oldClrType: typeof(long), + oldType: "bigint", + oldNullable: true); + + migrationBuilder.AddColumn( + name: "SkillId", + table: "ProjectSections", + type: "uniqueidentifier", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); + + migrationBuilder.AddPrimaryKey( + name: "PK_ProjectSections", + table: "ProjectSections", + column: "Id"); + + migrationBuilder.CreateTable( + name: "Skills", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Skills", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_ProjectSections_SkillId", + table: "ProjectSections", + column: "SkillId"); + + migrationBuilder.AddForeignKey( + name: "FK_AdditionalTimes_ProjectSections_ProjectSectionId", + table: "AdditionalTimes", + column: "ProjectSectionId", + principalTable: "ProjectSections", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_ProjectSections_ProjectNodes_TaskNodeId", + table: "ProjectSections", + column: "TaskNodeId", + principalTable: "ProjectNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ProjectSections_Skills_SkillId", + table: "ProjectSections", + column: "SkillId", + principalTable: "Skills", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_TaskSectionActivities_ProjectSections_SectionId", + table: "TaskSectionActivities", + column: "SectionId", + principalTable: "ProjectSections", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_AdditionalTimes_ProjectSections_ProjectSectionId", + table: "AdditionalTimes"); + + migrationBuilder.DropForeignKey( + name: "FK_ProjectSections_ProjectNodes_TaskNodeId", + table: "ProjectSections"); + + migrationBuilder.DropForeignKey( + name: "FK_ProjectSections_Skills_SkillId", + table: "ProjectSections"); + + migrationBuilder.DropForeignKey( + name: "FK_TaskSectionActivities_ProjectSections_SectionId", + table: "TaskSectionActivities"); + + migrationBuilder.DropTable( + name: "Skills"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ProjectSections", + table: "ProjectSections"); + + migrationBuilder.DropIndex( + name: "IX_ProjectSections_SkillId", + table: "ProjectSections"); + + migrationBuilder.DropColumn( + name: "SkillId", + table: "ProjectSections"); + + migrationBuilder.RenameTable( + name: "ProjectSections", + newName: "TaskSections"); + + migrationBuilder.RenameIndex( + name: "IX_ProjectSections_TaskNodeId", + table: "TaskSections", + newName: "IX_TaskSections_TaskNodeId"); + + migrationBuilder.AddColumn( + name: "AssignedUserId", + table: "ProjectNodes", + type: "bigint", + nullable: true); + + migrationBuilder.AlterColumn( + name: "CurrentAssignedUserId", + table: "TaskSections", + type: "bigint", + nullable: true, + oldClrType: typeof(long), + oldType: "bigint"); + + migrationBuilder.AddColumn( + name: "SectionType", + table: "TaskSections", + type: "nvarchar(50)", + maxLength: 50, + nullable: false, + defaultValue: ""); + + migrationBuilder.AddPrimaryKey( + name: "PK_TaskSections", + table: "TaskSections", + column: "Id"); + + migrationBuilder.CreateIndex( + name: "IX_ProjectNodes_Level_AssignedUserId", + table: "ProjectNodes", + columns: new[] { "Level", "AssignedUserId" }); + + migrationBuilder.AddForeignKey( + name: "FK_AdditionalTimes_TaskSections_ProjectSectionId", + table: "AdditionalTimes", + column: "ProjectSectionId", + principalTable: "TaskSections", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_TaskSectionActivities_TaskSections_SectionId", + table: "TaskSectionActivities", + column: "SectionId", + principalTable: "TaskSections", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_TaskSections_ProjectNodes_TaskNodeId", + table: "TaskSections", + column: "TaskNodeId", + principalTable: "ProjectNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125112542_change section key name.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125112542_change section key name.Designer.cs new file mode 100644 index 00000000..9f6ea58c --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125112542_change section key name.Designer.cs @@ -0,0 +1,346 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251125112542_change section key name")] + partial class changesectionkeyname + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.22") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("HasAssignmentOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("HasTimeOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("Level") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Level"); + + b.HasIndex("ParentId"); + + b.ToTable("ProjectNodes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialEstimatedHours") + .HasColumnType("time"); + + b.Property("ProjectNodeId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectNodeId"); + + b.HasIndex("SkillId"); + + b.ToTable("ProjectSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("AdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "ProjectNode") + .WithMany("Sections") + .HasForeignKey("ProjectNodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectNode"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Navigation("Children"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125112542_change section key name.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125112542_change section key name.cs new file mode 100644 index 00000000..8fd3deda --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125112542_change section key name.cs @@ -0,0 +1,62 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class changesectionkeyname : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ProjectSections_ProjectNodes_TaskNodeId", + table: "ProjectSections"); + + migrationBuilder.RenameColumn( + name: "TaskNodeId", + table: "ProjectSections", + newName: "ProjectNodeId"); + + migrationBuilder.RenameIndex( + name: "IX_ProjectSections_TaskNodeId", + table: "ProjectSections", + newName: "IX_ProjectSections_ProjectNodeId"); + + migrationBuilder.AddForeignKey( + name: "FK_ProjectSections_ProjectNodes_ProjectNodeId", + table: "ProjectSections", + column: "ProjectNodeId", + principalTable: "ProjectNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ProjectSections_ProjectNodes_ProjectNodeId", + table: "ProjectSections"); + + migrationBuilder.RenameColumn( + name: "ProjectNodeId", + table: "ProjectSections", + newName: "TaskNodeId"); + + migrationBuilder.RenameIndex( + name: "IX_ProjectSections_ProjectNodeId", + table: "ProjectSections", + newName: "IX_ProjectSections_TaskNodeId"); + + migrationBuilder.AddForeignKey( + name: "FK_ProjectSections_ProjectNodes_TaskNodeId", + table: "ProjectSections", + column: "TaskNodeId", + principalTable: "ProjectNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125145830_change project node on delete to cascade.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125145830_change project node on delete to cascade.Designer.cs new file mode 100644 index 00000000..c8e06582 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125145830_change project node on delete to cascade.Designer.cs @@ -0,0 +1,346 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251125145830_change project node on delete to cascade")] + partial class changeprojectnodeondeletetocascade + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.22") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("HasAssignmentOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("HasTimeOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("Level") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Level"); + + b.HasIndex("ParentId"); + + b.ToTable("ProjectNodes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialEstimatedHours") + .HasColumnType("time"); + + b.Property("ProjectNodeId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectNodeId"); + + b.HasIndex("SkillId"); + + b.ToTable("ProjectSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("AdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "ProjectNode") + .WithMany("Sections") + .HasForeignKey("ProjectNodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectNode"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Navigation("Children"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125145830_change project node on delete to cascade.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125145830_change project node on delete to cascade.cs new file mode 100644 index 00000000..c2d73e3d --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125145830_change project node on delete to cascade.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class changeprojectnodeondeletetocascade : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125164239_change section and additionalTime description.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125164239_change section and additionalTime description.Designer.cs new file mode 100644 index 00000000..c35702a7 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125164239_change section and additionalTime description.Designer.cs @@ -0,0 +1,349 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251125164239_change section and additionalTime description")] + partial class changesectionandadditionalTimedescription + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.22") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("HasAssignmentOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("HasTimeOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("Level") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Level"); + + b.HasIndex("ParentId"); + + b.ToTable("ProjectNodes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialDescription") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("InitialEstimatedHours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectNodeId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectNodeId"); + + b.HasIndex("SkillId"); + + b.ToTable("ProjectSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("ProjectSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("AdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "ProjectNode") + .WithMany("Sections") + .HasForeignKey("ProjectNodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectNode"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Navigation("Children"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125164239_change section and additionalTime description.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125164239_change section and additionalTime description.cs new file mode 100644 index 00000000..6c2696bc --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251125164239_change section and additionalTime description.cs @@ -0,0 +1,142 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class changesectionandadditionalTimedescription : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ProjectNodes_ProjectNodes_ParentId", + table: "ProjectNodes"); + + migrationBuilder.DropForeignKey( + name: "FK_TaskSectionActivities_ProjectSections_SectionId", + table: "TaskSectionActivities"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TaskSectionActivities", + table: "TaskSectionActivities"); + + migrationBuilder.DropColumn( + name: "AllocatedTime", + table: "ProjectSections"); + + migrationBuilder.RenameTable( + name: "TaskSectionActivities", + newName: "ProjectSectionActivities"); + + migrationBuilder.RenameIndex( + name: "IX_TaskSectionActivities_SectionId", + table: "ProjectSectionActivities", + newName: "IX_ProjectSectionActivities_SectionId"); + + migrationBuilder.AlterColumn( + name: "InitialEstimatedHours", + table: "ProjectSections", + type: "nvarchar(30)", + maxLength: 30, + nullable: false, + oldClrType: typeof(TimeSpan), + oldType: "time"); + + migrationBuilder.AddColumn( + name: "InitialDescription", + table: "ProjectSections", + type: "nvarchar(500)", + maxLength: 500, + nullable: true); + + migrationBuilder.AddPrimaryKey( + name: "PK_ProjectSectionActivities", + table: "ProjectSectionActivities", + column: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_ProjectNodes_ProjectNodes_ParentId", + table: "ProjectNodes", + column: "ParentId", + principalTable: "ProjectNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_ProjectSectionActivities_ProjectSections_SectionId", + table: "ProjectSectionActivities", + column: "SectionId", + principalTable: "ProjectSections", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ProjectNodes_ProjectNodes_ParentId", + table: "ProjectNodes"); + + migrationBuilder.DropForeignKey( + name: "FK_ProjectSectionActivities_ProjectSections_SectionId", + table: "ProjectSectionActivities"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ProjectSectionActivities", + table: "ProjectSectionActivities"); + + migrationBuilder.DropColumn( + name: "InitialDescription", + table: "ProjectSections"); + + migrationBuilder.RenameTable( + name: "ProjectSectionActivities", + newName: "TaskSectionActivities"); + + migrationBuilder.RenameIndex( + name: "IX_ProjectSectionActivities_SectionId", + table: "TaskSectionActivities", + newName: "IX_TaskSectionActivities_SectionId"); + + migrationBuilder.AlterColumn( + name: "InitialEstimatedHours", + table: "ProjectSections", + type: "time", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(30)", + oldMaxLength: 30); + + migrationBuilder.AddColumn( + name: "AllocatedTime", + table: "ProjectSections", + type: "time", + nullable: true); + + migrationBuilder.AddPrimaryKey( + name: "PK_TaskSectionActivities", + table: "TaskSectionActivities", + column: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_ProjectNodes_ProjectNodes_ParentId", + table: "ProjectNodes", + column: "ParentId", + principalTable: "ProjectNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_TaskSectionActivities_ProjectSections_SectionId", + table: "TaskSectionActivities", + column: "SectionId", + principalTable: "ProjectSections", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251126122836_AddUserRoleTable.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251126122836_AddUserRoleTable.Designer.cs new file mode 100644 index 00000000..1132e866 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251126122836_AddUserRoleTable.Designer.cs @@ -0,0 +1,406 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251126122836_AddUserRoleTable")] + partial class AddUserRoleTable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.22") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("AssignedUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("HasAssignmentOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("HasTimeOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("Level") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Level"); + + b.HasIndex("ParentId"); + + b.HasIndex("Level", "AssignedUserId"); + + b.ToTable("ProjectNodes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialEstimatedHours") + .HasColumnType("time"); + + b.Property("SectionType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskNodeId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TaskNodeId"); + + b.ToTable("TaskSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("AdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("GozareshgirRoleId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "TaskNode") + .WithMany("Sections") + .HasForeignKey("TaskNodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TaskNode"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("RolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.Property("UserId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("UserId"); + + b1.ToTable("RoleUsers", (string)null); + + b1.WithOwner("User") + .HasForeignKey("UserId"); + + b1.Navigation("User"); + }); + + b.Navigation("RoleUser"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Navigation("Children"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251126122836_AddUserRoleTable.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251126122836_AddUserRoleTable.cs new file mode 100644 index 00000000..23d03281 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251126122836_AddUserRoleTable.cs @@ -0,0 +1,46 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class AddUserRoleTable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "RoleUsers", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + RoleId = table.Column(type: "bigint", nullable: false), + UserId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RoleUsers", x => x.Id); + table.ForeignKey( + name: "FK_RoleUsers_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_RoleUsers_UserId", + table: "RoleUsers", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RoleUsers"); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251201120420_change projects from nodes to three seprated pieces.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251201120420_change projects from nodes to three seprated pieces.Designer.cs new file mode 100644 index 00000000..a865122a --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251201120420_change projects from nodes to three seprated pieces.Designer.cs @@ -0,0 +1,556 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251201120420_change projects from nodes to three seprated pieces")] + partial class changeprojectsfromnodestothreesepratedpieces + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("PlannedEndDate") + .HasColumnType("datetime2"); + + b.Property("PlannedStartDate") + .HasColumnType("datetime2"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Projects", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectPhases", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialDescription") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("InitialEstimatedHours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("TaskId"); + + b.ToTable("ProjectSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("ProjectSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("ProjectSectionAdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("HasTimeOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("ProjectTasks", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("GozareshgirRoleId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("Phases") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", "Task") + .WithMany("Sections") + .HasForeignKey("TaskId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("Task"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("Tasks") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("RolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.Property("UserId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("UserId"); + + b1.ToTable("RoleUsers", (string)null); + + b1.WithOwner("User") + .HasForeignKey("UserId"); + + b1.Navigation("User"); + }); + + b.Navigation("RoleUser"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Navigation("Phases"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251201120420_change projects from nodes to three seprated pieces.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251201120420_change projects from nodes to three seprated pieces.cs new file mode 100644 index 00000000..b6e789f8 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251201120420_change projects from nodes to three seprated pieces.cs @@ -0,0 +1,287 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class changeprojectsfromnodestothreesepratedpieces : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_AdditionalTimes_ProjectSections_ProjectSectionId", + table: "AdditionalTimes"); + + migrationBuilder.DropForeignKey( + name: "FK_ProjectSections_ProjectNodes_ProjectNodeId", + table: "ProjectSections"); + + migrationBuilder.DropTable( + name: "ProjectNodes"); + + migrationBuilder.DropPrimaryKey( + name: "PK_AdditionalTimes", + table: "AdditionalTimes"); + + migrationBuilder.RenameTable( + name: "AdditionalTimes", + newName: "ProjectSectionAdditionalTimes"); + + migrationBuilder.RenameColumn( + name: "ProjectNodeId", + table: "ProjectSections", + newName: "TaskId"); + + migrationBuilder.RenameIndex( + name: "IX_ProjectSections_ProjectNodeId", + table: "ProjectSections", + newName: "IX_ProjectSections_TaskId"); + + migrationBuilder.RenameIndex( + name: "IX_AdditionalTimes_ProjectSectionId", + table: "ProjectSectionAdditionalTimes", + newName: "IX_ProjectSectionAdditionalTimes_ProjectSectionId"); + + migrationBuilder.AddColumn( + name: "IsActive", + table: "ProjectSectionActivities", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AlterColumn( + name: "Reason", + table: "ProjectSectionAdditionalTimes", + type: "nvarchar(500)", + maxLength: 500, + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(1000)", + oldMaxLength: 1000, + oldNullable: true); + + migrationBuilder.AddPrimaryKey( + name: "PK_ProjectSectionAdditionalTimes", + table: "ProjectSectionAdditionalTimes", + column: "Id"); + + migrationBuilder.CreateTable( + name: "Projects", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + StartDate = table.Column(type: "datetime2", nullable: true), + EndDate = table.Column(type: "datetime2", nullable: true), + PlannedStartDate = table.Column(type: "datetime2", nullable: true), + PlannedEndDate = table.Column(type: "datetime2", nullable: true), + Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + HasAssignmentOverride = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Projects", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ProjectPhases", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ProjectId = table.Column(type: "uniqueidentifier", nullable: false), + Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + StartDate = table.Column(type: "datetime2", nullable: true), + EndDate = table.Column(type: "datetime2", nullable: true), + OrderIndex = table.Column(type: "int", nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + HasAssignmentOverride = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectPhases", x => x.Id); + table.ForeignKey( + name: "FK_ProjectPhases_Projects_ProjectId", + column: x => x.ProjectId, + principalTable: "Projects", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ProjectTasks", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + PhaseId = table.Column(type: "uniqueidentifier", nullable: false), + Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + Priority = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + StartDate = table.Column(type: "datetime2", nullable: true), + EndDate = table.Column(type: "datetime2", nullable: true), + DueDate = table.Column(type: "datetime2", nullable: true), + OrderIndex = table.Column(type: "int", nullable: false), + AllocatedTime = table.Column(type: "nvarchar(30)", maxLength: 30, nullable: true), + HasTimeOverride = table.Column(type: "bit", nullable: false), + HasAssignmentOverride = table.Column(type: "bit", nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectTasks", x => x.Id); + table.ForeignKey( + name: "FK_ProjectTasks_ProjectPhases_PhaseId", + column: x => x.PhaseId, + principalTable: "ProjectPhases", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ProjectPhases_ProjectId", + table: "ProjectPhases", + column: "ProjectId"); + + migrationBuilder.CreateIndex( + name: "IX_ProjectTasks_PhaseId", + table: "ProjectTasks", + column: "PhaseId"); + + migrationBuilder.AddForeignKey( + name: "FK_ProjectSectionAdditionalTimes_ProjectSections_ProjectSectionId", + table: "ProjectSectionAdditionalTimes", + column: "ProjectSectionId", + principalTable: "ProjectSections", + principalColumn: "Id"); + + // migrationBuilder.AddForeignKey( + // name: "FK_ProjectSections_ProjectTasks_TaskId", + // table: "ProjectSections", + // column: "TaskId", + // principalTable: "ProjectTasks", + // principalColumn: "Id", + // onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ProjectSectionAdditionalTimes_ProjectSections_ProjectSectionId", + table: "ProjectSectionAdditionalTimes"); + + // migrationBuilder.DropForeignKey( + // name: "FK_ProjectSections_ProjectTasks_TaskId", + // table: "ProjectSections"); + + migrationBuilder.DropTable( + name: "ProjectTasks"); + + migrationBuilder.DropTable( + name: "ProjectPhases"); + + migrationBuilder.DropTable( + name: "Projects"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ProjectSectionAdditionalTimes", + table: "ProjectSectionAdditionalTimes"); + + migrationBuilder.DropColumn( + name: "IsActive", + table: "ProjectSectionActivities"); + + migrationBuilder.RenameTable( + name: "ProjectSectionAdditionalTimes", + newName: "AdditionalTimes"); + + migrationBuilder.RenameColumn( + name: "TaskId", + table: "ProjectSections", + newName: "ProjectNodeId"); + + migrationBuilder.RenameIndex( + name: "IX_ProjectSections_TaskId", + table: "ProjectSections", + newName: "IX_ProjectSections_ProjectNodeId"); + + migrationBuilder.RenameIndex( + name: "IX_ProjectSectionAdditionalTimes_ProjectSectionId", + table: "AdditionalTimes", + newName: "IX_AdditionalTimes_ProjectSectionId"); + + migrationBuilder.AlterColumn( + name: "Reason", + table: "AdditionalTimes", + type: "nvarchar(1000)", + maxLength: 1000, + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(500)", + oldMaxLength: 500, + oldNullable: true); + + migrationBuilder.AddPrimaryKey( + name: "PK_AdditionalTimes", + table: "AdditionalTimes", + column: "Id"); + + migrationBuilder.CreateTable( + name: "ProjectNodes", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ParentId = table.Column(type: "uniqueidentifier", nullable: true), + AllocatedTime = table.Column(type: "time", nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + HasAssignmentOverride = table.Column(type: "bit", nullable: false, defaultValue: false), + HasTimeOverride = table.Column(type: "bit", nullable: false, defaultValue: false), + Level = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectNodes", x => x.Id); + table.ForeignKey( + name: "FK_ProjectNodes_ProjectNodes_ParentId", + column: x => x.ParentId, + principalTable: "ProjectNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_ProjectNodes_Level", + table: "ProjectNodes", + column: "Level"); + + migrationBuilder.CreateIndex( + name: "IX_ProjectNodes_ParentId", + table: "ProjectNodes", + column: "ParentId"); + + migrationBuilder.AddForeignKey( + name: "FK_AdditionalTimes_ProjectSections_ProjectSectionId", + table: "AdditionalTimes", + column: "ProjectSectionId", + principalTable: "ProjectSections", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_ProjectSections_ProjectNodes_ProjectNodeId", + table: "ProjectSections", + column: "ProjectNodeId", + principalTable: "ProjectNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251201150949_SalaryPaymentSettingInit.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251201150949_SalaryPaymentSettingInit.Designer.cs new file mode 100644 index 00000000..df7b277f --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251201150949_SalaryPaymentSettingInit.Designer.cs @@ -0,0 +1,524 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251201150949_SalaryPaymentSettingInit")] + partial class SalaryPaymentSettingInit + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.22") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasColumnType("time"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("HasAssignmentOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("HasTimeOverride") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("Level") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Level"); + + b.HasIndex("ParentId"); + + b.ToTable("ProjectNodes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialDescription") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("InitialEstimatedHours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectNodeId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectNodeId"); + + b.HasIndex("SkillId"); + + b.ToTable("ProjectSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("ProjectSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("AdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("GozareshgirRoleId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndSettingDate") + .HasColumnType("datetime2"); + + b.Property("HolidayWorking") + .HasColumnType("bit"); + + b.Property("MonthlySalary") + .HasColumnType("float"); + + b.Property("StartSettingDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("SalaryPaymentSetting", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", "ProjectNode") + .WithMany("Sections") + .HasForeignKey("ProjectNodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectNode"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("RolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.WorkingHours", "WorkingHoursList", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("EndShiftOne") + .HasColumnType("time(0)"); + + b1.Property("EndShiftTwo") + .HasColumnType("time(0)"); + + b1.Property("HasRestTime") + .HasColumnType("bit"); + + b1.Property("HasShiftOne") + .HasColumnType("bit"); + + b1.Property("HasShiftTow") + .HasColumnType("bit"); + + b1.Property("PersianDayOfWeek") + .HasColumnType("int"); + + b1.Property("RestTime") + .HasColumnType("time(0)"); + + b1.Property("SalaryPaymentSettingId") + .HasColumnType("bigint"); + + b1.Property("ShiftDurationInMinutes") + .HasColumnType("int"); + + b1.Property("StartShiftOne") + .HasColumnType("time(0)"); + + b1.Property("StartShiftTwo") + .HasColumnType("time(0)"); + + b1.HasKey("Id"); + + b1.HasIndex("SalaryPaymentSettingId"); + + b1.ToTable("WorkingHours", (string)null); + + b1.WithOwner("SalaryPaymentSetting") + .HasForeignKey("SalaryPaymentSettingId"); + + b1.Navigation("SalaryPaymentSetting"); + }); + + b.Navigation("WorkingHoursList"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.Property("UserId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("UserId"); + + b1.ToTable("RoleUsers", (string)null); + + b1.WithOwner("User") + .HasForeignKey("UserId"); + + b1.Navigation("User"); + }); + + b.Navigation("RoleUser"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectNode", b => + { + b.Navigation("Children"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251201150949_SalaryPaymentSettingInit.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251201150949_SalaryPaymentSettingInit.cs new file mode 100644 index 00000000..8ae61fbb --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251201150949_SalaryPaymentSettingInit.cs @@ -0,0 +1,87 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class SalaryPaymentSettingInit : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "SalaryPaymentSetting", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + HolidayWorking = table.Column(type: "bit", nullable: false), + UserId = table.Column(type: "bigint", nullable: false), + MonthlySalary = table.Column(type: "float", nullable: false), + StartSettingDate = table.Column(type: "datetime2", nullable: true), + EndSettingDate = table.Column(type: "datetime2", nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SalaryPaymentSetting", x => x.Id); + }); + + + + migrationBuilder.CreateTable( + name: "WorkingHours", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + StartShiftOne = table.Column(type: "time(0)", nullable: false), + EndShiftOne = table.Column(type: "time(0)", nullable: false), + StartShiftTwo = table.Column(type: "time(0)", nullable: false), + EndShiftTwo = table.Column(type: "time(0)", nullable: false), + RestTime = table.Column(type: "time(0)", nullable: false), + HasShiftOne = table.Column(type: "bit", nullable: false), + HasShiftTow = table.Column(type: "bit", nullable: false), + HasRestTime = table.Column(type: "bit", nullable: false), + ShiftDurationInMinutes = table.Column(type: "int", nullable: false), + PersianDayOfWeek = table.Column(type: "int", nullable: false), + SalaryPaymentSettingId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_WorkingHours", x => x.Id); + table.ForeignKey( + name: "FK_WorkingHours_SalaryPaymentSetting_SalaryPaymentSettingId", + column: x => x.SalaryPaymentSettingId, + principalTable: "SalaryPaymentSetting", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + + + migrationBuilder.CreateIndex( + name: "IX_WorkingHours_SalaryPaymentSettingId", + table: "WorkingHours", + column: "SalaryPaymentSettingId"); + + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + + migrationBuilder.DropTable( + name: "WorkingHours"); + + migrationBuilder.DropTable( + name: "SalaryPaymentSetting"); + + + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251202113519_IsActiveDayToWorkingHours.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251202113519_IsActiveDayToWorkingHours.Designer.cs new file mode 100644 index 00000000..f6ad2cf2 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251202113519_IsActiveDayToWorkingHours.Designer.cs @@ -0,0 +1,648 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251202113519_IsActiveDayToWorkingHours")] + partial class IsActiveDayToWorkingHours + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("PlannedEndDate") + .HasColumnType("datetime2"); + + b.Property("PlannedStartDate") + .HasColumnType("datetime2"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Projects", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectPhases", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialDescription") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("InitialEstimatedHours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("TaskId"); + + b.ToTable("ProjectSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("ProjectSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("ProjectSectionAdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("HasTimeOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("ProjectTasks", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("GozareshgirRoleId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndSettingDate") + .HasColumnType("datetime2"); + + b.Property("HolidayWorking") + .HasColumnType("bit"); + + b.Property("MonthlySalary") + .HasColumnType("float"); + + b.Property("StartSettingDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("SalaryPaymentSetting", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("Phases") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", "Task") + .WithMany("Sections") + .HasForeignKey("TaskId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("Task"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("Tasks") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("RolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.WorkingHours", "WorkingHoursList", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("EndShiftOne") + .HasColumnType("time(0)"); + + b1.Property("EndShiftTwo") + .HasColumnType("time(0)"); + + b1.Property("HasRestTime") + .HasColumnType("bit"); + + b1.Property("HasShiftOne") + .HasColumnType("bit"); + + b1.Property("HasShiftTow") + .HasColumnType("bit"); + + b1.Property("IsActiveDay") + .HasColumnType("bit"); + + b1.Property("PersianDayOfWeek") + .HasColumnType("int"); + + b1.Property("RestTime") + .HasColumnType("time(0)"); + + b1.Property("SalaryPaymentSettingId") + .HasColumnType("bigint"); + + b1.Property("ShiftDurationInMinutes") + .HasColumnType("int"); + + b1.Property("StartShiftOne") + .HasColumnType("time(0)"); + + b1.Property("StartShiftTwo") + .HasColumnType("time(0)"); + + b1.HasKey("Id"); + + b1.HasIndex("SalaryPaymentSettingId"); + + b1.ToTable("WorkingHours", (string)null); + + b1.WithOwner("SalaryPaymentSetting") + .HasForeignKey("SalaryPaymentSettingId"); + + b1.Navigation("SalaryPaymentSetting"); + }); + + b.Navigation("WorkingHoursList"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.Property("UserId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("UserId"); + + b1.ToTable("RoleUsers", (string)null); + + b1.WithOwner("User") + .HasForeignKey("UserId"); + + b1.Navigation("User"); + }); + + b.Navigation("RoleUser"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Navigation("Phases"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251202113519_IsActiveDayToWorkingHours.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251202113519_IsActiveDayToWorkingHours.cs new file mode 100644 index 00000000..8e4cf65f --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251202113519_IsActiveDayToWorkingHours.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class IsActiveDayToWorkingHours : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsActiveDay", + table: "WorkingHours", + type: "bit", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsActiveDay", + table: "WorkingHours"); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251202145954_CheckoutInit.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251202145954_CheckoutInit.Designer.cs new file mode 100644 index 00000000..a529f983 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251202145954_CheckoutInit.Designer.cs @@ -0,0 +1,706 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251202145954_CheckoutInit")] + partial class CheckoutInit + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CheckoutAgg.Entities.Checkout", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CheckoutEndDate") + .HasColumnType("datetime2"); + + b.Property("CheckoutStartDate") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("DeductionFromSalary") + .HasColumnType("float"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MandatoryHours") + .HasColumnType("int"); + + b.Property("Month") + .HasColumnType("int"); + + b.Property("MonthlySalaryDefined") + .HasColumnType("float"); + + b.Property("MonthlySalaryPay") + .HasColumnType("float"); + + b.Property("RemainingHours") + .HasColumnType("int"); + + b.Property("TotalDaysWorked") + .HasColumnType("int"); + + b.Property("TotalHoursWorked") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Checkouts", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("PlannedEndDate") + .HasColumnType("datetime2"); + + b.Property("PlannedStartDate") + .HasColumnType("datetime2"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Projects", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectPhases", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialDescription") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("InitialEstimatedHours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("OriginalAssignedUserId") + .HasColumnType("bigint"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("TaskId"); + + b.ToTable("ProjectSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("ProjectSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("ProjectSectionAdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("HasTimeOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("ProjectTasks", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("GozareshgirRoleId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndSettingDate") + .HasColumnType("datetime2"); + + b.Property("HolidayWorking") + .HasColumnType("bit"); + + b.Property("MonthlySalary") + .HasColumnType("float"); + + b.Property("StartSettingDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("SalaryPaymentSetting", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("Phases") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", "Task") + .WithMany("Sections") + .HasForeignKey("TaskId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("Task"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("Tasks") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("RolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.WorkingHours", "WorkingHoursList", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("EndShiftOne") + .HasColumnType("time(0)"); + + b1.Property("EndShiftTwo") + .HasColumnType("time(0)"); + + b1.Property("HasRestTime") + .HasColumnType("bit"); + + b1.Property("HasShiftOne") + .HasColumnType("bit"); + + b1.Property("HasShiftTow") + .HasColumnType("bit"); + + b1.Property("IsActiveDay") + .HasColumnType("bit"); + + b1.Property("PersianDayOfWeek") + .HasColumnType("int"); + + b1.Property("RestTime") + .HasColumnType("time(0)"); + + b1.Property("SalaryPaymentSettingId") + .HasColumnType("bigint"); + + b1.Property("ShiftDurationInMinutes") + .HasColumnType("int"); + + b1.Property("StartShiftOne") + .HasColumnType("time(0)"); + + b1.Property("StartShiftTwo") + .HasColumnType("time(0)"); + + b1.HasKey("Id"); + + b1.HasIndex("SalaryPaymentSettingId"); + + b1.ToTable("WorkingHours", (string)null); + + b1.WithOwner("SalaryPaymentSetting") + .HasForeignKey("SalaryPaymentSettingId"); + + b1.Navigation("SalaryPaymentSetting"); + }); + + b.Navigation("WorkingHoursList"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.Property("UserId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("UserId"); + + b1.ToTable("RoleUsers", (string)null); + + b1.WithOwner("User") + .HasForeignKey("UserId"); + + b1.Navigation("User"); + }); + + b.Navigation("RoleUser"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Navigation("Phases"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251202145954_CheckoutInit.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251202145954_CheckoutInit.cs new file mode 100644 index 00000000..8aa33809 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251202145954_CheckoutInit.cs @@ -0,0 +1,50 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class CheckoutInit : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + + migrationBuilder.CreateTable( + name: "Checkouts", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + CheckoutStartDate = table.Column(type: "datetime2", nullable: false), + CheckoutEndDate = table.Column(type: "datetime2", nullable: false), + Year = table.Column(type: "int", nullable: false), + Month = table.Column(type: "int", nullable: false), + FullName = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), + UserId = table.Column(type: "bigint", nullable: false), + MandatoryHours = table.Column(type: "int", nullable: false), + TotalHoursWorked = table.Column(type: "int", nullable: false), + TotalDaysWorked = table.Column(type: "int", nullable: false), + RemainingHours = table.Column(type: "int", nullable: false), + MonthlySalaryDefined = table.Column(type: "float", nullable: false), + MonthlySalaryPay = table.Column(type: "float", nullable: false), + DeductionFromSalary = table.Column(type: "float", nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Checkouts", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Checkouts"); + + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251203071011_add user refresh token.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251203071011_add user refresh token.Designer.cs new file mode 100644 index 00000000..3d7eedab --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251203071011_add user refresh token.Designer.cs @@ -0,0 +1,707 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251203071011_add user refresh token")] + partial class adduserrefreshtoken + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("PlannedEndDate") + .HasColumnType("datetime2"); + + b.Property("PlannedStartDate") + .HasColumnType("datetime2"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Projects", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectPhases", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialDescription") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("InitialEstimatedHours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("OriginalAssignedUserId") + .HasColumnType("bigint"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("TaskId"); + + b.ToTable("ProjectSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("ProjectSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("ProjectSectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectSectionId"); + + b.ToTable("ProjectSectionAdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("HasTimeOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("ProjectTasks", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("GozareshgirRoleId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndSettingDate") + .HasColumnType("datetime2"); + + b.Property("HolidayWorking") + .HasColumnType("bit"); + + b.Property("MonthlySalary") + .HasColumnType("float"); + + b.Property("StartSettingDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("SalaryPaymentSetting", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ExpiresAt") + .HasColumnType("datetime2"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("RevokedAt") + .HasColumnType("datetime2"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserAgent") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ExpiresAt"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("UserRefreshTokens", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("Phases") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", "Task") + .WithMany("Sections") + .HasForeignKey("TaskId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("Task"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("ProjectSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("Tasks") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("RolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.WorkingHours", "WorkingHoursList", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("EndShiftOne") + .HasColumnType("time(0)"); + + b1.Property("EndShiftTwo") + .HasColumnType("time(0)"); + + b1.Property("HasRestTime") + .HasColumnType("bit"); + + b1.Property("HasShiftOne") + .HasColumnType("bit"); + + b1.Property("HasShiftTow") + .HasColumnType("bit"); + + b1.Property("PersianDayOfWeek") + .HasColumnType("int"); + + b1.Property("RestTime") + .HasColumnType("time(0)"); + + b1.Property("SalaryPaymentSettingId") + .HasColumnType("bigint"); + + b1.Property("ShiftDurationInMinutes") + .HasColumnType("int"); + + b1.Property("StartShiftOne") + .HasColumnType("time(0)"); + + b1.Property("StartShiftTwo") + .HasColumnType("time(0)"); + + b1.HasKey("Id"); + + b1.HasIndex("SalaryPaymentSettingId"); + + b1.ToTable("WorkingHours", (string)null); + + b1.WithOwner("SalaryPaymentSetting") + .HasForeignKey("SalaryPaymentSettingId"); + + b1.Navigation("SalaryPaymentSetting"); + }); + + b.Navigation("WorkingHoursList"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.Property("UserId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("UserId"); + + b1.ToTable("RoleUsers", (string)null); + + b1.WithOwner("User") + .HasForeignKey("UserId"); + + b1.Navigation("User"); + }); + + b.Navigation("RoleUser"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b => + { + b.HasOne("GozareshgirProgramManager.Domain.UserAgg.Entities.User", "User") + .WithMany("RefreshTokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Navigation("Phases"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Navigation("RefreshTokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251203071011_add user refresh token.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251203071011_add user refresh token.cs new file mode 100644 index 00000000..c4e6c962 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251203071011_add user refresh token.cs @@ -0,0 +1,62 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class adduserrefreshtoken : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "UserRefreshTokens", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + UserId = table.Column(type: "bigint", nullable: false), + Token = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: false), + ExpiresAt = table.Column(type: "datetime2", nullable: false), + RevokedAt = table.Column(type: "datetime2", nullable: true), + IpAddress = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + UserAgent = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_UserRefreshTokens", x => x.Id); + table.ForeignKey( + name: "FK_UserRefreshTokens_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_UserRefreshTokens_ExpiresAt", + table: "UserRefreshTokens", + column: "ExpiresAt"); + + migrationBuilder.CreateIndex( + name: "IX_UserRefreshTokens_Token", + table: "UserRefreshTokens", + column: "Token", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_UserRefreshTokens_UserId", + table: "UserRefreshTokens", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "UserRefreshTokens"); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251203174140_add sections.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251203174140_add sections.Designer.cs new file mode 100644 index 00000000..902c1fb7 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251203174140_add sections.Designer.cs @@ -0,0 +1,786 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251203174140_add sections")] + partial class addsections + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("PhaseSection"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("PlannedEndDate") + .HasColumnType("datetime2"); + + b.Property("PlannedStartDate") + .HasColumnType("datetime2"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Projects", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectPhases", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectSection"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("HasTimeOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("ProjectTasks", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialDescription") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("InitialEstimatedHours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("OriginalAssignedUserId") + .HasColumnType("bigint"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("TaskId"); + + b.ToTable("TaskSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("TaskSectionId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TaskSectionId"); + + b.ToTable("TaskSectionAdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("GozareshgirRoleId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndSettingDate") + .HasColumnType("datetime2"); + + b.Property("HolidayWorking") + .HasColumnType("bit"); + + b.Property("MonthlySalary") + .HasColumnType("float"); + + b.Property("StartSettingDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("SalaryPaymentSetting", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ExpiresAt") + .HasColumnType("datetime2"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("RevokedAt") + .HasColumnType("datetime2"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserAgent") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ExpiresAt"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("UserRefreshTokens", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("PhaseSections") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("Phases") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("ProjectSections") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("Tasks") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", "Task") + .WithMany("Sections") + .HasForeignKey("TaskId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("Task"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("TaskSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("RolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.WorkingHours", "WorkingHoursList", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("EndShiftOne") + .HasColumnType("time(0)"); + + b1.Property("EndShiftTwo") + .HasColumnType("time(0)"); + + b1.Property("HasRestTime") + .HasColumnType("bit"); + + b1.Property("HasShiftOne") + .HasColumnType("bit"); + + b1.Property("HasShiftTow") + .HasColumnType("bit"); + + b1.Property("IsActiveDay") + .HasColumnType("bit"); + + b1.Property("PersianDayOfWeek") + .HasColumnType("int"); + + b1.Property("RestTime") + .HasColumnType("time(0)"); + + b1.Property("SalaryPaymentSettingId") + .HasColumnType("bigint"); + + b1.Property("ShiftDurationInMinutes") + .HasColumnType("int"); + + b1.Property("StartShiftOne") + .HasColumnType("time(0)"); + + b1.Property("StartShiftTwo") + .HasColumnType("time(0)"); + + b1.HasKey("Id"); + + b1.HasIndex("SalaryPaymentSettingId"); + + b1.ToTable("WorkingHours", (string)null); + + b1.WithOwner("SalaryPaymentSetting") + .HasForeignKey("SalaryPaymentSettingId"); + + b1.Navigation("SalaryPaymentSetting"); + }); + + b.Navigation("WorkingHoursList"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.Property("UserId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("UserId"); + + b1.ToTable("RoleUsers", (string)null); + + b1.WithOwner("User") + .HasForeignKey("UserId"); + + b1.Navigation("User"); + }); + + b.Navigation("RoleUser"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b => + { + b.HasOne("GozareshgirProgramManager.Domain.UserAgg.Entities.User", "User") + .WithMany("RefreshTokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Navigation("Phases"); + + b.Navigation("ProjectSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Navigation("PhaseSections"); + + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Navigation("RefreshTokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251203174140_add sections.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251203174140_add sections.cs new file mode 100644 index 00000000..fb691678 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251203174140_add sections.cs @@ -0,0 +1,288 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class addsections : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + + migrationBuilder.DropForeignKey( + name: "FK_ProjectSections_Skills_SkillId", + table: "ProjectSections"); + + migrationBuilder.DropTable( + name: "ProjectSectionActivities"); + + migrationBuilder.DropTable( + name: "ProjectSectionAdditionalTimes"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ProjectSections", + table: "ProjectSections"); + + migrationBuilder.RenameTable( + name: "ProjectSections", + newName: "TaskSections"); + + migrationBuilder.RenameIndex( + name: "IX_ProjectSections_TaskId", + table: "TaskSections", + newName: "IX_TaskSections_TaskId"); + + migrationBuilder.RenameIndex( + name: "IX_ProjectSections_SkillId", + table: "TaskSections", + newName: "IX_TaskSections_SkillId"); + + migrationBuilder.AddPrimaryKey( + name: "PK_TaskSections", + table: "TaskSections", + column: "Id"); + + migrationBuilder.CreateTable( + name: "PhaseSection", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + PhaseId = table.Column(type: "uniqueidentifier", nullable: false), + UserId = table.Column(type: "bigint", nullable: false), + SkillId = table.Column(type: "uniqueidentifier", nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PhaseSection", x => x.Id); + table.ForeignKey( + name: "FK_PhaseSection_ProjectPhases_PhaseId", + column: x => x.PhaseId, + principalTable: "ProjectPhases", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ProjectSection", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ProjectId = table.Column(type: "uniqueidentifier", nullable: false), + UserId = table.Column(type: "bigint", nullable: false), + SkillId = table.Column(type: "uniqueidentifier", nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectSection", x => x.Id); + table.ForeignKey( + name: "FK_ProjectSection_Projects_ProjectId", + column: x => x.ProjectId, + principalTable: "Projects", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TaskSectionActivities", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + SectionId = table.Column(type: "uniqueidentifier", nullable: false), + UserId = table.Column(type: "bigint", nullable: false), + StartDate = table.Column(type: "datetime2", nullable: false), + EndDate = table.Column(type: "datetime2", nullable: true), + Notes = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + EndNotes = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + IsActive = table.Column(type: "bit", nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TaskSectionActivities", x => x.Id); + table.ForeignKey( + name: "FK_TaskSectionActivities_TaskSections_SectionId", + column: x => x.SectionId, + principalTable: "TaskSections", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TaskSectionAdditionalTimes", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Hours = table.Column(type: "nvarchar(30)", maxLength: 30, nullable: false), + Reason = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true), + AddedByUserId = table.Column(type: "bigint", nullable: true), + AddedAt = table.Column(type: "datetime2", nullable: false), + TaskSectionId = table.Column(type: "uniqueidentifier", nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TaskSectionAdditionalTimes", x => x.Id); + table.ForeignKey( + name: "FK_TaskSectionAdditionalTimes_TaskSections_TaskSectionId", + column: x => x.TaskSectionId, + principalTable: "TaskSections", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_PhaseSection_PhaseId", + table: "PhaseSection", + column: "PhaseId"); + + migrationBuilder.CreateIndex( + name: "IX_ProjectSection_ProjectId", + table: "ProjectSection", + column: "ProjectId"); + + migrationBuilder.CreateIndex( + name: "IX_TaskSectionActivities_SectionId", + table: "TaskSectionActivities", + column: "SectionId"); + + migrationBuilder.CreateIndex( + name: "IX_TaskSectionAdditionalTimes_TaskSectionId", + table: "TaskSectionAdditionalTimes", + column: "TaskSectionId"); + + migrationBuilder.AddForeignKey( + name: "FK_TaskSections_ProjectTasks_TaskId", + table: "TaskSections", + column: "TaskId", + principalTable: "ProjectTasks", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_TaskSections_Skills_SkillId", + table: "TaskSections", + column: "SkillId", + principalTable: "Skills", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_TaskSections_ProjectTasks_TaskId", + table: "TaskSections"); + + migrationBuilder.DropForeignKey( + name: "FK_TaskSections_Skills_SkillId", + table: "TaskSections"); + + migrationBuilder.DropTable( + name: "PhaseSection"); + + migrationBuilder.DropTable( + name: "ProjectSection"); + + migrationBuilder.DropTable( + name: "TaskSectionActivities"); + + migrationBuilder.DropTable( + name: "TaskSectionAdditionalTimes"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TaskSections", + table: "TaskSections"); + + migrationBuilder.RenameTable( + name: "TaskSections", + newName: "ProjectSections"); + + migrationBuilder.RenameIndex( + name: "IX_TaskSections_TaskId", + table: "ProjectSections", + newName: "IX_ProjectSections_TaskId"); + + migrationBuilder.RenameIndex( + name: "IX_TaskSections_SkillId", + table: "ProjectSections", + newName: "IX_ProjectSections_SkillId"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ProjectSections", + table: "ProjectSections", + column: "Id"); + + migrationBuilder.CreateTable( + name: "ProjectSectionActivities", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + SectionId = table.Column(type: "uniqueidentifier", nullable: false), + CreationDate = table.Column(type: "datetime2", nullable: false), + EndDate = table.Column(type: "datetime2", nullable: true), + EndNotes = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + IsActive = table.Column(type: "bit", nullable: false), + Notes = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + StartDate = table.Column(type: "datetime2", nullable: false), + UserId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectSectionActivities", x => x.Id); + table.ForeignKey( + name: "FK_ProjectSectionActivities_ProjectSections_SectionId", + column: x => x.SectionId, + principalTable: "ProjectSections", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ProjectSectionAdditionalTimes", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + AddedAt = table.Column(type: "datetime2", nullable: false), + AddedByUserId = table.Column(type: "bigint", nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: false), + Hours = table.Column(type: "nvarchar(30)", maxLength: 30, nullable: false), + ProjectSectionId = table.Column(type: "uniqueidentifier", nullable: true), + Reason = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectSectionAdditionalTimes", x => x.Id); + table.ForeignKey( + name: "FK_ProjectSectionAdditionalTimes_ProjectSections_ProjectSectionId", + column: x => x.ProjectSectionId, + principalTable: "ProjectSections", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_ProjectSectionActivities_SectionId", + table: "ProjectSectionActivities", + column: "SectionId"); + + migrationBuilder.CreateIndex( + name: "IX_ProjectSectionAdditionalTimes_ProjectSectionId", + table: "ProjectSectionAdditionalTimes", + column: "ProjectSectionId"); + + + migrationBuilder.AddForeignKey( + name: "FK_ProjectSections_Skills_SkillId", + table: "ProjectSections", + column: "SkillId", + principalTable: "Skills", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251206064818_add phase section and task section.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251206064818_add phase section and task section.Designer.cs new file mode 100644 index 00000000..4de07c56 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251206064818_add phase section and task section.Designer.cs @@ -0,0 +1,839 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251206064818_add phase section and task section")] + partial class addphasesectionandtasksection + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CheckoutAgg.Entities.Checkout", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CheckoutEndDate") + .HasColumnType("datetime2"); + + b.Property("CheckoutStartDate") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("DeductionFromSalary") + .HasColumnType("float"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MandatoryHours") + .HasColumnType("int"); + + b.Property("Month") + .HasColumnType("int"); + + b.Property("MonthlySalaryDefined") + .HasColumnType("float"); + + b.Property("MonthlySalaryPay") + .HasColumnType("float"); + + b.Property("RemainingHours") + .HasColumnType("int"); + + b.Property("TotalDaysWorked") + .HasColumnType("int"); + + b.Property("TotalHoursWorked") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Checkouts", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("PhaseSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("PlannedEndDate") + .HasColumnType("datetime2"); + + b.Property("PlannedStartDate") + .HasColumnType("datetime2"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Projects", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectPhases", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("HasTimeOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("ProjectTasks", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialDescription") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("InitialEstimatedHours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("OriginalAssignedUserId") + .HasColumnType("bigint"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("TaskId"); + + b.ToTable("TaskSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("TaskSectionId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TaskSectionId"); + + b.ToTable("TaskSectionAdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("GozareshgirRoleId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndSettingDate") + .HasColumnType("datetime2"); + + b.Property("HolidayWorking") + .HasColumnType("bit"); + + b.Property("MonthlySalary") + .HasColumnType("float"); + + b.Property("StartSettingDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("SalaryPaymentSetting", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ExpiresAt") + .HasColumnType("datetime2"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("RevokedAt") + .HasColumnType("datetime2"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserAgent") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ExpiresAt"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("UserRefreshTokens", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("PhaseSections") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("Phases") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("ProjectSections") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("Tasks") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", "Task") + .WithMany("Sections") + .HasForeignKey("TaskId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("Task"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("TaskSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("RolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.WorkingHours", "WorkingHoursList", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("EndShiftOne") + .HasColumnType("time(0)"); + + b1.Property("EndShiftTwo") + .HasColumnType("time(0)"); + + b1.Property("HasRestTime") + .HasColumnType("bit"); + + b1.Property("HasShiftOne") + .HasColumnType("bit"); + + b1.Property("HasShiftTow") + .HasColumnType("bit"); + + b1.Property("IsActiveDay") + .HasColumnType("bit"); + + b1.Property("PersianDayOfWeek") + .HasColumnType("int"); + + b1.Property("RestTime") + .HasColumnType("time(0)"); + + b1.Property("SalaryPaymentSettingId") + .HasColumnType("bigint"); + + b1.Property("ShiftDurationInMinutes") + .HasColumnType("int"); + + b1.Property("StartShiftOne") + .HasColumnType("time(0)"); + + b1.Property("StartShiftTwo") + .HasColumnType("time(0)"); + + b1.HasKey("Id"); + + b1.HasIndex("SalaryPaymentSettingId"); + + b1.ToTable("WorkingHours", (string)null); + + b1.WithOwner("SalaryPaymentSetting") + .HasForeignKey("SalaryPaymentSettingId"); + + b1.Navigation("SalaryPaymentSetting"); + }); + + b.Navigation("WorkingHoursList"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.Property("UserId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("UserId"); + + b1.ToTable("RoleUsers", (string)null); + + b1.WithOwner("User") + .HasForeignKey("UserId"); + + b1.Navigation("User"); + }); + + b.Navigation("RoleUser"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b => + { + b.HasOne("GozareshgirProgramManager.Domain.UserAgg.Entities.User", "User") + .WithMany("RefreshTokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Navigation("Phases"); + + b.Navigation("ProjectSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Navigation("PhaseSections"); + + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Navigation("RefreshTokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251206064818_add phase section and task section.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251206064818_add phase section and task section.cs new file mode 100644 index 00000000..889ac9de --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251206064818_add phase section and task section.cs @@ -0,0 +1,138 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class addphasesectionandtasksection : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_PhaseSection_ProjectPhases_PhaseId", + table: "PhaseSection"); + + migrationBuilder.DropForeignKey( + name: "FK_ProjectSection_Projects_ProjectId", + table: "ProjectSection"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ProjectSection", + table: "ProjectSection"); + + migrationBuilder.DropPrimaryKey( + name: "PK_PhaseSection", + table: "PhaseSection"); + + migrationBuilder.RenameTable( + name: "ProjectSection", + newName: "ProjectSections"); + + migrationBuilder.RenameTable( + name: "PhaseSection", + newName: "PhaseSections"); + + migrationBuilder.RenameIndex( + name: "IX_ProjectSection_ProjectId", + table: "ProjectSections", + newName: "IX_ProjectSections_ProjectId"); + + migrationBuilder.RenameIndex( + name: "IX_PhaseSection_PhaseId", + table: "PhaseSections", + newName: "IX_PhaseSections_PhaseId"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ProjectSections", + table: "ProjectSections", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_PhaseSections", + table: "PhaseSections", + column: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_PhaseSections_ProjectPhases_PhaseId", + table: "PhaseSections", + column: "PhaseId", + principalTable: "ProjectPhases", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ProjectSections_Projects_ProjectId", + table: "ProjectSections", + column: "ProjectId", + principalTable: "Projects", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_PhaseSections_ProjectPhases_PhaseId", + table: "PhaseSections"); + + migrationBuilder.DropForeignKey( + name: "FK_ProjectSections_Projects_ProjectId", + table: "ProjectSections"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ProjectSections", + table: "ProjectSections"); + + migrationBuilder.DropPrimaryKey( + name: "PK_PhaseSections", + table: "PhaseSections"); + + migrationBuilder.RenameTable( + name: "ProjectSections", + newName: "ProjectSection"); + + migrationBuilder.RenameTable( + name: "PhaseSections", + newName: "PhaseSection"); + + migrationBuilder.RenameIndex( + name: "IX_ProjectSections_ProjectId", + table: "ProjectSection", + newName: "IX_ProjectSection_ProjectId"); + + migrationBuilder.RenameIndex( + name: "IX_PhaseSections_PhaseId", + table: "PhaseSection", + newName: "IX_PhaseSection_PhaseId"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ProjectSection", + table: "ProjectSection", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_PhaseSection", + table: "PhaseSection", + column: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_PhaseSection_ProjectPhases_PhaseId", + table: "PhaseSection", + column: "PhaseId", + principalTable: "ProjectPhases", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ProjectSection_Projects_ProjectId", + table: "ProjectSection", + column: "ProjectId", + principalTable: "Projects", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251207080830_RoleAndRolePermissionTablerenamed.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251207080830_RoleAndRolePermissionTablerenamed.Designer.cs new file mode 100644 index 00000000..c7e4fc0a --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251207080830_RoleAndRolePermissionTablerenamed.Designer.cs @@ -0,0 +1,905 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251207080830_RoleAndRolePermissionTablerenamed")] + partial class RoleAndRolePermissionTablerenamed + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CheckoutAgg.Entities.Checkout", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CheckoutEndDate") + .HasColumnType("datetime2"); + + b.Property("CheckoutStartDate") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("DeductionFromSalary") + .HasColumnType("float"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MandatoryHours") + .HasColumnType("int"); + + b.Property("Month") + .HasColumnType("int"); + + b.Property("MonthlySalaryDefined") + .HasColumnType("float"); + + b.Property("MonthlySalaryPay") + .HasColumnType("float"); + + b.Property("RemainingHours") + .HasColumnType("int"); + + b.Property("TotalDaysWorked") + .HasColumnType("int"); + + b.Property("TotalHoursWorked") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Checkouts", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.HolidayAgg.Holiday", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Year") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("nvarchar(4)"); + + b.HasKey("Id"); + + b.ToTable("Holidays", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.HolidayItemAgg.HolidayItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("HolidayId") + .HasColumnType("bigint"); + + b.Property("HolidayYear") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("nvarchar(4)"); + + b.Property("Holidaydate") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("HolidayId"); + + b.ToTable("Holidayitems", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("PhaseSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("PlannedEndDate") + .HasColumnType("datetime2"); + + b.Property("PlannedStartDate") + .HasColumnType("datetime2"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Projects", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectPhases", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("HasTimeOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("ProjectTasks", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialDescription") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("InitialEstimatedHours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("OriginalAssignedUserId") + .HasColumnType("bigint"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("TaskId"); + + b.ToTable("TaskSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("TaskSectionId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TaskSectionId"); + + b.ToTable("TaskSectionAdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("GozareshgirRoleId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("PmRoles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndSettingDate") + .HasColumnType("datetime2"); + + b.Property("HolidayWorking") + .HasColumnType("bit"); + + b.Property("MonthlySalary") + .HasColumnType("float"); + + b.Property("StartSettingDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("SalaryPaymentSetting", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ExpiresAt") + .HasColumnType("datetime2"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("RevokedAt") + .HasColumnType("datetime2"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserAgent") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ExpiresAt"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("UserRefreshTokens", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.HolidayItemAgg.HolidayItem", b => + { + b.HasOne("GozareshgirProgramManager.Domain.HolidayAgg.Holiday", "Holidayss") + .WithMany("HolidayItems") + .HasForeignKey("HolidayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Holidayss"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("PhaseSections") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("Phases") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("ProjectSections") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("Tasks") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", "Task") + .WithMany("Sections") + .HasForeignKey("TaskId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("Task"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("TaskSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("PmRolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.WorkingHours", "WorkingHoursList", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("EndShiftOne") + .HasColumnType("time(0)"); + + b1.Property("EndShiftTwo") + .HasColumnType("time(0)"); + + b1.Property("HasRestTime") + .HasColumnType("bit"); + + b1.Property("HasShiftOne") + .HasColumnType("bit"); + + b1.Property("HasShiftTow") + .HasColumnType("bit"); + + b1.Property("IsActiveDay") + .HasColumnType("bit"); + + b1.Property("PersianDayOfWeek") + .HasColumnType("int"); + + b1.Property("RestTime") + .HasColumnType("time(0)"); + + b1.Property("SalaryPaymentSettingId") + .HasColumnType("bigint"); + + b1.Property("ShiftDurationInMinutes") + .HasColumnType("int"); + + b1.Property("StartShiftOne") + .HasColumnType("time(0)"); + + b1.Property("StartShiftTwo") + .HasColumnType("time(0)"); + + b1.HasKey("Id"); + + b1.HasIndex("SalaryPaymentSettingId"); + + b1.ToTable("WorkingHours", (string)null); + + b1.WithOwner("SalaryPaymentSetting") + .HasForeignKey("SalaryPaymentSettingId"); + + b1.Navigation("SalaryPaymentSetting"); + }); + + b.Navigation("WorkingHoursList"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.Property("UserId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("UserId"); + + b1.ToTable("RoleUsers", (string)null); + + b1.WithOwner("User") + .HasForeignKey("UserId"); + + b1.Navigation("User"); + }); + + b.Navigation("RoleUser"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b => + { + b.HasOne("GozareshgirProgramManager.Domain.UserAgg.Entities.User", "User") + .WithMany("RefreshTokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.HolidayAgg.Holiday", b => + { + b.Navigation("HolidayItems"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Navigation("Phases"); + + b.Navigation("ProjectSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Navigation("PhaseSections"); + + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Navigation("RefreshTokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251207080830_RoleAndRolePermissionTablerenamed.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251207080830_RoleAndRolePermissionTablerenamed.cs new file mode 100644 index 00000000..4b02748e --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251207080830_RoleAndRolePermissionTablerenamed.cs @@ -0,0 +1,109 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class RoleAndRolePermissionTablerenamed : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RolePermissions"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Roles", + table: "Roles"); + + migrationBuilder.RenameTable( + name: "Roles", + newName: "PmRoles"); + + migrationBuilder.AddPrimaryKey( + name: "PK_PmRoles", + table: "PmRoles", + column: "Id"); + + + + migrationBuilder.CreateTable( + name: "PmRolePermissions", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Code = table.Column(type: "int", nullable: false), + RoleId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PmRolePermissions", x => x.Id); + table.ForeignKey( + name: "FK_PmRolePermissions_PmRoles_RoleId", + column: x => x.RoleId, + principalTable: "PmRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + + + migrationBuilder.CreateIndex( + name: "IX_PmRolePermissions_RoleId", + table: "PmRolePermissions", + column: "RoleId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + + migrationBuilder.DropTable( + name: "PmRolePermissions"); + + + + migrationBuilder.DropPrimaryKey( + name: "PK_PmRoles", + table: "PmRoles"); + + migrationBuilder.RenameTable( + name: "PmRoles", + newName: "Roles"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Roles", + table: "Roles", + column: "Id"); + + migrationBuilder.CreateTable( + name: "RolePermissions", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + RoleId = table.Column(type: "bigint", nullable: false), + Code = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RolePermissions", x => x.Id); + table.ForeignKey( + name: "FK_RolePermissions_Roles_RoleId", + column: x => x.RoleId, + principalTable: "Roles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_RolePermissions_RoleId", + table: "RolePermissions", + column: "RoleId"); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/AppDbContextModelSnapshot.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/AppDbContextModelSnapshot.cs new file mode 100644 index 00000000..8e4c3871 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/AppDbContextModelSnapshot.cs @@ -0,0 +1,902 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + partial class AppDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CheckoutAgg.Entities.Checkout", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CheckoutEndDate") + .HasColumnType("datetime2"); + + b.Property("CheckoutStartDate") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("DeductionFromSalary") + .HasColumnType("float"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MandatoryHours") + .HasColumnType("int"); + + b.Property("Month") + .HasColumnType("int"); + + b.Property("MonthlySalaryDefined") + .HasColumnType("float"); + + b.Property("MonthlySalaryPay") + .HasColumnType("float"); + + b.Property("RemainingHours") + .HasColumnType("int"); + + b.Property("TotalDaysWorked") + .HasColumnType("int"); + + b.Property("TotalHoursWorked") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Checkouts", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.HolidayAgg.Holiday", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Year") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("nvarchar(4)"); + + b.HasKey("Id"); + + b.ToTable("Holidays", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.HolidayItemAgg.HolidayItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("HolidayId") + .HasColumnType("bigint"); + + b.Property("HolidayYear") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("nvarchar(4)"); + + b.Property("Holidaydate") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("HolidayId"); + + b.ToTable("Holidayitems", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("PhaseSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("PlannedEndDate") + .HasColumnType("datetime2"); + + b.Property("PlannedStartDate") + .HasColumnType("datetime2"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Projects", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectPhases", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("HasTimeOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("ProjectTasks", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialDescription") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("InitialEstimatedHours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("OriginalAssignedUserId") + .HasColumnType("bigint"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("TaskId"); + + b.ToTable("TaskSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("TaskSectionId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TaskSectionId"); + + b.ToTable("TaskSectionAdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("GozareshgirRoleId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("PmRoles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndSettingDate") + .HasColumnType("datetime2"); + + b.Property("HolidayWorking") + .HasColumnType("bit"); + + b.Property("MonthlySalary") + .HasColumnType("float"); + + b.Property("StartSettingDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("SalaryPaymentSetting", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ExpiresAt") + .HasColumnType("datetime2"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("RevokedAt") + .HasColumnType("datetime2"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserAgent") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ExpiresAt"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("UserRefreshTokens", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.HolidayItemAgg.HolidayItem", b => + { + b.HasOne("GozareshgirProgramManager.Domain.HolidayAgg.Holiday", "Holidayss") + .WithMany("HolidayItems") + .HasForeignKey("HolidayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Holidayss"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("PhaseSections") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("Phases") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("ProjectSections") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("Tasks") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", "Task") + .WithMany("Sections") + .HasForeignKey("TaskId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("Task"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("TaskSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("PmRolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.WorkingHours", "WorkingHoursList", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("EndShiftOne") + .HasColumnType("time(0)"); + + b1.Property("EndShiftTwo") + .HasColumnType("time(0)"); + + b1.Property("HasRestTime") + .HasColumnType("bit"); + + b1.Property("HasShiftOne") + .HasColumnType("bit"); + + b1.Property("HasShiftTow") + .HasColumnType("bit"); + + b1.Property("IsActiveDay") + .HasColumnType("bit"); + + b1.Property("PersianDayOfWeek") + .HasColumnType("int"); + + b1.Property("RestTime") + .HasColumnType("time(0)"); + + b1.Property("SalaryPaymentSettingId") + .HasColumnType("bigint"); + + b1.Property("ShiftDurationInMinutes") + .HasColumnType("int"); + + b1.Property("StartShiftOne") + .HasColumnType("time(0)"); + + b1.Property("StartShiftTwo") + .HasColumnType("time(0)"); + + b1.HasKey("Id"); + + b1.HasIndex("SalaryPaymentSettingId"); + + b1.ToTable("WorkingHours", (string)null); + + b1.WithOwner("SalaryPaymentSetting") + .HasForeignKey("SalaryPaymentSettingId"); + + b1.Navigation("SalaryPaymentSetting"); + }); + + b.Navigation("WorkingHoursList"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.Property("UserId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("UserId"); + + b1.ToTable("RoleUsers", (string)null); + + b1.WithOwner("User") + .HasForeignKey("UserId"); + + b1.Navigation("User"); + }); + + b.Navigation("RoleUser"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b => + { + b.HasOne("GozareshgirProgramManager.Domain.UserAgg.Entities.User", "User") + .WithMany("RefreshTokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.HolidayAgg.Holiday", b => + { + b.Navigation("HolidayItems"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Navigation("Phases"); + + b.Navigation("ProjectSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Navigation("PhaseSections"); + + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Navigation("RefreshTokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Context/GozareshgirDbContext.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Context/GozareshgirDbContext.cs new file mode 100644 index 00000000..181e1779 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Context/GozareshgirDbContext.cs @@ -0,0 +1,22 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Domain.HolidayAgg; +using GozareshgirProgramManager.Domain.HolidayItemAgg; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Context; + +public class GozareshgirDbContext : DbContext, IGozareshgirDbContext +{ + public GozareshgirDbContext(DbContextOptions options) : base(options) + { + } + + public DbSet HolidayItems { get; set; } = null!; + public DbSet Holidays { get; set; } = null!; + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.ApplyConfigurationsFromAssembly(typeof(GozareshgirDbContext).Assembly); + base.OnModelCreating(modelBuilder); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Context/ProgramManagerDbContext.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Context/ProgramManagerDbContext.cs new file mode 100644 index 00000000..2fc4854c --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Context/ProgramManagerDbContext.cs @@ -0,0 +1,61 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; + using GozareshgirProgramManager.Domain.CheckoutAgg.Entities; + using GozareshgirProgramManager.Domain.CustomerAgg; +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Domain.CustomerAgg; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.RoleAgg.Entities; +using GozareshgirProgramManager.Domain.RoleUserAgg; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities; +using GozareshgirProgramManager.Domain.UserAgg.Entities; +using GozareshgirProgramManager.Domain.SkillAgg.Entities; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Context; + +public class ProgramManagerDbContext : DbContext, IProgramManagerDbContext +{ + public ProgramManagerDbContext(DbContextOptions options) : base(options) + { + } + + public DbSet Customers { get; set; } = null!; + public DbSet TaskSections { get; set; } = null!; + public DbSet ProjectSections { get; set; } = null!; + public DbSet PhaseSections { get; set; } = null!; + + // New Hierarchy entities + public DbSet Projects { get; set; } = null!; + public DbSet ProjectPhases { get; set; } = null!; + public DbSet ProjectTasks { get; set; } = null!; + + public DbSet TaskSectionActivities { get; set; } = null!; + public DbSet TaskSectionAdditionalTimes { get; set; } = null!; + + public DbSet Users { get; set; } = null!; + public DbSet RefreshTokens { get; set; } = null!; + + public DbSet Checkouts { get; set; } = null!; + public DbSet SalaryPaymentSettings { get; set; } = null!; + public DbSet Roles { get; set; } = null!; + + public DbSet Skills { get; set; } = null!; + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.ApplyConfigurationsFromAssembly(typeof(ProgramManagerDbContext).Assembly); + base.OnModelCreating(modelBuilder); + } + + public async Task SeedSkillsIfEmptyAsync() + { + if (!Skills.Any()) + { + Skills.AddRange( + new Skill("UI/UX Design"), + new Skill("Frontend"), + new Skill("Backend") + ); + await SaveChangesAsync(); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/AdditionalTimeMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/AdditionalTimeMapping.cs new file mode 100644 index 00000000..6c73bc87 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/AdditionalTimeMapping.cs @@ -0,0 +1,23 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class AdditionalTimeMapping:IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("AdditionalTimes"); + + builder.HasKey(ts => ts.Id); + + builder.Property(ts => ts.Id) + .ValueGeneratedNever(); + + builder.Property(x => x.Reason).HasMaxLength(1000); + + builder.Property(x => x.Hours).HasTimeSpanConversion(); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/CheckoutMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/CheckoutMapping.cs new file mode 100644 index 00000000..3c8d83f8 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/CheckoutMapping.cs @@ -0,0 +1,19 @@ +using GozareshgirProgramManager.Domain.CheckoutAgg.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class CheckoutMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("Checkouts"); + builder.HasKey(s => s.Id); + + builder.Property(s => s.Id) + .ValueGeneratedNever(); + + builder.Property(x => x.FullName).HasMaxLength(100); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/CustomerMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/CustomerMapping.cs new file mode 100644 index 00000000..e40e9b14 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/CustomerMapping.cs @@ -0,0 +1,29 @@ +using GozareshgirProgramManager.Domain.CustomerAgg; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class CustomerMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("Customers"); + + builder.HasKey(c => c.Id); + + builder.Property(c => c.Id) + .ValueGeneratedNever(); + + builder.Property(c => c.Name) + .IsRequired() + .HasMaxLength(200); + + builder.Property(c => c.Email) + .IsRequired() + .HasMaxLength(256); + + builder.Property(c => c.CreatedAt) + .IsRequired(); + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/HolidayItemMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/HolidayItemMapping.cs new file mode 100644 index 00000000..42eff124 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/HolidayItemMapping.cs @@ -0,0 +1,20 @@ +using GozareshgirProgramManager.Domain.HolidayItemAgg; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class HolidayItemMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("Holidayitems"); + builder.HasKey(x => x.Id); + + builder.Property(x => x.HolidayYear).HasMaxLength(4); + + builder.HasOne(x => x.Holidayss) + .WithMany(x => x.HolidayItems) + .HasForeignKey(x => x.HolidayId); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/HolidayMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/HolidayMapping.cs new file mode 100644 index 00000000..3038d89a --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/HolidayMapping.cs @@ -0,0 +1,20 @@ +using GozareshgirProgramManager.Domain.HolidayAgg; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class HolidayMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("Holidays"); + builder.HasKey(x => x.Id); + + builder.Property(x => x.Year).HasMaxLength(4); + + builder.HasMany(x => x.HolidayItems) + .WithOne(x => x.Holidayss) + .HasForeignKey(x => x.HolidayId); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/PhaseSectionMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/PhaseSectionMapping.cs new file mode 100644 index 00000000..c1db7d49 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/PhaseSectionMapping.cs @@ -0,0 +1,21 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class PhaseSectionMapping:IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(ps => ps.Id); + + builder.Property(ps => ps.Id) + .ValueGeneratedOnAdd(); + + builder.HasOne(ps => ps.Phase) + .WithMany(p => p.PhaseSections) + .HasForeignKey(ps => ps.PhaseId) + .OnDelete(DeleteBehavior.Cascade); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectMapping.cs new file mode 100644 index 00000000..69a79750 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectMapping.cs @@ -0,0 +1,58 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class ProjectMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("Projects"); + + builder.HasKey(p => p.Id); + + builder.Property(p => p.Id) + .ValueGeneratedNever(); + + builder.Property(p => p.Name) + .HasMaxLength(200) + .IsRequired(); + + builder.Property(p => p.Description) + .HasMaxLength(1000) + .IsRequired(false); + + builder.Property(p => p.CreationDate) + .IsRequired(); + + builder.Property(p => p.StartDate) + .IsRequired(false); + + builder.Property(p => p.EndDate) + .IsRequired(false); + + builder.Property(p => p.PlannedStartDate) + .IsRequired(false); + + builder.Property(p => p.PlannedEndDate) + .IsRequired(false); + + builder.Property(p => p.Status) + .HasConversion() + .HasMaxLength(50) + .IsRequired(); + + builder.Property(p => p.HasAssignmentOverride) + .IsRequired(); + + // One-to-many relationship with ProjectPhases + builder.HasMany(p => p.Phases) + .WithOne(ph => ph.Project) + .HasForeignKey(ph => ph.ProjectId) + .OnDelete(DeleteBehavior.Cascade); + + + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectPhaseMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectPhaseMapping.cs new file mode 100644 index 00000000..838b7f0e --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectPhaseMapping.cs @@ -0,0 +1,64 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class ProjectPhaseMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("ProjectPhases"); + + builder.HasKey(ph => ph.Id); + + builder.Property(ph => ph.Id) + .ValueGeneratedNever(); + + builder.Property(ph => ph.Name) + .HasMaxLength(200) + .IsRequired(); + + builder.Property(ph => ph.Description) + .HasMaxLength(1000) + .IsRequired(false); + + builder.Property(ph => ph.CreationDate) + .IsRequired(); + + builder.Property(ph => ph.ProjectId) + .IsRequired(); + + builder.Property(ph => ph.Status) + .HasConversion() + .HasMaxLength(50) + .IsRequired(); + + builder.Property(ph => ph.StartDate) + .IsRequired(false); + + builder.Property(ph => ph.EndDate) + .IsRequired(false); + + builder.Property(ph => ph.OrderIndex) + .IsRequired(); + + + builder.Property(ph => ph.HasAssignmentOverride) + .IsRequired(); + + // Relationship with Project + builder.HasOne(ph => ph.Project) + .WithMany(p => p.Phases) + .HasForeignKey(ph => ph.ProjectId) + .OnDelete(DeleteBehavior.Cascade); + + // One-to-many relationship with ProjectTasks + builder.HasMany(ph => ph.Tasks) + .WithOne(t => t.Phase) + .HasForeignKey(t => t.PhaseId) + .OnDelete(DeleteBehavior.Cascade); + + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectSectionMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectSectionMapping.cs new file mode 100644 index 00000000..ebc8df44 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectSectionMapping.cs @@ -0,0 +1,20 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class ProjectSectionMapping:IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + builder.Property(x => x.Id) + .ValueGeneratedNever(); + + builder.HasOne(x => x.Project) + .WithMany(x => x.ProjectSections) + .HasForeignKey(x => x.ProjectId) + .OnDelete(DeleteBehavior.Cascade); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectTaskMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectTaskMapping.cs new file mode 100644 index 00000000..705af3d6 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectTaskMapping.cs @@ -0,0 +1,79 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class ProjectTaskMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("ProjectTasks"); + + builder.HasKey(t => t.Id); + + builder.Property(t => t.Id) + .ValueGeneratedNever(); + + builder.Property(t => t.Name) + .HasMaxLength(200) + .IsRequired(); + + builder.Property(t => t.Description) + .HasMaxLength(1000) + .IsRequired(false); + + builder.Property(t => t.CreationDate) + .IsRequired(); + + builder.Property(t => t.PhaseId) + .IsRequired(); + + builder.Property(t => t.Status) + .HasConversion() + .HasMaxLength(50) + .IsRequired(); + + builder.Property(t => t.Priority) + .HasConversion() + .HasMaxLength(50) + .IsRequired(); + + builder.Property(t => t.StartDate) + .IsRequired(false); + + builder.Property(t => t.EndDate) + .IsRequired(false); + + builder.Property(t => t.DueDate) + .IsRequired(false); + + builder.Property(t => t.OrderIndex) + .IsRequired(); + + builder.Property(t => t.AllocatedTime) + .HasTimeSpanConversion() + .IsRequired(false); + + builder.Property(t => t.HasTimeOverride) + .IsRequired(); + + builder.Property(t => t.HasAssignmentOverride) + .IsRequired(); + + // Relationship with ProjectPhase + builder.HasOne(t => t.Phase) + .WithMany(ph => ph.Tasks) + .HasForeignKey(t => t.PhaseId) + .OnDelete(DeleteBehavior.Cascade); + + // One-to-many relationship with ProjectSections + builder.HasMany(t => t.Sections) + .WithOne(s => s.Task) + .HasForeignKey(s => s.TaskId) + .OnDelete(DeleteBehavior.Cascade); + + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/RefreshTokenMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/RefreshTokenMapping.cs new file mode 100644 index 00000000..42ac6330 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/RefreshTokenMapping.cs @@ -0,0 +1,50 @@ +using GozareshgirProgramManager.Domain.UserAgg.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class RefreshTokenMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("UserRefreshTokens"); + builder.HasKey(x => x.Id); + + builder.Property(x => x.Token) + .HasMaxLength(500) + .IsRequired(); + + builder.Property(x => x.ExpiresAt) + .IsRequired(); + + builder.Property(x => x.RevokedAt) + .IsRequired(false); + + builder.Property(x => x.IpAddress) + .HasMaxLength(50) + .IsRequired(false); + + builder.Property(x => x.UserAgent) + .HasMaxLength(500) + .IsRequired(false); + + builder.Property(x => x.UserId) + .IsRequired(); + + // رابطه با User + builder.HasOne(x => x.User) + .WithMany(u => u.RefreshTokens) + .HasForeignKey(x => x.UserId) + .OnDelete(DeleteBehavior.Cascade); + + // Index برای بهینه‌سازی جستجو + builder.HasIndex(x => x.Token) + .IsUnique(); + + builder.HasIndex(x => x.UserId); + + builder.HasIndex(x => x.ExpiresAt); + } +} + diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/RoleMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/RoleMapping.cs new file mode 100644 index 00000000..085a3d81 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/RoleMapping.cs @@ -0,0 +1,23 @@ +using GozareshgirProgramManager.Domain.RoleAgg.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class RoleMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("PmRoles"); + builder.HasKey(x => x.Id); + + builder.Property(x => x.RoleName).HasMaxLength(100).IsRequired(); + + builder.OwnsMany(x => x.Permissions, navigationBuilder => + { + navigationBuilder.HasKey(x => x.Id); + navigationBuilder.ToTable("PmRolePermissions"); + navigationBuilder.WithOwner(x => x.Role); + }); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/SalaryPaymentSettingMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/SalaryPaymentSettingMapping.cs new file mode 100644 index 00000000..f6d69733 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/SalaryPaymentSettingMapping.cs @@ -0,0 +1,50 @@ +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Enums; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class SalaryPaymentSettingMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("SalaryPaymentSetting"); + builder.HasKey(x => x.Id); + + builder.Property(x => x.StartSettingDate).IsRequired(false); + builder.Property(x => x.EndSettingDate).IsRequired(false); + + builder.OwnsMany(x => x.WorkingHoursList, navigationBuilder => + { + navigationBuilder.HasKey(x => x.Id); + navigationBuilder.ToTable("WorkingHours"); + navigationBuilder.WithOwner(x => x.SalaryPaymentSetting); + + navigationBuilder.Property(x => x.StartShiftOne) + .HasColumnType("time(0)") + .IsRequired(true); + + navigationBuilder.Property(x => x.EndShiftOne) + .HasColumnType("time(0)") + .IsRequired(true); + + navigationBuilder.Property(x => x.StartShiftTwo) + .HasColumnType("time(0)") + .IsRequired(true); + + navigationBuilder.Property(x => x.EndShiftTwo) + .HasColumnType("time(0)") + .IsRequired(true); + + navigationBuilder.Property(x => x.RestTime) + .HasColumnType("time(0)") + .IsRequired(true); + + navigationBuilder + .Property(x => x.PersianDayOfWeek) + .HasConversion(); + + }); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/SkillMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/SkillMapping.cs new file mode 100644 index 00000000..b142abe8 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/SkillMapping.cs @@ -0,0 +1,27 @@ +using GozareshgirProgramManager.Domain.SkillAgg.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class SkillMapping:IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("Skills"); + + builder.HasKey(s => s.Id); + + builder.Property(s => s.Id) + .ValueGeneratedNever(); + + builder.Property(s => s.Name) + .IsRequired() + .HasMaxLength(200); + + builder.HasMany(x=>x.Sections) + .WithOne(x => x.Skill) + .HasForeignKey(f=>f.SkillId) + .OnDelete(DeleteBehavior.Cascade); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/TaskSectionActivityMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/TaskSectionActivityMapping.cs new file mode 100644 index 00000000..84f4227e --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/TaskSectionActivityMapping.cs @@ -0,0 +1,53 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class TaskSectionActivityMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("TaskSectionActivities"); + + builder.HasKey(a => a.Id); + + builder.Property(a => a.Id) + .ValueGeneratedNever(); + + builder.Property(a => a.SectionId) + .IsRequired(); + + builder.Property(a => a.UserId) + .IsRequired(); + + builder.Property(a => a.StartDate) + .IsRequired(); + + builder.Property(a => a.EndDate) + .IsRequired(false); + + builder.Property(a => a.Notes) + .HasMaxLength(1000) + .IsRequired(false); + + builder.Property(a => a.EndNotes) + .HasMaxLength(1000) + .IsRequired(false); + + builder.Property(a => a.IsActive) + .IsRequired(); + + builder.Property(a => a.CreationDate) + .IsRequired(); + + // Relationship with TaskSection + builder.HasOne(a => a.Section) + .WithMany(s => s.Activities) + .HasForeignKey(a => a.SectionId) + .OnDelete(DeleteBehavior.Cascade); + + // Ignore domain events + builder.Ignore(a => a.DomainEvents); + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/TaskSectionAdditionalTimeMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/TaskSectionAdditionalTimeMapping.cs new file mode 100644 index 00000000..e6789d94 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/TaskSectionAdditionalTimeMapping.cs @@ -0,0 +1,39 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class TaskSectionAdditionalTimeMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("TaskSectionAdditionalTimes"); + + builder.HasKey(at => at.Id); + + builder.Property(at => at.Id) + .ValueGeneratedNever(); + + builder.Property(at => at.Hours) + .HasTimeSpanConversion() + .IsRequired(); + + builder.Property(at => at.Reason) + .HasMaxLength(500) + .IsRequired(false); + + builder.Property(at => at.AddedByUserId) + .IsRequired(false); + + builder.Property(at => at.AddedAt) + .IsRequired(); + + builder.Property(at => at.CreationDate) + .IsRequired(); + + // Ignore domain events + builder.Ignore(at => at.DomainEvents); + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/TaskSectionMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/TaskSectionMapping.cs new file mode 100644 index 00000000..836580f0 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/TaskSectionMapping.cs @@ -0,0 +1,53 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class TaskSectionMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("TaskSections"); + + builder.HasKey(ts => ts.Id); + + builder.Property(ts => ts.Id) + .ValueGeneratedNever(); + + builder.Property(ts => ts.TaskId) + .IsRequired(); + + + builder.Property(ts => ts.InitialEstimatedHours) + .HasTimeSpanConversion(); + + builder.Property(ts => ts.Status) + .HasConversion() + .HasMaxLength(50) + .IsRequired(); + + builder.Property(x=>x.InitialDescription) + .HasMaxLength(500) + .IsRequired(false); + + builder.Property(ts => ts.CurrentAssignedUserId); + + // Navigation to ProjectTask (Task level) + builder.HasOne(ts => ts.Task) + .WithMany(t => t.Sections) + .HasForeignKey(ts => ts.TaskId) + .OnDelete(DeleteBehavior.Cascade); + + builder.HasMany(ts => ts.Activities) + .WithOne(a => a.Section) + .HasForeignKey(a => a.SectionId) + .OnDelete(DeleteBehavior.Cascade); + + builder.HasOne(x => x.Skill) + .WithMany(y => y.Sections).HasForeignKey(y => y.SkillId) + .OnDelete(DeleteBehavior.Cascade); + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/UserMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/UserMapping.cs new file mode 100644 index 00000000..39ca99ac --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/UserMapping.cs @@ -0,0 +1,34 @@ +using GozareshgirProgramManager.Domain.UserAgg.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings; + +public class UserMapping :IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("Users"); + builder.HasKey(x => x.Id); + + builder.Property(x => x.FullName).HasMaxLength(100).IsRequired(); + builder.Property(x => x.UserName).HasMaxLength(100).IsRequired(); + builder.Property(x => x.Password).HasMaxLength(1000).IsRequired(); + builder.Property(x => x.ProfilePhotoPath).HasMaxLength(500).IsRequired(false); + builder.Property(x => x.Mobile).HasMaxLength(20).IsRequired(); + builder.Property(x => x.Email).HasMaxLength(150).IsRequired(false); ; + builder.Property(x => x.VerifyCode).HasMaxLength(10).IsRequired(false); + builder.OwnsMany(x => x.RoleUser, navigationBuilder => + { + navigationBuilder.HasKey(x => x.Id); + navigationBuilder.ToTable("RoleUsers"); + navigationBuilder.WithOwner(x => x.User); + }); + + builder.HasMany(x=>x.RefreshTokens) + .WithOne(x=>x.User) + .HasForeignKey(x=>x.UserId) + .OnDelete(DeleteBehavior.Cascade); + + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/CheckoutRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/CheckoutRepository.cs new file mode 100644 index 00000000..a34fcce7 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/CheckoutRepository.cs @@ -0,0 +1,22 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.CheckoutAgg.Entities; +using GozareshgirProgramManager.Domain.CheckoutAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class CheckoutRepository : RepositoryBase, ICheckoutRepository +{ + private readonly ProgramManagerDbContext _context; + public CheckoutRepository(ProgramManagerDbContext context) : base(context) + { + _context = context; + } + + public async Task> GetCheckoutListByIds(List checkoutIds) + { + return await _context.Checkouts.Where(x => checkoutIds.Contains(x.Id)).ToListAsync(); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/CustomerRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/CustomerRepository.cs new file mode 100644 index 00000000..da0d9037 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/CustomerRepository.cs @@ -0,0 +1,38 @@ +using Microsoft.EntityFrameworkCore; +using GozareshgirProgramManager.Domain.CustomerAgg; +using GozareshgirProgramManager.Domain.CustomerAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class CustomerRepository : ICustomerRepository +{ + private readonly ProgramManagerDbContext _context; + + public CustomerRepository(ProgramManagerDbContext context) + { + _context = context; + } + + public async Task GetByIdAsync(Guid id, CancellationToken cancellationToken = default) + { + return await _context.Customers + .FirstOrDefaultAsync(c => c.Id == id, cancellationToken); + } + + public async Task AddAsync(Customer customer, CancellationToken cancellationToken = default) + { + await _context.Customers.AddAsync(customer, cancellationToken); + } + + public void Update(Customer customer) + { + _context.Customers.Update(customer); + } + + public void Delete(Customer customer) + { + _context.Customers.Remove(customer); + } +} + diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/OrderRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/OrderRepository.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/PhaseSectionRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/PhaseSectionRepository.cs new file mode 100644 index 00000000..c582dffd --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/PhaseSectionRepository.cs @@ -0,0 +1,18 @@ +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; +public class PhaseSectionRepository : RepositoryBase, IPhaseSectionRepository +{ + private readonly ProgramManagerDbContext _programManagerDbContext; + public PhaseSectionRepository(ProgramManagerDbContext context) : base(context) + { + _programManagerDbContext = context; + } + +} + + + diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProductRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProductRepository.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectPhaseRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectPhaseRepository.cs new file mode 100644 index 00000000..81306c82 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectPhaseRepository.cs @@ -0,0 +1,60 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class ProjectPhaseRepository : RepositoryBase, IProjectPhaseRepository +{ + private readonly ProgramManagerDbContext _context; + + public ProjectPhaseRepository(ProgramManagerDbContext context) : base(context) + { + _context = context; + } + + public Task GetWithTasksAsync(Guid phaseId) + { + return _context.ProjectPhases + .Include(p => p.Tasks) + .ThenInclude(t => t.Sections) + .ThenInclude(s => s.Skill) + .Include(p => p.Tasks) + .ThenInclude(t => t.Sections) + .ThenInclude(s => s.Activities) + .Include(p => p.Tasks) + .ThenInclude(t => t.Sections) + .ThenInclude(s => s.AdditionalTimes) + .FirstOrDefaultAsync(p => p.Id == phaseId); + } + + public Task> GetByProjectIdAsync(Guid projectId) + { + return _context.ProjectPhases + .Where(p => p.ProjectId == projectId) + .OrderBy(p => p.OrderIndex) + .ToListAsync(); + } + + public Task> GetPhasesWithAssignmentOverridesAsync() + { + return _context.ProjectPhases + .Where(p => p.HasAssignmentOverride) + .ToListAsync(); + } + + public Task> GetByStatusAsync(PhaseStatus status) + { + return _context.ProjectPhases + .Where(p => p.Status == status) + .ToListAsync(); + } + + public void Remove(ProjectPhase phase) + { + _context.ProjectPhases.Remove(phase); + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectRepository.cs new file mode 100644 index 00000000..21afca93 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectRepository.cs @@ -0,0 +1,70 @@ + +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class ProjectRepository : RepositoryBase, IProjectRepository +{ + private readonly ProgramManagerDbContext _context; + + public ProjectRepository(ProgramManagerDbContext context) : base(context) + { + _context = context; + } + + public Task GetWithFullHierarchyAsync(Guid projectId) + { + return _context.Projects + .Include(p => p.Phases) + .ThenInclude(ph => ph.Tasks) + .ThenInclude(t => t.Sections) + .ThenInclude(s => s.Skill) + .Include(p => p.Phases) + .ThenInclude(ph => ph.Tasks) + .ThenInclude(t => t.Sections) + .ThenInclude(s => s.Activities) + .Include(p => p.Phases) + .ThenInclude(ph => ph.Tasks) + .ThenInclude(t => t.Sections) + .ThenInclude(s => s.AdditionalTimes) + .FirstOrDefaultAsync(p => p.Id == projectId); + } + + public Task GetWithPhasesAsync(Guid projectId) + { + return _context.Projects + .Include(p => p.Phases) + .FirstOrDefaultAsync(p => p.Id == projectId); + } + + public Task> GetByStatusAsync(ProjectStatus status) + { + return _context.Projects + .Where(p => p.Status == status) + .ToListAsync(); + } + + public Task> GetProjectsWithAssignmentOverridesAsync() + { + return _context.Projects + .Where(p => p.HasAssignmentOverride) + .ToListAsync(); + } + + public Task> SearchByNameAsync(string searchTerm) + { + return _context.Projects + .Where(p => p.Name.Contains(searchTerm)) + .ToListAsync(); + } + + public void Remove(Project project) + { + _context.Projects.Remove(project); + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectSectionRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectSectionRepository.cs new file mode 100644 index 00000000..d2b115db --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectSectionRepository.cs @@ -0,0 +1,17 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class ProjectSectionRepository : RepositoryBase, IProjectSectionRepository +{ + private readonly ProgramManagerDbContext _programManagerDbContext; + public ProjectSectionRepository(ProgramManagerDbContext context) : base(context) + { + _programManagerDbContext = context; + } +} + diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectTaskRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectTaskRepository.cs new file mode 100644 index 00000000..4e09e8cb --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectTaskRepository.cs @@ -0,0 +1,79 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using TaskStatus = GozareshgirProgramManager.Domain.ProjectAgg.Enums.TaskStatus; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class ProjectTaskRepository : RepositoryBase, IProjectTaskRepository +{ + private readonly ProgramManagerDbContext _context; + + public ProjectTaskRepository(ProgramManagerDbContext context) : base(context) + { + _context = context; + } + + public Task GetWithSectionsAsync(Guid taskId) + { + return _context.ProjectTasks + .Include(t => t.Sections) + .ThenInclude(s => s.Skill) + .Include(t => t.Sections) + .ThenInclude(s => s.Activities) + .Include(t => t.Sections) + .ThenInclude(s => s.AdditionalTimes) + .FirstOrDefaultAsync(t => t.Id == taskId); + } + + public Task> GetByPhaseIdAsync(Guid phaseId) + { + return _context.ProjectTasks + .Where(t => t.PhaseId == phaseId) + .OrderBy(t => t.OrderIndex) + .ToListAsync(); + } + + public Task> GetTasksWithTimeOverridesAsync() + { + return _context.ProjectTasks + .Where(t => t.HasTimeOverride) + .ToListAsync(); + } + + public Task> GetTasksWithAssignmentOverridesAsync() + { + return _context.ProjectTasks + .Where(t => t.HasAssignmentOverride) + .ToListAsync(); + } + + public Task> GetByStatusAsync(TaskStatus status) + { + return _context.ProjectTasks + .Where(t => t.Status == status) + .ToListAsync(); + } + + public Task> GetByPriorityAsync(TaskPriority priority) + { + return _context.ProjectTasks + .Where(t => t.Priority == priority) + .ToListAsync(); + } + + public Task> GetAssignedToUserAsync(long userId) + { + return _context.ProjectTasks + .Where(t => t.Sections.Any(s => s.CurrentAssignedUserId == userId)) + .ToListAsync(); + } + + public void Remove(ProjectTask task) + { + _context.ProjectTasks.Remove(task); + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/RoleRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/RoleRepository.cs new file mode 100644 index 00000000..01198c37 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/RoleRepository.cs @@ -0,0 +1,24 @@ +using GozareshgirProgramManager.Domain.RoleAgg.Entities; +using GozareshgirProgramManager.Domain.RoleAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class RoleRepository : RepositoryBase, IRoleRepository +{ + private readonly ProgramManagerDbContext _context; + public RoleRepository(ProgramManagerDbContext context) : base(context) + { + _context = context; + } + + public async Task GetByGozareshgirRoleIdAsync(long? gozareshgirRolId) + { + return await _context.Roles.FirstOrDefaultAsync(x => x.GozareshgirRoleId == gozareshgirRolId); + } + + + +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/SalaryPaymentSettingRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/SalaryPaymentSettingRepository.cs new file mode 100644 index 00000000..a3d43ccd --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/SalaryPaymentSettingRepository.cs @@ -0,0 +1,60 @@ +using GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Queries.GetSalarySettingToEdit; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.DTOs; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class SalaryPaymentSettingRepository : RepositoryBase, ISalaryPaymentSettingRepository +{ + private readonly ProgramManagerDbContext _context; + public SalaryPaymentSettingRepository(ProgramManagerDbContext context) : base(context) + { + _context = context; + } + + + public async Task GetSalarySettingByUserId(long userId) + { + return await _context.SalaryPaymentSettings.FirstOrDefaultAsync(x => x.UserId == userId); + } + + + public async Task> GetAllSettings(List userIdList) + { + _context.SalaryPaymentSettings.AsNoTracking(); + var query = await _context.SalaryPaymentSettings.Where(s=> userIdList.Contains(s.UserId)) + .Join(_context.Users.AsNoTracking(), + setting => setting.UserId, + user => user.Id, + (setting, user) => new { setting, user } + ) + .Select(x => new UserSalarySettingDto + { + UserId = x.user.Id, + HolidayWorking = x.setting!.HolidayWorking, + FullName = x.user.FullName, + MonthlySalary = x.setting.MonthlySalary, + WorkingHoursListDto = x.setting.WorkingHoursList + .Where(wh => wh.IsActiveDay) + .Select(wh => new WorkingHoursListDto() + { + ShiftDuration = wh.ShiftDuration, + PersianDayOfWeek = wh.PersianDayOfWeek + }).ToList() + }) + .ToListAsync(); + + return query; + + } + + public void RemoveRangeSalarySettings(List removedItems) + { + _context.SalaryPaymentSettings.RemoveRange(removedItems); + + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/SkillRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/SkillRepository.cs new file mode 100644 index 00000000..935bfda3 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/SkillRepository.cs @@ -0,0 +1,16 @@ +using GozareshgirProgramManager.Domain.SkillAgg.Entities; +using GozareshgirProgramManager.Domain.SkillAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class SkillRepository:RepositoryBase, ISkillRepository +{ + private readonly ProgramManagerDbContext _context; + public SkillRepository(ProgramManagerDbContext context) : base(context) + { + _context = context; + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/TaskSectionActivityRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/TaskSectionActivityRepository.cs new file mode 100644 index 00000000..4ae98bf7 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/TaskSectionActivityRepository.cs @@ -0,0 +1,83 @@ +using GozareshgirProgramManager.Application.Modules.Projects.DTOs; +using GozareshgirProgramManager.Application.Modules.Projects.Extensions; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class TaskSectionActivityRepository : RepositoryBase, ITaskSectionActivityRepository +{ + private readonly ProgramManagerDbContext _programManagerDbContext; + + public TaskSectionActivityRepository(ProgramManagerDbContext programManagerDbContext) : base(programManagerDbContext) + { + _programManagerDbContext = programManagerDbContext; + } + + public async Task> GetBySectionIdAsync(Guid sectionId) + { + return await _programManagerDbContext.TaskSectionActivities + .Where(a => a.SectionId == sectionId).ToListAsync(); + } + + public async Task> GetByUserIdAsync(long userId) + { + return await _programManagerDbContext.TaskSectionActivities + .Where(x => x.UserId == userId).ToListAsync(); + } + + public async Task> GetActiveByUserAsync(long userId) + { + return await _programManagerDbContext.TaskSectionActivities + .Where(x => x.UserId == userId && x.IsActive) + .ToListAsync(); + } + + public async Task> GetByDateRangeAsync(DateTime from, DateTime to) + { + return await _programManagerDbContext.TaskSectionActivities + .Where(x => x.EndDate >= from && x.StartDate <= to).ToListAsync(); + } + + public async Task> GetByDateRangeUserIdAsync(DateTime from, DateTime to, long userId) + { + return await _programManagerDbContext.TaskSectionActivities + .Where(x => x.EndDate >= from && x.StartDate <= to && x.UserId == userId).ToListAsync(); + } + + public async Task GetTotalTimeSpentByUserInRangeAsync(long userId, DateTime from, DateTime to) + { + var data = await GetByDateRangeUserIdAsync(from, to, userId); + + return data.Aggregate(TimeSpan.Zero, (total, activity) => + { + var adjustedStart = activity.StartDate < from ? from : activity.StartDate; + var adjustedEnd = activity.EndDate > to ? to : (activity.EndDate ?? to); + return total.Add(adjustedEnd - adjustedStart); + }); + } + + public async Task> GetTotalTimeSpentPerUserInRangeAsync(DateTime from, + DateTime to) + { + var data = await GetByDateRangeAsync(from, to); + var result = data + .GroupBy(x => x.UserId) + .Select(group => + { + var totalTime = group.Aggregate(TimeSpan.Zero, (total, activity) => + { + var adjustedStart = activity.StartDate < from ? from : activity.StartDate; + var adjustedEnd = activity.EndDate > to ? to : (activity.EndDate ?? to); + return total.Add(adjustedEnd - adjustedStart); + }); + return (totalTime, group.Key); + }) + .ToList(); + + return result; + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/TaskSectionRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/TaskSectionRepository.cs new file mode 100644 index 00000000..80564915 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/TaskSectionRepository.cs @@ -0,0 +1,31 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class TaskSectionRepository:RepositoryBase,ITaskSectionRepository +{ + private readonly ProgramManagerDbContext _context; + public TaskSectionRepository(ProgramManagerDbContext context) : base(context) + { + _context = context; + } + + public async Task GetByIdWithActivitiesAsync(Guid id, CancellationToken cancellationToken = default) + { + return await _context.TaskSections + .Include(x => x.Activities) + .FirstOrDefaultAsync(x => x.Id == id, cancellationToken); + } + + public async Task GetByIdWithFullDataAsync(Guid id, CancellationToken cancellationToken = default) + { + return await _context.TaskSections + .Include(x => x.Activities) + .Include(x => x.AdditionalTimes) + .FirstOrDefaultAsync(x => x.Id == id, cancellationToken); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/UserRefreshTokenRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/UserRefreshTokenRepository.cs new file mode 100644 index 00000000..7200e888 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/UserRefreshTokenRepository.cs @@ -0,0 +1,20 @@ +using System.Linq.Expressions; +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Domain.UserAgg.Entities; +using GozareshgirProgramManager.Domain.UserAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class UserRefreshTokenRepository : RepositoryBase, IUserRefreshTokenRepository +{ + private readonly ProgramManagerDbContext _context; + public UserRefreshTokenRepository(ProgramManagerDbContext context) : base(context) + { + _context = context; + } + + +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/UserRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/UserRepository.cs new file mode 100644 index 00000000..7b83ef6e --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/UserRepository.cs @@ -0,0 +1,87 @@ +using GozareshgirProgramManager.Domain.UserAgg.Entities; +using GozareshgirProgramManager.Domain.UserAgg.Repositories; +using GozareshgirProgramManager.Infrastructure.Persistence._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories; + +public class UserRepository : RepositoryBase, IUserRepository +{ + private readonly ProgramManagerDbContext _context; + public UserRepository(ProgramManagerDbContext context) : base(context) + { + _context = context; + } + + public Task GetByIdAsync(long id) + { + throw new NotImplementedException(); + } + + public async Task GetByGozareshgirAccountId(long accountId) + { + return await _context.Users.FirstOrDefaultAsync(x => x.AccountId == accountId); + } + + public Task GetByEmailAsync(string email) + { + throw new NotImplementedException(); + } + + public Task GetByMobileAsync(string mobile) + { + throw new NotImplementedException(); + } + + public Task> GetAllAsync() + { + throw new NotImplementedException(); + } + + public Task> GetActiveUsersAsync() + { + throw new NotImplementedException(); + } + + public Task AddAsync(User user) + { + throw new NotImplementedException(); + } + + public void Update(User user) + { + throw new NotImplementedException(); + } + + public void Delete(User user) + { + throw new NotImplementedException(); + } + + public Task ExistsAsync(long id) + { + throw new NotImplementedException(); + } + + public Task UsernameExistsAsync(string username) + { + throw new NotImplementedException(); + } + + public Task EmailExistsAsync(string email) + { + throw new NotImplementedException(); + } + + public Task MobileExistsAsync(string mobile) + { + throw new NotImplementedException(); + } + + public async Task GetUserWithRolesByIdAsync(long userId, CancellationToken cancellationToken) + { + return await _context.Users.Include(x => x.RoleUser) + .FirstOrDefaultAsync(x=>x.Id == userId, cancellationToken); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Seed/DataSeeder.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Seed/DataSeeder.cs new file mode 100644 index 00000000..5afe7e82 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Seed/DataSeeder.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using GozareshgirProgramManager.Domain.SkillAgg.Entities; +using System.Linq; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Seed +{ + public class DataSeeder : IDataSeeder + { + private readonly ProgramManagerDbContext _dbContext; + public DataSeeder(ProgramManagerDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task SeedAllAsync() + { + await SeedSkillsIfEmptyAsync(); + // در آینده متدهای Seed دیگر را اینجا فراخوانی کنید + } + + private async Task SeedSkillsIfEmptyAsync() + { + if (!_dbContext.Skills.Any()) + { + _dbContext.Skills.AddRange( + new Skill("UI/UX Design"), + new Skill("Frontend"), + new Skill("Backend") + ); + await _dbContext.SaveChangesAsync(); + } + } + } +} + diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Seed/IDataSeeder.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Seed/IDataSeeder.cs new file mode 100644 index 00000000..2db95adc --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Seed/IDataSeeder.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace GozareshgirProgramManager.Infrastructure.Persistence.Seed +{ + public interface IDataSeeder + { + Task SeedAllAsync(); + } +} + diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/UnitOfWork.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/UnitOfWork.cs new file mode 100644 index 00000000..2a071185 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/UnitOfWork.cs @@ -0,0 +1,53 @@ +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using MediatR; +using Microsoft.Identity.Client; +using GozareshgirProgramManager.Application._Common.Models; + +namespace GozareshgirProgramManager.Infrastructure.Persistence; + +public class UnitOfWork : IUnitOfWork +{ + private readonly ProgramManagerDbContext _context; + private readonly IPublisher _publisher; + + public UnitOfWork(ProgramManagerDbContext context, IPublisher publisher) + { + _context = context; + _publisher = publisher; + } + + public async Task SaveChangesAsync(CancellationToken cancellationToken = default) + { + // Publish Domain Events before saving + await PublishDomainEvents(cancellationToken); + + return await _context.SaveChangesAsync(cancellationToken); + } + + private async Task PublishDomainEvents(CancellationToken cancellationToken) + { + var domainEntities = _context.ChangeTracker + .Entries>() + .Where(x => x.Entity.DomainEvents.Any()) + .ToList(); + + var domainEvents = domainEntities + .SelectMany(x => x.Entity.DomainEvents) + .ToList(); + + domainEntities.ForEach(entity => entity.Entity.ClearDomainEvents()); + + foreach (var domainEvent in domainEvents) + { + var notificationType = typeof(DomainEventNotification<>).MakeGenericType(domainEvent.GetType()); + var notification = Activator.CreateInstance(notificationType, domainEvent); + + if (notification != null) + { + await _publisher.Publish(notification, cancellationToken); + } + } + } +} + diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/_Common/PropertyBuilderExtensions.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/_Common/PropertyBuilderExtensions.cs new file mode 100644 index 00000000..672d399e --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/_Common/PropertyBuilderExtensions.cs @@ -0,0 +1,21 @@ +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace GozareshgirProgramManager.Infrastructure.Persistence._Common; + +public static class PropertyBuilderExtensions +{ + public static PropertyBuilder HasTimeSpanConversion(this PropertyBuilder builder) + { + return builder.HasConversion( + v => v == TimeSpan.Zero ? "" : v.ToString(), + v => string.IsNullOrWhiteSpace(v) ? TimeSpan.Zero : TimeSpan.Parse(v) + ).HasMaxLength(30); + } + public static PropertyBuilder HasTimeSpanConversion(this PropertyBuilder builder) + { + return builder.HasConversion( + v =>v==null || v == TimeSpan.Zero ? "" : v.ToString(), + v => string.IsNullOrWhiteSpace(v) ? TimeSpan.Zero : TimeSpan.Parse(v) + ).HasMaxLength(30); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/_Common/RepositoryBase.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/_Common/RepositoryBase.cs new file mode 100644 index 00000000..def0cf17 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/_Common/RepositoryBase.cs @@ -0,0 +1,70 @@ +using System.Linq.Expressions; +using GozareshgirProgramManager.Domain._Common; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Infrastructure.Persistence._Common; + +public class RepositoryBase : IRepository where T : class +{ + private readonly DbContext _context; + + public RepositoryBase(DbContext context) + { + _context = context; + } + + public void AddRange(IEnumerable entities) + { + _context.AddRange(entities); + } + public void Create(T entity) + { + _context.Add(entity); + } + + public async Task CreateAsync(T entity) + { + await _context.AddAsync(entity); + } + + + public bool ExistsIgnoreQueryFilter(Expression> expression) + { + return _context.Set().IgnoreQueryFilters().Any(expression); + } + + public bool Exists(Expression> expression) + { + return _context.Set().Any(expression); + } + + public T Get(TKey id) + { + return _context.Find(id); + } + + public async Task GetByIdAsync(TKey id) + { + return await _context.Set().FindAsync(id); + } + + public List Get() + { + return _context.Set().ToList(); + } + + public IQueryable GetQueryable() + { + return _context.Set().AsQueryable(); + } + + public void Remove(T entity) + { + _context.Set().Remove(entity); + } + + public void RemoveRange(IEnumerable entities) + { + _context.Set().RemoveRange(entities); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/Authentication/AuthHelper.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/Authentication/AuthHelper.cs new file mode 100644 index 00000000..ec70492e --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/Authentication/AuthHelper.cs @@ -0,0 +1,215 @@ +using System.Security.Claims; +using GozareshgirProgramManager.Application._Common.Interfaces; +using Microsoft.AspNetCore.Http; + +namespace GozareshgirProgramManager.Infrastructure.Services.Authentication; + +/// +/// سرویس کمکی برای کار با JWT و HttpContext +/// این کلاس فقط با توکن و Context کار می‌کند و هیچ عملیات دیتابیسی ندارد +/// +public class AuthHelper : IAuthHelper +{ + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly JwtTokenGenerator _jwtTokenGenerator; + + public AuthHelper( + IHttpContextAccessor httpContextAccessor, + JwtTokenGenerator jwtTokenGenerator) + { + _httpContextAccessor = httpContextAccessor; + _jwtTokenGenerator = jwtTokenGenerator; + } + + public LoginSession SignIn(long userId, string userName, string fullName, long accountId, List roles) + { + + // 1. تولید Access Token + var accessToken = GenerateAccessToken(userId, userName, fullName, accountId, roles); + var accessTokenExpiration = DateTime.Now.AddMinutes(30); + + // 2. تولید Refresh Token + var refreshToken = GenerateRefreshToken(); + var refreshTokenExpiration = GetRefreshTokenExpiration(); + + // 3. ذخیره Refresh Token در Cookie + _httpContextAccessor.HttpContext?.Response.Cookies.Append("rf-token", refreshToken, new CookieOptions + { + HttpOnly = true, + Secure = true, + SameSite = SameSiteMode.Lax, + Expires = refreshTokenExpiration + }); + + // 4. تنظیم Authorization Header (اختیاری - معمولاً کلاینت خودش این کار را می‌کند) + _httpContextAccessor.HttpContext?.Response.Headers.Append("Authorization", $"Bearer {accessToken}"); + + return new LoginSession + { + AccessToken = accessToken, + RefreshToken = refreshToken, + RefreshTokenExpiration = refreshTokenExpiration, + AccessTokenExpiration = accessTokenExpiration + }; + } + + /// + /// تولید Access Token + /// + public string GenerateAccessToken(long userId, string userName, string fullName, long? accountId, List roles) + { + return _jwtTokenGenerator.GenerateAccessToken(userId, userName, fullName, accountId, roles); + } + + /// + /// تولید Refresh Token + /// + public string GenerateRefreshToken() + { + return _jwtTokenGenerator.GenerateRefreshToken(); + } + + /// + /// دریافت تاریخ انقضای Refresh Token + /// + public DateTime GetRefreshTokenExpiration() + { + return _jwtTokenGenerator.GetRefreshTokenExpiration(); + } + + /// + /// اعتبارسنجی توکن و استخراج Claims + /// + public ClaimsPrincipal? ValidateToken(string token) + { + return _jwtTokenGenerator.ValidateToken(token); + } + + /// + /// اعتبارسنجی توکن منقضی شده (بدون چک زمان) + /// + public ClaimsPrincipal? ValidateExpiredToken(string token) + { + return _jwtTokenGenerator.ValidateExpiredToken(token); + } + + /// + /// استخراج UserId از توکن (حتی اگر منقضی شده باشد) + /// + public long? GetUserIdFromToken(string token) + { + try + { + var principal = _jwtTokenGenerator.ValidateExpiredToken(token); + if (principal == null) return null; + + var userIdClaim = principal.FindFirst(ClaimTypes.NameIdentifier)?.Value; + return long.TryParse(userIdClaim, out var userId) ? userId : null; + } + catch + { + return null; + } + } + + /// + /// دریافت اطلاعات IP کاربر جاری + /// + public string? GetClientIpAddress() + { + return _httpContextAccessor.HttpContext?.Connection.RemoteIpAddress?.ToString(); + } + + /// + /// دریافت User Agent کاربر جاری + /// + public string? GetUserAgent() + { + return _httpContextAccessor.HttpContext?.Request.Headers["User-Agent"].ToString(); + } + + /// + /// دریافت Refresh Token از Header + /// + public string? GetRefreshTokenFromCookie() + { + return _httpContextAccessor.HttpContext?.Request.Cookies["rf-token"]; + } + + /// + /// بررسی احراز هویت کاربر جاری + /// + public bool IsAuthenticated() + { + return _httpContextAccessor.HttpContext?.User?.Identity?.IsAuthenticated ?? false; + } + + /// + /// دریافت شناسه کاربر جاری از Claims + /// + public long? GetCurrentUserId() + { + var userIdClaim = _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; + return long.TryParse(userIdClaim, out var userId) ? userId : null; + } + + /// + /// دریافت نام کاربری جاری از Claims + /// + public string? GetCurrentUserName() + { + return _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.Name)?.Value; + } + + /// + /// دریافت نام کامل کاربر جاری از Claims + /// + public string? GetCurrentFullName() + { + return _httpContextAccessor.HttpContext?.User?.FindFirst("FullName")?.Value; + } + + /// + /// دریافت AccountId کاربر جاری از Claims + /// + public long? GetCurrentAccountId() + { + var accountIdClaim = _httpContextAccessor.HttpContext?.User?.FindFirst("AccountId")?.Value; + return long.TryParse(accountIdClaim, out var accountId) ? accountId : null; + } + + /// + /// دریافت نقش‌های کاربر جاری از Claims + /// + public List GetCurrentUserRoles() + { + var roles = _httpContextAccessor.HttpContext?.User?.FindAll(ClaimTypes.Role) + .Select(c => c.Value) + .ToList(); + + return roles ?? new List(); + } + + /// + /// بررسی دسترسی کاربر به نقش خاص + /// + public bool HasRole(string roleName) + { + return _httpContextAccessor.HttpContext?.User?.IsInRole(roleName) ?? false; + } + + /// + /// بررسی دسترسی کاربر به یکی از نقش‌ها + /// + public bool HasAnyRole(params string[] roleNames) + { + return roleNames.Any(HasRole); + } + + public void SignOut() + { + _httpContextAccessor.HttpContext?.Response.Cookies.Delete("rf-token"); + _httpContextAccessor.HttpContext?.Response.Headers.Remove("Authorization"); + } +} + diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/Authentication/JwtSettings.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/Authentication/JwtSettings.cs new file mode 100644 index 00000000..97d0b849 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/Authentication/JwtSettings.cs @@ -0,0 +1,14 @@ +namespace GozareshgirProgramManager.Infrastructure.Services.Authentication; +/// +/// تنظیمات JWT +/// +public class JwtSettings +{ + public int RefreshTokenExpirationDays { get; set; } = 7; + public int AccessTokenExpirationMinutes { get; set; } = 30; + public string Audience { get; set; } = string.Empty; + public string Issuer { get; set; } = string.Empty; + public string SecretKey { get; set; } = string.Empty; +} + + diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/Authentication/JwtTokenGenerator.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/Authentication/JwtTokenGenerator.cs new file mode 100644 index 00000000..2b15bd15 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/Authentication/JwtTokenGenerator.cs @@ -0,0 +1,153 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Security.Cryptography; +using System.Text; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; + +namespace GozareshgirProgramManager.Infrastructure.Services.Authentication; + +/// +/// سرویس تولید توکن JWT +/// +public class JwtTokenGenerator +{ + private readonly JwtSettings _jwtSettings; + + public JwtTokenGenerator(IOptions jwtSettings) + { + _jwtSettings = jwtSettings.Value; + } + + /// + /// تولید Access Token + /// + public string GenerateAccessToken(long userId, string userName, string fullName, long? accountId, List roles) + { + var claims = new List + { + new(ClaimTypes.NameIdentifier, userId.ToString()), + new(ClaimTypes.Name, userName), + new("FullName", fullName), + new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) + }; + + if (accountId.HasValue) + { + claims.Add(new Claim("AccountId", accountId.Value.ToString())); + } + + // افزودن نقش‌ها به Claims + claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role))); + + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey)); + var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + var expires = DateTime.Now.AddMinutes(_jwtSettings.AccessTokenExpirationMinutes); + + var token = new JwtSecurityToken( + issuer: _jwtSettings.Issuer, + audience: _jwtSettings.Audience, + claims: claims, + expires: expires, + signingCredentials: credentials + ); + + return new JwtSecurityTokenHandler().WriteToken(token); + } + + /// + /// تولید Refresh Token + /// + public string GenerateRefreshToken() + { + var randomNumber = new byte[64]; + using var rng = RandomNumberGenerator.Create(); + rng.GetBytes(randomNumber); + return Convert.ToBase64String(randomNumber); + } + + /// + /// اعتبارسنجی و استخراج اطلاعات از توکن + /// + public ClaimsPrincipal? ValidateToken(string token) + { + try + { + var tokenHandler = new JwtSecurityTokenHandler(); + var key = Encoding.UTF8.GetBytes(_jwtSettings.SecretKey); + + var validationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(key), + ValidateIssuer = true, + ValidIssuer = _jwtSettings.Issuer, + ValidateAudience = true, + ValidAudience = _jwtSettings.Audience, + ValidateLifetime = true, + ClockSkew = TimeSpan.Zero + }; + + var principal = tokenHandler.ValidateToken(token, validationParameters, out var validatedToken); + + if (validatedToken is not JwtSecurityToken jwtToken || + !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase)) + { + return null; + } + + return principal; + } + catch + { + return null; + } + } + + /// + /// اعتبارسنجی توکن بدون چک کردن زمان انقضا (برای استخراج اطلاعات از توکن منقضی شده) + /// + public ClaimsPrincipal? ValidateExpiredToken(string token) + { + try + { + var tokenHandler = new JwtSecurityTokenHandler(); + var key = Encoding.UTF8.GetBytes(_jwtSettings.SecretKey); + + var validationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(key), + ValidateIssuer = true, + ValidIssuer = _jwtSettings.Issuer, + ValidateAudience = true, + ValidAudience = _jwtSettings.Audience, + ValidateLifetime = false, // توکن منقضی شده هم قبول می‌شود + ClockSkew = TimeSpan.Zero + }; + + var principal = tokenHandler.ValidateToken(token, validationParameters, out var validatedToken); + + if (validatedToken is not JwtSecurityToken jwtToken || + !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase)) + { + return null; + } + + return principal; + } + catch + { + return null; + } + } + + /// + /// دریافت تاریخ انقضای Refresh Token + /// + public DateTime GetRefreshTokenExpiration() + { + return DateTime.Now.AddDays(_jwtSettings.RefreshTokenExpirationDays); + } +} + diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/CacheService.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/CacheService.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/DateTimeService.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/DateTimeService.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/EmailService.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/EmailService.cs new file mode 100644 index 00000000..e69de29b diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/FileService.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Services/FileService.cs new file mode 100644 index 00000000..e69de29b diff --git a/Query.Bootstrapper/Query.Bootstrapper.csproj b/Query.Bootstrapper/Query.Bootstrapper.csproj index 2a4ad0a3..dfbcb641 100644 --- a/Query.Bootstrapper/Query.Bootstrapper.csproj +++ b/Query.Bootstrapper/Query.Bootstrapper.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable diff --git a/Query/Query.csproj b/Query/Query.csproj index 38ac1440..e3f95f0d 100644 --- a/Query/Query.csproj +++ b/Query/Query.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable diff --git a/ServiceHost/Areas/Admin/Controllers/AuthController.cs b/ServiceHost/Areas/Admin/Controllers/AuthController.cs new file mode 100644 index 00000000..cac9318f --- /dev/null +++ b/ServiceHost/Areas/Admin/Controllers/AuthController.cs @@ -0,0 +1,143 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Users.Commands.LoginUser; +using GozareshgirProgramManager.Application.Modules.Users.Commands.RefreshUserToken; +using GozareshgirProgramManager.Application.Modules.Users.Commands.SignOutUser; +using GozareshgirProgramManager.Application.Modules.Users.Commands.SsoLogin; +using MediatR; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using ServiceHost.BaseControllers; + +namespace ServiceHost.Areas.Admin.Controllers; + +/// +/// کنترلر احراز هویت +/// +[Route("api/[controller]")] +[ApiController] +public class AuthController :AdminBaseController +{ + private readonly IAuthHelper _authHelper; + private readonly IMediator _mediator; + + public AuthController(IAuthHelper authHelper, IMediator mediator) + { + _authHelper = authHelper; + _mediator = mediator; + } + + /// + /// ورود به سیستم با شناسه کاربری + /// + /// شناسه کاربر + /// فقط Access Token - Refresh Token در سرور ذخیره می‌شود + [HttpPost("login")] + [AllowAnonymous] + public async Task>> Login([FromBody] LoginByIdRequest request) + { + var command = new LoginUserCommand(request.UserId); + var result = await _mediator.Send(command); + + return result; + } + + /// + /// ورود به سیستم از طریق SSO با استفاده از توکن JWT + /// توکن JWT از query string دریافت می‌شود و Claims آن استخراج می‌شود + /// سپس کاربر بر اساس AccountId موجود در Claims لاگین می‌شود + /// + /// JWT Token از سیستم خارجی + /// Access Token و اطلاعات کاربر + [HttpGet("sso-login")] + [AllowAnonymous] + public async Task>> SsoLogin([FromQuery] string token) + { + if (string.IsNullOrWhiteSpace(token)) + { + return BadRequest(OperationResult.Failure("توکن الزامی است", ErrorType.BadRequest)); + } + + var command = new SsoLoginCommand(token); + var result = await _mediator.Send(command); + + return result; + } + + /// + /// خروج از سیستم + /// + [HttpPost("signout")] + [Authorize] + public new async Task> SignOut() + { + // دریافت Refresh Token از Header با استفاده از AuthHelper + var refreshToken = _authHelper.GetRefreshTokenFromCookie(); + + if (string.IsNullOrEmpty(refreshToken)) + { + return OperationResult.Failure("توکن تازه‌سازی یافت نشد"); + } + + var command = new SignOutUserCommand(refreshToken); + var result = await _mediator.Send(command); + + if (result.IsSuccess) + { + return Ok(result); + } + + return StatusCode(result.ErrorType switch + { + ErrorType.Unauthorized => 401, + ErrorType.BadRequest => 400, + ErrorType.NotFound => 404, + _ => 500 + }, result); + } + + /// + /// تازه‌سازی توکن دسترسی + /// توکن منقضی شده را می‌گیرد و Access Token جدید برمی‌گرداند + /// Refresh Token از دیتابیس خوانده می‌شود و به فرانت داده نمی‌شود + /// + [HttpPost("refresh")] + [AllowAnonymous] + public async Task> RefreshAccessToken() + { + + var refreshTokenCommand = new RefreshUserTokenCommand(); + var result = await _mediator.Send(refreshTokenCommand); + + return result; + } + + /// + /// دریافت اطلاعات کاربر جاری + /// + [HttpGet("current")] + public IActionResult GetCurrentUser() + { + if (!_authHelper.IsAuthenticated()) + { + return Unauthorized(new { message = "کاربر احراز هویت نشده است" }); + } + + return Ok(new + { + userId = _authHelper.GetCurrentUserId(), + fullName= _authHelper.GetCurrentFullName(), + roles = _authHelper.GetCurrentUserRoles() + }); + } +} + +/// +/// درخواست ورود با شناسه کاربری +/// +public class LoginByIdRequest +{ + public long UserId { get; set; } +} + + diff --git a/ServiceHost/Areas/Admin/Controllers/CheckoutController.cs b/ServiceHost/Areas/Admin/Controllers/CheckoutController.cs new file mode 100644 index 00000000..69128d3a --- /dev/null +++ b/ServiceHost/Areas/Admin/Controllers/CheckoutController.cs @@ -0,0 +1,93 @@ +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Checkouts.Commands.CreateCheckout; +using GozareshgirProgramManager.Application.Modules.Checkouts.Queries.GetCheckoutList; +using GozareshgirProgramManager.Application.Modules.Checkouts.Queries.GetUserToGropCreate; +using GozareshgirProgramManager.Domain.CheckoutAgg.Enums; +using MediatR; +using Microsoft.AspNetCore.Mvc; +using ServiceHost.BaseControllers; + +namespace ServiceHost.Areas.Admin.Controllers; + +public class CheckoutController : AdminBaseController +{ + private readonly IMediator _mediator; + + public CheckoutController(IMediator mediator) + { + _mediator = mediator; + } + + [HttpGet("GetUsersToGroupCreating")] + public async Task>> GetUserListWhoHaveSettings([FromQuery] GetUserToGroupCreatingQuery command) + { + + var res = await _mediator.Send(command); + + return res; + } + + //[HttpGet("TypeOfCheckoutHandlerDictionary")] + //public IActionResult GetTypeOfCheckoutHandlerDictionary() + //{ + // var names = Enum.GetNames(typeof(TypeOfCheckoutHandler)); + // List result = new List(); + + // foreach (var name in names) + // { + // if (name == "CreateInGroup") + // { + // result.Add("CreateInGroup ایجاد گروهی sample('1404', '8', UserIdList : [1,2,3] "); + // result.Add("------------------------------------------------------------------------------------------------------------------------------------"); + // } + + // if (name == "CreateInGroup") + // { + // result.Add("GroupEditing ویرایش گروهی sample(checkoutIdList : ['3fa85f64-5717-4562-b3fc-2c963f66afa6', '3fa85f64-5717-4562-b3fc-2c963f66afa6'])"); + // result.Add("------------------------------------------------------------------------------------------------------------------------------------"); + // } + + // if (name == "CreateInGroup") + // result.Add("SingleEdit ویرایش تکی sample(checkoutId : '3fa85f64-5717-4562-b3fc-2c963f66afa6')" ); + // } + // return Ok(result); + //} + + [HttpPost("Create")] + public async Task Create([FromBody] List? UserIdlist, string Year, string Month) + { + var createCommand = new CreateOrEditCheckoutCommand( + TypeOfCheckoutHandler.CreateInGroup, + Year, + Month,UserIdlist, new List()); + + + var res = await _mediator.Send(createCommand); + + return res; + } + + [HttpPost("Edit")] + public async Task EditSingleOrGroup([FromBody] List CheckoutIdList) + { + var createCommand = new CreateOrEditCheckoutCommand( + TypeOfCheckoutHandler.GroupEditing, + null, + null, null, CheckoutIdList); + + + var res = await _mediator.Send(createCommand); + + return res; + } + + + [HttpGet("GetCheckoutList")] + public async Task>>> GetCheckoutList([FromQuery] GetCheckoutListQuery command) + { + + var res = await _mediator.Send(command); + + return res; + } +} \ No newline at end of file diff --git a/ServiceHost/Areas/Admin/Controllers/GeneralController.cs b/ServiceHost/Areas/Admin/Controllers/GeneralController.cs new file mode 100644 index 00000000..64b27217 --- /dev/null +++ b/ServiceHost/Areas/Admin/Controllers/GeneralController.cs @@ -0,0 +1,29 @@ +using System.Globalization; +using Microsoft.AspNetCore.Mvc; +using ServiceHost.BaseControllers; + +namespace ServiceHost.Areas.Admin.Controllers; + +public class GeneralController:AdminBaseController +{ + /// + /// نمایش اطلاعات عمومی مانند تاریخ ها و سال ها + /// + /// + [HttpGet("Dates")] + public IActionResult GetDates() + { + var pc = new PersianCalendar(); + var now = DateTime.Now; + var currentYear = pc.GetYear(now); + var years = Enumerable.Range(1370, currentYear - 1370 + 1).ToList(); + var months = Enumerable.Range(1, 12).ToList(); + var currentDate = new { Year = currentYear, Month = pc.GetMonth(now), Day = pc.GetDayOfMonth(now) }; + return new JsonResult(new + { + years, + months, + currentDate + }); + } +} \ No newline at end of file diff --git a/ServiceHost/Areas/Admin/Controllers/ProjectController.cs b/ServiceHost/Areas/Admin/Controllers/ProjectController.cs new file mode 100644 index 00000000..a52e8ab1 --- /dev/null +++ b/ServiceHost/Areas/Admin/Controllers/ProjectController.cs @@ -0,0 +1,102 @@ +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.AssignProject; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeStatusSection; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProject; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.DeleteProject; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.EditProject; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.SetTimeProject; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.TransferSection; +using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectAssignDetails; +using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList; +using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardList; +using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectSetTimeDetails; +using MediatR; +using Microsoft.AspNetCore.Mvc; +using ServiceHost.BaseControllers; + +namespace ServiceHost.Areas.Admin.Controllers; + +public class ProjectController : AdminBaseController +{ + private readonly IMediator _mediator; + + public ProjectController(IMediator mediator) + { + _mediator = mediator; + } + + [HttpGet] + public async Task>> Get([FromQuery]GetProjectsListQuery query) + { + var res=await _mediator.Send(query); + return res; + } + + [HttpPost] + public async Task> Create([FromBody] CreateProjectCommand command) + { + var res=await _mediator.Send(command); + return res; + } + + [HttpPut] + public async Task> Edit([FromBody] EditProjectCommand command) + { + var res=await _mediator.Send(command); + return res; + } + + [HttpDelete] + public async Task> Delete([FromQuery] DeleteProjectCommand command) + { + var res=await _mediator.Send(command); + return res; + } + + [HttpGet("assign")] + public async Task>> GetAssignableProjects(GetProjectAssignDetailsQuery query) + { + var res=await _mediator.Send(query); + return res; + } + + [HttpPost("assign")] + public async Task> Assign(AssignProjectCommand command) + { + var res=await _mediator.Send(command); + return res; + } + [HttpGet("set-time")] + public async Task>> GetSetTimeProjectDetails(ProjectSetTimeDetailsQuery query) + { + var res=await _mediator.Send(query); + return res; + } + [HttpPost("set-time")] + public async Task> SetTimeProject(SetTimeProjectCommand command) + { + var res=await _mediator.Send(command); + return res; + } + + [HttpPost("change-status")] + public async Task> ChangeStatus(ChangeStatusSectionCommand command) + { + var res = await _mediator.Send(command); + return res; + } + + [HttpPost("transfer-section")] + public async Task> TransferSection([FromBody] TransferSectionCommand command) + { + var res = await _mediator.Send(command); + return res; + } + + [HttpGet("board")] + public async Task>>> GetProjectBoard([FromQuery] ProjectBoardListQuery query) + { + var res = await _mediator.Send(query); + return res; + } +} \ No newline at end of file diff --git a/ServiceHost/Areas/Admin/Controllers/RoleController.cs b/ServiceHost/Areas/Admin/Controllers/RoleController.cs new file mode 100644 index 00000000..b074f105 --- /dev/null +++ b/ServiceHost/Areas/Admin/Controllers/RoleController.cs @@ -0,0 +1,46 @@ +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Roles.Commands.CreateRole; +using GozareshgirProgramManager.Application.Modules.Roles.Commands.EditRole; +using GozareshgirProgramManager.Application.Modules.Roles.Queries.GetRoles; +using MediatR; +using Microsoft.AspNetCore.Mvc; +using ServiceHost.BaseControllers; + +namespace ServiceHost.Areas.Admin.Controllers; + +public class RoleController : AdminBaseController +{ + private readonly IMediator _mediator; + + public RoleController(IMediator mediator) + { + _mediator = mediator; + } + + + [HttpGet] + public async Task>> Get([FromQuery] GetRolesQuery query) + { + var res = await _mediator.Send(query); + return res; + } + + + [HttpPost] + public async Task> Create([FromBody] CreateRoleCommand command) + { + var res = await _mediator.Send(command); + return res; + } + + + + [HttpPost("edit")] + public async Task> Edit([FromBody] EditRoleCommand command) + { + var res = await _mediator.Send(command); + return res; + } + + +} \ No newline at end of file diff --git a/ServiceHost/Areas/Admin/Controllers/SalaryPaymentSettingsController.cs b/ServiceHost/Areas/Admin/Controllers/SalaryPaymentSettingsController.cs new file mode 100644 index 00000000..bb09a5a3 --- /dev/null +++ b/ServiceHost/Areas/Admin/Controllers/SalaryPaymentSettingsController.cs @@ -0,0 +1,67 @@ +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Commands.CreateSalarySettings; +using GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Commands.EditSalarySettings; +using GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Queries.GetSalarySettingToEdit; +using GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Queries.GetUserListWhoHaveSettings; +using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Enums; +using MediatR; +using Microsoft.AspNetCore.Mvc; +using ServiceHost.BaseControllers; + +namespace ServiceHost.Areas.Admin.Controllers; + +public class SalaryPaymentSettingsController : AdminBaseController +{ + private readonly IMediator _mediator; + + public SalaryPaymentSettingsController(IMediator mediator) + { + _mediator = mediator; + } + + [HttpGet("PersianDayOfWeekDictionary")] + public IActionResult GetPersianDayOfWeekDictionary() + { + var names = Enum.GetNames(typeof(PersianDayOfWeek)); + + return Ok(names); + } + + [HttpGet("GetUsers")] + public async Task>> GetUserListWhoHaveSettings([FromQuery] GetUserListWhoHaveSettingsQuery command) + { + + var res = await _mediator.Send(command); + + return res; + } + + [HttpGet("GetToEdit/{UserId}")] + public async Task>> GetSalarySettingsByUserId(long UserId) + { + var query = new GetSalarySettingToEditQuery(UserId); + var res = await _mediator.Send(query); + + return res; + } + + [HttpPost("edit")] + public async Task> Edit([FromBody] EditSalarySettingsCommand command) + { + var res = await _mediator.Send(command); + return res; + } + + + [HttpPost("create")] + public async Task> Create([FromBody] CreateSalarySettingsCommand command) + { + var res = await _mediator.Send(command); + return res; + + } + + + +} + diff --git a/ServiceHost/Areas/Admin/Controllers/SkillController.cs b/ServiceHost/Areas/Admin/Controllers/SkillController.cs new file mode 100644 index 00000000..4fcc373e --- /dev/null +++ b/ServiceHost/Areas/Admin/Controllers/SkillController.cs @@ -0,0 +1,24 @@ +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Skills.Queries.GetSkillList; +using MediatR; +using Microsoft.AspNetCore.Mvc; +using ServiceHost.BaseControllers; + +namespace ServiceHost.Areas.Admin.Controllers; + +public class SkillController:AdminBaseController +{ + private readonly IMediator _mediator; + + public SkillController(IMediator mediator) + { + _mediator = mediator; + } + + [HttpGet] + public async Task>> GetList([FromQuery]GetSkillListQuery query) + { + var res = await _mediator.Send(query); + return res; + } +} \ No newline at end of file diff --git a/ServiceHost/Areas/Admin/Controllers/UserController.cs b/ServiceHost/Areas/Admin/Controllers/UserController.cs new file mode 100644 index 00000000..9fabaf9f --- /dev/null +++ b/ServiceHost/Areas/Admin/Controllers/UserController.cs @@ -0,0 +1,67 @@ +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Users.Commands.CreateUser; +using GozareshgirProgramManager.Application.Modules.Users.Commands.EditUser; +using GozareshgirProgramManager.Application.Modules.Users.Queries.GetSingleUser; +using GozareshgirProgramManager.Application.Modules.Users.Queries.GetUsers; +using GozareshgirProgramManager.Application.Modules.Users.Queries.GetUserSelectList; +using MediatR; +using Microsoft.AspNetCore.Mvc; +using ServiceHost.BaseControllers; + +namespace ServiceHost.Areas.Admin.Controllers; + +public class UserController : AdminBaseController +{ + private readonly IMediator _mediator; + + + public UserController(IMediator mediator) + { + _mediator = mediator; + } + + + [HttpGet] + public async Task>> Get([FromQuery] GetUsersQuery query) + { + var res = await _mediator.Send(query); + return res; + } + + + [HttpGet("{accountId}")] + public async Task>> GetUserByAccountId(string accountId) + { + var query = new GetSingleUserQuery(accountId); + var res = await _mediator.Send(query); + + return res; + } + + [HttpGet("GetUserSelectList")] + public async Task>> GetUserSelectList() + { + var query = new GetUserSelectListQuery(); + var res = await _mediator.Send(query); + + return res; + } + + + [HttpPost("create")] + public async Task> Create([FromBody] CreateUserCommand command) + { + var res = await _mediator.Send(command); + return res; + } + + + [HttpPost("edit")] + public async Task> Edit([FromBody] EditUserCommand command) + { + var res = await _mediator.Send(command); + return res; + } + + +} \ No newline at end of file diff --git a/ServiceHost/Program.cs b/ServiceHost/Program.cs index d6882906..a414829e 100644 --- a/ServiceHost/Program.cs +++ b/ServiceHost/Program.cs @@ -37,6 +37,11 @@ using Parbad.Builder; using Parbad.Gateway.Sepehr; using Swashbuckle.AspNetCore.SwaggerUI; using AccountManagement.Domain.InternalApiCaller; +using FluentValidation; +using GozareshgirProgramManager.Application._Bootstrapper; +using GozareshgirProgramManager.Application.Modules.Users.Commands.CreateUser; +using GozareshgirProgramManager.Infrastructure; +using GozareshgirProgramManager.Infrastructure.Persistence.Seed; var builder = WebApplication.CreateBuilder(args); @@ -55,6 +60,11 @@ var connectionString = builder.Configuration.GetConnectionString("MesbahDb"); var connectionStringTestDb = builder.Configuration.GetConnectionString("TestDb"); var connectionStringProgramManager = builder.Configuration.GetConnectionString("ProgramManagerDb"); + +builder.Services.AddProgramManagerApplication(); +builder.Services.AddProgramManagerInfrastructure(builder.Configuration); +builder.Services.AddValidatorsFromAssemblyContaining(); +builder.Services.AddScoped(); #region MongoDb var mongoConnectionSection = builder.Configuration.GetSection("MongoDb"); @@ -216,6 +226,7 @@ builder.Services.AddSignalR(); builder.Services.AddSwaggerGen(options => { options.UseInlineDefinitionsForEnums(); + options.CustomSchemaIds(type => type.FullName); var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); diff --git a/ServiceHost/ServiceHost.csproj b/ServiceHost/ServiceHost.csproj index 56999321..28681ae7 100644 --- a/ServiceHost/ServiceHost.csproj +++ b/ServiceHost/ServiceHost.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable true @@ -68,6 +68,8 @@ + + @@ -77,6 +79,8 @@ + + diff --git a/WorkFlow/Application/WorkFlow.Application.Contracts/WorkFlow.Application.Contracts.csproj b/WorkFlow/Application/WorkFlow.Application.Contracts/WorkFlow.Application.Contracts.csproj index 62f2add8..55d6ce9b 100644 --- a/WorkFlow/Application/WorkFlow.Application.Contracts/WorkFlow.Application.Contracts.csproj +++ b/WorkFlow/Application/WorkFlow.Application.Contracts/WorkFlow.Application.Contracts.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable diff --git a/WorkFlow/Application/WorkFlow.Application/WorkFlow.Application.csproj b/WorkFlow/Application/WorkFlow.Application/WorkFlow.Application.csproj index 231fd693..ea896886 100644 --- a/WorkFlow/Application/WorkFlow.Application/WorkFlow.Application.csproj +++ b/WorkFlow/Application/WorkFlow.Application/WorkFlow.Application.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable diff --git a/WorkFlow/Domain/WorkFlow.Domain/WorkFlow.Domain.csproj b/WorkFlow/Domain/WorkFlow.Domain/WorkFlow.Domain.csproj index 242d5353..5d5c21f8 100644 --- a/WorkFlow/Domain/WorkFlow.Domain/WorkFlow.Domain.csproj +++ b/WorkFlow/Domain/WorkFlow.Domain/WorkFlow.Domain.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable diff --git a/WorkFlow/Infrastructure/WorkFlow.Infrastructure.ACL/WorkFlow.Infrastructure.ACL.csproj b/WorkFlow/Infrastructure/WorkFlow.Infrastructure.ACL/WorkFlow.Infrastructure.ACL.csproj index ed7e9ba4..9bc635b9 100644 --- a/WorkFlow/Infrastructure/WorkFlow.Infrastructure.ACL/WorkFlow.Infrastructure.ACL.csproj +++ b/WorkFlow/Infrastructure/WorkFlow.Infrastructure.ACL/WorkFlow.Infrastructure.ACL.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable diff --git a/WorkFlow/Infrastructure/WorkFlow.Infrastructure.Config/WorkFlow.Infrastructure.Config.csproj b/WorkFlow/Infrastructure/WorkFlow.Infrastructure.Config/WorkFlow.Infrastructure.Config.csproj index 0fe5e5ec..b5bb9483 100644 --- a/WorkFlow/Infrastructure/WorkFlow.Infrastructure.Config/WorkFlow.Infrastructure.Config.csproj +++ b/WorkFlow/Infrastructure/WorkFlow.Infrastructure.Config/WorkFlow.Infrastructure.Config.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable diff --git a/WorkFlow/Infrastructure/WorkFlow.Infrastructure.EfCore/WorkFlow.Infrastructure.EfCore.csproj b/WorkFlow/Infrastructure/WorkFlow.Infrastructure.EfCore/WorkFlow.Infrastructure.EfCore.csproj index de6a663d..f5e37417 100644 --- a/WorkFlow/Infrastructure/WorkFlow.Infrastructure.EfCore/WorkFlow.Infrastructure.EfCore.csproj +++ b/WorkFlow/Infrastructure/WorkFlow.Infrastructure.EfCore/WorkFlow.Infrastructure.EfCore.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable diff --git a/_0_Framework/_0_Framework_b.csproj b/_0_Framework/_0_Framework_b.csproj index bb6a3bd7..4b8e918f 100644 --- a/_0_Framework/_0_Framework_b.csproj +++ b/_0_Framework/_0_Framework_b.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 diff --git a/backService/backService.csproj b/backService/backService.csproj index eb699246..848d38c6 100644 --- a/backService/backService.csproj +++ b/backService/backService.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0