Compare commits

...

30 Commits

Author SHA1 Message Date
7a73e69afa Merge branch 'master' into Fix/program-manager/fix-some-bugs 2026-01-22 11:06:58 +03:30
gozareshgir
21302803b6 insurance WorkingDays bug Fixed 2026-01-19 12:32:51 +03:30
gozareshgir
8ec13ffae1 Merge branch 'master' of https://pm.gozareshgir.ir/gozareshgir/OriginalGozareshgir 2026-01-14 14:40:50 +03:30
gozareshgir
5508d4e88f Checkout Compute Minuts Base 2026-01-14 14:39:51 +03:30
43abb74c61 Merge branch 'Feature/program-manager/chat'
# Conflicts:
#	ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/TaskChat/Queries/GetMessages/GetMessagesQuery.cs
2026-01-14 10:57:07 +03:30
73e6681baa add message type to search query 2026-01-14 10:46:44 +03:30
90b2fd2eab add order for skills in set time 2026-01-14 10:13:57 +03:30
b7172630e2 set orders for projects 2026-01-13 15:49:51 +03:30
0604514190 Merge branch 'refs/heads/master' into Fix/program-manager/fix-some-bugs 2026-01-13 14:51:25 +03:30
d9c431e20e add project name search for board list 2026-01-13 09:23:53 +03:30
ff5180eb75 remove add task to phase 2026-01-12 17:39:54 +03:30
a1c9335487 add remaining time and spent time to get project list 2026-01-12 16:48:54 +03:30
gozareshgir
2746bf69ea Merge branch 'master' into Feature/SmsRepoetApi 2026-01-12 14:38:15 +03:30
gozareshgir
77dbb50512 BlueDeActiveAfterZeroDebt hangfire completed 2026-01-12 14:32:50 +03:30
gozareshgir
1c7e8824c7 DeActiveInstitutionEndOfContract hangfire completed 2026-01-12 13:10:58 +03:30
20ece4886c add task priority to CreateProjectCommand 2026-01-12 12:20:08 +03:30
0eff1b9a66 change default task priority from medium to low 2026-01-12 12:07:43 +03:30
gozareshgir
0d33d79620 unblock hangfire completed 2026-01-11 22:07:58 +03:30
gozareshgir
e4355faffc block and unblock 2026-01-11 21:10:29 +03:30
gozareshgir
577fe5db76 Merge branch 'master' of https://pm.gozareshgir.ir/gozareshgir/OriginalGozareshgir into Feature/SmsRepoetApi 2026-01-11 12:58:36 +03:30
SamSys
ec8333c715 merg from master 2026-01-08 15:00:40 +03:30
SamSys
8aa93e089a legal Action Sms completed 2026-01-08 14:56:33 +03:30
SamSys
0ab3052251 Send Warning and leagal action Message 2026-01-08 14:04:34 +03:30
SamSys
5202779d9f changes 2026-01-08 12:18:01 +03:30
SamSys
67a85735f0 merge from master 2026-01-08 11:36:18 +03:30
SamSys
35e6355069 get Warning sms List on new repo 2026-01-08 11:19:25 +03:30
SamSys
4de2e12ac5 AmaApiReport 2026-01-07 18:38:12 +03:30
SamSys
23b65cfbfe GetSms Report Expand List 2026-01-07 16:59:21 +03:30
SamSys
48b75d2baa Sms Report get list init 2026-01-07 16:29:03 +03:30
SamSys
63edb33bf5 Sms Report Init 2026-01-07 14:49:44 +03:30
37 changed files with 3195 additions and 1730 deletions

View File

@@ -2,6 +2,8 @@
public enum TypeOfSmsSetting
{
//همه انواع پیامک
All = 0,
/// <summary>
/// پیامک
@@ -23,7 +25,7 @@ public enum TypeOfSmsSetting
/// <summary>
/// پیامک
/// هشدار اول
/// هشدار بدهی
/// </summary>
Warning,
@@ -38,4 +40,14 @@ public enum TypeOfSmsSetting
/// </summary>
InstitutionContractConfirm,
/// <summary>
/// ارسال کد تاییدیه قرارداد مالی
/// </summary>
SendInstitutionContractConfirmationCode,
/// <summary>
/// یادآور وظایف
/// </summary>
TaskReminder,
}

View File

@@ -18,3 +18,17 @@ public class ApiResultViewModel
public string DeliveryColor { get; set; }
public string FullName { get; set; }
}
public class ApiReportDto
{
public int MessageId { get; set; }
public long Mobile { get; set; }
public string SendUnixTime { get; set; }
public string DeliveryState { get; set; }
public string DeliveryUnixTime { get; set; }
public string DeliveryColor { get; set; }
}

View File

@@ -19,6 +19,13 @@ public interface ISmsService
bool SendAccountsInfo(string number,string fullName, string userName);
Task<ApiResultViewModel> GetByMessageId(int messId);
Task<List<ApiResultViewModel>> GetApiResult(string startDate, string endDate);
#region ForApi
Task<List<ApiReportDto>> GetApiReport(string startDate, string endDate);
#endregion
string DeliveryStatus(byte? dv);
string DeliveryColorStatus(byte? dv);
string UnixTimeStampToDateTime(int? unixTimeStamp);

View File

