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

View File

@@ -17,4 +17,18 @@ public class ApiResultViewModel
public string DeliveryUnixTime { get; set; } public string DeliveryUnixTime { get; set; }
public string DeliveryColor { get; set; } public string DeliveryColor { get; set; }
public string FullName { 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); bool SendAccountsInfo(string number,string fullName, string userName);
Task<ApiResultViewModel> GetByMessageId(int messId); Task<ApiResultViewModel> GetByMessageId(int messId);
Task<List<ApiResultViewModel>> GetApiResult(string startDate, string endDate); Task<List<ApiResultViewModel>> GetApiResult(string startDate, string endDate);
#region ForApi
Task<List<ApiReportDto>> GetApiReport(string startDate, string endDate);
#endregion
string DeliveryStatus(byte? dv); string DeliveryStatus(byte? dv);
string DeliveryColorStatus(byte? dv); string DeliveryColorStatus(byte? dv);
string UnixTimeStampToDateTime(int? unixTimeStamp); string UnixTimeStampToDateTime(int? unixTimeStamp);

View File

@@ -1,5 +1,6 @@
using _0_Framework.Application; using _0_Framework.Application;
using _0_Framework.Application.Enums;
using _0_Framework.Application.Sms; using _0_Framework.Application.Sms;
using Company.Domain.ContarctingPartyAgg; using Company.Domain.ContarctingPartyAgg;
using Company.Domain.InstitutionContractAgg; using Company.Domain.InstitutionContractAgg;
@@ -12,19 +13,21 @@ public class JobSchedulerRegistrator
private readonly IBackgroundJobClient _backgroundJobClient; private readonly IBackgroundJobClient _backgroundJobClient;
private readonly SmsReminder _smsReminder; private readonly SmsReminder _smsReminder;
private readonly IInstitutionContractRepository _institutionContractRepository; private readonly IInstitutionContractRepository _institutionContractRepository;
private readonly IInstitutionContractSmsServiceRepository _institutionContractSmsServiceRepository;
private static DateTime? _lastRunCreateTransaction; private static DateTime? _lastRunCreateTransaction;
private static DateTime? _lastRunSendMonthlySms; private static DateTime? _lastRunSendMonthlySms;
private readonly ISmsService _smsService; private readonly ISmsService _smsService;
private readonly ILogger<JobSchedulerRegistrator> _logger; 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; _smsReminder = smsReminder;
_backgroundJobClient = backgroundJobClient; _backgroundJobClient = backgroundJobClient;
_institutionContractRepository = institutionContractRepository; _institutionContractRepository = institutionContractRepository;
_smsService = smsService; _smsService = smsService;
_logger = logger; _logger = logger;
_institutionContractSmsServiceRepository = institutionContractSmsServiceRepository;
} }
public void Register() public void Register()
@@ -58,17 +61,43 @@ public class JobSchedulerRegistrator
"*/1 * * * *" // هر 1 دقیقه یکبار چک کن "*/1 * * * *" // هر 1 دقیقه یکبار چک کن
); );
//RecurringJob.AddOrUpdate( RecurringJob.AddOrUpdate(
// "InstitutionContract.SendWarningSms", "InstitutionContract.SendWarningSms",
// () => SendWarningSms(), () => SendWarningSms(),
// "*/1 * * * *" // هر 1 دقیقه یکبار چک کن "*/1 * * * *" // هر 1 دقیقه یکبار چک کن
//); );
//RecurringJob.AddOrUpdate( RecurringJob.AddOrUpdate(
// "InstitutionContract.SendLegalActionSms", "InstitutionContract.SendLegalActionSms",
// () => SendLegalActionSms(), () => SendLegalActionSms(),
// "*/1 * * * *" // هر 1 دقیقه یکبار چک کن "*/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,14 +108,14 @@ public class JobSchedulerRegistrator
[DisableConcurrentExecution(timeoutInSeconds: 1200)] [DisableConcurrentExecution(timeoutInSeconds: 1200)]
public async System.Threading.Tasks.Task CreateFinancialTransaction() public async System.Threading.Tasks.Task CreateFinancialTransaction()
{ {
var now =DateTime.Now; var now = DateTime.Now;
var endOfMonth = now.ToFarsi().FindeEndOfMonth(); var endOfMonth = now.ToFarsi().FindeEndOfMonth();
var endOfMonthGr = endOfMonth.ToGeorgianDateTime(); var endOfMonthGr = endOfMonth.ToGeorgianDateTime();
_logger.LogInformation("CreateFinancialTransaction job run"); _logger.LogInformation("CreateFinancialTransaction job run");
if (now.Date == endOfMonthGr.Date && now.Hour >= 2 && now.Hour < 4 && if (now.Date == endOfMonthGr.Date && now.Hour >= 2 && now.Hour < 4 &&
now.Date != _lastRunCreateTransaction?.Date) now.Date != _lastRunCreateTransaction?.Date)
{ {
var month = endOfMonth.Substring(5, 2); var month = endOfMonth.Substring(5, 2);
var year = endOfMonth.Substring(0, 4); var year = endOfMonth.Substring(0, 4);
var monthName = month.ToFarsiMonthByNumber(); var monthName = month.ToFarsiMonthByNumber();
@@ -101,17 +130,17 @@ public class JobSchedulerRegistrator
try try
{ {
await _institutionContractRepository.CreateTransactionForInstitutionContracts(endNewGr, endNewFa, description); await _institutionContractRepository.CreateTransactionForInstitutionContracts(endNewGr, endNewFa, description);
_lastRunCreateTransaction = now; _lastRunCreateTransaction = now;
Console.WriteLine("CreateTransAction executed"); Console.WriteLine("CreateTransAction executed");
} }
catch (Exception e) catch (Exception e)
{ {
await _smsService.Alarm("09114221321", "خطا-ایجاد سند مالی"); await _smsService.Alarm("09114221321", "خطا-ایجاد سند مالی");
} }
} }
} }
@@ -134,7 +163,7 @@ public class JobSchedulerRegistrator
try try
{ {
await _institutionContractRepository.SendMonthlySms(now); await _institutionContractSmsServiceRepository.SendMonthlySms(now);
_lastRunSendMonthlySms = now; _lastRunSendMonthlySms = now;
Console.WriteLine("Send Monthly sms executed"); Console.WriteLine("Send Monthly sms executed");
@@ -156,7 +185,7 @@ public class JobSchedulerRegistrator
public async System.Threading.Tasks.Task SendReminderSms() public async System.Threading.Tasks.Task SendReminderSms()
{ {
_logger.LogInformation("SendReminderSms job run"); _logger.LogInformation("SendReminderSms job run");
await _institutionContractRepository.SendReminderSmsForBackgroundTask(); await _institutionContractSmsServiceRepository.SendReminderSmsForBackgroundTask();
} }
/// <summary> /// <summary>
@@ -167,7 +196,7 @@ public class JobSchedulerRegistrator
public async System.Threading.Tasks.Task SendBlockSms() public async System.Threading.Tasks.Task SendBlockSms()
{ {
_logger.LogInformation("SendBlockSms job run"); _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() public async System.Threading.Tasks.Task SendInstitutionContractConfirmSms()
{ {
_logger.LogInformation("SendInstitutionContractConfirmSms job run"); _logger.LogInformation("SendInstitutionContractConfirmSms job run");
await _institutionContractRepository.SendInstitutionContractConfirmSmsTask(); await _institutionContractSmsServiceRepository.SendInstitutionContractConfirmSmsTask();
} }
/// <summary> /// <summary>
@@ -190,14 +219,86 @@ public class JobSchedulerRegistrator
public async System.Threading.Tasks.Task SendWarningSms() public async System.Threading.Tasks.Task SendWarningSms()
{ {
_logger.LogInformation("SendWarningSms job run"); _logger.LogInformation("SendWarningSms job run");
await _institutionContractRepository.SendWarningSmsTask(); await _institutionContractSmsServiceRepository.SendWarningOrLegalActionSmsTask(TypeOfSmsSetting.Warning);
} }
/// <summary>
/// پیامک اقدام قضایی
/// </summary>
/// <returns></returns>
[DisableConcurrentExecution(timeoutInSeconds: 100)] [DisableConcurrentExecution(timeoutInSeconds: 100)]
public async System.Threading.Tasks.Task SendLegalActionSms() public async System.Threading.Tasks.Task SendLegalActionSms()
{ {
_logger.LogInformation("SendWarningSms job run"); _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); 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 #region CreateMontlyTransaction
@@ -162,24 +104,12 @@ public interface IInstitutionContractRepository : IRepository<long, InstitutionC
#endregion #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<long> GetIdByInstallmentId(long installmentId);
Task<InstitutionContract> GetPreviousContract(long currentInstitutionContractId); 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 System.Collections.Generic;
using _0_Framework.Domain; using System.Threading.Tasks;
namespace Company.Domain.SmsResultAgg; namespace Company.Domain.SmsResultAgg;
public interface ISmsResultRepository : IRepository<long, SmsResult> 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); 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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using _0_Framework.Application;
namespace CompanyManagment.App.Contracts.SmsResult; namespace CompanyManagment.App.Contracts.SmsResult;
public interface ISmsResultApplication 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); OperationResult Create(CreateSmsResult command);
List<SmsResultViewModel> Search(SmsResultSearchModel searchModel); List<SmsResultViewModel> Search(SmsResultSearchModel searchModel);
} }

View File

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

View File

@@ -1,8 +1,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using _0_Framework.Application; using _0_Framework.Application;
using Company.Domain.SmsResultAgg; using Company.Domain.SmsResultAgg;
using CompanyManagment.App.Contracts.SmsResult; using CompanyManagment.App.Contracts.SmsResult;
using CompanyManagment.App.Contracts.SmsResult.Dto;
namespace CompanyManagment.Application; namespace CompanyManagment.Application;
@@ -15,6 +17,23 @@ public class SmsResultApplication : ISmsResultApplication
_smsResultRepository = smsResultRepository; _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) public OperationResult Create(CreateSmsResult command)
{ {
var op = new OperationResult(); var op = new OperationResult();

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,20 @@
using System.Collections.Generic; using _0_Framework.Application;
using System.Linq;
using _0_Framework.Application;
using _0_Framework.InfraStructure; using _0_Framework.InfraStructure;
using Company.Domain.SmsResultAgg; using Company.Domain.SmsResultAgg;
using CompanyManagment.App.Contracts.SmsResult; 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; namespace CompanyManagment.EFCore.Repository;
public class SmsResultRepository : RepositoryBase<long, SmsResult> , ISmsResultRepository public class SmsResultRepository : RepositoryBase<long, SmsResult>, ISmsResultRepository
{ {
private readonly CompanyContext _context; private readonly CompanyContext _context;
public SmsResultRepository(CompanyContext context) : base(context) public SmsResultRepository(CompanyContext context) : base(context)
@@ -15,9 +22,263 @@ public class SmsResultRepository : RepositoryBase<long, SmsResult> , ISmsResultR
_context = context; _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) public List<App.Contracts.SmsResult.SmsResultViewModel> Search(SmsResultSearchModel searchModel)
{ {
var query = _context.SmsResults.Select(x => new App.Contracts.SmsResult.SmsResultViewModel() var query = _context.SmsResults.Select(x => new App.Contracts.SmsResult.SmsResultViewModel()
{ {
Id = x.id, Id = x.id,
@@ -64,7 +325,7 @@ public class SmsResultRepository : RepositoryBase<long, SmsResult> , ISmsResultR
var endGr = end.ToGeorgianDateTime(); var endGr = end.ToGeorgianDateTime();
query = query.Where(x => x.CreationDate.Date >= startGr.Date && x.CreationDate.Date <= endGr.Date); query = query.Where(x => x.CreationDate.Date >= startGr.Date && x.CreationDate.Date <= endGr.Date);
} }
else if (!string.IsNullOrWhiteSpace(searchModel.Year) && string.IsNullOrWhiteSpace(searchModel.Month)) else if (!string.IsNullOrWhiteSpace(searchModel.Year) && string.IsNullOrWhiteSpace(searchModel.Month))
{ {
@@ -74,7 +335,7 @@ public class SmsResultRepository : RepositoryBase<long, SmsResult> , ISmsResultR
var startGr = start.ToGeorgianDateTime(); var startGr = start.ToGeorgianDateTime();
var endGr = end.ToGeorgianDateTime(); var endGr = end.ToGeorgianDateTime();
query = query.Where(x => x.CreationDate.Date >= startGr.Date && x.CreationDate.Date <= endGr.Date); query = query.Where(x => x.CreationDate.Date >= startGr.Date && x.CreationDate.Date <= endGr.Date);
} }
} }
@@ -82,12 +343,12 @@ public class SmsResultRepository : RepositoryBase<long, SmsResult> , ISmsResultR
query = query.OrderByDescending(x => x.CreationDate) 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(); 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) 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) if(startDate.TryToGeorgianDateTime(out var st) == false || endDate.TryToGeorgianDateTime(out var ed) == false)
{ return new List<ApiResultViewModel>();
st = startDate.ToGeorgianDateTime();
}
if (!string.IsNullOrWhiteSpace(endDate) && endDate.Length == 10)
{
ed = endDate.ToGeorgianDateTime();
}
var res = new List<ApiResultViewModel>(); var res = new List<ApiResultViewModel>();
Int32 unixTimestamp = (int)st.Subtract(new DateTime(1970, 1, 1)).TotalSeconds; Int32 unixTimestamp = (int)st.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
Int32 unixTimestamp2 = (int)ed.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; 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) public string DeliveryStatus(byte? dv)
{ {
string mess = ""; string mess = "";

View File

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

View File

@@ -209,22 +209,38 @@ public class CreateOrEditCheckoutCommandHandler : IBaseCommandHandler<CreateOrEd
} }
} }
//حقوق نهایی ////حقوق نهایی
var monthlySalaryPay = (totalHoursWorked * monthlySalaryDefined) / mandatoryHours; //var monthlySalaryPay = (totalHoursWorked * monthlySalaryDefined) / mandatoryHours;
// اگر اضافه کار داشت حقوق تعین شده به عنوان حقوق نهایی در نظر گرفته میشود //// اگر اضافه کار داشت حقوق تعین شده به عنوان حقوق نهایی در نظر گرفته میشود
monthlySalaryPay = monthlySalaryPay > monthlySalaryDefined ? monthlySalaryDefined : monthlySalaryPay; //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; 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 var computeResult = new ComputeResultDto
{ {
MandatoryHours = mandatoryHours, MandatoryHours = mandatoryHours,
MonthlySalaryPay = monthlySalaryPay, MonthlySalaryPay = monthlySalaryPay,
DeductionFromSalary = deductionFromSalary, DeductionFromSalary = 0 /*deductionFromSalary*/,
RemainingHours = remainingTime RemainingHours = remainingTime
}; };
Console.WriteLine(mandatoryHours); 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._Common.Models;
using GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Queries.GetUserListWhoHaveSettings; using GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Queries.GetUserListWhoHaveSettings;
using GozareshgirProgramManager.Domain._Common; using GozareshgirProgramManager.Domain._Common;
using GozareshgirProgramManager.Domain.CheckoutAgg.Enums; using GozareshgirProgramManager.Domain.CheckoutAgg.Enums;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using PersianTools.Core; using PersianDateTime = PersianTools.Core.PersianDateTime;
namespace GozareshgirProgramManager.Application.Modules.Checkouts.Queries.GetUserToGropCreate; namespace GozareshgirProgramManager.Application.Modules.Checkouts.Queries.GetUserToGropCreate;
@@ -45,8 +46,8 @@ public class GetUserToGroupCreatingQueryHandler : IBaseQueryHandler<GetUserToGro
"ایجاد فیش فقط برای ماه های گذشته امکان پذیر است"); "ایجاد فیش فقط برای ماه های گذشته امکان پذیر است");
var lastMonthStart = lastMonth; //var lastMonthStart = lastMonth;
var lastMonthEnd = lastMonth; var lastMonthEnd = ((selectedDate.ToFarsi().FindeEndOfMonth())).ToGeorgianDateTime();
var query = var query =
await (from u in _context.Users await (from u in _context.Users
@@ -60,8 +61,8 @@ public class GetUserToGroupCreatingQueryHandler : IBaseQueryHandler<GetUserToGro
// LEFT JOIN // LEFT JOIN
//فیش //فیش
join ch in _context.Checkouts join ch in _context.Checkouts
.Where(x => x.CheckoutStartDate < lastMonthStart .Where(x => x.CheckoutStartDate < lastMonthEnd
&& x.CheckoutEndDate >= lastMonthStart) && x.CheckoutEndDate > selectedDate)
on u.Id equals ch.UserId into chJoin on u.Id equals ch.UserId into chJoin
from ch in chJoin.DefaultIfEmpty() 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; namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProject;
public record CreateProjectCommand(string Name,ProjectHierarchyLevel Level, public record CreateProjectCommand(string Name,ProjectHierarchyLevel Level,
ProjectTaskPriority? Priority,
Guid? ParentId):IBaseCommand; Guid? ParentId):IBaseCommand;

View File

@@ -16,7 +16,8 @@ public class CreateProjectCommandHandler : IBaseCommandHandler<CreateProjectComm
private readonly IUnitOfWork _unitOfWork; 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; _projectRepository = projectRepository;
_unitOfWork = unitOfWork; _unitOfWork = unitOfWork;
@@ -55,8 +56,8 @@ public class CreateProjectCommandHandler : IBaseCommandHandler<CreateProjectComm
{ {
if (!request.ParentId.HasValue) if (!request.ParentId.HasValue)
throw new BadRequestException("برای ایجاد فاز، شناسه پروژه الزامی است"); throw new BadRequestException("برای ایجاد فاز، شناسه پروژه الزامی است");
if(!_projectRepository.Exists(x=>x.Id == request.ParentId.Value)) if (!_projectRepository.Exists(x => x.Id == request.ParentId.Value))
{ {
throw new BadRequestException("والد پروژه یافت نشد"); throw new BadRequestException("والد پروژه یافت نشد");
} }
@@ -69,14 +70,15 @@ public class CreateProjectCommandHandler : IBaseCommandHandler<CreateProjectComm
{ {
if (!request.ParentId.HasValue) if (!request.ParentId.HasValue)
throw new BadRequestException("برای ایجاد تسک، شناسه فاز الزامی است"); throw new BadRequestException("برای ایجاد تسک، شناسه فاز الزامی است");
if(!_projectPhaseRepository.Exists(x=>x.Id == request.ParentId.Value)) if (!_projectPhaseRepository.Exists(x => x.Id == request.ParentId.Value))
{ {
throw new BadRequestException("والد پروژه یافت نشد"); 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); await _projectTaskRepository.CreateAsync(projectTask);
} }
} }

View File

@@ -10,8 +10,10 @@ public class GetProjectItemDto
public int Percentage { get; init; } public int Percentage { get; init; }
public ProjectHierarchyLevel Level { get; init; } public ProjectHierarchyLevel Level { get; init; }
public Guid? ParentId { 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 Front { get; set; }
public AssignmentStatus Backend { get; set; } public AssignmentStatus Backend { get; set; }
public AssignmentStatus Design { get; set; } public AssignmentStatus Design { get; set; }

View File

@@ -16,7 +16,8 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
_context = context; _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 projects = new List<GetProjectDto>();
var phases = new List<GetPhaseDto>(); var phases = new List<GetPhaseDto>();
@@ -51,13 +52,14 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
{ {
return new List<GetProjectDto>(); return new List<GetProjectDto>();
} }
var entities = await query var entities = await query
.OrderByDescending(p => p.CreationDate) .OrderByDescending(p => p.CreationDate)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
var result = new List<GetProjectDto>(); var result = new List<GetProjectDto>();
foreach (var project in entities) foreach (var project in entities)
{ {
var (percentage, totalTime) = await CalculateProjectPercentage(project, cancellationToken); var (percentage, totalTime,remainingTime) = await CalculateProjectPercentage(project, cancellationToken);
result.Add(new GetProjectDto result.Add(new GetProjectDto
{ {
Id = project.Id, Id = project.Id,
@@ -65,10 +67,12 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
Level = ProjectHierarchyLevel.Project, Level = ProjectHierarchyLevel.Project,
ParentId = null, ParentId = null,
Percentage = percentage, Percentage = percentage,
TotalHours = (int)totalTime.TotalHours, TotalTime = totalTime,
Minutes = totalTime.Minutes, RemainingTime = remainingTime
}); });
} }
result = result.OrderByDescending(x => x.Percentage).ToList();
return result; return result;
} }
@@ -79,13 +83,14 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
{ {
query = query.Where(x => x.ProjectId == parentId); query = query.Where(x => x.ProjectId == parentId);
} }
var entities = await query var entities = await query
.OrderByDescending(p => p.CreationDate) .OrderByDescending(p => p.CreationDate)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
var result = new List<GetPhaseDto>(); var result = new List<GetPhaseDto>();
foreach (var phase in entities) foreach (var phase in entities)
{ {
var (percentage, totalTime) = await CalculatePhasePercentage(phase, cancellationToken); var (percentage, totalTime,remainingTime) = await CalculatePhasePercentage(phase, cancellationToken);
result.Add(new GetPhaseDto result.Add(new GetPhaseDto
{ {
Id = phase.Id, Id = phase.Id,
@@ -93,10 +98,12 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
Level = ProjectHierarchyLevel.Phase, Level = ProjectHierarchyLevel.Phase,
ParentId = phase.ProjectId, ParentId = phase.ProjectId,
Percentage = percentage, Percentage = percentage,
TotalHours = (int)totalTime.TotalHours, TotalTime = totalTime,
Minutes = totalTime.Minutes, RemainingTime = remainingTime
}); });
} }
result = result.OrderByDescending(x => x.Percentage).ToList();
return result; return result;
} }
@@ -107,6 +114,7 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
{ {
query = query.Where(x => x.PhaseId == parentId); query = query.Where(x => x.PhaseId == parentId);
} }
var entities = await query var entities = await query
.OrderByDescending(t => t.CreationDate) .OrderByDescending(t => t.CreationDate)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
@@ -118,7 +126,7 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
foreach (var task in entities) 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 var sections = await _context.TaskSections
.Include(s => s.Activities) .Include(s => s.Activities)
.Include(s => s.Skill) .Include(s => s.Skill)
@@ -140,13 +148,12 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
// محاسبه SpentTime و RemainingTime // محاسبه SpentTime و RemainingTime
var spentTime = TimeSpan.FromTicks(sections.Sum(s => s.Activities.Sum(a => a.GetTimeSpent().Ticks))); var spentTime = TimeSpan.FromTicks(sections.Sum(s => s.Activities.Sum(a => a.GetTimeSpent().Ticks)));
var remainingTime = totalTime - spentTime;
// ساخت section DTOs برای تمام Skills // ساخت section DTOs برای تمام Skills
var sectionDtos = allSkills.Select(skill => var sectionDtos = allSkills.Select(skill =>
{ {
var section = sections.FirstOrDefault(s => s.SkillId == skill.Id); var section = sections.FirstOrDefault(s => s.SkillId == skill.Id);
if (section == null) if (section == null)
{ {
// اگر section وجود نداشت، یک DTO با وضعیت Unassigned برمی‌گردانیم // اگر section وجود نداشت، یک DTO با وضعیت Unassigned برمی‌گردانیم
@@ -184,18 +191,20 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
Level = ProjectHierarchyLevel.Task, Level = ProjectHierarchyLevel.Task,
ParentId = task.PhaseId, ParentId = task.PhaseId,
Percentage = percentage, Percentage = percentage,
TotalHours = (int)totalTime.TotalHours, TotalTime = totalTime,
Minutes = totalTime.Minutes,
SpentTime = spentTime, SpentTime = spentTime,
RemainingTime = remainingTime, RemainingTime = remainingTime,
Sections = sectionDtos, Sections = sectionDtos,
Priority = task.Priority Priority = task.Priority
}); });
} }
result = result.OrderByDescending(x => x.Percentage).ToList();
return result; 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()) if (!items.Any())
return; 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 // For projects: gather all phases, then tasks, then sections
var phases = await _context.ProjectPhases 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 // For phases: gather tasks, then sections
var tasks = await _context.ProjectTasks 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 var phases = await _context.ProjectPhases
.Where(ph => ph.ProjectId == project.Id) .Where(ph => ph.ProjectId == project.Id)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
if (!phases.Any()) if (!phases.Any())
return (0, TimeSpan.Zero); return (0, TimeSpan.Zero,TimeSpan.Zero);
var phasePercentages = new List<int>(); var phasePercentages = new List<int>();
var totalTime = TimeSpan.Zero; var totalTime = TimeSpan.Zero;
var remainingTime = TimeSpan.Zero;
foreach (var phase in phases) foreach (var phase in phases)
{ {
var (phasePercentage, phaseTime) = await CalculatePhasePercentage(phase, cancellationToken); var (phasePercentage, phaseTime,phaseRemainingTime) = await CalculatePhasePercentage(phase, cancellationToken);
phasePercentages.Add(phasePercentage); phasePercentages.Add(phasePercentage);
totalTime += phaseTime; totalTime += phaseTime;
remainingTime += phaseRemainingTime;
} }
var averagePercentage = phasePercentages.Any() ? (int)phasePercentages.Average() : 0; var averagePercentage = phasePercentages.Any() ? (int)phasePercentages.Average() : 0;
return (averagePercentage, totalTime); return (averagePercentage, totalTime,remainingTime);
} }
private async Task<(int Percentage, TimeSpan TotalTime)> CalculatePhasePercentage(ProjectPhase phase, CancellationToken cancellationToken) private async Task<(int Percentage, TimeSpan TotalTime,TimeSpan RemainingTime)> CalculatePhasePercentage(ProjectPhase phase,
CancellationToken cancellationToken)
{ {
var tasks = await _context.ProjectTasks var tasks = await _context.ProjectTasks
.Where(t => t.PhaseId == phase.Id) .Where(t => t.PhaseId == phase.Id)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
if (!tasks.Any()) if (!tasks.Any())
return (0, TimeSpan.Zero); return (0, TimeSpan.Zero,TimeSpan.Zero);
var taskPercentages = new List<int>(); var taskPercentages = new List<int>();
var totalTime = TimeSpan.Zero; var totalTime = TimeSpan.Zero;
var remainingTime = TimeSpan.Zero;
foreach (var task in tasks) foreach (var task in tasks)
{ {
var (taskPercentage, taskTime) = await CalculateTaskPercentage(task, cancellationToken); var (taskPercentage, taskTime,taskRemainingTime) = await CalculateTaskPercentage(task, cancellationToken);
taskPercentages.Add(taskPercentage); taskPercentages.Add(taskPercentage);
totalTime += taskTime; totalTime += taskTime;
remainingTime += taskRemainingTime;
} }
var averagePercentage = taskPercentages.Any() ? (int)taskPercentages.Average() : 0; var averagePercentage = taskPercentages.Any() ? (int)taskPercentages.Average() : 0;
return (averagePercentage, totalTime); return (averagePercentage, totalTime,remainingTime);
} }
private async Task<(int Percentage, TimeSpan TotalTime)> CalculateTaskPercentage(ProjectTask task, CancellationToken cancellationToken) private async Task<(int Percentage, TimeSpan TotalTime, TimeSpan RemainingTime)> CalculateTaskPercentage(
ProjectTask task, CancellationToken cancellationToken)
{ {
var sections = await _context.TaskSections var sections = await _context.TaskSections
.Include(s => s.Activities) .Include(s => s.Activities)
.Include(x=>x.AdditionalTimes) .Include(x => x.AdditionalTimes)
.Where(s => s.TaskId == task.Id) .Where(s => s.TaskId == task.Id)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
if (!sections.Any()) if (!sections.Any())
return (0, TimeSpan.Zero); return (0, TimeSpan.Zero, TimeSpan.Zero);
var sectionPercentages = new List<int>(); var sectionPercentages = new List<int>();
var totalTime = TimeSpan.Zero; var totalTime = TimeSpan.Zero;
var spentTime = TimeSpan.Zero;
foreach (var section in sections) foreach (var section in sections)
{ {
var (sectionPercentage, sectionTime) = CalculateSectionPercentage(section); var (sectionPercentage, sectionTime) = CalculateSectionPercentage(section);
var sectionSpent = TimeSpan.FromTicks(section.Activities.Sum(x => x.GetTimeSpent().Ticks));
sectionPercentages.Add(sectionPercentage); sectionPercentages.Add(sectionPercentage);
totalTime += sectionTime; totalTime += sectionTime;
spentTime += sectionSpent;
} }
var remainingTime = totalTime - spentTime;
var averagePercentage = sectionPercentages.Any() ? (int)sectionPercentages.Average() : 0; var averagePercentage = sectionPercentages.Any() ? (int)sectionPercentages.Average() : 0;
return (averagePercentage, totalTime); return (averagePercentage, totalTime, remainingTime);
} }
private static (int Percentage, TimeSpan TotalTime) CalculateSectionPercentage(TaskSection section) 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) private static AssignmentStatus GetAssignmentStatus(TaskSection? section)
@@ -341,7 +365,7 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
// بررسی وجود user // بررسی وجود user
bool hasUser = section.CurrentAssignedUserId > 0; bool hasUser = section.CurrentAssignedUserId > 0;
// بررسی وجود time (InitialEstimatedHours بزرگتر از صفر باشد) // بررسی وجود time (InitialEstimatedHours بزرگتر از صفر باشد)
bool hasTime = section.InitialEstimatedHours > TimeSpan.Zero; bool hasTime = section.InitialEstimatedHours > TimeSpan.Zero;
@@ -356,5 +380,4 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
// تعیین تکلیف نشده: نه user دارد نه time // تعیین تکلیف نشده: نه user دارد نه time
return AssignmentStatus.Unassigned; return AssignmentStatus.Unassigned;
} }
} }

