Merge remote-tracking branch 'origin/Main' into Main
This commit is contained in:
@@ -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));
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user