@@ -1,5 +1,6 @@
using _0_Framework.Application;
using _0_Framework.Application.Enums;
using _0_Framework.Application.Sms;
using Company.Domain.ContarctingPartyAgg;
using Company.Domain.InstitutionContractAgg;
@@ -12,19 +13,21 @@ public class JobSchedulerRegistrator
private readonly IBackgroundJobClient _backgroundJobClient;
private readonly SmsReminder _smsReminder;
private readonly IInstitutionContractRepository _institutionContractRepository;
private readonly IInstitutionContractSmsServiceRepository _institutionContractSmsServiceRepository;
private static DateTime? _lastRunCreateTransaction;
private static DateTime? _lastRunSendMonthlySms;
private readonly ISmsService _smsService;
private readonly ILogger<JobSchedulerRegistrator> _logger;
public JobSchedulerRegistrator(SmsReminder smsReminder, IBackgroundJobClient backgroundJobClient, IInstitutionContractRepository institutionContractRepository, ISmsService smsService, ILogger<JobSchedulerRegistrator> logger)
public JobSchedulerRegistrator(SmsReminder smsReminder, IBackgroundJobClient backgroundJobClient, IInstitutionContractRepository institutionContractRepository, ISmsService smsService, ILogger<JobSchedulerRegistrator> logger, IInstitutionContractSmsServiceRepository institutionContractSmsServiceRepository)
{
_smsReminder = smsReminder;
_backgroundJobClient = backgroundJobClient;
_institutionContractRepository = institutionContractRepository;
_smsService = smsService;
_logger = logger;
_institutionContractSmsServiceRepository = institutionContractSmsServiceRepository;
}
public void Register()
@@ -58,17 +61,43 @@ public class JobSchedulerRegistrator
"*/1 * * * *" // هر 1 دقیقه یکبار چک کن
);
//RecurringJob.AddOrUpdate(
// "InstitutionContract.SendWarningSms",
// () => SendWarningSms(),
// "*/1 * * * *" // هر 1 دقیقه یکبار چک کن
//);
RecurringJob.AddOrUpdate(
"InstitutionContract.SendWarningSms",
() => SendWarningSms(),
"*/1 * * * *" // هر 1 دقیقه یکبار چک کن
);
//RecurringJob.AddOrUpdate(
// "InstitutionContract.SendLegalActionSms",
// () => SendLegalActionSms(),
// "*/1 * * * *" // هر 1 دقیقه یکبار چک کن
//);
RecurringJob.AddOrUpdate(
"InstitutionContract.SendLegalActionSms",
() => SendLegalActionSms(),
"*/1 * * * *" // هر 1 دقیقه یکبار چک کن
);
RecurringJob.AddOrUpdate(
"InstitutionContract.Block",
() => Block(),
"*/30 * * * *" // هر 30 دقیقه یکبار چک کن
);
RecurringJob.AddOrUpdate(
"InstitutionContract.UnBlock",
() => UnBlock(),
"*/10 * * * *"
);
RecurringJob.AddOrUpdate(
"InstitutionContract.DeActiveInstitutionEndOfContract",
() => DeActiveInstitutionEndOfContract(),
"*/30 * * * *"
);
RecurringJob.AddOrUpdate(
"InstitutionContract.BlueDeActiveAfterZeroDebt",
() => BlueDeActiveAfterZeroDebt(),
"*/10 * * * *"
);
}
@@ -79,7 +108,7 @@ public class JobSchedulerRegistrator
[DisableConcurrentExecution(timeoutInSeconds: 1200)]
public async System.Threading.Tasks.Task CreateFinancialTransaction()
{
var now =DateTime.Now;
var now = DateTime.Now;
var endOfMonth = now.ToFarsi().FindeEndOfMonth();
var endOfMonthGr = endOfMonth.ToGeorgianDateTime();
_logger.LogInformation("CreateFinancialTransaction job run");
@@ -134,7 +163,7 @@ public class JobSchedulerRegistrator
try
{
await _institutionContractRepository.SendMonthlySms(now);
await _institutionContractSmsServiceRepository.SendMonthlySms(now);
_lastRunSendMonthlySms = now;
Console.WriteLine("Send Monthly sms executed");
@@ -156,7 +185,7 @@ public class JobSchedulerRegistrator
public async System.Threading.Tasks.Task SendReminderSms()
{
_logger.LogInformation("SendReminderSms job run");
await _institutionContractRepository.SendReminderSmsForBackgroundTask();
await _institutionContractSmsServiceRepository.SendReminderSmsForBackgroundTask();
}
/// <summary>
@@ -167,7 +196,7 @@ public class JobSchedulerRegistrator
public async System.Threading.Tasks.Task SendBlockSms()
{
_logger.LogInformation("SendBlockSms job run");
await _institutionContractRepository.SendBlockSmsForBackgroundTask();
await _institutionContractSmsServiceRepository.SendBlockSmsForBackgroundTask();
}
@@ -179,7 +208,7 @@ public class JobSchedulerRegistrator
public async System.Threading.Tasks.Task SendInstitutionContractConfirmSms()
{
_logger.LogInformation("SendInstitutionContractConfirmSms job run");
await _institutionContractRepository.SendInstitutionContractConfirmSmsTask();
await _institutionContractSmsServiceRepository.SendInstitutionContractConfirmSmsTask();
}
/// <summary>
@@ -190,14 +219,86 @@ public class JobSchedulerRegistrator
public async System.Threading.Tasks.Task SendWarningSms()
{
_logger.LogInformation("SendWarningSms job run");
await _institutionContractRepository.SendWarningSmsTask();
await _institutionContractSmsServiceRepository.SendWarningOrLegalActionSmsTask(TypeOfSmsSetting.Warning);
}
/// <summary>
/// پیامک اقدام قضایی
/// </summary>
/// <returns></returns>
[DisableConcurrentExecution(timeoutInSeconds: 100)]
public async System.Threading.Tasks.Task SendLegalActionSms()
{
_logger.LogInformation("SendWarningSms job run");
await _institutionContractRepository.SendLegalActionSmsTask();
await _institutionContractSmsServiceRepository.SendWarningOrLegalActionSmsTask(TypeOfSmsSetting.LegalAction);
}
/// <summary>
/// بلاگ سازی
/// </summary>
/// <returns></returns>
[DisableConcurrentExecution(timeoutInSeconds: 100)]
public async System.Threading.Tasks.Task Block()
{
_logger.LogInformation("block job run");
var now = DateTime.Now;
var executeDate = now.ToFarsi().Substring(8, 2);
if (executeDate == "20")
{
if (now.Hour >= 9 && now.Hour < 10)
{
await _institutionContractSmsServiceRepository.Block(now);
}
}
}
/// <summary>
/// آنبلاک
/// </summary>
/// <returns></returns>
[DisableConcurrentExecution(timeoutInSeconds: 100)]
public async System.Threading.Tasks.Task UnBlock()
{
_logger.LogInformation("UnBlock job run");
await _institutionContractSmsServiceRepository.UnBlock();
}
/// <summary>
/// غیر فعال سازی قراداد های پایان یافته
/// </summary>
/// <returns></returns>
[DisableConcurrentExecution(timeoutInSeconds: 100)]
public async System.Threading.Tasks.Task DeActiveInstitutionEndOfContract()
{
_logger.LogInformation("DeActiveInstitutionEndOfContract job run");
var now = DateTime.Now;
var executeDate = now.ToFarsi().Substring(8, 2);
if (executeDate == "01")
{
if (now.Hour >= 9 && now.Hour < 10)
{
await _institutionContractSmsServiceRepository.DeActiveInstitutionEndOfContract(now);
}
}
}
/// <summary>
/// غیرفعال سازس قرارداد های آبی که بدهی ندارند
/// </summary>
/// <returns></returns>
[DisableConcurrentExecution(timeoutInSeconds: 800)]
public async System.Threading.Tasks.Task BlueDeActiveAfterZeroDebt()
{
_logger.LogInformation("BlueDeActiveAfterZeroDebt job run");
await _institutionContractSmsServiceRepository.BlueDeActiveAfterZeroDebt();
}
}

View File

@@ -91,65 +91,7 @@ public interface IInstitutionContractRepository : IRepository<long, InstitutionC
Task<List<InstitutionContractPrintViewModel>> PrintAllAsync(List<long> ids);
#region ReminderSMS
/// <summary>
/// دریافت لیست - ارسال پیامک
/// فراخوانی از سمت بک گراند سرویس
/// </summary>
/// <returns></returns>
Task<bool> SendReminderSmsForBackgroundTask();
/// <summary>
/// ارسال پیامک صورت حساب ماهانه
/// </summary>
/// <param name="now"></param>
/// <returns></returns>
Task SendMonthlySms(DateTime now);
/// <summary>
/// ارسال پیامک مسدودی از طرف بک گراند سرویس
/// </summary>
/// <returns></returns>
Task SendBlockSmsForBackgroundTask();
/// <summary>
/// دریافت لیست واجد شرایط بلاک
/// جهت ارسال پیامک مسدودی
/// </summary>
/// <param name="checkDate"></param>
/// <returns></returns>
Task<List<BlockSmsListData>> GetBlockListData(DateTime checkDate);
/// <summary>
/// ارسال پیامک مسدودی
/// </summary>
/// <param name="smsListData"></param>
/// <param name="typeOfSms"></param>
/// <param name="sendMessStart"></param>
/// <param name="sendMessEnd"></param>
/// <returns></returns>
Task SendBlockSmsToContractingParties(List<BlockSmsListData> smsListData, string typeOfSms,
string sendMessStart, string sendMessEnd);
/// <summary>
///دریافت لیست بدهکارن
/// جهت ارسال پیامک
/// </summary>
/// <returns></returns>
Task<List<SmsListData>> GetSmsListData(DateTime checkDate, TypeOfSmsSetting typeOfSmsSetting);
/// <summary>
/// ارسال پیامک های یاد آور بدهی
/// </summary>
/// <returns></returns>
Task SendReminderSmsToContractingParties(List<SmsListData> smsListData, string typeOfSms, string sendMessStart, string sendMessEnd);
/// <summary>
/// ارسال پیامک یادآور تایید قراداد مالی
/// </summary>
/// <returns></returns>
Task SendInstitutionContractConfirmSmsTask();
#endregion
#region CreateMontlyTransaction
@@ -162,24 +104,12 @@ public interface IInstitutionContractRepository : IRepository<long, InstitutionC
#endregion
#region WarningSms
/// <summary>
/// پیامک های هشدار
/// </summary>
/// <returns></returns>
Task SendWarningSmsTask();
#endregion
#region legalAction
/// <summary>
/// پیامک اقدام قضائی
/// </summary>
/// <returns></returns>
Task SendLegalActionSmsTask();
#endregion
Task<long> GetIdByInstallmentId(long installmentId);
Task<InstitutionContract> GetPreviousContract(long currentInstitutionContractId);

View File

@@ -0,0 +1,145 @@
using _0_Framework.Application.Enums;
using _0_Framework.Domain;
using CompanyManagment.App.Contracts.InstitutionContract;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Company.Domain.InstitutionContractAgg;
public interface IInstitutionContractSmsServiceRepository : IRepository<long, InstitutionContract>
{
#region reminderSMs
/// <summary>
/// ارسال پیامک یادآور تایید قراداد مالی
/// </summary>
/// <returns></returns>
Task SendInstitutionContractConfirmSmsTask();
#endregion
//هشدار و اقدام قضایی
#region WarningOrLegalActionSmsListData
/// <summary>
/// اجرای تسک پیامک هشدار یا اقدام قضایی
/// </summary>
/// <param name="typeOfSmsSetting"></param>
/// <returns></returns>
Task SendWarningOrLegalActionSmsTask(TypeOfSmsSetting typeOfSmsSetting);
/// <summary>
/// دریافت لیست بدهکاران آبی جهت هشدار یا اقدام قضایی
/// </summary>
/// <param name="typeOfSmsSetting"></param>
/// <returns></returns>
Task<List<SmsListData>> GetWarningOrLegalActionSmsListData(TypeOfSmsSetting typeOfSmsSetting);
/// <summary>
/// ارسال پیامک هشدار یا اقدام قضایی
/// </summary>
/// <param name="smsListData"></param>
/// <param name="typeOfSmsSetting"></param>
/// <returns></returns>
Task SendWarningOrLegalActionSms(List<SmsListData> smsListData, TypeOfSmsSetting typeOfSmsSetting);
#endregion
//بلاک - آنبلاک - پیامک بلاک -
// غیر فعال سازی قراداد های پایان یافته
#region Block
/// <summary>
/// ارسال پیامک مسدودی از طرف بک گراند سرویس
/// </summary>
/// <returns></returns>
Task SendBlockSmsForBackgroundTask();
/// <summary>
/// دریافت لیست واجد شرایط بلاک
/// جهت ارسال پیامک مسدودی
/// </summary>
/// <param name="checkDate"></param>
/// <returns></returns>
Task<List<BlockSmsListData>> GetBlockListData(DateTime checkDate);
/// <summary>
/// ارسال پیامک مسدودی
/// </summary>
/// <param name="smsListData"></param>
/// <param name="typeOfSms"></param>
/// <param name="sendMessStart"></param>
/// <param name="sendMessEnd"></param>
/// <returns></returns>
Task SendBlockSmsToContractingParties(List<BlockSmsListData> smsListData, string typeOfSms,
string sendMessStart, string sendMessEnd);
/// <summary>
/// بلاک سازی
/// </summary>
/// <param name="checkDate"></param>
/// <returns></returns>
Task Block(DateTime checkDate);
/// <summary>
/// دریافت لیست بدهکارانی که باید بلاک شوند
/// </summary>
/// <param name="checkDate"></param>
/// <returns></returns>
Task<List<long>> GetToBeBlockList(DateTime checkDate);
/// <summary>
/// آنبلاک
/// </summary>
/// <returns></returns>
Task UnBlock();
/// <summary>
/// غیر فعالسازی قرارداد های پایان یافته
/// </summary>
/// <param name="checkDate"></param>
/// <returns></returns>
Task DeActiveInstitutionEndOfContract(DateTime checkDate);
/// <summary>
/// غیرفعال سازس قرارداد های آبی که بدهی ندارند
/// </summary>
/// <returns></returns>
Task BlueDeActiveAfterZeroDebt();
#endregion
#region ReminderSMS
/// <summary>
/// دریافت لیست - ارسال پیامک
/// فراخوانی از سمت بک گراند سرویس
/// </summary>
/// <returns></returns>
Task<bool> SendReminderSmsForBackgroundTask();
/// <summary>
/// ارسال پیامک صورت حساب ماهانه
/// </summary>
/// <param name="now"></param>
/// <returns></returns>
Task SendMonthlySms(DateTime now);
/// <summary>
///دریافت لیست بدهکارن
/// جهت ارسال پیامک
/// </summary>
/// <returns></returns>
Task<List<SmsListData>> GetSmsListData(DateTime checkDate, TypeOfSmsSetting typeOfSmsSetting);
/// <summary>
/// ارسال پیامک های یاد آور بدهی
/// </summary>
/// <returns></returns>
Task SendReminderSmsToContractingParties(List<SmsListData> smsListData, string typeOfSms, string sendMessStart, string sendMessEnd);
#endregion
}

View File

@@ -1,10 +1,30 @@
using CompanyManagment.App.Contracts.SmsResult;
using _0_Framework.Domain;
using CompanyManagment.App.Contracts.SmsResult;
using CompanyManagment.App.Contracts.SmsResult.Dto;
using System.Collections.Generic;
using _0_Framework.Domain;
using System.Threading.Tasks;
namespace Company.Domain.SmsResultAgg;
public interface ISmsResultRepository : IRepository<long, SmsResult>
{
#region ForApi
/// <summary>
/// دریافت لیست پیامکها
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
Task<List<SmsReportDto>> GetSmsReportList(SmsReportSearchModel searchModel);
/// <summary>
/// دریافت اکسپند لیست هر تاریخ
/// </summary>
/// <param name="searchModel"></param>
/// <param name="date"></param>
/// <returns></returns>
Task<List<SmsReportListDto>> GetSmsReportExpandList(SmsReportSearchModel searchModel, string date);
#endregion
List<SmsResultViewModel> Search(SmsResultSearchModel searchModel);
}

View File

@@ -0,0 +1,15 @@
namespace CompanyManagment.App.Contracts.SmsResult.Dto;
/// <summary>
/// وضعیت ارسال پیامک
/// </summary>
public enum SendStatus
{
All=0,
/// <summary>
/// موفق
/// </summary>
Success,
//ناموفق
Failed,
}

View File

@@ -0,0 +1,54 @@
using System;
namespace CompanyManagment.App.Contracts.SmsResult.Dto;
public class SmsReportDto
{
/// <summary>
/// تاریخ ارسال
/// </summary>
public string SentDate { get; set; }
}
public class SmsReportListDto
{
/// <summary>
/// آی دی
/// </summary>
public long Id { get; set; }
/// <summary>
/// آی دی پیامک در sms.ir
/// </summary>
public int MessageId { get; set; }
/// <summary>
/// وضعیت ارسال
/// </summary>
public string Status { get; set; }
/// <summary>
/// نوع پیامک
/// </summary>
public string TypeOfSms { get; set; }
/// <summary>
/// نام طرف حساب
/// </summary>
public string ContractingPartyName { get; set; }
/// <summary>
/// شماره موبایل
/// </summary>
public string Mobile { get; set; }
/// <summary>
/// ساعت و دقیقه
/// </summary>
public string HourAndMinute { get; set; }
}

View File

@@ -0,0 +1,43 @@
using _0_Framework.Application.Enums;
namespace CompanyManagment.App.Contracts.SmsResult.Dto;
public class SmsReportSearchModel
{
//نوع پیامک
public TypeOfSmsSetting TypeOfSms { get; set; }
/// <summary>
/// وضعیت ارسال پیامک
/// </summary>
public SendStatus SendStatus { get; set; }
/// <summary>
/// شماره موبایل
/// </summary>
public string Mobile { get; set; }
/// <summary>
/// آی دی طرف حساب
/// </summary>
public long ContractingPatyId { get; set; }
/// <summary>
/// سال
/// </summary>
public string Year { get; set; }
/// <summary>
/// ماه
/// </summary>
public string Month { get; set; }
/// <summary>
/// تاریخ شروع
/// </summary>
public string StartDateFa { get; set; }
/// <summary>
/// تاریخ پایان
/// </summary>
public string EndDateFa { get; set; }
}

View File

@@ -1,14 +1,34 @@
using System;
using _0_Framework.Application;
using CompanyManagment.App.Contracts.SmsResult.Dto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using _0_Framework.Application;
namespace CompanyManagment.App.Contracts.SmsResult;
public interface ISmsResultApplication
{
#region ForApi
/// <summary>
/// دریافت لیست پیامکها
/// </summary>
/// <param name="searchModel"></param>
/// <returns></returns>
Task<List<SmsReportDto>> GetSmsReportList(SmsReportSearchModel searchModel);
/// <summary>
/// دریافت اکسپند لیست هر تاریخ
/// </summary>
/// <param name="searchModel"></param>
/// <param name="date"></param>
/// <returns></returns>
Task<List<SmsReportListDto>> GetSmsReportExpandList(SmsReportSearchModel searchModel, string date);
#endregion
OperationResult Create(CreateSmsResult command);
List<SmsResultViewModel> Search(SmsResultSearchModel searchModel);
}

View File

@@ -1524,6 +1524,7 @@ public class InsuranceListApplication : IInsuranceListApplication
var dateOfBirth = employeeData.DateOfBirthGr.ToFarsi();
var dateOfIssue = employeeData.DateOfIssueGr.ToFarsi();
var leftDate = employeeData.LeftWorkDateGr != null ? employeeData.LeftWorkDateGr.Value.AddDays(-1) : new DateTime();
var workingDays = Tools.GetEmployeeInsuranceWorkingDays(employeeData.StartWorkDateGr, leftDate, startDateGr, endDateGr, employeeData.EmployeeId);
var leftWorkFa = workingDays.hasLeftWorkInMonth ? employeeData.LeftWorkDateGr.ToFarsi() : "";
var startWorkFa = employeeData.StartWorkDateGr.ToFarsi();
@@ -1606,7 +1607,7 @@ public class InsuranceListApplication : IInsuranceListApplication
MaritalStatus = employeeData.MaritalStatus,
StartMonthCurrent = startMonthFa,
WorkingDays = workingDays.countWorkingDays,
WorkingDays = employeeData.WorkingDays,
StartWorkDate = startWorkFa,
StartWorkDateGr = employeeData.StartWorkDateGr,
LeftWorkDate = leftWorkFa,

View File

@@ -1,8 +1,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using _0_Framework.Application;
using Company.Domain.SmsResultAgg;
using CompanyManagment.App.Contracts.SmsResult;
using CompanyManagment.App.Contracts.SmsResult.Dto;
namespace CompanyManagment.Application;
@@ -15,6 +17,23 @@ public class SmsResultApplication : ISmsResultApplication
_smsResultRepository = smsResultRepository;
}
#region ForApi
public async Task<List<SmsReportDto>> GetSmsReportList(SmsReportSearchModel searchModel)
{
return await _smsResultRepository.GetSmsReportList(searchModel);
}
public async Task<List<SmsReportListDto>> GetSmsReportExpandList(SmsReportSearchModel searchModel, string date)
{
return await _smsResultRepository.GetSmsReportExpandList(searchModel, date);
}
#endregion
public OperationResult Create(CreateSmsResult command)
{
var op = new OperationResult();

View File

@@ -1,13 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using _0_Framework.Application;
using _0_Framework.Application;
using _0_Framework.Application.Enums;
using Company.Domain.InstitutionContractAgg;
using Company.Domain.SmsResultAgg;
using CompanyManagment.App.Contracts.InstitutionContract;
using CompanyManagment.App.Contracts.SmsResult;
using CompanyManagment.EFCore.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace CompanyManagment.Application;
@@ -15,11 +16,13 @@ public class SmsSettingApplication : ISmsSettingApplication
{
private readonly ISmsSettingsRepository _smsSettingsRepository;
private readonly IInstitutionContractRepository _institutionContractRepository;
private readonly IInstitutionContractSmsServiceRepository _institutionContractSmsServiceRepository;
public SmsSettingApplication(ISmsSettingsRepository smsSettingsRepository, IInstitutionContractRepository institutionContractRepository)
public SmsSettingApplication(ISmsSettingsRepository smsSettingsRepository, IInstitutionContractRepository institutionContractRepository, IInstitutionContractSmsServiceRepository institutionContractSmsServiceRepository)
{
_smsSettingsRepository = smsSettingsRepository;
_institutionContractRepository = institutionContractRepository;
_institutionContractSmsServiceRepository = institutionContractSmsServiceRepository;
}
@@ -116,12 +119,12 @@ public class SmsSettingApplication : ISmsSettingApplication
public async Task<List<SmsListData>> GetSmsListData(TypeOfSmsSetting typeOfSmsSetting)
{
return await _institutionContractRepository.GetSmsListData(DateTime.Now, typeOfSmsSetting);
return await _institutionContractSmsServiceRepository.GetSmsListData(DateTime.Now, typeOfSmsSetting);
}
public async Task<List<BlockSmsListData>> GetBlockSmsListData(TypeOfSmsSetting typeOfSmsSetting)
{
return await _institutionContractRepository.GetBlockListData(DateTime.Now);
return await _institutionContractSmsServiceRepository.GetBlockListData(DateTime.Now);
}
@@ -134,7 +137,7 @@ public class SmsSettingApplication : ISmsSettingApplication
if (command.Any())
{
await _institutionContractRepository.SendReminderSmsToContractingParties(command, typeOfSms, sendMessStart, sendMessEnd);
await _institutionContractSmsServiceRepository.SendReminderSmsToContractingParties(command, typeOfSms, sendMessStart, sendMessEnd);
return op.Succcedded();
}
else
@@ -153,7 +156,7 @@ public class SmsSettingApplication : ISmsSettingApplication
string sendMessEnd = "پایان مسدودی آنی ";
if (command.Any())
{
await _institutionContractRepository.SendBlockSmsToContractingParties(command, typeOfSms, sendMessStart,
await _institutionContractSmsServiceRepository.SendBlockSmsToContractingParties(command, typeOfSms, sendMessStart,
sendMessEnd);
return op.Succcedded();
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,20 @@
using System.Collections.Generic;
using System.Linq;
using _0_Framework.Application;
using _0_Framework.Application;
using _0_Framework.InfraStructure;
using Company.Domain.SmsResultAgg;
using CompanyManagment.App.Contracts.SmsResult;
using CompanyManagment.App.Contracts.SmsResult.Dto;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using _0_Framework.Application.Enums;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
namespace CompanyManagment.EFCore.Repository;
public class SmsResultRepository : RepositoryBase<long, SmsResult> , ISmsResultRepository
public class SmsResultRepository : RepositoryBase<long, SmsResult>, ISmsResultRepository
{
private readonly CompanyContext _context;
public SmsResultRepository(CompanyContext context) : base(context)
@@ -15,6 +22,260 @@ public class SmsResultRepository : RepositoryBase<long, SmsResult> , ISmsResultR
_context = context;
}
#region ForApi
public async Task<List<SmsReportDto>> GetSmsReportList(SmsReportSearchModel searchModel)
{
// مرحله 1: همه رکوردها را با projection ساده بگیرید
var rawQuery = await _context.SmsResults
.Select(x => new
{
x.id,
x.ContractingPatyId,
x.Mobile,
x.Status,
x.TypeOfSms,
x.CreationDate,
DateOnly = x.CreationDate.Date // فقط تاریخ بدون ساعت
})
.AsNoTracking()
.ToListAsync(); // اینجا SQL اجرا می‌شود و همه داده‌ها به client می‌آیند
if (searchModel.ContractingPatyId > 0)
{
rawQuery = rawQuery.Where(x => x.ContractingPatyId == searchModel.ContractingPatyId).ToList();
}
if (!string.IsNullOrWhiteSpace(searchModel.Mobile))
{
rawQuery = rawQuery.Where(x => x.Mobile.Contains(searchModel.Mobile)).ToList();
}
if (searchModel.TypeOfSms != TypeOfSmsSetting.All && searchModel.TypeOfSms != TypeOfSmsSetting.Warning)
{
var typeOfSms = "All";
switch (searchModel.TypeOfSms)
{
case TypeOfSmsSetting.InstitutionContractDebtReminder:
typeOfSms = "یادآور بدهی ماهانه";
break;
case TypeOfSmsSetting.MonthlyInstitutionContract:
typeOfSms = "صورت حساب ماهانه";
break;
case TypeOfSmsSetting.BlockContractingParty:
typeOfSms = "اعلام مسدودی طرف حساب";
break;
case TypeOfSmsSetting.LegalAction:
typeOfSms = "اقدام قضایی";
break;
case TypeOfSmsSetting.InstitutionContractConfirm:
typeOfSms = "یادآور تایید قرارداد مالی";
break;
case TypeOfSmsSetting.SendInstitutionContractConfirmationCode:
typeOfSms = "کد تاییدیه قرارداد مالی";
break;
case TypeOfSmsSetting.TaskReminder:
typeOfSms = "یادآور وظایف";
break;
}
rawQuery = rawQuery.Where(x => x.TypeOfSms == typeOfSms).ToList();
}
if (searchModel.TypeOfSms == TypeOfSmsSetting.Warning)
{
rawQuery = rawQuery.Where(x => x.TypeOfSms.Contains("هشدار")).ToList();
}
if (searchModel.SendStatus != SendStatus.All)
{
var status = "All";
switch (searchModel.SendStatus)
{
case SendStatus.Success: status = "موفق";
break;
case SendStatus.Failed: status = "ناموفق";
break;
}
rawQuery = rawQuery.Where(x => x.Status == status).ToList();
}
#region searchByDate
if (!string.IsNullOrWhiteSpace(searchModel.StartDateFa) &&
!string.IsNullOrWhiteSpace(searchModel.EndDateFa))
{
if (searchModel.StartDateFa.TryToGeorgianDateTime(out var startGr) == false ||
searchModel.EndDateFa.TryToGeorgianDateTime(out var endGr) == false)
return new List<SmsReportDto>();
rawQuery = rawQuery.Where(x => x.CreationDate.Date >= startGr.Date && x.CreationDate.Date <= endGr.Date).ToList();
}
else
{
if (!string.IsNullOrWhiteSpace(searchModel.Year) && !string.IsNullOrWhiteSpace(searchModel.Month))
{
var start = searchModel.Year + "/" + searchModel.Month + "/01";
var end = start.FindeEndOfMonth();
var startGr = start.ToGeorgianDateTime();
var endGr = end.ToGeorgianDateTime();
rawQuery = rawQuery.Where(x => x.CreationDate.Date >= startGr.Date && x.CreationDate.Date <= endGr.Date).ToList();
}
else if (!string.IsNullOrWhiteSpace(searchModel.Year) && string.IsNullOrWhiteSpace(searchModel.Month))
{
var start = searchModel.Year + "/01/01";
var findEndOfYear = searchModel.Year + "/12/01";
var end = findEndOfYear.FindeEndOfMonth();
var startGr = start.ToGeorgianDateTime();
var endGr = end.ToGeorgianDateTime();
rawQuery = rawQuery.Where(x => x.CreationDate.Date >= startGr.Date && x.CreationDate.Date <= endGr.Date).ToList();
}
}
#endregion
// مرحله 2: گروه‌بندی و انتخاب آخرین رکورد هر روز روی Client
var grouped = rawQuery
.GroupBy(x => x.DateOnly)
.Select(g => g.OrderByDescending(x => x.CreationDate).First())
.OrderByDescending(x => x.CreationDate)
.ToList();
// مرحله 3: تبدیل به DTO و ToFarsi
var result = grouped.Select(x => new SmsReportDto
{
SentDate = x.CreationDate.ToFarsi()
}).ToList();
return result;
}
public async Task<List<SmsReportListDto>> GetSmsReportExpandList(SmsReportSearchModel searchModel, string date)
{
if(string.IsNullOrWhiteSpace(date))
return new List<SmsReportListDto>();
if (date.TryToGeorgianDateTime(out var searchDate) == false)
return new List<SmsReportListDto>();
var query = await _context.SmsResults.Where(x => x.CreationDate.Date == searchDate.Date)
.Select(x =>
new
{
x.id,
x.MessageId,
x.Status,
x.TypeOfSms,
x.ContractingPartyName,
x.Mobile,
x.ContractingPatyId,
x.InstitutionContractId,
x.CreationDate,
x.CreationDate.Hour,
x.CreationDate.Minute
}).AsNoTracking()
.ToListAsync(); ;
if (searchModel.ContractingPatyId > 0)
{
query = query.Where(x => x.ContractingPatyId == searchModel.ContractingPatyId).ToList();
}
if (!string.IsNullOrWhiteSpace(searchModel.Mobile))
{
query = query.Where(x => x.Mobile.Contains(searchModel.Mobile)).ToList();
}
if (searchModel.TypeOfSms != TypeOfSmsSetting.All && searchModel.TypeOfSms != TypeOfSmsSetting.Warning)
{
var typeOfSms = "All";
switch (searchModel.TypeOfSms)
{
case TypeOfSmsSetting.InstitutionContractDebtReminder:
typeOfSms = "یادآور بدهی ماهانه";
break;
case TypeOfSmsSetting.MonthlyInstitutionContract:
typeOfSms = "صورت حساب ماهانه";
break;
case TypeOfSmsSetting.BlockContractingParty:
typeOfSms = "اعلام مسدودی طرف حساب";
break;
case TypeOfSmsSetting.LegalAction:
typeOfSms = "اقدام قضایی";
break;
case TypeOfSmsSetting.InstitutionContractConfirm:
typeOfSms = "یادآور تایید قرارداد مالی";
break;
case TypeOfSmsSetting.SendInstitutionContractConfirmationCode:
typeOfSms = "کد تاییدیه قرارداد مالی";
break;
case TypeOfSmsSetting.TaskReminder:
typeOfSms = "یادآور وظایف";
break;
}
query = query.Where(x => x.TypeOfSms == typeOfSms).ToList();
}
if (searchModel.TypeOfSms == TypeOfSmsSetting.Warning)
{
query = query.Where(x => x.TypeOfSms.Contains("هشدار")).ToList();
}
if (searchModel.SendStatus != SendStatus.All)
{
var status = "All";
switch (searchModel.SendStatus)
{
case SendStatus.Success:
status = "موفق";
break;
case SendStatus.Failed:
status = "ناموفق";
break;
}
query = query.Where(x => x.Status == status).ToList();
}
if (query.Count == 0)
return new List<SmsReportListDto>();
var result = query.OrderByDescending(x => x.CreationDate.Hour)
.ThenByDescending(x => x.CreationDate.Minute).Select(x =>
new SmsReportListDto()
{
Id = x.id,
MessageId = x.MessageId,
Status = x.Status,
TypeOfSms = x.TypeOfSms,
ContractingPartyName = x.ContractingPartyName,
Mobile = x.Mobile,
HourAndMinute = x.CreationDate.TimeOfDay.ToString(@"hh\:mm"),
}).ToList();
return result;
}
#endregion
public List<App.Contracts.SmsResult.SmsResultViewModel> Search(SmsResultSearchModel searchModel)
{
@@ -82,7 +343,7 @@ public class SmsResultRepository : RepositoryBase<long, SmsResult> , ISmsResultR
query = query.OrderByDescending(x => x.CreationDate)
.ThenByDescending(x=>x.CreationDate.Hour).ThenByDescending(x=>x.CreationDate.Minute);
.ThenByDescending(x => x.CreationDate.Hour).ThenByDescending(x => x.CreationDate.Minute);
return query.Skip(searchModel.PageIndex).Take(30).ToList();

View File

@@ -207,16 +207,11 @@ public class SmsService : ISmsService
}
public async Task<List<ApiResultViewModel>> GetApiResult(string startDate, string endDate)
{
var st = new DateTime(2024, 6, 2);
var ed = new DateTime(2024, 7, 1);
if (!string.IsNullOrWhiteSpace(startDate) && startDate.Length == 10)
{
st = startDate.ToGeorgianDateTime();
}
if (!string.IsNullOrWhiteSpace(endDate) && endDate.Length == 10)
{
ed = endDate.ToGeorgianDateTime();
}
if(startDate.TryToGeorgianDateTime(out var st) == false || endDate.TryToGeorgianDateTime(out var ed) == false)
return new List<ApiResultViewModel>();
var res = new List<ApiResultViewModel>();
Int32 unixTimestamp = (int)st.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
Int32 unixTimestamp2 = (int)ed.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
@@ -248,6 +243,44 @@ public class SmsService : ISmsService
return res;
}
public async Task<List<ApiReportDto>> GetApiReport(string startDate, string endDate)
{
if (startDate.TryToGeorgianDateTime(out var st) == false || endDate.TryToGeorgianDateTime(out var ed) == false)
return new List<ApiReportDto>();
var res = new List<ApiReportDto>();
Int32 unixTimestamp = (int)st.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
Int32 unixTimestamp2 = (int)ed.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
// int? fromDateUnixTime = null; // unix time - for instance: 1700598600
//int? toDateUnixTime = null; // unix time - for instance: 1703190600
int pageNumber = 2;
int pageSize = 100; // max: 100
SmsIr smsIr = new SmsIr("Og5M562igmzJRhQPnq0GdtieYdLgtfikjzxOmeQBPxJjZtyge5Klc046Lfw1mxSa");
var response = await smsIr.GetArchivedReportAsync(pageNumber, pageSize, unixTimestamp, unixTimestamp2);
MessageReportResult[] messages = response.Data;
foreach (var message in messages)
{
var appendData = new ApiReportDto()
{
MessageId = message.MessageId,
Mobile = message.Mobile,
SendUnixTime = UnixTimeStampToDateTime(message.SendDateTime),
DeliveryState = DeliveryStatus(message.DeliveryState),
DeliveryUnixTime = UnixTimeStampToDateTime(message.DeliveryDateTime),
DeliveryColor = DeliveryColorStatus(message.DeliveryState),
};
res.Add(appendData);
}
return res;
}
public string DeliveryStatus(byte? dv)
{
string mess = "";

View File

@@ -563,6 +563,7 @@ public class PersonalBootstrapper
services.AddTransient<ISmsSettingsRepository, SmsSettingsRepository>();
services.AddTransient<ISmsSettingApplication, SmsSettingApplication>();
services.AddTransient<IInstitutionContractSmsServiceRepository, InstitutionContractSmsServiceRepository>();
#endregion

View File

@@ -209,22 +209,38 @@ public class CreateOrEditCheckoutCommandHandler : IBaseCommandHandler<CreateOrEd
}
}
//حقوق نهایی
var monthlySalaryPay = (totalHoursWorked * monthlySalaryDefined) / mandatoryHours;
// اگر اضافه کار داشت حقوق تعین شده به عنوان حقوق نهایی در نظر گرفته میشود
monthlySalaryPay = monthlySalaryPay > monthlySalaryDefined ? monthlySalaryDefined : monthlySalaryPay;
////حقوق نهایی
//var monthlySalaryPay = (totalHoursWorked * monthlySalaryDefined) / mandatoryHours;
//// اگر اضافه کار داشت حقوق تعین شده به عنوان حقوق نهایی در نظر گرفته میشود
//monthlySalaryPay = monthlySalaryPay > monthlySalaryDefined ? monthlySalaryDefined : monthlySalaryPay;
//حقوق کسر شده
var deductionFromSalary = monthlySalaryDefined - monthlySalaryPay;
////حقوق کسر شده
//var deductionFromSalary = monthlySalaryDefined - monthlySalaryPay;
//new chang salary compute
var monthlySalaryPay = totalHoursWorked * monthlySalaryDefined;
//زمان باقی مانده
var remainingTime = totalHoursWorked - mandatoryHours;
//تناسب به دقیقه
#region MyRegion
//var monthlySalaryDefinedTest = monthlySalaryDefined * mandatoryHours;
//var monthlySalaryPayTest = totalHoursWorked * monthlySalaryDefined;
////// اگر اضافه کار داشت حقوق تعین شده به عنوان حقوق نهایی در نظر گرفته میشود
//monthlySalaryPayTest = monthlySalaryPayTest > monthlySalaryDefinedTest ? monthlySalaryDefinedTest : monthlySalaryPayTest;
//////حقوق کسر شده
//var deductionFromSalaryTest = monthlySalaryDefinedTest - monthlySalaryPayTest;
#endregion
var computeResult = new ComputeResultDto
{
MandatoryHours = mandatoryHours,
MonthlySalaryPay = monthlySalaryPay,
DeductionFromSalary = deductionFromSalary,
DeductionFromSalary = 0 /*deductionFromSalary*/,
RemainingHours = remainingTime
};
Console.WriteLine(mandatoryHours);

View File

@@ -1,10 +1,11 @@
using GozareshgirProgramManager.Application._Common.Interfaces;
using DNTPersianUtils.Core;
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;
using PersianDateTime = PersianTools.Core.PersianDateTime;
namespace GozareshgirProgramManager.Application.Modules.Checkouts.Queries.GetUserToGropCreate;
@@ -45,8 +46,8 @@ public class GetUserToGroupCreatingQueryHandler : IBaseQueryHandler<GetUserToGro
"ایجاد فیش فقط برای ماه های گذشته امکان پذیر است");
var lastMonthStart = lastMonth;
var lastMonthEnd = lastMonth;
//var lastMonthStart = lastMonth;
var lastMonthEnd = ((selectedDate.ToFarsi().FindeEndOfMonth())).ToGeorgianDateTime();
var query =
await (from u in _context.Users
@@ -60,8 +61,8 @@ public class GetUserToGroupCreatingQueryHandler : IBaseQueryHandler<GetUserToGro
// LEFT JOIN
//فیش
join ch in _context.Checkouts
.Where(x => x.CheckoutStartDate < lastMonthStart
&& x.CheckoutEndDate >= lastMonthStart)
.Where(x => x.CheckoutStartDate < lastMonthEnd
&& x.CheckoutEndDate > selectedDate)
on u.Id equals ch.UserId into chJoin
from ch in chJoin.DefaultIfEmpty()

View File

@@ -1,16 +0,0 @@
using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AddTaskToPhase;
/// <summary>
/// Command to add a task to an existing phase
/// </summary>
public record AddTaskToPhaseCommand(
Guid PhaseId,
string Name,
string? Description = null,
ProjectTaskPriority Priority = ProjectTaskPriority.Medium,
int OrderIndex = 0,
DateTime? DueDate = null
) : IBaseCommand;

View File

@@ -1,53 +0,0 @@
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<AddTaskToPhaseCommand, OperationResult>
{
private readonly IProjectPhaseRepository _phaseRepository;
private readonly IUnitOfWork _unitOfWork;
public AddTaskToPhaseCommandHandler(
IProjectPhaseRepository phaseRepository,
IUnitOfWork unitOfWork)
{
_phaseRepository = phaseRepository;
_unitOfWork = unitOfWork;
}
public async Task<OperationResult> 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}");
}
}
}