View File

@@ -9,8 +9,8 @@ public class GetTaskDto
public int Percentage { get; init; } public int Percentage { get; init; }
public ProjectHierarchyLevel Level { get; init; } public ProjectHierarchyLevel Level { get; init; }
public Guid? ParentId { 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 // Task-specific fields
public TimeSpan SpentTime { get; init; } 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 record ProjectBoardListQuery: IBaseQuery<List<ProjectBoardListResponse>>
{ {
public long? UserId { get; set; } public long? UserId { get; set; }
public string? ProjectName { get; set; }
public TaskSectionStatus? Status { 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.Application._Common.Models;
using GozareshgirProgramManager.Domain.ProjectAgg.Enums; using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query.Internal;
namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardList; namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardList;
@@ -24,7 +23,8 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
var currentUserId = _authHelper.GetCurrentUserId(); var currentUserId = _authHelper.GetCurrentUserId();
var queryable = _programManagerDbContext.TaskSections.AsNoTracking() 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) .Include(x => x.Task)
.ThenInclude(x => x.Phase) .ThenInclude(x => x.Phase)
.ThenInclude(x => x.Project) .ThenInclude(x => x.Project)
@@ -45,10 +45,18 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
{ {
queryable = queryable.Where(x => x.CurrentAssignedUserId == request.UserId); 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 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) var assignedUser = data.Select(x => x.CurrentAssignedUserId)
.Concat(data.Select(x => x.OriginalAssignedUserId)).ToList(); .Concat(data.Select(x => x.OriginalAssignedUserId)).ToList();
var allUserIds = activityUserIds.Concat(assignedUser).Distinct().ToList(); var allUserIds = activityUserIds.Concat(assignedUser).Distinct().ToList();
@@ -62,6 +70,9 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
.OrderByDescending(x => x.CurrentAssignedUserId == currentUserId) .OrderByDescending(x => x.CurrentAssignedUserId == currentUserId)
.ThenByDescending(x=>x.Task.Priority) .ThenByDescending(x=>x.Task.Priority)
.ThenBy(x => GetStatusOrder(x.Status)) .ThenBy(x => GetStatusOrder(x.Status))
.ThenBy(x=>x.Task.Phase.ProjectId)
.ThenBy(x=>x.Task.PhaseId)
.ThenBy(x=>x.TaskId)
.Select(x => .Select(x =>
{ {
// محاسبه یکبار برای هر Activity و Cache کردن نتیجه // محاسبه یکبار برای هر Activity و Cache کردن نتیجه
@@ -72,7 +83,7 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
{ {
Activity = a, Activity = a,
TimeSpent = timeSpent, TimeSpent = timeSpent,
TotalSeconds = timeSpent.TotalSeconds, timeSpent.TotalSeconds,
FormattedTime = timeSpent.ToString(@"hh\:mm") FormattedTime = timeSpent.ToString(@"hh\:mm")
}; };
}).ToList(); }).ToList();

View File

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

View File

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

View File

@@ -41,15 +41,7 @@ public class ProjectPhase : ProjectHierarchyNode
public ProjectDeployStatus DeployStatus { get; set; } public ProjectDeployStatus DeployStatus { get; set; }
#region Task Management #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) public void RemoveTask(Guid taskId)
{ {
var task = _tasks.FirstOrDefault(t => t.Id == taskId); var task = _tasks.FirstOrDefault(t => t.Id == taskId);

View File

@@ -16,11 +16,11 @@ public class ProjectTask : ProjectHierarchyNode
_sections = new List<TaskSection>(); _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; PhaseId = phaseId;
_sections = new List<TaskSection>(); _sections = new List<TaskSection>();
Priority = ProjectTaskPriority.Medium; Priority = priority;
AddDomainEvent(new TaskCreatedEvent(Id, phaseId, name)); 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.GetMessages;
using GozareshgirProgramManager.Application.Modules.TaskChat.Queries.GetPinnedMessages; using GozareshgirProgramManager.Application.Modules.TaskChat.Queries.GetPinnedMessages;
using GozareshgirProgramManager.Application.Modules.TaskChat.Queries.SearchMessages; using GozareshgirProgramManager.Application.Modules.TaskChat.Queries.SearchMessages;
using GozareshgirProgramManager.Domain.TaskChatAgg.Enums;
using MediatR; using MediatR;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using ServiceHost.BaseControllers; using ServiceHost.BaseControllers;
@@ -30,15 +31,17 @@ public class TaskChatController : ProgramManagerBaseController
/// دریافت لیست پیام‌های یک تسک /// دریافت لیست پیام‌های یک تسک
/// </summary> /// </summary>
/// <param name="taskId">شناسه تسک</param> /// <param name="taskId">شناسه تسک</param>
/// <param name="messageType">نوع پیام</param>
/// <param name="page">صفحه (پیش‌فرض: 1)</param> /// <param name="page">صفحه (پیش‌فرض: 1)</param>
/// <param name="pageSize">تعداد در هر صفحه (پیش‌فرض: 50)</param> /// <param name="pageSize">تعداد در هر صفحه (پیش‌فرض: 50)</param>
[HttpGet("{taskId:guid}/messages")] [HttpGet("{taskId:guid}/messages")]
public async Task<ActionResult<OperationResult<PaginationResult<MessageDto>>>> GetMessages( public async Task<ActionResult<OperationResult<PaginationResult<MessageDto>>>> GetMessages(
Guid taskId, Guid taskId,
[FromQuery] MessageType? messageType,
[FromQuery] int page = 1, [FromQuery] int page = 1,
[FromQuery] int pageSize = 50) [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); var result = await _mediator.Send(query);
return result; 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> </p>
</a> </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"> 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> <i class="fa fa-file-text-o faSize"></i>
<p> <p>