Merge remote-tracking branch 'origin/Main' into Main

This commit is contained in:
2026-02-03 14:24:58 +03:30
14 changed files with 369 additions and 161 deletions

View File

@@ -1,5 +1,4 @@
using System;
using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using _0_Framework.Application;
using Microsoft.AspNetCore.SignalR;
@@ -24,7 +23,6 @@ public class SendSmsHub : Hub
await base.OnConnectedAsync();
}
public async Task send(long id)
{
await Groups.AddToGroupAsync(Context.ConnectionId, GetGroupName(id));

View File

@@ -136,12 +136,34 @@ public class SmsSettingApplication : ISmsSettingApplication
public async Task<OperationResult> InstantSendReminderSms(List<SmsListData> command)
{
var op = new OperationResult();
//if (_hostEnvironment.IsDevelopment())
//{
// return op.Failed(" در محیط توسعه امکان ارسال وجود ندارد ");
//}
List<string> devModeNumberList = [];
if (_hostEnvironment.IsDevelopment())
{
int taker = 0;
switch (command.Count)
{
case >= 3:
taker = 3;
break;
case > 0:
case < 3:
taker = command.Count;
break;
default:
taker = 0;
}
if (taker > 0)
{
devModeNumberList = ["09114221321", "09116967898", "09116067106"];
command = command.Take(taker).ToList();
for (int i = 0; i < 3; i++)
{
command[i].PhoneNumber = devModeNumberList[i];
}
}
}
string typeOfSms = "یادآور بدهی ماهانه";
string sendMessStart = "شروع یادآور آنی";
string sendMessEnd = "پایان یادآور آنی";
@@ -163,10 +185,32 @@ public class SmsSettingApplication : ISmsSettingApplication
{
var op = new OperationResult();
List<string> devModeNumberList = [];
if (_hostEnvironment.IsDevelopment())
{
return op.Failed(" در محیط توسعه امکان ارسال وجود ندارد ");
int taker = 0;
switch (command.Count)
{
case >= 3:
taker = 3;
break;
case > 0:
case < 3:
taker = command.Count;
break;
default:
taker = 0;
}
if (taker > 0)
{
devModeNumberList = ["09114221321", "09116967898", "09116067106"];
command = command.Take(taker).ToList();
for (int i = 0; i < 3; i++)
{
command[i].PhoneNumber = devModeNumberList[i];
}
}
}
string typeOfSms = "اعلام مسدودی طرف حساب";
@@ -289,16 +333,7 @@ public class SmsSettingApplication : ISmsSettingApplication
{
var op = new OperationResult();
//if (_hostEnvironment.IsDevelopment())
//{
// var str = "";
// foreach (var item in phoneNumbers)
// {
// str += $" {item}, ";
// }
// return op.Failed(" در محیط توسعه امکان ارسال وجود ندارد " + " لیست ارسال شما " + str);
//}
if (typeOfSmsSetting == TypeOfSmsSetting.InstitutionContractDebtReminder)
{
if (phoneNumbers.Any())

View File

@@ -939,13 +939,26 @@ public class InstitutionContractSmsServiceRepository : RepositoryBase<long, Inst
public async Task SendBlockSmsToContractingParties(List<BlockSmsListData> smsListData, string typeOfSms,
string sendMessStart, string sendMessEnd)
{
var accountId = _authHelper.CurrentAccountId();
var currentAccountId = _authHelper.CurrentAccountId();
var signalR = _hubContext.Clients.Group(SendSmsHub.GetGroupName(currentAccountId));
if (smsListData.Any())
{
await _smsService.Alarm("09114221321", sendMessStart);
Thread.Sleep(1000);
await _smsService.Alarm("09111485044", sendMessStart);
Thread.Sleep(1000);
try
{
var sendingStart = await _smsService.Alarm("09114221321", sendMessStart);
Thread.Sleep(1000);
if (!sendingStart)
{
await signalR.SendAsync("sendToApi", "failed");
return;
}
}
catch (Exception e)
{
await signalR.SendAsync("sendToApi", "failed");
return;
}
int successProcess = 1;
int countList = smsListData.Count;
@@ -963,6 +976,7 @@ public class InstitutionContractSmsServiceRepository : RepositoryBase<long, Inst
item.PartyName, item.PhoneNumber, item.ContractingPartyId, item.InstitutionContractId);
await _smsResultRepository.CreateAsync(createSmsResult);
await _smsResultRepository.SaveChangesAsync();
await signalR.SendAsync("sendStatus", true, item.PhoneNumber);
}
else
{
@@ -974,6 +988,7 @@ public class InstitutionContractSmsServiceRepository : RepositoryBase<long, Inst
item.PartyName, item.PhoneNumber, item.ContractingPartyId, item.InstitutionContractId);
await _smsResultRepository.CreateAsync(createSmsResult);
await _smsResultRepository.SaveChangesAsync();
await signalR.SendAsync("sendStatus", true, item.PhoneNumber);
}
}
@@ -981,13 +996,13 @@ public class InstitutionContractSmsServiceRepository : RepositoryBase<long, Inst
{
string name = item.PartyName.Length > 18 ? item.PartyName.Substring(0, 18) : item.PartyName;
string errMess = $"{name}-خطا";
await signalR.SendAsync("sendStatus", false, item.PhoneNumber);
await _smsService.Alarm("09114221321", errMess);
}
Thread.Sleep(600);
var percent = (successProcess / (double)countList) * 100;
await _hubContext.Clients.Group(SendSmsHub.GetGroupName(accountId))
.SendAsync("showStatus", (int)percent);
await signalR.SendAsync("showStatus", (int)percent);
successProcess += 1;
}
@@ -2099,89 +2114,102 @@ public class InstitutionContractSmsServiceRepository : RepositoryBase<long, Inst
string sendMessStart, string sendMessEnd)
{
//ارسال پیامک با اساس لیست
var accountId = _authHelper.CurrentAccountId();
var gr = _hubContext.Clients.Group(SendSmsHub.GetGroupName(accountId));
#region SendSMSFromList
var currentAccountId = _authHelper.CurrentAccountId();
var signalR = _hubContext.Clients.Group(SendSmsHub.GetGroupName(currentAccountId));
if (smsListData.Any())
{
//await _smsService.Alarm("09114221321", sendMessStart);
//Thread.Sleep(1000);
//await _smsService.Alarm("09111485044", sendMessStart);
//Thread.Sleep(1000);
try
{
var sendingStart = await _smsService.Alarm("09114221321", sendMessStart);
Thread.Sleep(1000);
if (!sendingStart)
{
await signalR.SendAsync("sendToApi", "failed");
return;
}
}
catch (Exception e)
{
await signalR.SendAsync("sendToApi", "failed");
return;
}
int successProcess = 1;
int countList = smsListData.Count;
for (int i = 0; i < 100; i++)
{
var percent = (successProcess / (double)100) * 100;
await gr.SendAsync("showStatus", (int)percent);
if (i == 5)
{
await gr.SendAsync("error", "خطا در شماره 5");
}
if (i == 10)
{
await gr.SendAsync("error", "خطا در شماره 10");
}
successProcess += 1;
Thread.Sleep(600);
}
//foreach (var item in smsListData)
#region Test
//for (int i = 0; i < 100; i++)
//{
// try
// {
// if (item.TypeOfSmsMethod == "MonthlyBill")
// {
// var res = await _smsService.MonthlyBill(item.PhoneNumber, item.TemplateId, item.PartyName,
// item.Amount,
// $"{item.ContractingPartyId}", item.AproveId);
// if (res.isSucceded)
// {
// var createSmsResult = new Company.Domain.SmsResultAgg.SmsResult(res.messaeId,
// res.message, typeOfSms, item.PartyName, item.PhoneNumber,
// item.ContractingPartyId, item.InstitutionContractId);
// await _smsResultRepository.CreateAsync(createSmsResult);
// await _smsResultRepository.SaveChangesAsync();
// }
// }
// else
// {
// var res = await _smsService.MonthlyBillNew(item.PhoneNumber, item.TemplateId, item.PartyName,
// item.Amount, item.Code1, item.Code2);
// if (res.isSucceded)
// {
// var createSmsResult = new Company.Domain.SmsResultAgg.SmsResult(res.messaeId,
// res.message, typeOfSms, item.PartyName, item.PhoneNumber,
// item.ContractingPartyId, item.InstitutionContractId);
// await _smsResultRepository.CreateAsync(createSmsResult);
// await _smsResultRepository.SaveChangesAsync();
// }
// }
// Thread.Sleep(600);
// }
// catch (Exception e)
// {
// string name = item.PartyName.Length > 18 ? item.PartyName.Substring(0, 18) : item.PartyName;
// string errMess = $"{name}-خطا";
// _logger.LogError(errMess);
// await _smsService.Alarm("09114221321", errMess);
// }
// var percent = (successProcess / (double)countList) * 100;
// await _hubContext.Clients.Group(SendSmsHub.GetGroupName(7))
// .SendAsync("showStatus", (int)percent);
// Thread.Sleep(1000);
// successProcess += 1;
//}
#endregion
foreach (var item in smsListData)
{
try
{
if (item.TypeOfSmsMethod == "MonthlyBill")
{
var res = await _smsService.MonthlyBill(item.PhoneNumber, item.TemplateId, item.PartyName,
item.Amount,
$"{item.ContractingPartyId}", item.AproveId);
if (res.isSucceded)
{
var createSmsResult = new Company.Domain.SmsResultAgg.SmsResult(res.messaeId,
res.message, typeOfSms, item.PartyName, item.PhoneNumber,
item.ContractingPartyId, item.InstitutionContractId);
await _smsResultRepository.CreateAsync(createSmsResult);
await _smsResultRepository.SaveChangesAsync();
await signalR.SendAsync("sendStatus", true, item.PhoneNumber);
}
}
else
{
var res = await _smsService.MonthlyBillNew(item.PhoneNumber, item.TemplateId, item.PartyName,
item.Amount, item.Code1, item.Code2);
if (res.isSucceded)
{
var createSmsResult = new Company.Domain.SmsResultAgg.SmsResult(res.messaeId,
res.message, typeOfSms, item.PartyName, item.PhoneNumber,
item.ContractingPartyId, item.InstitutionContractId);
await _smsResultRepository.CreateAsync(createSmsResult);
await _smsResultRepository.SaveChangesAsync();
await signalR.SendAsync("sendStatus", true, item.PhoneNumber);
}
}
Thread.Sleep(600);
}
catch (Exception e)
{
string name = item.PartyName.Length > 18 ? item.PartyName.Substring(0, 18) : item.PartyName;
string errMess = $"{name}-خطا";
await signalR.SendAsync("sendStatus", false, item.PhoneNumber);
_logger.LogError(errMess);
await _smsService.Alarm("09114221321", errMess);
}
var percent = (successProcess / (double)countList) * 100;
await signalR.SendAsync("showStatus", (int)percent);
successProcess += 1;
}
//await _smsService.Alarm("09114221321", sendMessEnd);

View File

@@ -82,25 +82,45 @@ public class RollCallEmployeeRepository : RepositoryBase<long, RollCallEmployee>
var service = _rollCallServiceRepository.GetAllServiceByWorkshopId(workshopId);
//اگر سرویس حضور غیاب نداشت
if (!service.Any(x => x.StartService.Date <= contractStart.Date && x.EndService.Date >= contractEnd.Date))
return false;
//var rollCallEmployee = GetByEmployeeIdAndWorkshopId(employeeId, workshopId);
//if (rollCallEmployee == null)
// return false;
var rollCallEmployee = _context.RollCallEmployees
.Where(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId)
.Include(x => x.EmployeesStatus);
if (!rollCallEmployee.Any())
var rollCallEmployee = _context.RollCallEmployees.Include(xs => xs.EmployeesStatus)
.FirstOrDefault(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId);
//اگر تنظیمات حضور غیاب نداشت
if (rollCallEmployee == null)
return false;
//اگر استاتوس نداشت
if (!rollCallEmployee.EmployeesStatus.Any())
return false;
var a = rollCallEmployee.Any(x => x.EmployeesStatus.Any(s =>
(s.StartDate <= contractStart.Date && s.EndDate.Date >= contractEnd.Date) ||
(s.StartDate.Date <= contractStart.Date && s.EndDate.Date > contractStart.Date)));
//var result = _employeeRollCallStatusRepository.w(x => x.RollCallEmployeeId == rollCallEmployee.Id &&
// (x.StartDate.Date <= contractStart.Date && x.EndDate.Date >= contractEnd.Date) ||
// (x.StartDate.Date <= contractStart.Date && x.EndDate.Date > contractStart.Date));
return a;
var leftWork =
_context.LeftWorkList.FirstOrDefault(x =>
x.StartWorkDate <= contractEnd.Date && x.LeftWorkDate > contractStart);
if (leftWork == null)
return false;
var status = rollCallEmployee.EmployeesStatus.FirstOrDefault(s =>
(s.StartDate <= contractStart.Date && s.EndDate.Date >= contractEnd.Date));
//اگر استاتوس کامل پوشش داد
if (status != null)
return true;
status = rollCallEmployee.EmployeesStatus.FirstOrDefault(s =>
(s.StartDate.Date <= contractStart.Date && s.EndDate.Date > contractStart.Date &&
s.EndDate.Date < contractEnd.Date));
//اگر قبل از پایان فیس استاتوس قطع شده ولی ترک کار داره
if (status != null && leftWork.HasLeft)
return true;
return false;
}
public List<RollCallEmployeeViewModel> GetByWorkshopId(long workshopId)
{

View File

@@ -2859,7 +2859,7 @@ public class YearlySalaryRepository : RepositoryBase<long, YearlySalary>, IYearl
var contactCanToleaveList = new List<ContractsCanToLeave>();
var allContractsBetween = _context.Contracts.AsSplitQuery().Include(x => x.WorkingHoursList)
.Where(x => x.WorkshopIds == workshopId && x.EmployeeId == employeeId &&
x.ContractEnd >= startDate && x.ContarctStart <= endDate).ToList();
x.ContractEnd >= startDate && x.ContarctStart <= endDate).OrderBy(x=>x.ContarctStart).ToList();
var isWorkshopStaticCheckout = _context.Workshops.FirstOrDefault(x => x.id == workshopId)!.IsStaticCheckout;
int mandatoryDays = 0;
double allCanToLeave = 0;

View File

@@ -607,17 +607,14 @@ public class SmsService : ISmsService
//var bulkSendResult = smsIr.BulkSendAsync(95007079000006, "your text message", new string[] { "9120000000" });
var verificationSendResult =
var verificationSendResult = await
smsIr.VerifySendAsync(number, 662874, new VerifySendParameter[] { new("ALARM", message) });
Thread.Sleep(1000);
var status = verificationSendResult.Result.Status;
var mess = verificationSendResult.Result.Message;
var messaeId = verificationSendResult.Result.Data.MessageId;
if (verificationSendResult.IsCompletedSuccessfully) return true;
var resStartStatus = verificationSendResult.Result;
var resResult = verificationSendResult.Status;
var reseExceptiont = verificationSendResult.Exception;
Thread.Sleep(800);
if (verificationSendResult.Message == "موفق")
{
return true;
}
return false;
}

View File

@@ -14,6 +14,7 @@ public record SetTimeProjectCommand(
public class SetTimeSectionTime
{
public Guid? Id { get; set; }
public string Description { get; set; }
public int Hours { get; set; }
public int Minutes { get; set; }

View File

@@ -352,6 +352,15 @@ public class SetTimeProjectCommandHandler : IBaseCommandHandler<SetTimeProjectCo
return OperationResult.Success();
}
private void ValidateTotalTimeNotLessThanSpent(TimeSpan newTotalTime, TimeSpan currentTotalSpent)
{
if (newTotalTime < currentTotalSpent)
{
throw new BadRequestException(
$"تایم کل سکشن نمی‌تواند کمتر از زمان مصرف شده ({currentTotalSpent.TotalHours:F2} ساعت) باشد");
}
}
private void SetSectionTime(TaskSection section, SetTimeProjectSkillItem sectionItem, long? addedByUserId)
{
var initData = sectionItem.InitData;
@@ -366,18 +375,69 @@ public class SetTimeProjectCommandHandler : IBaseCommandHandler<SetTimeProjectCo
// تنظیم زمان اولیه
section.UpdateInitialEstimatedHours(initialTime, initData.Description);
section.ClearAdditionalTimes();
// افزودن زمان‌های اضافی
bool hasAdditionalTime = false;
foreach (var additionalTime in sectionItem.AdditionalTime)
// مدیریت هوشمند زمان‌های اضافی
var existingAdditionalTimes = section.AdditionalTimes.ToList();
var incomingAdditionalTimes = sectionItem.AdditionalTime ?? [];
var currentTotalSpent = section.GetTotalTimeSpent();
bool hasRealChange = false;
// حذف آیتم‌هایی که دیگر در لیست نیستند
foreach (var existingTime in existingAdditionalTimes)
{
var additionalTimeSpan = TimeSpan.FromHours(additionalTime.Hours).Add(TimeSpan.FromMinutes(additionalTime.Minutes));
section.AddAdditionalTime(additionalTimeSpan, additionalTime.Type, additionalTime.Description, addedByUserId);
hasAdditionalTime = true;
var stillExists = incomingAdditionalTimes.Any(x => x.Id == existingTime.Id);
if (!stillExists)
{
section.RemoveAdditionalTime(existingTime.Id);
hasRealChange = true;
}
}
// ویرایش یا اضافه کردن آیتم‌های جدید
foreach (var additionalTime in incomingAdditionalTimes)
{
var additionalTimeSpan = TimeSpan.FromHours(additionalTime.Hours)
.Add(TimeSpan.FromMinutes(additionalTime.Minutes));
if (additionalTimeSpan <= TimeSpan.Zero)
continue;
var existingAdditionalTime = existingAdditionalTimes.FirstOrDefault(x => x.Id == additionalTime.Id);
if (existingAdditionalTime != null)
{
// اگر آیتم با این ID وجود دارد، بررسی کن اگر تغییر کرده باشد
if (existingAdditionalTime.HasChanged(additionalTimeSpan, additionalTime.Description))
{
var newTotalTime = section.InitialEstimatedHours
.Add(existingAdditionalTimes
.Where(x => x.Id != existingAdditionalTime.Id)
.Aggregate(TimeSpan.Zero, (acc, x) => acc.Add(x.Hours))
.Add(additionalTimeSpan));
ValidateTotalTimeNotLessThanSpent(newTotalTime, currentTotalSpent);
// ویرایش بدون حذف و ایجاد دوباره
existingAdditionalTime.Update(additionalTimeSpan, additionalTime.Description);
hasRealChange = true;
}
}
else
{
// اگر ID نداشت یا ID جدید بود، اضافه کن
if (additionalTime.Id == null || additionalTime.Id == Guid.Empty)
{
var newTotalTime = section.FinalEstimatedHours.Add(additionalTimeSpan);
ValidateTotalTimeNotLessThanSpent(newTotalTime, currentTotalSpent);
section.AddAdditionalTime(additionalTimeSpan, additionalTime.Type,additionalTime.Description, addedByUserId);
hasRealChange = true;
}
}
}
// تغییر status به Incomplete فقط اگر زمان اضافی اضافه شده باشد و در وضعیتی غیر از ReadyToStart باشد
if (hasAdditionalTime && section.Status != TaskSectionStatus.ReadyToStart)
// تغییر status به Incomplete فقط اگر تغییری واقعی اعمال شده باشد و در وضعیتی غیر از ReadyToStart باشد
if (hasRealChange && section.Status != TaskSectionStatus.ReadyToStart)
{
// اگر سکشن درحال انجام است، باید متوقف شود قبل از تغییر status
if (section.Status == TaskSectionStatus.InProgress)

View File

@@ -232,28 +232,30 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
// For projects: gather all phases, then tasks, then sections
var phases = await _context.ProjectPhases
.Where(ph => projectIds.Contains(ph.ProjectId))
.Select(ph => ph.Id)
.Select(ph => new { ph.Id, ph.ProjectId })
.ToListAsync(cancellationToken);
var phaseIds = phases.Select(ph => ph.Id).ToList();
var tasks = await _context.ProjectTasks
.Where(t => phases.Contains(t.PhaseId))
.Select(t => t.Id)
.Where(t => phaseIds.Contains(t.PhaseId))
.Select(t => new { t.Id, t.PhaseId })
.ToListAsync(cancellationToken);
var taskIds = tasks.Select(t => t.Id).ToList();
var sections = await _context.TaskSections
.Include(s => s.Skill)
.Where(s => tasks.Contains(s.TaskId))
.Where(s => taskIds.Contains(s.TaskId))
.ToListAsync(cancellationToken);
// Convert to tuple list for AggregatePhaseStatuses
var tasksList = tasks.Select(t => (t.Id, t.PhaseId)).ToList();
foreach (var item in items)
{
var relatedPhases = phases; // used for filtering tasks by project
var relatedTasks = await _context.ProjectTasks
.Where(t => t.PhaseId != Guid.Empty && relatedPhases.Contains(t.PhaseId))
.Select(t => t.Id)
.ToListAsync(cancellationToken);
var itemSections = sections.Where(s => relatedTasks.Contains(s.TaskId));
item.Backend = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "Backend"));
item.Front = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "Frontend"));
item.Design = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "UI/UX Design"));
var projectPhaseIds = phases.Where(ph => ph.ProjectId == item.Id).Select(ph => ph.Id).ToList();
// برای هر Skill، وضعیت‌های تمام Phases را تجمیع کنیم
item.Backend = AggregatePhaseStatuses(projectPhaseIds, tasksList, sections, "Backend");
item.Front = AggregatePhaseStatuses(projectPhaseIds, tasksList, sections, "Frontend");
item.Design = AggregatePhaseStatuses(projectPhaseIds, tasksList, sections, "UI/UX Design");
}
}
@@ -263,24 +265,22 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
// For phases: gather tasks, then sections
var tasks = await _context.ProjectTasks
.Where(t => phaseIds.Contains(t.PhaseId))
.Select(t => t.Id)
.Select(t => new { t.Id, t.PhaseId })
.ToListAsync(cancellationToken);
var taskIds = tasks.Select(t => t.Id).ToList();
var sections = await _context.TaskSections
.Include(s => s.Skill)
.Where(s => tasks.Contains(s.TaskId))
.Where(s => taskIds.Contains(s.TaskId))
.ToListAsync(cancellationToken);
foreach (var item in items)
{
// Filter tasks for this phase
var phaseTaskIds = await _context.ProjectTasks
.Where(t => t.PhaseId == item.Id)
.Select(t => t.Id)
.ToListAsync(cancellationToken);
var phaseTaskIds = tasks.Where(t => t.PhaseId == item.Id).Select(t => t.Id).ToList();
var itemSections = sections.Where(s => phaseTaskIds.Contains(s.TaskId));
item.Backend = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "Backend"));
item.Front = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "Frontend"));
item.Design = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "UI/UX Design"));
item.Backend = AggregateAssignmentStatus(itemSections.Where(x => x.Skill?.Name == "Backend"));
item.Front = AggregateAssignmentStatus(itemSections.Where(x => x.Skill?.Name == "Frontend"));
item.Design = AggregateAssignmentStatus(itemSections.Where(x => x.Skill?.Name == "UI/UX Design"));
}
}
@@ -384,4 +384,57 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
// تعیین تکلیف نشده: نه user دارد نه time
return AssignmentStatus.Unassigned;
}
}
private static AssignmentStatus AggregatePhaseStatuses(
List<Guid> phaseIds,
List<(Guid Id, Guid PhaseId)> tasks,
List<TaskSection> sections,
string skillName)
{
var phaseStatuses = new List<AssignmentStatus>();
foreach (var phaseId in phaseIds)
{
var phaseTaskIds = tasks.Where(t => t.PhaseId == phaseId).Select(t => t.Id).ToList();
var phaseSections = sections.Where(s => phaseTaskIds.Contains(s.TaskId) && s.Skill?.Name == skillName);
var phaseStatus = AggregateAssignmentStatus(phaseSections);
phaseStatuses.Add(phaseStatus);
}
// الآن تجمیع وضعیت‌های Phases
if (!phaseStatuses.Any())
return AssignmentStatus.Unassigned;
// اگر هر یکی Unassigned باشد → Unassigned
if (phaseStatuses.Any(s => s == AssignmentStatus.Unassigned))
return AssignmentStatus.Unassigned;
// اگر Unassigned نیست و هر یکی UserOnly باشد → UserOnly
if (phaseStatuses.Any(s => s == AssignmentStatus.UserOnly))
return AssignmentStatus.UserOnly;
// فقط اگر همه Assigned باشند → Assigned
return AssignmentStatus.Assigned;
}
private static AssignmentStatus AggregateAssignmentStatus(IEnumerable<TaskSection> sections)
{
var sectionList = sections.ToList();
if (!sectionList.Any())
return AssignmentStatus.Unassigned;
var statuses = sectionList.Select(GetAssignmentStatus).ToList();
// اگر هر یکی Unassigned باشد → Unassigned (بدترین وضعیت)
if (statuses.Any(s => s == AssignmentStatus.Unassigned))
return AssignmentStatus.Unassigned;
// اگر Unassigned نیست و هر یکی UserOnly باشد → UserOnly (وضعیت متوسط)
if (statuses.Any(s => s == AssignmentStatus.UserOnly))
return AssignmentStatus.UserOnly;
// فقط اگر همه Assigned باشند → Assigned (بهترین وضعیت)
return AssignmentStatus.Assigned;
}
}