View File

@@ -4,4 +4,5 @@ using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProject;
public record CreateProjectCommand(string Name,ProjectHierarchyLevel Level,
ProjectTaskPriority? Priority,
Guid? ParentId):IBaseCommand;

View File

@@ -16,7 +16,8 @@ public class CreateProjectCommandHandler : IBaseCommandHandler<CreateProjectComm
private readonly IUnitOfWork _unitOfWork;
public CreateProjectCommandHandler(IProjectRepository projectRepository, IUnitOfWork unitOfWork, IProjectTaskRepository projectTaskRepository, IProjectPhaseRepository projectPhaseRepository)
public CreateProjectCommandHandler(IProjectRepository projectRepository, IUnitOfWork unitOfWork,
IProjectTaskRepository projectTaskRepository, IProjectPhaseRepository projectPhaseRepository)
{
_projectRepository = projectRepository;
_unitOfWork = unitOfWork;
@@ -56,7 +57,7 @@ public class CreateProjectCommandHandler : IBaseCommandHandler<CreateProjectComm
if (!request.ParentId.HasValue)
throw new BadRequestException("برای ایجاد فاز، شناسه پروژه الزامی است");
if(!_projectRepository.Exists(x=>x.Id == request.ParentId.Value))
if (!_projectRepository.Exists(x => x.Id == request.ParentId.Value))
{
throw new BadRequestException("والد پروژه یافت نشد");
}
@@ -70,13 +71,14 @@ public class CreateProjectCommandHandler : IBaseCommandHandler<CreateProjectComm
if (!request.ParentId.HasValue)
throw new BadRequestException("برای ایجاد تسک، شناسه فاز الزامی است");
if(!_projectPhaseRepository.Exists(x=>x.Id == request.ParentId.Value))
if (!_projectPhaseRepository.Exists(x => x.Id == request.ParentId.Value))
{
throw new BadRequestException("والد پروژه یافت نشد");
}
var projectTask = new ProjectTask(request.Name, request.ParentId.Value);
var priority = request.Priority ?? ProjectTaskPriority.Low;
var projectTask = new ProjectTask(request.Name, request.ParentId.Value, priority);
await _projectTaskRepository.CreateAsync(projectTask);
}
}

