using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using _0_Framework.Application; using _0_Framework.Domain.CustomizeCheckoutShared.Enums; using _0_Framework.InfraStructure; using AccountMangement.Infrastructure.EFCore; using Company.Domain.AdminMonthlyOverviewAgg; using CompanyManagment.App.Contracts.AdminMonthlyOverview; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; using Microsoft.EntityFrameworkCore; using Tools = _0_Framework_b.Application.Tools; namespace CompanyManagment.EFCore.Repository; public class AdminMonthlyOverviewRepository : RepositoryBase, IAdminMonthlyOverviewRepository { private readonly CompanyContext _companyContext; private readonly AccountContext _accountContext; public AdminMonthlyOverviewRepository(CompanyContext companyContext, AccountContext accountContext) : base(companyContext) { _companyContext = companyContext; _accountContext = accountContext; } public async Task> GetWorkshopStatus(AdminMonthlyOverviewSearchModel searchModel) { var year = searchModel.Year; var month = searchModel.Month; var accountId = searchModel.AdminAccountId; // اگر تبدیل تاریخ به میلادی موفق نبود، لیست خالی برگردان if ($"{year:0000}/{month:00}/01".TryToGeorgianDateTime(out var targetStartDate) == false) return []; var targetEndDate = Tools.FindeEndOfMonth(targetStartDate.ToFarsi()).ToGeorgianDateTime(); _ = $"{year:0000}/{month:00}/01".ToGeorgianDateTime().AddMonthsFa(1, out var nextFirstMonth); var nextEndMonth = Tools.FindeEndOfMonth(nextFirstMonth.ToFarsi()).ToGeorgianDateTime(); // دریافت اطلاعات ادمین var adminAccount = await _accountContext.Accounts.FirstOrDefaultAsync(x => x.id == searchModel.AdminAccountId); // اگر ادمین پیدا نشد، لیست خالی برگردان if (adminAccount == null) return []; // دریافت طرف حساب های معتبر برای تاریخ مورد نظر var contractingPartyIds = _companyContext.InstitutionContractSet.AsNoTracking() .Where(c => c.ContractStartGr <= targetEndDate && c.ContractEndGr >= targetStartDate) .Select(c => c.ContractingPartyId); // دریافت کارگاه‌های مرتبط با اکانت var workshopAccounts = _companyContext.WorkshopAccounts .AsNoTracking() .Where(w => w.AccountId == accountId) .Select(w => w.WorkshopId).ToList(); var workshopsHasLeftWorkEmployees = _companyContext.LeftWorkList.Where(x => ((x.StartWorkDate <= targetEndDate && x.LeftWorkDate.AddDays(-1) >= targetStartDate) || (x.StartWorkDate <= nextEndMonth && x.LeftWorkDate.AddDays(-1) >= nextFirstMonth)) && workshopAccounts.Contains(x.WorkshopId)).Select(x => x.WorkshopId); // دریافت کارگاه‌های مربوط به طرف حساب و اکانت // Replace the selected code with the following to return a list of anonymous objects containing both workshop and contractingParty var workshopsWithContractingParty = await _companyContext.Workshops .AsNoTracking() .Where(w => workshopsHasLeftWorkEmployees.Contains(w.id) && w.IsActive) .Include(w => w.WorkshopEmployers) .ThenInclude(we => we.Employer) .ThenInclude(e => e.ContractingParty).AsSplitQuery(). Where(w => w.WorkshopEmployers.Any(we => we.Employer != null && contractingPartyIds.Contains(we.Employer.ContractingPartyId))) .Select(w => new { Workshop = w, ContractingParty = w.WorkshopEmployers .Where(we => we.Employer != null && contractingPartyIds.Contains(we.Employer.ContractingPartyId)) .Select(we => we.Employer.ContractingParty) .FirstOrDefault() }) .ToListAsync(); var workshopIds = workshopsWithContractingParty.Select(x => x.Workshop.id).ToList(); // پیدا کردن کارگاه‌هایی که قبلاً برای این ماه/سال AdminMonthlyOverview دارند var adminMonthlyOverviewWorkshopIds = await _companyContext.AdminMonthlyOverviews .AsNoTracking() .Where(x => workshopIds.Contains(x.WorkshopId) && x.Month == month && x.Year == year) .Select(x => x.WorkshopId) .ToListAsync(); // پیدا کردن کارگاه‌هایی که نیاز به ایجاد AdminMonthlyOverview جدید دارند var notExistAdminMonthlyReviewsWorkshopIds = workshopIds .Except(adminMonthlyOverviewWorkshopIds) .ToList(); // ایجاد رکوردهای AdminMonthlyOverview که وجود ندارند if (notExistAdminMonthlyReviewsWorkshopIds.Any()) await CreateRangeAdminMonthlyOverview(notExistAdminMonthlyReviewsWorkshopIds, month, year); // به‌روزرسانی وضعیت‌ها await UpdateAdminMonthlyOverviewStatus(year, month, workshopIds, targetStartDate,targetEndDate, nextFirstMonth,nextEndMonth); if (searchModel.ActivationStatus != IsActive.None) { var isBlock = searchModel.ActivationStatus == IsActive.True ? "false" : "true"; workshopsWithContractingParty = workshopsWithContractingParty .Where(x => x.ContractingParty?.IsBlock == isBlock).ToList(); workshopIds = workshopsWithContractingParty.Select(x => x.Workshop.id).ToList(); } // دریافت همه AdminMonthlyOverview برای این کارگاه‌ها/ماه/سال var adminMonthlyOverviewsQuery = _companyContext.AdminMonthlyOverviews .Where(x => workshopIds.Contains(x.WorkshopId) && x.Month == month && x.Year == year); if (searchModel.WorkshopId > 0) { adminMonthlyOverviewsQuery = adminMonthlyOverviewsQuery.Where(x => x.WorkshopId == searchModel.WorkshopId); } if (searchModel.EmployerId > 0) { var searchWorkshopId = workshopsWithContractingParty.Where(x => x.Workshop.WorkshopEmployers.Any(e => e.EmployerId == searchModel.EmployerId)).Select(x => x.Workshop.id).ToList(); adminMonthlyOverviewsQuery = adminMonthlyOverviewsQuery.Where(x => searchWorkshopId.Contains(x.WorkshopId)); } var employeeCheckoutCounts = _companyContext.LeftWorkList.Where(x => x.StartWorkDate <= targetStartDate && x.LeftWorkDate.AddDays(-1) >= targetStartDate && workshopIds.Contains(x.WorkshopId)) .GroupBy(x => x.WorkshopId).Select(x => new { EmployeeCounts = x.Count(), WorkshopId = x.Key }).ToList(); var employeeContractCounts = _companyContext.LeftWorkList.Where(x => x.StartWorkDate <= nextFirstMonth && x.LeftWorkDate.AddDays(-1) >= nextFirstMonth && workshopIds.Contains(x.WorkshopId)) .GroupBy(x => x.WorkshopId).Select(x => new { EmployeeCounts = x.Count(), WorkshopId = x.Key }).ToList(); var adminMonthlyOverviewsList = await adminMonthlyOverviewsQuery.ToListAsync(); var now = DateTime.Today; //پرسنل ادمین اجرایی var operatorAdminAccounts = _accountContext.AccountLeftWorks .Where(x => workshopIds.Contains(x.WorkshopId) && x.StartWorkGr <= now && x.LeftWorkGr >= now && x.RoleId == 5).Select(x => new { x.WorkshopId, x.AccountId }) .Join(_accountContext.Accounts, x => x.AccountId, account => account.id, (x, account) => new { x.WorkshopId, account.Fullname }).ToList(); var adminMonthlyOverviewList = adminMonthlyOverviewsList.Select(x => { var employeeCheckoutCount = employeeCheckoutCounts.FirstOrDefault(e => e.WorkshopId == x.WorkshopId); var employeeContractCount = employeeContractCounts.FirstOrDefault(e => e.WorkshopId == x.WorkshopId); var workshopWithContractingParty = workshopsWithContractingParty.FirstOrDefault(w => w.Workshop.id == x.WorkshopId); var operatorAccount = operatorAdminAccounts.FirstOrDefault(o => o.WorkshopId == x.WorkshopId); var workshop = workshopWithContractingParty?.Workshop; var contractingParty = workshopWithContractingParty?.ContractingParty; var employer = workshop?.WorkshopEmployers.FirstOrDefault()?.Employer; return new AdminMonthlyOverviewListViewModel { WorkshopId = x.WorkshopId, Status = x.Status, Id = x.id, WorkshopName = workshop?.WorkshopFullName ?? "", WorkshopArchiveCode = workshop?.ArchiveCode ?? "", WorkshopArchiveCodeInt = workshop?.ArchiveCode.ExtractIntNumbers() ?? 0, Address = workshop?.Address ?? "", City = workshop?.City ?? "", Province = workshop?.State ?? "", EmployerName = employer?.FullName ?? "", EmployerPhoneNumber = employer?.Phone ?? "", AdminFullName = operatorAccount?.Fullname ?? "", CheckoutEmployeeCount = employeeCheckoutCount?.EmployeeCounts ?? 0, ContractEmployeeCount = employeeContractCount?.EmployeeCounts ?? 0, AgentPhoneNumber = "", IsBlock = contractingParty?.IsBlock == "true" }; }).OrderBy(x => x.IsBlock).ThenBy(x => x.WorkshopArchiveCodeInt).ToList(); return adminMonthlyOverviewList; } public async Task GetCounter(int year, int month, long accountId) { var searchModel = new AdminMonthlyOverviewSearchModel() { AdminAccountId = accountId, Month = month, Year = year }; var list = await GetWorkshopStatus(searchModel); var allCount = list.Count; var archivedCount = list.Count(x => x.Status == AdminMonthlyOverviewStatus.Archived); var createDocCount = list.Count(x => x.Status == AdminMonthlyOverviewStatus.CreateDocuments); var visitCompleteCount = list.Count(x => x.Status == AdminMonthlyOverviewStatus.VisitCompleted); var visitInProgressCount = list.Count(x => x.Status == AdminMonthlyOverviewStatus.VisitInProgress); var visitPendingCount = list.Count(x => x.Status == AdminMonthlyOverviewStatus.VisitPending); return new AdminMonthlyOverViewCounterVm { All = allCount, Archived = archivedCount, VisitPending = visitPendingCount, VisitInProgress = visitInProgressCount, VisitCompleted = visitCompleteCount, CreateDocument = createDocCount }; } private async Task UpdateAdminMonthlyOverviewStatus(int year, int month, List workshopIds, DateTime targetStartDate,DateTime targetEndDate, DateTime nextStartMonth,DateTime nextEndMonth) { var vipGroup = _companyContext.CustomizeWorkshopEmployeeSettings.Where(x => x.CustomizeWorkshopGroupSettingId == 117) .Select(x => x.EmployeeId) .Except([5976]).ToList(); var workingCheckoutEmployeeIds = _companyContext.LeftWorkList.AsNoTracking() .Join( _companyContext.Contracts.AsNoTracking(), leftWork => new { leftWork.EmployeeId, WorkshopId = leftWork.WorkshopId }, contract => new { contract.EmployeeId, WorkshopId = contract.WorkshopIds }, (leftWork, contract) => new { leftWork, contract } ) .Where(x => workshopIds.Contains(x.leftWork.WorkshopId) && x.leftWork.StartWorkDate <= targetEndDate && x.leftWork.LeftWorkDate.AddDays(-1) >= targetStartDate && x.contract.ContarctStart <= targetEndDate && x.contract.ContractEnd >= targetStartDate && !vipGroup.Contains(x.leftWork.EmployeeId) && !_companyContext.EmployeeClientTemps .Any(temp => temp.EmployeeId == x.leftWork.EmployeeId && temp.WorkshopId == x.leftWork.WorkshopId) ) .Select(x => new { x.leftWork.WorkshopId, x.leftWork.EmployeeId }); var workingContractEmployeeIds = _companyContext.LeftWorkList.AsNoTracking() .Where(x => workshopIds.Contains(x.WorkshopId) && x.StartWorkDate <= nextEndMonth && x.LeftWorkDate.AddDays(-1) >= nextStartMonth && !vipGroup.Contains(x.EmployeeId) && !_companyContext.EmployeeClientTemps .Any(temp => temp.EmployeeId == x.EmployeeId && temp.WorkshopId == x.WorkshopId) ).Select(x => new { x.WorkshopId, x.EmployeeId }); var contractSet = (await _companyContext.Contracts.AsNoTracking() .Where(x => x.ContarctStart <= nextEndMonth && x.ContractEnd >= nextStartMonth && workshopIds.Contains(x.WorkshopIds)) .Select(x => new { x.WorkshopIds, x.EmployeeId }) .ToListAsync()) .Select(x => (x.WorkshopIds, x.EmployeeId)) .ToHashSet(); var checkoutSet = (await _companyContext.CheckoutSet.AsNoTracking() .Where(x => x.ContractStart <= targetEndDate && x.ContractEnd >= targetStartDate && workshopIds.Contains(x.WorkshopId)) .Select(x => new { x.WorkshopId, x.EmployeeId }) .ToListAsync()) .Select(x => (x.WorkshopId, x.EmployeeId)) .ToHashSet(); var workingCheckoutGrouping = workingCheckoutEmployeeIds.GroupBy(x => x.WorkshopId).ToList(); var workingContractGrouping = workingContractEmployeeIds.GroupBy(x => x.WorkshopId).Select(x => new { WorkshopId = x.Key, Data = x.ToList() }).ToList(); var workshopsWithFullContracts = workingContractGrouping .Where(g => g.Data.All(emp => contractSet.Contains((emp.WorkshopId, emp.EmployeeId)))) .Select(g => g.WorkshopId) .ToList(); var list = workingContractEmployeeIds.ToList().Where(x=>!contractSet.Any(a=>a.EmployeeId== x.EmployeeId&&a.WorkshopIds == x.WorkshopId)).ToList(); var workshopsWithFullCheckout = workingCheckoutGrouping .Where(g => g.All(emp => checkoutSet.Contains((emp.WorkshopId, emp.EmployeeId)))) .Select(g => g.Key) .ToList(); var fullyCoveredWorkshops = workshopsWithFullContracts.Intersect(workshopsWithFullCheckout).ToList(); //var notFullyCoveredWorkshops = groupedCheckout // .Where(g => g.Any(emp => // !contractSet.Contains((emp.WorkshopId, emp.EmployeeId)) || // !checkoutSet.Contains((emp.WorkshopId, emp.EmployeeId)))) // .Select(g => g.Key) // .ToList(); var notFullyCoveredWorkshops = workshopIds.Except(fullyCoveredWorkshops); var adminMonthlyOverviews = _companyContext.AdminMonthlyOverviews .Where(x => x.Month == month && x.Year == year); var adminMonthlyOverviewsWithFullContracts = await adminMonthlyOverviews .Where(x => fullyCoveredWorkshops.Contains(x.WorkshopId) && x.Status == AdminMonthlyOverviewStatus.CreateDocuments) .ToListAsync(); var adminMonthlyOverviewsWithNotFullContracts = await adminMonthlyOverviews .Where(x => notFullyCoveredWorkshops.Contains(x.WorkshopId) && x.Status != AdminMonthlyOverviewStatus.CreateDocuments) .ToListAsync(); foreach (var adminMonthlyOverview in adminMonthlyOverviewsWithFullContracts) adminMonthlyOverview.SetStatus(AdminMonthlyOverviewStatus.VisitPending); foreach (var adminMonthlyOverview in adminMonthlyOverviewsWithNotFullContracts) adminMonthlyOverview.SetStatus(AdminMonthlyOverviewStatus.CreateDocuments); await _companyContext.SaveChangesAsync(); } private async Task CreateRangeAdminMonthlyOverview(List workshopIds, int month, int year) { foreach (var workshopId in workshopIds) { var adminMonthlyOverview = new AdminMonthlyOverview(workshopId, month, year, AdminMonthlyOverviewStatus.CreateDocuments); await _companyContext.AddAsync(adminMonthlyOverview); } await _companyContext.SaveChangesAsync(); } }