View File

@@ -28,6 +28,17 @@ public class TaskSectionAdditionalTime : EntityBase<Guid>
{
Reason = reason;
}
public void Update(TimeSpan hours, string? reason = null)
{
Hours = hours;
Reason = reason;
}
public bool HasChanged(TimeSpan newHours, string? newReason)
{
return Hours != newHours || Reason != newReason;
}
}
public enum TaskSectionAdditionalTimeType

View File

@@ -260,10 +260,10 @@ public class SmsReportController : AdminBaseController
/// <param name="phoneNumbers"></param>
/// <returns></returns>
[HttpPost("InstantReminderSmsSend")]
public async Task<ActionResult<OperationResult>> InstantReminderSmsSend([FromBody] List<string> phoneNumbers)
public async Task<ActionResult> InstantReminderSmsSend([FromBody] List<string> phoneNumbers)
{
var result = await _smsSettingApplication.InstantSmsSendApi(TypeOfSmsSetting.InstitutionContractDebtReminder, phoneNumbers);
return result;
var result = _smsSettingApplication.InstantSmsSendApi(TypeOfSmsSetting.InstitutionContractDebtReminder, phoneNumbers);
return Ok();
}
/// <summary>
@@ -272,10 +272,10 @@ public class SmsReportController : AdminBaseController
/// <param name="phoneNumbers"></param>
/// <returns></returns>
[HttpPost("InstantBlockSmsSend")]
public async Task<ActionResult<OperationResult>> InstantBlockSmsSend([FromBody] List<string> phoneNumbers)
public async Task<ActionResult> InstantBlockSmsSend([FromBody] List<string> phoneNumbers)
{
var result = await _smsSettingApplication.InstantSmsSendApi(TypeOfSmsSetting.BlockContractingParty, phoneNumbers);
return result;
var result = _smsSettingApplication.InstantSmsSendApi(TypeOfSmsSetting.BlockContractingParty, phoneNumbers);
return Ok();
}
#endregion
}