View File

@@ -10,8 +10,10 @@ public class GetProjectItemDto
public int Percentage { get; init; }
public ProjectHierarchyLevel Level { get; init; }
public Guid? ParentId { get; init; }
public int TotalHours { get; set; }
public int Minutes { get; set; }
public TimeSpan TotalTime { get; init; }
public TimeSpan RemainingTime { get; init; }
public AssignmentStatus Front { get; set; }
public AssignmentStatus Backend { get; set; }
public AssignmentStatus Design { get; set; }

View File

@@ -16,7 +16,8 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
_context = context;
}
public async Task<OperationResult<GetProjectsListResponse>> Handle(GetProjectsListQuery request, CancellationToken cancellationToken)
public async Task<OperationResult<GetProjectsListResponse>> Handle(GetProjectsListQuery request,
CancellationToken cancellationToken)
{
var projects = new List<GetProjectDto>();
var phases = new List<GetPhaseDto>();
@@ -51,13 +52,14 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
{
return new List<GetProjectDto>();
}
var entities = await query
.OrderByDescending(p => p.CreationDate)
.ToListAsync(cancellationToken);
var result = new List<GetProjectDto>();
foreach (var project in entities)
{
var (percentage, totalTime) = await CalculateProjectPercentage(project, cancellationToken);
var (percentage, totalTime,remainingTime) = await CalculateProjectPercentage(project, cancellationToken);
result.Add(new GetProjectDto
{
Id = project.Id,
@@ -65,10 +67,12 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
Level = ProjectHierarchyLevel.Project,
ParentId = null,
Percentage = percentage,
TotalHours = (int)totalTime.TotalHours,
Minutes = totalTime.Minutes,
TotalTime = totalTime,
RemainingTime = remainingTime
});
}
result = result.OrderByDescending(x => x.Percentage).ToList();
return result;
}
@@ -79,13 +83,14 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
{
query = query.Where(x => x.ProjectId == parentId);
}
var entities = await query
.OrderByDescending(p => p.CreationDate)
.ToListAsync(cancellationToken);
var result = new List<GetPhaseDto>();
foreach (var phase in entities)
{
var (percentage, totalTime) = await CalculatePhasePercentage(phase, cancellationToken);
var (percentage, totalTime,remainingTime) = await CalculatePhasePercentage(phase, cancellationToken);
result.Add(new GetPhaseDto
{
Id = phase.Id,
@@ -93,10 +98,12 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
Level = ProjectHierarchyLevel.Phase,
ParentId = phase.ProjectId,
Percentage = percentage,
TotalHours = (int)totalTime.TotalHours,
Minutes = totalTime.Minutes,
TotalTime = totalTime,
RemainingTime = remainingTime
});
}
result = result.OrderByDescending(x => x.Percentage).ToList();
return result;
}
@@ -107,6 +114,7 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
{
query = query.Where(x => x.PhaseId == parentId);
}
var entities = await query
.OrderByDescending(t => t.CreationDate)
.ToListAsync(cancellationToken);
@@ -118,7 +126,7 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
foreach (var task in entities)
{
var (percentage, totalTime) = await CalculateTaskPercentage(task, cancellationToken);
var (percentage, totalTime,remainingTime) = await CalculateTaskPercentage(task, cancellationToken);
var sections = await _context.TaskSections
.Include(s => s.Activities)
.Include(s => s.Skill)
@@ -140,7 +148,6 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
// محاسبه SpentTime و RemainingTime
var spentTime = TimeSpan.FromTicks(sections.Sum(s => s.Activities.Sum(a => a.GetTimeSpent().Ticks)));
var remainingTime = totalTime - spentTime;
// ساخت section DTOs برای تمام Skills
var sectionDtos = allSkills.Select(skill =>
@@ -184,18 +191,20 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
Level = ProjectHierarchyLevel.Task,
ParentId = task.PhaseId,
Percentage = percentage,
TotalHours = (int)totalTime.TotalHours,
Minutes = totalTime.Minutes,
TotalTime = totalTime,
SpentTime = spentTime,
RemainingTime = remainingTime,
Sections = sectionDtos,
Priority = task.Priority
});
}
result = result.OrderByDescending(x => x.Percentage).ToList();
return result;
}
private async Task SetSkillFlags<TItem>(List<TItem> items, CancellationToken cancellationToken) where TItem : GetProjectItemDto
private async Task SetSkillFlags<TItem>(List<TItem> items, CancellationToken cancellationToken)
where TItem : GetProjectItemDto
{
if (!items.Any())
return;
@@ -213,7 +222,8 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
}
private async Task SetSkillFlagsForProjects<TItem>(List<TItem> items, List<Guid> projectIds, CancellationToken cancellationToken) where TItem : GetProjectItemDto
private async Task SetSkillFlagsForProjects<TItem>(List<TItem> items, List<Guid> projectIds,
CancellationToken cancellationToken) where TItem : GetProjectItemDto
{
// For projects: gather all phases, then tasks, then sections
var phases = await _context.ProjectPhases
@@ -243,7 +253,8 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
}
}
private async Task SetSkillFlagsForPhases<TItem>(List<TItem> items, List<Guid> phaseIds, CancellationToken cancellationToken) where TItem : GetProjectItemDto
private async Task SetSkillFlagsForPhases<TItem>(List<TItem> items, List<Guid> phaseIds,
CancellationToken cancellationToken) where TItem : GetProjectItemDto
{
// For phases: gather tasks, then sections
var tasks = await _context.ProjectTasks
@@ -269,68 +280,81 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
}
}
private async Task<(int Percentage, TimeSpan TotalTime)> CalculateProjectPercentage(Project project, CancellationToken cancellationToken)
private async Task<(int Percentage, TimeSpan TotalTime,TimeSpan RemainingTime)> CalculateProjectPercentage(Project project,
CancellationToken cancellationToken)
{
var phases = await _context.ProjectPhases
.Where(ph => ph.ProjectId == project.Id)
.ToListAsync(cancellationToken);
if (!phases.Any())
return (0, TimeSpan.Zero);
return (0, TimeSpan.Zero,TimeSpan.Zero);
var phasePercentages = new List<int>();
var totalTime = TimeSpan.Zero;
var remainingTime = TimeSpan.Zero;
foreach (var phase in phases)
{
var (phasePercentage, phaseTime) = await CalculatePhasePercentage(phase, cancellationToken);
var (phasePercentage, phaseTime,phaseRemainingTime) = await CalculatePhasePercentage(phase, cancellationToken);
phasePercentages.Add(phasePercentage);
totalTime += phaseTime;
}
var averagePercentage = phasePercentages.Any() ? (int)phasePercentages.Average() : 0;
return (averagePercentage, totalTime);
remainingTime += phaseRemainingTime;
}
private async Task<(int Percentage, TimeSpan TotalTime)> CalculatePhasePercentage(ProjectPhase phase, CancellationToken cancellationToken)
var averagePercentage = phasePercentages.Any() ? (int)phasePercentages.Average() : 0;
return (averagePercentage, totalTime,remainingTime);
}
private async Task<(int Percentage, TimeSpan TotalTime,TimeSpan RemainingTime)> CalculatePhasePercentage(ProjectPhase phase,
CancellationToken cancellationToken)
{
var tasks = await _context.ProjectTasks
.Where(t => t.PhaseId == phase.Id)
.ToListAsync(cancellationToken);
if (!tasks.Any())
return (0, TimeSpan.Zero);
return (0, TimeSpan.Zero,TimeSpan.Zero);
var taskPercentages = new List<int>();
var totalTime = TimeSpan.Zero;
var remainingTime = TimeSpan.Zero;
foreach (var task in tasks)
{
var (taskPercentage, taskTime) = await CalculateTaskPercentage(task, cancellationToken);
var (taskPercentage, taskTime,taskRemainingTime) = await CalculateTaskPercentage(task, cancellationToken);
taskPercentages.Add(taskPercentage);
totalTime += taskTime;
}
var averagePercentage = taskPercentages.Any() ? (int)taskPercentages.Average() : 0;
return (averagePercentage, totalTime);
remainingTime += taskRemainingTime;
}
private async Task<(int Percentage, TimeSpan TotalTime)> CalculateTaskPercentage(ProjectTask task, CancellationToken cancellationToken)
var averagePercentage = taskPercentages.Any() ? (int)taskPercentages.Average() : 0;
return (averagePercentage, totalTime,remainingTime);
}
private async Task<(int Percentage, TimeSpan TotalTime, TimeSpan RemainingTime)> CalculateTaskPercentage(
ProjectTask task, CancellationToken cancellationToken)
{
var sections = await _context.TaskSections
.Include(s => s.Activities)
.Include(x=>x.AdditionalTimes)
.Include(x => x.AdditionalTimes)
.Where(s => s.TaskId == task.Id)
.ToListAsync(cancellationToken);
if (!sections.Any())
return (0, TimeSpan.Zero);
return (0, TimeSpan.Zero, TimeSpan.Zero);
var sectionPercentages = new List<int>();
var totalTime = TimeSpan.Zero;
var spentTime = TimeSpan.Zero;
foreach (var section in sections)
{
var (sectionPercentage, sectionTime) = CalculateSectionPercentage(section);
var sectionSpent = TimeSpan.FromTicks(section.Activities.Sum(x => x.GetTimeSpent().Ticks));
sectionPercentages.Add(sectionPercentage);
totalTime += sectionTime;
spentTime += sectionSpent;
}
var remainingTime = totalTime - spentTime;
var averagePercentage = sectionPercentages.Any() ? (int)sectionPercentages.Average() : 0;
return (averagePercentage, totalTime);
return (averagePercentage, totalTime, remainingTime);
}
private static (int Percentage, TimeSpan TotalTime) CalculateSectionPercentage(TaskSection section)
{
return ((int)section.GetProgressPercentage(),section.FinalEstimatedHours);
return ((int)section.GetProgressPercentage(), section.FinalEstimatedHours);
}
private static AssignmentStatus GetAssignmentStatus(TaskSection? section)
@@ -357,4 +381,3 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
return AssignmentStatus.Unassigned;
}
}

View File

@@ -9,8 +9,8 @@ public class GetTaskDto
public int Percentage { get; init; }
public ProjectHierarchyLevel Level { get; init; }
public Guid? ParentId { get; init; }
public int TotalHours { get; set; }
public int Minutes { get; set; }
public TimeSpan TotalTime { get; set; }
// Task-specific fields
public TimeSpan SpentTime { get; init; }

View File

@@ -7,5 +7,6 @@ namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.Project
public record ProjectBoardListQuery: IBaseQuery<List<ProjectBoardListResponse>>
{
public long? UserId { get; set; }
public string? ProjectName { get; set; }
public TaskSectionStatus? Status { get; set; }
}

View File

@@ -3,7 +3,6 @@ using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Application._Common.Models;
using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query.Internal;
namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardList;
@@ -24,7 +23,8 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
var currentUserId = _authHelper.GetCurrentUserId();
var queryable = _programManagerDbContext.TaskSections.AsNoTracking()
.Where(x => x.InitialEstimatedHours > TimeSpan.Zero && x.Status != TaskSectionStatus.Completed)
.Where(x => x.InitialEstimatedHours > TimeSpan.Zero
&& x.Status != TaskSectionStatus.Completed)
.Include(x => x.Task)
.ThenInclude(x => x.Phase)
.ThenInclude(x => x.Project)
@@ -46,9 +46,17 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
queryable = queryable.Where(x => x.CurrentAssignedUserId == request.UserId);
}
if (!string.IsNullOrWhiteSpace(request.ProjectName))
{
queryable = queryable.Where(x=>x.Task.Name.Contains(request.ProjectName)
|| x.Task.Phase.Name.Contains(request.ProjectName)
|| x.Task.Phase.Project.Name.Contains(request.ProjectName));
}
var data = await queryable.ToListAsync(cancellationToken);
var activityUserIds = data.SelectMany(x => x.Activities).Select(a => a.UserId).Distinct().ToList();
var activityUserIds = data.SelectMany(x => x.Activities)
.Select(a => a.UserId).Distinct().ToList();
var assignedUser = data.Select(x => x.CurrentAssignedUserId)
.Concat(data.Select(x => x.OriginalAssignedUserId)).ToList();
var allUserIds = activityUserIds.Concat(assignedUser).Distinct().ToList();
@@ -62,6 +70,9 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
.OrderByDescending(x => x.CurrentAssignedUserId == currentUserId)
.ThenByDescending(x=>x.Task.Priority)
.ThenBy(x => GetStatusOrder(x.Status))
.ThenBy(x=>x.Task.Phase.ProjectId)
.ThenBy(x=>x.Task.PhaseId)
.ThenBy(x=>x.TaskId)
.Select(x =>
{
// محاسبه یکبار برای هر Activity و Cache کردن نتیجه
@@ -72,7 +83,7 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
{
Activity = a,
TimeSpent = timeSpent,
TotalSeconds = timeSpent.TotalSeconds,
timeSpent.TotalSeconds,
FormattedTime = timeSpent.ToString(@"hh\:mm")
};
}).ToList();