View File

@@ -796,12 +796,17 @@ public class IndexModel : PageModel
var firstContract = _contractApplication.GetDetails(ContractsId[0]);
var workshop = _workshopApplication.GetDetails(firstContract.WorkshopIds);
//int i = 0;
foreach (var item in ContractsId)
{
var contract = _contractApplication.GetDetails(item);
//=============== استثنا علی خادم دهقان - میز اداری پویا========
if (workshop.Id == 482 && contract.EmployeeId == 7175)
workshop.IsOldContract = false;
//==============================================================
//var workingHours = _workingHoursApplication.GetByContractId(contract.Id);
var workingHours = _workingHoursTempApplication.GetByContractIdConvertToShiftwork4(contract.Id);
var separation = _contractApplication.contractSeparation(ConvertYear, ConvertMonth,

View File

@@ -190,7 +190,7 @@
بانک ها </a>
</li>
<li permission="314">
<a class="clik3" asp-page="/Company/SmsResult/Index">
<a class="clik3" href="https://admin@(AppSetting.Value.Domain)/automatic-sms-reporting">
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg" style="width: 7px;margin: 0 6px;">
<circle cx="6.5" cy="6.5" r="6.5" fill="white"/>
</svg>

View File

@@ -253,7 +253,7 @@
بانک ها </a>
</li>
<li permission="314">
<a class="clik3" asp-area="Admin" asp-page="/Company/SmsResult/Index">
<a class="clik3" href="https://admin@(AppSetting.Value.Domain)/automatic-sms-reporting">
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg" style="width: 7px;margin: 0 6px;">
<circle cx="6.5" cy="6.5" r="6.5" fill="white" />
</svg>