View File

@@ -56,6 +56,7 @@ public class ProjectSetTimeDetailsQueryHandler
var skills = await _context.Skills
.AsNoTracking()
.OrderBy(x=>x.CreationDate)
.ToListAsync(cancellationToken);
var res = new ProjectSetTimeResponse(
@@ -84,7 +85,7 @@ public class ProjectSetTimeDetailsQueryHandler
UserId = section?.OriginalAssignedUserId ?? 0,
SkillId = skill.Id,
};
}).OrderBy(x => x.SkillId).ToList(),
}).ToList(),
task.Id,
level);
@@ -114,6 +115,7 @@ public class ProjectSetTimeDetailsQueryHandler
var skills = await _context.Skills
.AsNoTracking()
.OrderBy(x=>x.CreationDate)
.ToListAsync(cancellationToken);
var res = new ProjectSetTimeResponse(
@@ -135,7 +137,7 @@ public class ProjectSetTimeDetailsQueryHandler
UserId = section?.UserId ?? 0,
SkillId = skill.Id,
};
}).OrderBy(x => x.SkillId).ToList(),
}).ToList(),
phase.Id,
level);
@@ -165,6 +167,7 @@ public class ProjectSetTimeDetailsQueryHandler
var skills = await _context.Skills
.AsNoTracking()
.OrderBy(x=>x.CreationDate)
.ToListAsync(cancellationToken);
var res = new ProjectSetTimeResponse(
@@ -186,7 +189,7 @@ public class ProjectSetTimeDetailsQueryHandler
UserId = section?.UserId ?? 0,
SkillId = skill.Id,
};
}).OrderBy(x => x.SkillId).ToList(),
}).ToList(),
project.Id,
level);

View File

@@ -1,12 +1,15 @@
using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Application._Common.Models;
using GozareshgirProgramManager.Application.Modules.TaskChat.DTOs;
using GozareshgirProgramManager.Domain.TaskChatAgg.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace GozareshgirProgramManager.Application.Modules.TaskChat.Queries.GetMessages;
public record GetMessagesQuery(
Guid TaskId,
MessageType? MessageType,
int Page = 1,
int PageSize = 50
) : IBaseQuery<PaginationResult<MessageDto>>;
@@ -66,7 +69,12 @@ public class GetMessagesQueryHandler : IBaseQueryHandler<GetMessagesQuery, Pagin
var query = _context.TaskChatMessages
.Where(m => m.TaskId == request.TaskId && !m.IsDeleted)
.Include(m => m.ReplyToMessage)
.OrderBy(m => m.CreationDate);
.OrderBy(m => m.CreationDate).AsQueryable();
if (request.MessageType.HasValue)
{
query = query.Where(m => m.MessageType == request.MessageType.Value);
}
var totalCount = await query.CountAsync(cancellationToken);

View File

@@ -42,14 +42,6 @@ public class ProjectPhase : ProjectHierarchyNode
#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);

View File

@@ -16,11 +16,11 @@ public class ProjectTask : ProjectHierarchyNode
_sections = new List<TaskSection>();
}
public ProjectTask(string name, Guid phaseId, string? description = null) : base(name, description)
public ProjectTask(string name, Guid phaseId,ProjectTaskPriority priority, string? description = null) : base(name, description)
{
PhaseId = phaseId;
_sections = new List<TaskSection>();
Priority = ProjectTaskPriority.Medium;
Priority = priority;
AddDomainEvent(new TaskCreatedEvent(Id, phaseId, name));
}

View File

@@ -8,6 +8,7 @@ using GozareshgirProgramManager.Application.Modules.TaskChat.DTOs;
using GozareshgirProgramManager.Application.Modules.TaskChat.Queries.GetMessages;
using GozareshgirProgramManager.Application.Modules.TaskChat.Queries.GetPinnedMessages;
using GozareshgirProgramManager.Application.Modules.TaskChat.Queries.SearchMessages;
using GozareshgirProgramManager.Domain.TaskChatAgg.Enums;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using ServiceHost.BaseControllers;
@@ -30,15 +31,17 @@ public class TaskChatController : ProgramManagerBaseController
/// دریافت لیست پیام‌های یک تسک
/// </summary>
/// <param name="taskId">شناسه تسک</param>
/// <param name="messageType">نوع پیام</param>
/// <param name="page">صفحه (پیش‌فرض: 1)</param>
/// <param name="pageSize">تعداد در هر صفحه (پیش‌فرض: 50)</param>
[HttpGet("{taskId:guid}/messages")]
public async Task<ActionResult<OperationResult<PaginationResult<MessageDto>>>> GetMessages(
Guid taskId,
[FromQuery] MessageType? messageType,
[FromQuery] int page = 1,
[FromQuery] int pageSize = 50)
{
var query = new GetMessagesQuery(taskId, page, pageSize);
var query = new GetMessagesQuery(taskId,messageType, page, pageSize);
var result = await _mediator.Send(query);
return result;
}

View File

@@ -0,0 +1,59 @@
using _0_Framework.Application.Sms;
using CompanyManagment.App.Contracts.SmsResult;
using CompanyManagment.App.Contracts.SmsResult.Dto;
using Microsoft.AspNetCore.Mvc;
using ServiceHost.BaseControllers;
namespace ServiceHost.Areas.Admin.Controllers;
public class SmsReportController : AdminBaseController
{
private readonly ISmsResultApplication _smsResultApplication;
private readonly ISmsService _smsService;
public SmsReportController(ISmsResultApplication smsResultApplication, ISmsService smsService)
{
_smsResultApplication = smsResultApplication;
_smsService = smsService;
}
/// <summary>
/// دریافت لیست پیامک ها
/// </summary>
/// <param name="searchModel"></param>
/// <returns></returns>
[HttpGet]
public async Task<List<SmsReportDto>> GetSmsReportList(SmsReportSearchModel searchModel)
{
var result =await _smsResultApplication.GetSmsReportList(searchModel);
return result;
}
/// <summary>
/// دریافت اطلاعات هر تاریخ برای اکسپند
/// </summary>
/// <param name="searchModel"></param>
/// <param name="date"></param>
/// <returns></returns>
[HttpGet("GetExpandedList")]
public async Task<List<SmsReportListDto>> GetSmsReportExpandList(SmsReportSearchModel searchModel, string date)
{
var result =await _smsResultApplication.GetSmsReportExpandList(searchModel, date);
return result;
}
/// <summary>
/// گزارش ای پی آی
/// </summary>
/// <param name="startDate"></param>
/// <param name="endDate"></param>
/// <returns></returns>
[HttpGet("GetApiReport")]
public async Task<List<ApiReportDto>> GetApiReport(string startDate, string endDate)
{
var result =await _smsService.GetApiReport(startDate, endDate);
return result;
}
}

View File

@@ -1289,7 +1289,7 @@
تمدید قرارداد
</p>
</a>
<a permission="30715" class="btn btn-inverse pull-left rad" style="background-color: #f57373;border: 1px solid #f57373;margin-left:5px;"
<a class="btn btn-inverse pull-left rad" style="background-color: #f57373;border: 1px solid #f57373;margin-left:5px;"
asp-page="./FinancialStatments" asp-route-name="@item.ContractingPartyName" asp-route-id="@item.ContractingPartyId" asp-route-pageNumber="0">
<i class="fa fa-file-text-o faSize"></i>
<p>