Compare commits
53 Commits
Feature/pr
...
Feature/Ch
| Author | SHA1 | Date | |
|---|---|---|---|
| 63a3027a17 | |||
|
|
8ec13ffae1 | ||
|
|
5508d4e88f | ||
| 43abb74c61 | |||
| 73e6681baa | |||
| 90b2fd2eab | |||
| d9c431e20e | |||
|
|
2746bf69ea | ||
|
|
77dbb50512 | ||
|
|
1c7e8824c7 | ||
| 0eff1b9a66 | |||
|
|
0d33d79620 | ||
|
|
e4355faffc | ||
|
|
577fe5db76 | ||
| 587fa40d81 | |||
| b741ab9ed2 | |||
| b6fde4903a | |||
| 0772604432 | |||
|
|
ec8333c715 | ||
|
|
8aa93e089a | ||
| 59891d1199 | |||
| 7cb39b1b92 | |||
|
|
5580d56874 | ||
|
|
423b49e6e7 | ||
|
|
0ab3052251 | ||
| 38027352d6 | |||
| 43562fb49c | |||
|
|
5202779d9f | ||
| 80a58f8cdc | |||
| 7c611825a4 | |||
|
|
67a85735f0 | ||
|
|
bf46dfd1dc | ||
|
|
a1ed3ad648 | ||
|
|
35e6355069 | ||
| 8679abb1e7 | |||
| c8dddabdff | |||
| 6f076bdc77 | |||
|
|
4de2e12ac5 | ||
|
|
23b65cfbfe | ||
|
|
48b75d2baa | ||
| 140414b866 | |||
| 4ade9e12a6 | |||
|
|
63edb33bf5 | ||
| dd7e816767 | |||
| 1deeff996f | |||
| 95d66c2d89 | |||
| 609daf4353 | |||
| a81e01ce2b | |||
| 2cd838a5e3 | |||
| 34bd7ba444 | |||
| 43b124664e | |||
| d2dd67343b | |||
| 3d2b5ff6bd |
4
.gitignore
vendored
@@ -364,3 +364,7 @@ MigrationBackup/
|
|||||||
.idea
|
.idea
|
||||||
/ServiceHost/appsettings.Development.json
|
/ServiceHost/appsettings.Development.json
|
||||||
/ServiceHost/appsettings.json
|
/ServiceHost/appsettings.json
|
||||||
|
|
||||||
|
# Storage folder - ignore all uploaded files, thumbnails, and temporary files
|
||||||
|
ServiceHost/Storage
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -18,3 +18,17 @@ public class ApiResultViewModel
|
|||||||
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; }
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 * * * *"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -80,4 +80,6 @@ public interface ICheckoutRepository : IRepository<long, Checkout>
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
Task<Checkout> GetByWorkshopIdEmployeeIdInDate(long workshopId, long employeeId, DateTime inDate);
|
Task<Checkout> GetByWorkshopIdEmployeeIdInDate(long workshopId, long employeeId, DateTime inDate);
|
||||||
|
Task<PagedResult<CheckoutListClientDto>> GetListForClient(long workshopId,
|
||||||
|
CheckoutListClientSearchModel searchModel);
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Company.Domain.InstitutionContractSendFlagAgg;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface برای Repository مربوط به فلگ ارسال قرارداد
|
||||||
|
/// </summary>
|
||||||
|
public interface IInstitutionContractSendFlagRepository
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ایجاد یک رکورد جدید برای فلگ ارسال قرارداد
|
||||||
|
/// </summary>
|
||||||
|
Task Create(InstitutionContractSendFlag flag);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بازیابی فلگ بر اساس شناسه قرارداد
|
||||||
|
/// </summary>
|
||||||
|
Task<InstitutionContractSendFlag> GetByContractId(long contractId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بهروزرسانی فلگ ارسال
|
||||||
|
/// </summary>
|
||||||
|
Task Update(InstitutionContractSendFlag flag);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بررسی اینکه آیا قرارداد ارسال شده است
|
||||||
|
/// </summary>
|
||||||
|
Task<bool> IsContractSent(long contractId);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Company.Domain.InstitutionContractSendFlagAgg;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// نمایندگی فلگ ارسال قرارداد در MongoDB
|
||||||
|
/// این موجودیت برای ردیابی اینکه آیا قرارداد ارسال شده است استفاده میشود
|
||||||
|
/// </summary>
|
||||||
|
public class InstitutionContractSendFlag
|
||||||
|
{
|
||||||
|
public InstitutionContractSendFlag(long institutionContractId,bool isSent)
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid();
|
||||||
|
InstitutionContractId = institutionContractId;
|
||||||
|
IsSent = isSent;
|
||||||
|
CreatedDate = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// شناسه یکتای MongoDB
|
||||||
|
/// </summary>
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.String)]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// شناسه قرارداد در SQL
|
||||||
|
/// </summary>
|
||||||
|
public long InstitutionContractId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// آیا قرارداد ارسال شده است
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تاریخ و زمان ارسال
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? SentDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تاریخ و زمان ایجاد رکورد
|
||||||
|
/// </summary>
|
||||||
|
public DateTime CreatedDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تاریخ و زمان آخرین بهروزرسانی
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? LastModifiedDate { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// علامتگذاری قرارداد به عنوان ارسالشده
|
||||||
|
/// </summary>
|
||||||
|
public void MarkAsSent()
|
||||||
|
{
|
||||||
|
IsSent = true;
|
||||||
|
SentDate = DateTime.Now;
|
||||||
|
LastModifiedDate = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بازگردانی علامت ارسال
|
||||||
|
/// </summary>
|
||||||
|
public void MarkAsNotSent()
|
||||||
|
{
|
||||||
|
IsSent = false;
|
||||||
|
SentDate = null;
|
||||||
|
LastModifiedDate = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بهروزرسانی علامت آخری اصلاح
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateLastModified()
|
||||||
|
{
|
||||||
|
LastModifiedDate = DateTime.Now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Company.Domain.InstitutionContractSendFlagAgg;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace CompanyManagement.Infrastructure.Mongo.InstitutionContractSendFlagRepo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Repository برای مدیریت فلگ ارسال قرارداد در MongoDB
|
||||||
|
/// </summary>
|
||||||
|
public class InstitutionContractSendFlagRepository : IInstitutionContractSendFlagRepository
|
||||||
|
{
|
||||||
|
private readonly IMongoCollection<InstitutionContractSendFlag> _collection;
|
||||||
|
|
||||||
|
public InstitutionContractSendFlagRepository(IMongoDatabase database)
|
||||||
|
{
|
||||||
|
_collection = database.GetCollection<InstitutionContractSendFlag>("InstitutionContractSendFlag");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Create(InstitutionContractSendFlag flag)
|
||||||
|
{
|
||||||
|
await _collection.InsertOneAsync(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<InstitutionContractSendFlag> GetByContractId(long contractId)
|
||||||
|
{
|
||||||
|
var filter = Builders<InstitutionContractSendFlag>.Filter
|
||||||
|
.Eq(x => x.InstitutionContractId, contractId);
|
||||||
|
|
||||||
|
return await _collection.Find(filter).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task Update(InstitutionContractSendFlag flag)
|
||||||
|
{
|
||||||
|
var filter = Builders<InstitutionContractSendFlag>.Filter
|
||||||
|
.Eq(x => x.InstitutionContractId, flag.InstitutionContractId);
|
||||||
|
|
||||||
|
await _collection.ReplaceOneAsync(filter, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> IsContractSent(long contractId)
|
||||||
|
{
|
||||||
|
var flag = await GetByContractId(contractId);
|
||||||
|
return flag != null && flag.IsSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Remove(long contractId)
|
||||||
|
{
|
||||||
|
var filter = Builders<InstitutionContractSendFlag>.Filter
|
||||||
|
.Eq(x => x.InstitutionContractId, contractId);
|
||||||
|
|
||||||
|
await _collection.DeleteOneAsync(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -62,4 +62,40 @@ public interface ICheckoutApplication
|
|||||||
long workshopId, DateTime start, DateTime end);
|
long workshopId, DateTime start, DateTime end);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
Task<PagedResult<CheckoutListClientDto>> GetListForClient(long workshopId,
|
||||||
|
CheckoutListClientSearchModel searchModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CheckoutListClientSearchModel:PaginationRequest
|
||||||
|
{
|
||||||
|
public long? EmployeeId { get; set; }
|
||||||
|
public string Year { get; set; }
|
||||||
|
public string Month { get; set; }
|
||||||
|
public string StartDate { get; set; }
|
||||||
|
public string EndDate { get; set; }
|
||||||
|
public CheckoutClientListOrderType? OrderType { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CheckoutListClientDto
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
public string Year { get; set; }
|
||||||
|
public string Month { get; set; }
|
||||||
|
public string EmployeeName { get; set; }
|
||||||
|
public string ContractNo { get; set; }
|
||||||
|
public string ContractStart { get; set; }
|
||||||
|
public string ContractEnd { get; set; }
|
||||||
|
public bool Signature { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CheckoutClientListOrderType
|
||||||
|
{
|
||||||
|
ByCheckoutCreationDate,
|
||||||
|
BySignedCheckout,
|
||||||
|
ByUnSignedCheckout,
|
||||||
|
ByPersonnelCode,
|
||||||
|
ByPersonnelCodeDescending,
|
||||||
|
ByCheckoutStartDate,
|
||||||
|
ByCheckoutStartDateDescending
|
||||||
}
|
}
|
||||||
@@ -96,6 +96,8 @@ public class GetInstitutionContractListItemsViewModel
|
|||||||
/// مبلغ قسط
|
/// مبلغ قسط
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double InstallmentAmount { get; set; }
|
public double InstallmentAmount { get; set; }
|
||||||
|
|
||||||
|
public bool InstitutionContractIsSentFlag { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InstitutionContractListWorkshop
|
public class InstitutionContractListWorkshop
|
||||||
|
|||||||
@@ -305,6 +305,14 @@ public interface IInstitutionContractApplication
|
|||||||
Task<InstitutionContractDiscountResponse> SetDiscountForCreation(InstitutionContractSetDiscountForCreationRequest request);
|
Task<InstitutionContractDiscountResponse> SetDiscountForCreation(InstitutionContractSetDiscountForCreationRequest request);
|
||||||
Task<InstitutionContractDiscountResponse> ResetDiscountForCreation(InstitutionContractResetDiscountForExtensionRequest request);
|
Task<InstitutionContractDiscountResponse> ResetDiscountForCreation(InstitutionContractResetDiscountForExtensionRequest request);
|
||||||
Task<OperationResult> CreationComplete(InstitutionContractExtensionCompleteRequest request);
|
Task<OperationResult> CreationComplete(InstitutionContractExtensionCompleteRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تعیین فلگ ارسال قرارداد در MongoDB
|
||||||
|
/// اگر فلگ وجود نداشتند ایجاد میکند
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">درخواست تعیین فلگ</param>
|
||||||
|
/// <returns>نتیجه عملیات</returns>
|
||||||
|
Task<OperationResult> SetContractSendFlag(SetInstitutionContractSendFlagRequest request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CreationSetContractingPartyResponse
|
public class CreationSetContractingPartyResponse
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
namespace CompanyManagment.App.Contracts.InstitutionContract;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// درخواست برای تعیین فلگ ارسال قرارداد
|
||||||
|
/// </summary>
|
||||||
|
public class SetInstitutionContractSendFlagRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// شناسه قرارداد
|
||||||
|
/// </summary>
|
||||||
|
public long InstitutionContractId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// آیا قرارداد ارسال شده است
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSent { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
15
CompanyManagment.App.Contracts/SmsResult/Dto/SendStatus.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace CompanyManagment.App.Contracts.SmsResult.Dto;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// وضعیت ارسال پیامک
|
||||||
|
/// </summary>
|
||||||
|
public enum SendStatus
|
||||||
|
{
|
||||||
|
All=0,
|
||||||
|
/// <summary>
|
||||||
|
/// موفق
|
||||||
|
/// </summary>
|
||||||
|
Success,
|
||||||
|
//ناموفق
|
||||||
|
Failed,
|
||||||
|
}
|
||||||
54
CompanyManagment.App.Contracts/SmsResult/Dto/SmsReportDto.cs
Normal 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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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; }
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -706,5 +706,10 @@ public class CheckoutApplication : ICheckoutApplication
|
|||||||
return _checkoutRepository.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, start, end);
|
return _checkoutRepository.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<PagedResult<CheckoutListClientDto>> GetListForClient(long workshopId,CheckoutListClientSearchModel searchModel)
|
||||||
|
{
|
||||||
|
return await _checkoutRepository.GetListForClient(workshopId, searchModel);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,7 @@ using Company.Domain.PaymentTransactionAgg;
|
|||||||
using Company.Domain.RepresentativeAgg;
|
using Company.Domain.RepresentativeAgg;
|
||||||
using Company.Domain.RollCallServiceAgg;
|
using Company.Domain.RollCallServiceAgg;
|
||||||
using Company.Domain.WorkshopAgg;
|
using Company.Domain.WorkshopAgg;
|
||||||
|
using Company.Domain.InstitutionContractSendFlagAgg;
|
||||||
using CompanyManagment.App.Contracts.FinancialInvoice;
|
using CompanyManagment.App.Contracts.FinancialInvoice;
|
||||||
using CompanyManagment.App.Contracts.FinancialStatment;
|
using CompanyManagment.App.Contracts.FinancialStatment;
|
||||||
using CompanyManagment.App.Contracts.InstitutionContract;
|
using CompanyManagment.App.Contracts.InstitutionContract;
|
||||||
@@ -51,6 +52,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication
|
|||||||
private readonly IPaymentTransactionRepository _paymentTransactionRepository;
|
private readonly IPaymentTransactionRepository _paymentTransactionRepository;
|
||||||
private readonly IRollCallServiceRepository _rollCallServiceRepository;
|
private readonly IRollCallServiceRepository _rollCallServiceRepository;
|
||||||
private readonly ISepehrPaymentGatewayService _sepehrPaymentGatewayService;
|
private readonly ISepehrPaymentGatewayService _sepehrPaymentGatewayService;
|
||||||
|
private readonly IInstitutionContractSendFlagRepository _institutionContractSendFlagRepository;
|
||||||
|
|
||||||
|
|
||||||
public InstitutionContractApplication(IInstitutionContractRepository institutionContractRepository,
|
public InstitutionContractApplication(IInstitutionContractRepository institutionContractRepository,
|
||||||
@@ -62,7 +64,8 @@ public class InstitutionContractApplication : IInstitutionContractApplication
|
|||||||
IAccountApplication accountApplication, ISmsService smsService,
|
IAccountApplication accountApplication, ISmsService smsService,
|
||||||
IFinancialInvoiceRepository financialInvoiceRepository, IHttpClientFactory httpClientFactory,
|
IFinancialInvoiceRepository financialInvoiceRepository, IHttpClientFactory httpClientFactory,
|
||||||
IPaymentTransactionRepository paymentTransactionRepository, IRollCallServiceRepository rollCallServiceRepository,
|
IPaymentTransactionRepository paymentTransactionRepository, IRollCallServiceRepository rollCallServiceRepository,
|
||||||
ISepehrPaymentGatewayService sepehrPaymentGatewayService,ILogger<SepehrPaymentGateway> sepehrGatewayLogger)
|
ISepehrPaymentGatewayService sepehrPaymentGatewayService,ILogger<SepehrPaymentGateway> sepehrGatewayLogger,
|
||||||
|
IInstitutionContractSendFlagRepository institutionContractSendFlagRepository)
|
||||||
{
|
{
|
||||||
_institutionContractRepository = institutionContractRepository;
|
_institutionContractRepository = institutionContractRepository;
|
||||||
_contractingPartyRepository = contractingPartyRepository;
|
_contractingPartyRepository = contractingPartyRepository;
|
||||||
@@ -80,6 +83,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication
|
|||||||
_rollCallServiceRepository = rollCallServiceRepository;
|
_rollCallServiceRepository = rollCallServiceRepository;
|
||||||
_sepehrPaymentGatewayService = sepehrPaymentGatewayService;
|
_sepehrPaymentGatewayService = sepehrPaymentGatewayService;
|
||||||
_paymentGateway = new SepehrPaymentGateway(httpClientFactory,sepehrGatewayLogger);
|
_paymentGateway = new SepehrPaymentGateway(httpClientFactory,sepehrGatewayLogger);
|
||||||
|
_institutionContractSendFlagRepository = institutionContractSendFlagRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationResult Create(CreateInstitutionContract command)
|
public OperationResult Create(CreateInstitutionContract command)
|
||||||
@@ -894,6 +898,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication
|
|||||||
return opration.Succcedded();
|
return opration.Succcedded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void CreateContractingPartyAccount(long contractingPartyid, long accountId)
|
public void CreateContractingPartyAccount(long contractingPartyid, long accountId)
|
||||||
{
|
{
|
||||||
_institutionContractRepository.CreateContractingPartyAccount(contractingPartyid, accountId);
|
_institutionContractRepository.CreateContractingPartyAccount(contractingPartyid, accountId);
|
||||||
@@ -1820,6 +1825,59 @@ public class InstitutionContractApplication : IInstitutionContractApplication
|
|||||||
installments.Add(lastInstallment);
|
installments.Add(lastInstallment);
|
||||||
return installments;
|
return installments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// تعیین فلگ ارسال قرارداد
|
||||||
|
/// اگر فلگ وجود نداشتند ایجاد میکند
|
||||||
|
/// </summary>
|
||||||
|
public async Task<OperationResult> SetContractSendFlag(SetInstitutionContractSendFlagRequest request)
|
||||||
|
{
|
||||||
|
var operationResult = new OperationResult();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// بازیابی قرارداد از SQL
|
||||||
|
var contract = _institutionContractRepository.Get(request.InstitutionContractId);
|
||||||
|
if (contract == null)
|
||||||
|
return operationResult.Failed("قرارداد مورد نظر یافت نشد");
|
||||||
|
|
||||||
|
// بررسی اینکه آیا فلگ در MongoDB وجود دارد
|
||||||
|
var existingFlag = await _institutionContractSendFlagRepository
|
||||||
|
.GetByContractId(request.InstitutionContractId);
|
||||||
|
|
||||||
|
if (existingFlag != null)
|
||||||
|
{
|
||||||
|
// اگر فلگ وجود داشتند، آن را اپدیت کنیم
|
||||||
|
if (request.IsSent)
|
||||||
|
{
|
||||||
|
existingFlag.MarkAsSent();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
existingFlag.MarkAsNotSent();
|
||||||
|
}
|
||||||
|
existingFlag.UpdateLastModified();
|
||||||
|
await _institutionContractSendFlagRepository.Update(existingFlag);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// اگر فلگ وجود ندارد، آن را ایجاد کنیم
|
||||||
|
var newFlag = new InstitutionContractSendFlag(
|
||||||
|
request.InstitutionContractId,
|
||||||
|
request.IsSent
|
||||||
|
);
|
||||||
|
|
||||||
|
await _institutionContractSendFlagRepository.Create(newFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return operationResult.Succcedded();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return operationResult.Failed($"خطا در تعیین فلگ ارسال: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using System.Reflection.Metadata.Ecma335;
|
using System.Reflection.Metadata.Ecma335;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using _0_Framework.Application;
|
using _0_Framework.Application;
|
||||||
|
using _0_Framework.Exceptions;
|
||||||
using _0_Framework.InfraStructure;
|
using _0_Framework.InfraStructure;
|
||||||
using Company.Domain.CheckoutAgg;
|
using Company.Domain.CheckoutAgg;
|
||||||
using Company.Domain.LeftWorkAgg;
|
using Company.Domain.LeftWorkAgg;
|
||||||
@@ -50,9 +51,11 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
private readonly IRollCallMandatoryRepository _rollCallMandatoryRepository;
|
private readonly IRollCallMandatoryRepository _rollCallMandatoryRepository;
|
||||||
private readonly IRollCallEmployeeRepository _rollCallEmployeeRepository;
|
private readonly IRollCallEmployeeRepository _rollCallEmployeeRepository;
|
||||||
|
|
||||||
public CheckoutRepository(IAuthHelper authHelper, CompanyContext context, IConfiguration configuration, ILeftWorkRepository leftWorkRepository, IWorkingHoursTempApplication workingHoursTempApplication, IRollCallRepository rollCallRepository, IRollCallMandatoryRepository rollCallMandatoryRepository, IRollCallEmployeeRepository rollCallEmployeeRepository) : base(context)
|
public CheckoutRepository(IAuthHelper authHelper, CompanyContext context, IConfiguration configuration,
|
||||||
|
ILeftWorkRepository leftWorkRepository, IWorkingHoursTempApplication workingHoursTempApplication,
|
||||||
|
IRollCallRepository rollCallRepository, IRollCallMandatoryRepository rollCallMandatoryRepository,
|
||||||
|
IRollCallEmployeeRepository rollCallEmployeeRepository) : base(context)
|
||||||
{
|
{
|
||||||
|
|
||||||
_authHelper = authHelper;
|
_authHelper = authHelper;
|
||||||
_context = context;
|
_context = context;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
@@ -71,7 +74,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
/// <param name="سال به صورت رشته عددی"></param>
|
/// <param name="سال به صورت رشته عددی"></param>
|
||||||
/// <param name="ماه بصورت رشته عددی"></param>
|
/// <param name="ماه بصورت رشته عددی"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public (bool hasChekout, double FamilyAlloance, double OverTimePay, double RotatingShift, double Nightwork, double Fridaywork, double YraesPay) HasCheckout(long workshopId, long employeId, string year, string month)
|
public (bool hasChekout, double FamilyAlloance, double OverTimePay, double RotatingShift, double Nightwork, double
|
||||||
|
Fridaywork, double YraesPay) HasCheckout(long workshopId, long employeId, string year, string month)
|
||||||
{
|
{
|
||||||
var farisMonthName = Tools.ToFarsiMonthByNumber(month);
|
var farisMonthName = Tools.ToFarsiMonthByNumber(month);
|
||||||
|
|
||||||
@@ -90,7 +94,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (true, res.FamilyAllowance, res.OvertimePay, res.ShiftPay, res.NightworkPay, res.FridayPay,res.YearsPay);
|
return (true, res.FamilyAllowance, res.OvertimePay, res.ShiftPay, res.NightworkPay, res.FridayPay,
|
||||||
|
res.YearsPay);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EditCheckout GetDetails(long id)
|
public EditCheckout GetDetails(long id)
|
||||||
@@ -136,7 +141,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
ContractEndGr = x.ContractEnd,
|
ContractEndGr = x.ContractEnd,
|
||||||
ContractStart = x.ContractStart.ToFarsi(),
|
ContractStart = x.ContractStart.ToFarsi(),
|
||||||
ContractEnd = x.ContractEnd.ToFarsi()
|
ContractEnd = x.ContractEnd.ToFarsi()
|
||||||
|
|
||||||
})
|
})
|
||||||
.FirstOrDefault(x => x.Id == id);
|
.FirstOrDefault(x => x.Id == id);
|
||||||
}
|
}
|
||||||
@@ -152,7 +156,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
/// <param name="contractEnd"></param>
|
/// <param name="contractEnd"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
public async Task<CreateCheckoutListViewModel> GetContractResultToCreateCheckout(long workshopId, long employeeId, string year, string month, string contractStart,
|
public async Task<CreateCheckoutListViewModel> GetContractResultToCreateCheckout(long workshopId, long employeeId,
|
||||||
|
string year, string month, string contractStart,
|
||||||
string contractEnd)
|
string contractEnd)
|
||||||
{
|
{
|
||||||
DateTime startSreach;
|
DateTime startSreach;
|
||||||
@@ -165,7 +170,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
if (month == "0" && year == "0")
|
if (month == "0" && year == "0")
|
||||||
{
|
{
|
||||||
DateTime now = DateTime.Now;
|
DateTime now = DateTime.Now;
|
||||||
@@ -195,8 +199,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
startSreach = startStr.ToGeorgianDateTime();
|
startSreach = startStr.ToGeorgianDateTime();
|
||||||
endSearch = (startStr.FindeEndOfMonth()).ToGeorgianDateTime();
|
endSearch = (startStr.FindeEndOfMonth()).ToGeorgianDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var timer = new Stopwatch();
|
var timer = new Stopwatch();
|
||||||
timer.Start();
|
timer.Start();
|
||||||
|
|
||||||
@@ -211,7 +215,9 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
contractWorkshop => contractWorkshop.contract.EmployeeId,
|
contractWorkshop => contractWorkshop.contract.EmployeeId,
|
||||||
employee => employee.id,
|
employee => employee.id,
|
||||||
(contractWorkshop, employee) => new { contractWorkshop, employee })
|
(contractWorkshop, employee) => new { contractWorkshop, employee })
|
||||||
.Join(_context.LeftWorkList.AsSplitQuery().Where(l => l.WorkshopId == workshopId && l.StartWorkDate < endSearch && l.LeftWorkDate > startSreach),
|
.Join(
|
||||||
|
_context.LeftWorkList.AsSplitQuery().Where(l =>
|
||||||
|
l.WorkshopId == workshopId && l.StartWorkDate < endSearch && l.LeftWorkDate > startSreach),
|
||||||
contractWorkshopEmployee => contractWorkshopEmployee.contractWorkshop.contract.EmployeeId,
|
contractWorkshopEmployee => contractWorkshopEmployee.contractWorkshop.contract.EmployeeId,
|
||||||
leftwork => leftwork.EmployeeId,
|
leftwork => leftwork.EmployeeId,
|
||||||
(contractWorkshopEmployee, leftwork) => new { contractWorkshopEmployee, leftwork })
|
(contractWorkshopEmployee, leftwork) => new { contractWorkshopEmployee, leftwork })
|
||||||
@@ -221,16 +227,15 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
personnelCode => personnelCode.EmployeeId,
|
personnelCode => personnelCode.EmployeeId,
|
||||||
(contractWorkshopEmployeeleftWork, personnelCode) =>
|
(contractWorkshopEmployeeleftWork, personnelCode) =>
|
||||||
new { contractWorkshopEmployeeleftWork, personnelCode })
|
new { contractWorkshopEmployeeleftWork, personnelCode })
|
||||||
|
|
||||||
.GroupJoin(_context.CheckoutSet.AsSplitQuery(),
|
.GroupJoin(_context.CheckoutSet.AsSplitQuery(),
|
||||||
contractWorkshopEmployeeleftWorkPersonnelCode => contractWorkshopEmployeeleftWorkPersonnelCode
|
contractWorkshopEmployeeleftWorkPersonnelCode => contractWorkshopEmployeeleftWorkPersonnelCode
|
||||||
.contractWorkshopEmployeeleftWork.contractWorkshopEmployee.contractWorkshop.contract.id,
|
.contractWorkshopEmployeeleftWork.contractWorkshopEmployee.contractWorkshop.contract.id,
|
||||||
checkout => checkout.ContractId,
|
checkout => checkout.ContractId,
|
||||||
(contractWorkshopEmployeeleftWorkPersonnelCode, checkout) =>
|
(contractWorkshopEmployeeleftWorkPersonnelCode, checkout) =>
|
||||||
new { contractWorkshopEmployeeleftWorkPersonnelCode, checkout })
|
new { contractWorkshopEmployeeleftWorkPersonnelCode, checkout })
|
||||||
|
|
||||||
.GroupJoin(_context.EmployeeComputeOptionsSet.Where(o => o.WorkshopId == workshopId),
|
.GroupJoin(_context.EmployeeComputeOptionsSet.Where(o => o.WorkshopId == workshopId),
|
||||||
x => x.contractWorkshopEmployeeleftWorkPersonnelCode.contractWorkshopEmployeeleftWork.leftwork.EmployeeId,
|
x => x.contractWorkshopEmployeeleftWorkPersonnelCode.contractWorkshopEmployeeleftWork.leftwork
|
||||||
|
.EmployeeId,
|
||||||
option => option.EmployeeId,
|
option => option.EmployeeId,
|
||||||
(x, options) => new { x.checkout, x.contractWorkshopEmployeeleftWorkPersonnelCode, options })
|
(x, options) => new { x.checkout, x.contractWorkshopEmployeeleftWorkPersonnelCode, options })
|
||||||
.SelectMany(
|
.SelectMany(
|
||||||
@@ -250,11 +255,11 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
DateTime currentStart = ($"{DateTime.Now.ToFarsi().Substring(0, 8)}01").ToGeorgianDateTime();
|
DateTime currentStart = ($"{DateTime.Now.ToFarsi().Substring(0, 8)}01").ToGeorgianDateTime();
|
||||||
DateTime currentEnd = ($"{DateTime.Now.ToFarsi().FindeEndOfMonth()}").ToGeorgianDateTime();
|
DateTime currentEnd = ($"{DateTime.Now.ToFarsi().FindeEndOfMonth()}").ToGeorgianDateTime();
|
||||||
|
|
||||||
var chekoutCreated = result.checkout.FirstOrDefault(x => x.ContractStart < endSearch && x.ContractEnd > startSreach && x.IsActiveString == "true");
|
var chekoutCreated = result.checkout.FirstOrDefault(x =>
|
||||||
|
x.ContractStart < endSearch && x.ContractEnd > startSreach && x.IsActiveString == "true");
|
||||||
|
|
||||||
if (chekoutCreated != null)
|
if (chekoutCreated != null)
|
||||||
{
|
{
|
||||||
|
|
||||||
return new CreateCheckoutListViewModel
|
return new CreateCheckoutListViewModel
|
||||||
{
|
{
|
||||||
Id = chekoutCreated.ContractId,
|
Id = chekoutCreated.ContractId,
|
||||||
@@ -273,6 +278,7 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
EmployeeHasCreateCheckout = true
|
EmployeeHasCreateCheckout = true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var employeeJoin = result.contractWorkshopEmployeeleftWorkPersonnelCode.contractWorkshopEmployeeleftWork
|
var employeeJoin = result.contractWorkshopEmployeeleftWorkPersonnelCode.contractWorkshopEmployeeleftWork
|
||||||
.contractWorkshopEmployee.employee.id;
|
.contractWorkshopEmployee.employee.id;
|
||||||
|
|
||||||
@@ -283,11 +289,13 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
var startStatusSearch = leftWork.StartWorkDate > startSreach && leftWork.StartWorkDate <= endSearch
|
var startStatusSearch = leftWork.StartWorkDate > startSreach && leftWork.StartWorkDate <= endSearch
|
||||||
? leftWork.StartWorkDate
|
? leftWork.StartWorkDate
|
||||||
: startSreach;
|
: startSreach;
|
||||||
var endStatusSearch = leftWork.HasLeft && leftWork.LeftWorkDate > startSreach && leftWork.LeftWorkDate <= endSearch
|
var endStatusSearch = leftWork.HasLeft && leftWork.LeftWorkDate > startSreach &&
|
||||||
|
leftWork.LeftWorkDate <= endSearch
|
||||||
? leftWork.LeftWorkDate.AddDays(-1)
|
? leftWork.LeftWorkDate.AddDays(-1)
|
||||||
: startSreach;
|
: startSreach;
|
||||||
bool hasRollCall =
|
bool hasRollCall =
|
||||||
_rollCallEmployeeRepository.HasRollCallRecord(employeeJoin, workshopId, startStatusSearch, endStatusSearch);
|
_rollCallEmployeeRepository.HasRollCallRecord(employeeJoin, workshopId, startStatusSearch,
|
||||||
|
endStatusSearch);
|
||||||
|
|
||||||
bool extension = true;
|
bool extension = true;
|
||||||
bool laterThanEnd = false;
|
bool laterThanEnd = false;
|
||||||
@@ -300,11 +308,11 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
.contractWorkshopEmployee.contractWorkshop.contract.ContarctStart;
|
.contractWorkshopEmployee.contractWorkshop.contract.ContarctStart;
|
||||||
var contractEndGr = result.contractWorkshopEmployeeleftWorkPersonnelCode.contractWorkshopEmployeeleftWork
|
var contractEndGr = result.contractWorkshopEmployeeleftWorkPersonnelCode.contractWorkshopEmployeeleftWork
|
||||||
.contractWorkshopEmployee.contractWorkshop.contract.ContractEnd;
|
.contractWorkshopEmployee.contractWorkshop.contract.ContractEnd;
|
||||||
|
|
||||||
#region HasRollCall
|
#region HasRollCall
|
||||||
|
|
||||||
if (hasRollCall)
|
if (hasRollCall)
|
||||||
{
|
{
|
||||||
|
|
||||||
// اگر ترک کار کرده بود
|
// اگر ترک کار کرده بود
|
||||||
// اگر ترک کارش در بازه انتخاب شده بود
|
// اگر ترک کارش در بازه انتخاب شده بود
|
||||||
if (leftWork.HasLeft && leftWork.LeftWorkDate > startSreach && leftWork.LeftWorkDate <= endSearch)
|
if (leftWork.HasLeft && leftWork.LeftWorkDate > startSreach && leftWork.LeftWorkDate <= endSearch)
|
||||||
@@ -322,7 +330,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
? leftWork.StartWorkDate.ToFarsi()
|
? leftWork.StartWorkDate.ToFarsi()
|
||||||
: startSreach.ToFarsi();
|
: startSreach.ToFarsi();
|
||||||
contractEnd = leftWork.LeftWorkDate.AddDays(-1).ToFarsi();
|
contractEnd = leftWork.LeftWorkDate.AddDays(-1).ToFarsi();
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -334,7 +341,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
? leftWork.StartWorkDate.ToFarsi()
|
? leftWork.StartWorkDate.ToFarsi()
|
||||||
: startSreach.ToFarsi();
|
: startSreach.ToFarsi();
|
||||||
contractEnd = leftWork.LeftWorkDate.AddDays(-1).ToFarsi();
|
contractEnd = leftWork.LeftWorkDate.AddDays(-1).ToFarsi();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (endSearch < currentStart)
|
else if (endSearch < currentStart)
|
||||||
@@ -357,7 +363,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
: startSreach.ToFarsi();
|
: startSreach.ToFarsi();
|
||||||
contractEnd = leftWork.LeftWorkDate.AddDays(-1).ToFarsi();
|
contractEnd = leftWork.LeftWorkDate.AddDays(-1).ToFarsi();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (leftWork.HasLeft && leftWork.LeftWorkDate <= startSreach)
|
else if (leftWork.HasLeft && leftWork.LeftWorkDate <= startSreach)
|
||||||
{
|
{
|
||||||
@@ -365,7 +370,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
extension = false;
|
extension = false;
|
||||||
description = "به دلیل ترک کار پیش از تاریخ انتخاب شده مجاز به ایجاد فیش نمی باشید";
|
description = "به دلیل ترک کار پیش از تاریخ انتخاب شده مجاز به ایجاد فیش نمی باشید";
|
||||||
leftWorkDate = leftWork.LeftWorkDate.ToFarsi();
|
leftWorkDate = leftWork.LeftWorkDate.ToFarsi();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (!leftWork.HasLeft && startSreach == currentStart)
|
else if (!leftWork.HasLeft && startSreach == currentStart)
|
||||||
{
|
{
|
||||||
@@ -376,13 +380,9 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
? leftWork.StartWorkDate.ToFarsi()
|
? leftWork.StartWorkDate.ToFarsi()
|
||||||
: startSreach.ToFarsi();
|
: startSreach.ToFarsi();
|
||||||
contractEnd = endSearch.ToFarsi();
|
contractEnd = endSearch.ToFarsi();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (!leftWork.HasLeft && startSreach < currentStart)
|
else if (!leftWork.HasLeft && startSreach < currentStart)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (contractStartGr <= startSreach && contractStartGr > endSearch)
|
if (contractStartGr <= startSreach && contractStartGr > endSearch)
|
||||||
{
|
{
|
||||||
laterThanEnd = true;
|
laterThanEnd = true;
|
||||||
@@ -397,12 +397,11 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
contractStart = leftWork.StartWorkDate > startSreach
|
contractStart = leftWork.StartWorkDate > startSreach
|
||||||
? leftWork.StartWorkDate.ToFarsi()
|
? leftWork.StartWorkDate.ToFarsi()
|
||||||
: startSreach.ToFarsi();
|
: startSreach.ToFarsi();
|
||||||
contractEnd = (leftWork.LeftWorkDate > startSreach && leftWork.LeftWorkDate <= endSearch) ? leftWork.LeftWorkDate.AddDays(-1).ToFarsi() : endSearch.ToFarsi();
|
contractEnd = (leftWork.LeftWorkDate > startSreach && leftWork.LeftWorkDate <= endSearch)
|
||||||
|
? leftWork.LeftWorkDate.AddDays(-1).ToFarsi()
|
||||||
|
: endSearch.ToFarsi();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -468,13 +467,11 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
contractEnd = endSearch.ToFarsi();
|
contractEnd = endSearch.ToFarsi();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return new CreateCheckoutListViewModel
|
return new CreateCheckoutListViewModel
|
||||||
{
|
{
|
||||||
Id = result.contractWorkshopEmployeeleftWorkPersonnelCode.contractWorkshopEmployeeleftWork
|
Id = result.contractWorkshopEmployeeleftWorkPersonnelCode.contractWorkshopEmployeeleftWork
|
||||||
@@ -498,15 +495,14 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
ContractStart = contractStart,
|
ContractStart = contractStart,
|
||||||
ContractEnd = contractEnd,
|
ContractEnd = contractEnd,
|
||||||
LeftWorkDate = leftWorkDate,
|
LeftWorkDate = leftWorkDate,
|
||||||
EmployeeHasCreateCheckout = result.option != null ? result.option.CreateCheckout : result.contractWorkshopEmployeeleftWorkPersonnelCode.contractWorkshopEmployeeleftWork.contractWorkshopEmployee.contractWorkshop.workshop.CreateCheckout
|
EmployeeHasCreateCheckout = result.option != null
|
||||||
|
? result.option.CreateCheckout
|
||||||
|
: result.contractWorkshopEmployeeleftWorkPersonnelCode.contractWorkshopEmployeeleftWork
|
||||||
|
.contractWorkshopEmployee.contractWorkshop.workshop.CreateCheckout
|
||||||
};
|
};
|
||||||
|
|
||||||
}).Where(x => x.EmployeeHasCreateCheckout).OrderByDescending(x => x.Extension).ToList();
|
}).Where(x => x.EmployeeHasCreateCheckout).OrderByDescending(x => x.Extension).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Console.WriteLine("process : " + timer.Elapsed);
|
Console.WriteLine("process : " + timer.Elapsed);
|
||||||
|
|
||||||
return new CreateCheckoutListViewModel()
|
return new CreateCheckoutListViewModel()
|
||||||
@@ -517,7 +513,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
|
|
||||||
public async Task CreateCkeckout(Checkout command)
|
public async Task CreateCkeckout(Checkout command)
|
||||||
{
|
{
|
||||||
|
|
||||||
var creationDates = DateTime.Now;
|
var creationDates = DateTime.Now;
|
||||||
|
|
||||||
//var result = await _context.Database.ExecuteSqlInterpolatedAsync($"EXEC InsertQuery_Checkout {id},{employeeFullName},{isActiveString},{signature},{fathersName},{nationalCode},{dateOfBirth},{employeeId},{workshopName},{workshopId},{contractNo},{contractStart},{contractEnd},{month},{year},{contractId},{workingHoursId},{monthlySalary},{baseYearsPay},{consumableItems},{housingAllowance},{overtimePay},{nightworkPay},{fridayPay},{missionPay},{shiftPay},{familyAllowance},{bonusesPay},{yearsPay},{leavePay},{insuranceDeduction},{taxDeducation},{installmentDeduction},{salaryAidDeduction},{absenceDeduction},{creationDate},{archiveCode},{personnelCode},{sumOfWorkingDays},{totalClaims},{taxDeducation},{totalPayment}");
|
//var result = await _context.Database.ExecuteSqlInterpolatedAsync($"EXEC InsertQuery_Checkout {id},{employeeFullName},{isActiveString},{signature},{fathersName},{nationalCode},{dateOfBirth},{employeeId},{workshopName},{workshopId},{contractNo},{contractStart},{contractEnd},{month},{year},{contractId},{workingHoursId},{monthlySalary},{baseYearsPay},{consumableItems},{housingAllowance},{overtimePay},{nightworkPay},{fridayPay},{missionPay},{shiftPay},{familyAllowance},{bonusesPay},{yearsPay},{leavePay},{insuranceDeduction},{taxDeducation},{installmentDeduction},{salaryAidDeduction},{absenceDeduction},{creationDate},{archiveCode},{personnelCode},{sumOfWorkingDays},{totalClaims},{taxDeducation},{totalPayment}");
|
||||||
@@ -536,7 +531,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
if (command.HasInsuranceShareTheSameAsList)
|
if (command.HasInsuranceShareTheSameAsList)
|
||||||
entity.SetInsuranceShare();
|
entity.SetInsuranceShare();
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -678,9 +672,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
query = query.Where(x => x.ContractStartGr >= startyearGr && x.ContractEndGr <= endYearGr).ToList();
|
query = query.Where(x => x.ContractStartGr >= startyearGr && x.ContractEndGr <= endYearGr).ToList();
|
||||||
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
||||||
return query.OrderByDescending(x => x.ContractEndGr).ThenBy(x => x.PersonnelCodeInt).ToList();
|
return query.OrderByDescending(x => x.ContractEndGr).ThenBy(x => x.PersonnelCodeInt).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrWhiteSpace(searchModel.Year) && !string.IsNullOrWhiteSpace(searchModel.Month) &&
|
else if (!string.IsNullOrWhiteSpace(searchModel.Year) && !string.IsNullOrWhiteSpace(searchModel.Month) &&
|
||||||
string.IsNullOrWhiteSpace(searchModel.ContractStart) &&
|
string.IsNullOrWhiteSpace(searchModel.ContractStart) &&
|
||||||
@@ -799,7 +790,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
endDate >= x.ContractEndGr && startDate < x.ContractEndGr).ToList();
|
endDate >= x.ContractEndGr && startDate < x.ContractEndGr).ToList();
|
||||||
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
||||||
return query.OrderBy(x => x.PersonnelCodeInt).ToList();
|
return query.OrderBy(x => x.PersonnelCodeInt).ToList();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrWhiteSpace(searchModel.ContractStart) &&
|
else if (!string.IsNullOrWhiteSpace(searchModel.ContractStart) &&
|
||||||
!string.IsNullOrWhiteSpace(searchModel.ContractEnd) &&
|
!string.IsNullOrWhiteSpace(searchModel.ContractEnd) &&
|
||||||
@@ -813,17 +803,12 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
|
|
||||||
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
||||||
return query.OrderByDescending(x => x.ContractEndGr).ThenBy(x => x.PersonnelCodeInt).ToList();
|
return query.OrderByDescending(x => x.ContractEndGr).ThenBy(x => x.PersonnelCodeInt).ToList();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return query.OrderByDescending(x => x.Id)
|
return query.OrderByDescending(x => x.Id)
|
||||||
.ThenByDescending(x => x.Year).ThenBy(x => x.PersonnelCodeInt).Take(100).ToList();
|
.ThenByDescending(x => x.Year).ThenBy(x => x.PersonnelCodeInt).Take(100).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//foreach(var items in query)
|
//foreach(var items in query)
|
||||||
//{
|
//{
|
||||||
// var employeId = _context.WorkshopEmployers?.Where(x => x.WorkshopId == items.WorkshopId)
|
// var employeId = _context.WorkshopEmployers?.Where(x => x.WorkshopId == items.WorkshopId)
|
||||||
@@ -865,7 +850,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
ContractNo = x.ContractNo,
|
ContractNo = x.ContractNo,
|
||||||
ContractId = x.ContractId,
|
ContractId = x.ContractId,
|
||||||
HasRollCall = x.HasRollCall
|
HasRollCall = x.HasRollCall
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (searchModel.EmployeeId != 0 && searchModel.WorkshopId != 0)
|
if (searchModel.EmployeeId != 0 && searchModel.WorkshopId != 0)
|
||||||
@@ -884,11 +868,12 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
{
|
{
|
||||||
var start = searchModel.ContractStart.ToGeorgianDateTime();
|
var start = searchModel.ContractStart.ToGeorgianDateTime();
|
||||||
var end = searchModel.ContractEnd.ToGeorgianDateTime();
|
var end = searchModel.ContractEnd.ToGeorgianDateTime();
|
||||||
query = query.Where(x => x.ContractStartGr == start && x.ContractEndGr == end && x.EmployeeId == searchModel.EmployeeId && x.WorkshopId == searchModel.WorkshopId);
|
query = query.Where(x =>
|
||||||
|
x.ContractStartGr == start && x.ContractEndGr == end && x.EmployeeId == searchModel.EmployeeId &&
|
||||||
|
x.WorkshopId == searchModel.WorkshopId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return query.OrderBy(x => x.ContractStartGr).ToList();
|
return query.OrderBy(x => x.ContractStartGr).ToList();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CheckoutViewModel> PrintAll(List<long> id)
|
public List<CheckoutViewModel> PrintAll(List<long> id)
|
||||||
@@ -969,7 +954,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
SalaryAidDateTimeFa = s.SalaryAidDateTimeFa,
|
SalaryAidDateTimeFa = s.SalaryAidDateTimeFa,
|
||||||
SalaryAidDateTimeGe = s.SalaryAidDateTime
|
SalaryAidDateTimeGe = s.SalaryAidDateTime
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
CheckoutRollCall = item.CheckoutRollCall != null ? new CheckoutRollCallViewModel()
|
CheckoutRollCall = item.CheckoutRollCall != null
|
||||||
|
? new CheckoutRollCallViewModel()
|
||||||
{
|
{
|
||||||
TotalPresentTimeSpan = item.CheckoutRollCall.TotalPresentTimeSpan,
|
TotalPresentTimeSpan = item.CheckoutRollCall.TotalPresentTimeSpan,
|
||||||
TotalBreakTimeSpan = item.CheckoutRollCall.TotalBreakTimeSpan,
|
TotalBreakTimeSpan = item.CheckoutRollCall.TotalBreakTimeSpan,
|
||||||
@@ -977,7 +963,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
TotalPaidLeaveTmeSpan = item.CheckoutRollCall.TotalPaidLeaveTmeSpan,
|
TotalPaidLeaveTmeSpan = item.CheckoutRollCall.TotalPaidLeaveTmeSpan,
|
||||||
TotalMandatoryTimeSpan = item.CheckoutRollCall.TotalMandatoryTimeSpan,
|
TotalMandatoryTimeSpan = item.CheckoutRollCall.TotalMandatoryTimeSpan,
|
||||||
TotalSickLeaveTimeSpan = item.CheckoutRollCall.TotalSickLeaveTimeSpan,
|
TotalSickLeaveTimeSpan = item.CheckoutRollCall.TotalSickLeaveTimeSpan,
|
||||||
RollCallDaysCollection = item.CheckoutRollCall.RollCallDaysCollection.Select(d => new CheckoutRollCallDayViewModel()
|
RollCallDaysCollection = item.CheckoutRollCall.RollCallDaysCollection.Select(d =>
|
||||||
|
new CheckoutRollCallDayViewModel()
|
||||||
{
|
{
|
||||||
WorkingTimeSpan = d.WorkingTimeSpan,
|
WorkingTimeSpan = d.WorkingTimeSpan,
|
||||||
BreakTimeSpan = d.BreakTimeSpan,
|
BreakTimeSpan = d.BreakTimeSpan,
|
||||||
@@ -994,11 +981,12 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
SecondEndDate = d.SecondEndDate,
|
SecondEndDate = d.SecondEndDate,
|
||||||
SecondStartDate = d.SecondStartDate,
|
SecondStartDate = d.SecondStartDate,
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
|
}
|
||||||
} : null,
|
: null,
|
||||||
HasAmountConflict = item.HasAmountConflict,
|
HasAmountConflict = item.HasAmountConflict,
|
||||||
EmployeeMandatoryHoursTimeSpan = item.EmployeeMandatoryHours,
|
EmployeeMandatoryHoursTimeSpan = item.EmployeeMandatoryHours,
|
||||||
EmployeeMandatoryHoursStr = Tools.ToFarsiHoursAndMinutes(Convert.ToInt32(item.EmployeeMandatoryHours.TotalHours),item.EmployeeMandatoryHours.Minutes,"-")
|
EmployeeMandatoryHoursStr = Tools.ToFarsiHoursAndMinutes(
|
||||||
|
Convert.ToInt32(item.EmployeeMandatoryHours.TotalHours), item.EmployeeMandatoryHours.Minutes, "-")
|
||||||
};
|
};
|
||||||
var workshopName = _context.Workshops.FirstOrDefault(x => x.id == ch.WorkshopId);
|
var workshopName = _context.Workshops.FirstOrDefault(x => x.id == ch.WorkshopId);
|
||||||
ch.WorkshopName = workshopName.WorkshopName;
|
ch.WorkshopName = workshopName.WorkshopName;
|
||||||
@@ -1122,9 +1110,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
|
|
||||||
var totalPaidLeaveTimeSpans = hourlyPaidLeaveTimeSpans.Concat(dailyPaidLeaveTimeSpans);
|
var totalPaidLeaveTimeSpans = hourlyPaidLeaveTimeSpans.Concat(dailyPaidLeaveTimeSpans);
|
||||||
ch.TotalHourlyLeave = new TimeSpan(hourlyPaidLeaveTimeSpans.Sum(x => x.Ticks));
|
ch.TotalHourlyLeave = new TimeSpan(hourlyPaidLeaveTimeSpans.Sum(x => x.Ticks));
|
||||||
ch.TotalPaidLeave = new TimeSpan(totalPaidLeaveTimeSpans.Sum(x => x.Ticks)).ToFarsiDaysAndHoursAndMinutes("-");
|
ch.TotalPaidLeave =
|
||||||
|
new TimeSpan(totalPaidLeaveTimeSpans.Sum(x => x.Ticks)).ToFarsiDaysAndHoursAndMinutes("-");
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -1142,7 +1129,9 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
ch.TotalBreakTimeStr = ch.CheckoutRollCall.TotalBreakTimeSpan.ToFarsiHoursAndMinutes("-");
|
ch.TotalBreakTimeStr = ch.CheckoutRollCall.TotalBreakTimeSpan.ToFarsiHoursAndMinutes("-");
|
||||||
ch.TotalPresentTimeStr = ch.CheckoutRollCall.TotalPresentTimeSpan.ToFarsiHoursAndMinutes("-");
|
ch.TotalPresentTimeStr = ch.CheckoutRollCall.TotalPresentTimeSpan.ToFarsiHoursAndMinutes("-");
|
||||||
ch.TotalMandatoryTimeStr = ch.CheckoutRollCall.TotalMandatoryTimeSpan.ToFarsiHoursAndMinutes("-");
|
ch.TotalMandatoryTimeStr = ch.CheckoutRollCall.TotalMandatoryTimeSpan.ToFarsiHoursAndMinutes("-");
|
||||||
ch.TotalPaidLeave = Tools.ToFarsiHoursAndMinutes(Convert.ToInt32(ch.CheckoutRollCall.TotalPaidLeaveTmeSpan.TotalHours), ch.CheckoutRollCall.TotalPaidLeaveTmeSpan.Minutes, "-");
|
ch.TotalPaidLeave = Tools.ToFarsiHoursAndMinutes(
|
||||||
|
Convert.ToInt32(ch.CheckoutRollCall.TotalPaidLeaveTmeSpan.TotalHours),
|
||||||
|
ch.CheckoutRollCall.TotalPaidLeaveTmeSpan.Minutes, "-");
|
||||||
ch.MonthlyRollCall = ch.CheckoutRollCall.RollCallDaysCollection
|
ch.MonthlyRollCall = ch.CheckoutRollCall.RollCallDaysCollection
|
||||||
.Select(x => new CheckoutDailyRollCallViewModel
|
.Select(x => new CheckoutDailyRollCallViewModel
|
||||||
{
|
{
|
||||||
@@ -1163,13 +1152,12 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
BreakTimeString = $"{(int)(x.BreakTimeSpan.TotalHours)}:{x.BreakTimeSpan.Minutes:00}",
|
BreakTimeString = $"{(int)(x.BreakTimeSpan.TotalHours)}:{x.BreakTimeSpan.Minutes:00}",
|
||||||
RollCallDateFa = x.Date.ToFarsi()
|
RollCallDateFa = x.Date.ToFarsi()
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
if (ch.HasRollCall)
|
if (ch.HasRollCall)
|
||||||
ch.MonthlyRollCall = _rollCallRepository.GetEmployeeRollCallsForMonth(ch.EmployeeId, ch.WorkshopId, ch.ContractStartGr, ch.ContractEndGr);
|
ch.MonthlyRollCall = _rollCallRepository.GetEmployeeRollCallsForMonth(ch.EmployeeId, ch.WorkshopId,
|
||||||
|
ch.ContractStartGr, ch.ContractEndGr);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ch.CreateWorkingHoursTemp.ContractStartGr = ch.ContractStartGr;
|
ch.CreateWorkingHoursTemp.ContractStartGr = ch.ContractStartGr;
|
||||||
@@ -1178,9 +1166,11 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
ch.CreateWorkingHoursTemp.ContractEnd = ch.ContractEndGr.ToFarsi();
|
ch.CreateWorkingHoursTemp.ContractEnd = ch.ContractEndGr.ToFarsi();
|
||||||
ch.CreateWorkingHoursTemp.EmployeeId = ch.EmployeeId;
|
ch.CreateWorkingHoursTemp.EmployeeId = ch.EmployeeId;
|
||||||
ch.CreateWorkingHoursTemp.WorkshopId = ch.WorkshopId;
|
ch.CreateWorkingHoursTemp.WorkshopId = ch.WorkshopId;
|
||||||
ch.MonthlyRollCall = ConvertStaticToRollCall(ch.CreateWorkingHoursTemp, workshopName.WorkshopHolidayWorking);
|
ch.MonthlyRollCall =
|
||||||
|
ConvertStaticToRollCall(ch.CreateWorkingHoursTemp, workshopName.WorkshopHolidayWorking);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query.Add(ch);
|
query.Add(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1191,6 +1181,7 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
printNumer += 1;
|
printNumer += 1;
|
||||||
rec.PrintCounter = printNumer;
|
rec.PrintCounter = printNumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1216,7 +1207,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
Id = x.id,
|
Id = x.id,
|
||||||
EmployerFullName = x.FName + " " + x.LName,
|
EmployerFullName = x.FName + " " + x.LName,
|
||||||
IsLegal = x.IsLegal,
|
IsLegal = x.IsLegal,
|
||||||
|
|
||||||
}).Where(x => emp.Contains(x.Id)).ToList();
|
}).Where(x => emp.Contains(x.Id)).ToList();
|
||||||
if (employerlist.Count > 0)
|
if (employerlist.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -1245,7 +1235,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
|
|
||||||
var leaveList = _context.LeaveList.Where(x => x.WorkshopId == ch.WorkshopId && x.EmployeeId == ch.EmployeeId && x.LeaveType == "استحقاقی");
|
var leaveList = _context.LeaveList.Where(x =>
|
||||||
|
x.WorkshopId == ch.WorkshopId && x.EmployeeId == ch.EmployeeId && x.LeaveType == "استحقاقی");
|
||||||
var leaveViewModel = new List<LeaveViewModel>();
|
var leaveViewModel = new List<LeaveViewModel>();
|
||||||
|
|
||||||
foreach (var list in leaveList)
|
foreach (var list in leaveList)
|
||||||
@@ -1370,7 +1361,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
SalaryAidDateTimeFa = s.SalaryAidDateTimeFa,
|
SalaryAidDateTimeFa = s.SalaryAidDateTimeFa,
|
||||||
SalaryAidDateTimeGe = s.SalaryAidDateTime
|
SalaryAidDateTimeGe = s.SalaryAidDateTime
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
|
|
||||||
}).SingleOrDefault(x => x.Id == id);
|
}).SingleOrDefault(x => x.Id == id);
|
||||||
|
|
||||||
var workshopName = _context.Workshops.FirstOrDefault(x => x.id == ch.WorkshopId);
|
var workshopName = _context.Workshops.FirstOrDefault(x => x.id == ch.WorkshopId);
|
||||||
@@ -1390,6 +1380,7 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
};
|
};
|
||||||
employers.Add(employer);
|
employers.Add(employer);
|
||||||
}
|
}
|
||||||
|
|
||||||
ch.MaritalStatus = _context.Employees.Find(ch.EmployeeId)?.MaritalStatus;
|
ch.MaritalStatus = _context.Employees.Find(ch.EmployeeId)?.MaritalStatus;
|
||||||
ch.EmployerList = employers;
|
ch.EmployerList = employers;
|
||||||
var workingHours = _workingHoursTempApplication.GetByContractIdConvertToShiftwork4(ch.ContractId);
|
var workingHours = _workingHoursTempApplication.GetByContractIdConvertToShiftwork4(ch.ContractId);
|
||||||
@@ -1484,7 +1475,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
|
|
||||||
ch.TotalSickLeave = new TimeSpan(sickLeaveTimeSpans.Sum(x => x.Ticks)).ToFarsiDaysAndHoursAndMinutes("-");
|
ch.TotalSickLeave = new TimeSpan(sickLeaveTimeSpans.Sum(x => x.Ticks)).ToFarsiDaysAndHoursAndMinutes("-");
|
||||||
|
|
||||||
var hourlyPaidLeaveTimeSpans = hourlyPaidLeave.Select(x => TimeOnly.Parse(x.LeaveHourses).ToTimeSpan()).ToList();
|
var hourlyPaidLeaveTimeSpans =
|
||||||
|
hourlyPaidLeave.Select(x => TimeOnly.Parse(x.LeaveHourses).ToTimeSpan()).ToList();
|
||||||
|
|
||||||
var dailyPaidLeaveTimeSpans = dailyPaidLeave.Select(x =>
|
var dailyPaidLeaveTimeSpans = dailyPaidLeave.Select(x =>
|
||||||
{
|
{
|
||||||
@@ -1497,20 +1489,19 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
ch.TotalHourlyLeave = new TimeSpan(hourlyPaidLeaveTimeSpans.Sum(x => x.Ticks));
|
ch.TotalHourlyLeave = new TimeSpan(hourlyPaidLeaveTimeSpans.Sum(x => x.Ticks));
|
||||||
ch.TotalPaidLeave = new TimeSpan(totalPaidLeaveTimeSpans.Sum(x => x.Ticks)).ToFarsiDaysAndHoursAndMinutes("-");
|
ch.TotalPaidLeave = new TimeSpan(totalPaidLeaveTimeSpans.Sum(x => x.Ticks)).ToFarsiDaysAndHoursAndMinutes("-");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (ch.TotalPaymentHide == false)
|
if (ch.TotalPaymentHide == false)
|
||||||
{
|
{
|
||||||
ch.TotalClaims = "";
|
ch.TotalClaims = "";
|
||||||
ch.TotalDeductions = "";
|
ch.TotalDeductions = "";
|
||||||
ch.TotalPayment = "";
|
ch.TotalPayment = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch.HasRollCall)
|
if (ch.HasRollCall)
|
||||||
ch.MonthlyRollCall = _rollCallRepository.GetEmployeeRollCallsForMonth(ch.EmployeeId, ch.WorkshopId, ch.ContractStartGr, ch.ContractEndGr);
|
ch.MonthlyRollCall = _rollCallRepository.GetEmployeeRollCallsForMonth(ch.EmployeeId, ch.WorkshopId,
|
||||||
|
ch.ContractStartGr, ch.ContractEndGr);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ch.CreateWorkingHoursTemp.ContractStartGr = ch.ContractStartGr;
|
ch.CreateWorkingHoursTemp.ContractStartGr = ch.ContractStartGr;
|
||||||
@@ -1519,12 +1510,15 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
ch.CreateWorkingHoursTemp.ContractEnd = ch.ContractEndGr.ToFarsi();
|
ch.CreateWorkingHoursTemp.ContractEnd = ch.ContractEndGr.ToFarsi();
|
||||||
ch.CreateWorkingHoursTemp.EmployeeId = ch.EmployeeId;
|
ch.CreateWorkingHoursTemp.EmployeeId = ch.EmployeeId;
|
||||||
ch.CreateWorkingHoursTemp.WorkshopId = ch.WorkshopId;
|
ch.CreateWorkingHoursTemp.WorkshopId = ch.WorkshopId;
|
||||||
ch.MonthlyRollCall = ConvertStaticToRollCall(ch.CreateWorkingHoursTemp, workshopName.WorkshopHolidayWorking);
|
ch.MonthlyRollCall =
|
||||||
|
ConvertStaticToRollCall(ch.CreateWorkingHoursTemp, workshopName.WorkshopHolidayWorking);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<CheckoutDailyRollCallViewModel> ConvertStaticToRollCall(CreateWorkingHoursTemp workingHours, bool workshopHolidayWorking)
|
private List<CheckoutDailyRollCallViewModel> ConvertStaticToRollCall(CreateWorkingHoursTemp workingHours,
|
||||||
|
bool workshopHolidayWorking)
|
||||||
{
|
{
|
||||||
var rollCalls = _rollCallMandatoryRepository.ConvertStaticHoursToRollCall(workingHours,
|
var rollCalls = _rollCallMandatoryRepository.ConvertStaticHoursToRollCall(workingHours,
|
||||||
workshopHolidayWorking);
|
workshopHolidayWorking);
|
||||||
@@ -1557,7 +1551,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
int dateRange = (int)(lastDayOfCurrentMonth - firstDayOfCurrentMonth).TotalDays + 1;
|
int dateRange = (int)(lastDayOfCurrentMonth - firstDayOfCurrentMonth).TotalDays + 1;
|
||||||
|
|
||||||
|
|
||||||
var holidays = _context.HolidayItems.Where(x => x.HolidayYear.Contains(year.ToString())).Select(x => new HolidayItemViewModel
|
var holidays = _context.HolidayItems.Where(x => x.HolidayYear.Contains(year.ToString())).Select(x =>
|
||||||
|
new HolidayItemViewModel
|
||||||
{
|
{
|
||||||
Id = x.id,
|
Id = x.id,
|
||||||
Holidaydate = x.Holidaydate.ToFarsi(),
|
Holidaydate = x.Holidaydate.ToFarsi(),
|
||||||
@@ -1570,7 +1565,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
holidays = [];
|
holidays = [];
|
||||||
|
|
||||||
//all the dates from start to end, to be compared with present days to get absent dates
|
//all the dates from start to end, to be compared with present days to get absent dates
|
||||||
var completeDaysList = Enumerable.Range(0, dateRange).Select(offset => startMonthDay.AddDays(offset).Date).ToList();
|
var completeDaysList = Enumerable.Range(0, dateRange).Select(offset => startMonthDay.AddDays(offset).Date)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
var absentRecords = completeDaysList
|
var absentRecords = completeDaysList
|
||||||
.ExceptBy(rollCalls.Select(x => x.ShiftDate.Date), y => y.Date)
|
.ExceptBy(rollCalls.Select(x => x.ShiftDate.Date), y => y.Date)
|
||||||
@@ -1596,11 +1592,13 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
|
|
||||||
var presentDays = rollCalls.GroupBy(x => x.ShiftDate.Date).Select(x =>
|
var presentDays = rollCalls.GroupBy(x => x.ShiftDate.Date).Select(x =>
|
||||||
{
|
{
|
||||||
|
|
||||||
var orderedRollcalls = x.OrderBy(y => y.ShiftDate).ToList();
|
var orderedRollcalls = x.OrderBy(y => y.ShiftDate).ToList();
|
||||||
|
|
||||||
var rollCallTimeSpanPerDay =
|
var rollCallTimeSpanPerDay =
|
||||||
new TimeSpan(x.Where(y => y.EndDate != null).Sum(y => y.ShiftEndWithoutRest == null ? (y.EndDate - y.StartDate).Value!.Ticks : (y.ShiftEndWithoutRest - y.StartDate)!.Value.Ticks));
|
new TimeSpan(x.Where(y => y.EndDate != null).Sum(y =>
|
||||||
|
y.ShiftEndWithoutRest == null
|
||||||
|
? (y.EndDate - y.StartDate).Value!.Ticks
|
||||||
|
: (y.ShiftEndWithoutRest - y.StartDate)!.Value.Ticks));
|
||||||
var breakTimePerDay = new TimeSpan(x.Sum(r => r.BreakTimeSpan.Ticks));
|
var breakTimePerDay = new TimeSpan(x.Sum(r => r.BreakTimeSpan.Ticks));
|
||||||
|
|
||||||
var firstRollCall = orderedRollcalls.FirstOrDefault();
|
var firstRollCall = orderedRollcalls.FirstOrDefault();
|
||||||
@@ -1614,7 +1612,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
secondRCEndDate = secondRollCall.ShiftEndWithoutRest ?? secondRollCall.EndDate;
|
secondRCEndDate = secondRollCall.ShiftEndWithoutRest ?? secondRollCall.EndDate;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return new CheckoutDailyRollCallViewModel()
|
return new CheckoutDailyRollCallViewModel()
|
||||||
{
|
{
|
||||||
StartDate1 = firstRollCall?.StartDate?.ToString("HH:mm") ?? "",
|
StartDate1 = firstRollCall?.StartDate?.ToString("HH:mm") ?? "",
|
||||||
@@ -1686,12 +1683,15 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
{
|
{
|
||||||
return new List<CheckoutViewModel>();
|
return new List<CheckoutViewModel>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var employers =
|
var employers =
|
||||||
_context.Employers.Where(x => x.ContractingPartyId == contracingPartyAcc.PersonalContractingPartyId).Select(x => x.id).ToList();
|
_context.Employers.Where(x => x.ContractingPartyId == contracingPartyAcc.PersonalContractingPartyId)
|
||||||
|
.Select(x => x.id).ToList();
|
||||||
if (employers.Count < 1)
|
if (employers.Count < 1)
|
||||||
{
|
{
|
||||||
return new List<CheckoutViewModel>();
|
return new List<CheckoutViewModel>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var workshopIds = _context.WorkshopEmployers.Where(x => employers.Contains(x.EmployerId))
|
var workshopIds = _context.WorkshopEmployers.Where(x => employers.Contains(x.EmployerId))
|
||||||
.Select(x => x.WorkshopId).ToList();
|
.Select(x => x.WorkshopId).ToList();
|
||||||
var checkValid = workshopIds.Any(x => x == searchModel.WorkshopId);
|
var checkValid = workshopIds.Any(x => x == searchModel.WorkshopId);
|
||||||
@@ -1699,7 +1699,9 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
{
|
{
|
||||||
return new List<CheckoutViewModel>();
|
return new List<CheckoutViewModel>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
var query = _context.CheckoutSet.Include(w => w.CheckoutWarningMessageList)
|
var query = _context.CheckoutSet.Include(w => w.CheckoutWarningMessageList)
|
||||||
.AsSplitQuery().Select(x => new CheckoutViewModel()
|
.AsSplitQuery().Select(x => new CheckoutViewModel()
|
||||||
{
|
{
|
||||||
@@ -1741,9 +1743,7 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
{
|
{
|
||||||
WarningMessage = wm.WarningMessage,
|
WarningMessage = wm.WarningMessage,
|
||||||
TypeOfCheckoutWarning = wm.TypeOfCheckoutWarning,
|
TypeOfCheckoutWarning = wm.TypeOfCheckoutWarning,
|
||||||
|
|
||||||
}).ToList()
|
}).ToList()
|
||||||
|
|
||||||
}).Where(x => x.WorkshopId == searchModel.WorkshopId);
|
}).Where(x => x.WorkshopId == searchModel.WorkshopId);
|
||||||
if (searchModel.EmployeeId > 0)
|
if (searchModel.EmployeeId > 0)
|
||||||
{
|
{
|
||||||
@@ -1857,16 +1857,20 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
default:
|
default:
|
||||||
y2 = $"{searchModel.Year}/{searchModel.Month}/29";
|
y2 = $"{searchModel.Year}/{searchModel.Month}/29";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var start = y.ToGeorgianDateTime();
|
var start = y.ToGeorgianDateTime();
|
||||||
var end = y2.ToGeorgianDateTime();
|
var end = y2.ToGeorgianDateTime();
|
||||||
|
|
||||||
query = query.Where(x => x.ContractStartGr >= start && x.ContractStartGr < end && x.ContractEndGr > start && x.ContractEndGr <= end ||
|
query = query.Where(x =>
|
||||||
x.ContractStartGr <= start && x.ContractEndGr >= end || start <= x.ContractStartGr && end > x.ContractStartGr || end >= x.ContractEndGr && start < x.ContractEndGr);
|
x.ContractStartGr >= start && x.ContractStartGr < end && x.ContractEndGr > start &&
|
||||||
|
x.ContractEndGr <= end ||
|
||||||
|
x.ContractStartGr <= start && x.ContractEndGr >= end ||
|
||||||
|
start <= x.ContractStartGr && end > x.ContractStartGr ||
|
||||||
|
end >= x.ContractEndGr && start < x.ContractEndGr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchModel.SearchAll)
|
if (searchModel.SearchAll)
|
||||||
return query.OrderByDescending(x => x.Id).ToList();
|
return query.OrderByDescending(x => x.Id).ToList();
|
||||||
switch (searchModel.Sorting)
|
switch (searchModel.Sorting)
|
||||||
@@ -1897,8 +1901,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
break;
|
break;
|
||||||
default: return query.OrderByDescending(x => x.Id).Skip(searchModel.PageIndex).Take(30).ToList();
|
default: return query.OrderByDescending(x => x.Id).Skip(searchModel.PageIndex).Take(30).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -1928,12 +1930,10 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
var checkout = _context.CheckoutSet.Where(x => x.id == id)?.FirstOrDefault();
|
var checkout = _context.CheckoutSet.Where(x => x.id == id)?.FirstOrDefault();
|
||||||
_context.CheckoutSet.Remove(checkout);
|
_context.CheckoutSet.Remove(checkout);
|
||||||
_context.SaveChanges();
|
_context.SaveChanges();
|
||||||
return op.Succcedded(-1, "حذف با موفقیت انجام شد.");
|
return op.Succcedded(-1, "حذف با موفقیت انجام شد.");
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
@@ -1951,6 +1951,7 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
notRemoveList.Add(item);
|
notRemoveList.Add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return notRemoveList;
|
return notRemoveList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2010,7 +2011,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
// );
|
// );
|
||||||
|
|
||||||
var checkouts =
|
var checkouts =
|
||||||
_context.CheckoutSet.Include(w=>w.CheckoutWarningMessageList).Where(x => workshopAcounts.Contains(x.WorkshopId))
|
_context.CheckoutSet.Include(w => w.CheckoutWarningMessageList)
|
||||||
|
.Where(x => workshopAcounts.Contains(x.WorkshopId))
|
||||||
.Join(_context.Workshops.AsSplitQuery(),
|
.Join(_context.Workshops.AsSplitQuery(),
|
||||||
ch => ch.WorkshopId,
|
ch => ch.WorkshopId,
|
||||||
workshop => workshop.id,
|
workshop => workshop.id,
|
||||||
@@ -2033,7 +2035,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
{
|
{
|
||||||
res.ch,
|
res.ch,
|
||||||
res.workshop,
|
res.workshop,
|
||||||
option = _context.EmployeeComputeOptionsSet.FirstOrDefault(x=>x.WorkshopId == res.ch.WorkshopId &&x.EmployeeId == res.ch.EmployeeId),
|
option = _context.EmployeeComputeOptionsSet.FirstOrDefault(x =>
|
||||||
|
x.WorkshopId == res.ch.WorkshopId && x.EmployeeId == res.ch.EmployeeId),
|
||||||
res.workshopEmployer,
|
res.workshopEmployer,
|
||||||
contractingParty = _context.PersonalContractingParties
|
contractingParty = _context.PersonalContractingParties
|
||||||
.Include(p => p.Employers)
|
.Include(p => p.Employers)
|
||||||
@@ -2050,15 +2053,18 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
hasEmployeeOrWorkshpSearch = true;
|
hasEmployeeOrWorkshpSearch = true;
|
||||||
checkouts = checkouts.Where(x => x.ch.WorkshopId == searchModel.WorkshopId);
|
checkouts = checkouts.Where(x => x.ch.WorkshopId == searchModel.WorkshopId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchModel.EmployeeId != 0)
|
if (searchModel.EmployeeId != 0)
|
||||||
{
|
{
|
||||||
hasEmployeeOrWorkshpSearch = true;
|
hasEmployeeOrWorkshpSearch = true;
|
||||||
checkouts = checkouts.Where(x => x.ch.EmployeeId == searchModel.EmployeeId);
|
checkouts = checkouts.Where(x => x.ch.EmployeeId == searchModel.EmployeeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchModel.EmployerId != 0)
|
if (searchModel.EmployerId != 0)
|
||||||
{
|
{
|
||||||
hasEmployeeOrWorkshpSearch = true;
|
hasEmployeeOrWorkshpSearch = true;
|
||||||
checkouts = checkouts.Where(x => x.contractingParty.Employers.Select(c => c.id).Contains(searchModel.EmployerId));
|
checkouts = checkouts.Where(x =>
|
||||||
|
x.contractingParty.Employers.Select(c => c.id).Contains(searchModel.EmployerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(searchModel.ContractNo))
|
if (!string.IsNullOrWhiteSpace(searchModel.ContractNo))
|
||||||
@@ -2068,7 +2074,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//if (searchModel.IsActiveString == null)
|
//if (searchModel.IsActiveString == null)
|
||||||
//{
|
//{
|
||||||
// checkouts = checkouts.Where(x => x.ch.IsActiveString == "true");
|
// checkouts = checkouts.Where(x => x.ch.IsActiveString == "true");
|
||||||
@@ -2100,7 +2105,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
checkouts = checkouts.Where(x => x.ch.ContractStart >= startyearGr && x.ch.ContractEnd <= endYearGr);
|
checkouts = checkouts.Where(x => x.ch.ContractStart >= startyearGr && x.ch.ContractEnd <= endYearGr);
|
||||||
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
||||||
checkouts = checkouts.OrderByDescending(x => x.ch.ContractEnd);
|
checkouts = checkouts.OrderByDescending(x => x.ch.ContractEnd);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrWhiteSpace(searchModel.Year) && !string.IsNullOrWhiteSpace(searchModel.Month) &&
|
else if (!string.IsNullOrWhiteSpace(searchModel.Year) && !string.IsNullOrWhiteSpace(searchModel.Month) &&
|
||||||
string.IsNullOrWhiteSpace(searchModel.ContractStart) &&
|
string.IsNullOrWhiteSpace(searchModel.ContractStart) &&
|
||||||
@@ -2220,7 +2224,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
endDate >= x.ch.ContractEnd && startDate < x.ch.ContractEnd);
|
endDate >= x.ch.ContractEnd && startDate < x.ch.ContractEnd);
|
||||||
//if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
//if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
||||||
// checkouts = checkouts.OrderBy(x => x.ch.PersonnelCodeInt);
|
// checkouts = checkouts.OrderBy(x => x.ch.PersonnelCodeInt);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrWhiteSpace(searchModel.ContractStart) &&
|
else if (!string.IsNullOrWhiteSpace(searchModel.ContractStart) &&
|
||||||
!string.IsNullOrWhiteSpace(searchModel.ContractEnd) &&
|
!string.IsNullOrWhiteSpace(searchModel.ContractEnd) &&
|
||||||
@@ -2240,22 +2243,20 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
if (!string.IsNullOrEmpty(searchModel.EmployeeName))
|
if (!string.IsNullOrEmpty(searchModel.EmployeeName))
|
||||||
{
|
{
|
||||||
hasSearch = true;
|
hasSearch = true;
|
||||||
var employeeList = _context.Employees.Where(x => (!string.IsNullOrEmpty(x.FName) && x.FName.StartsWith(searchModel.EmployeeName)) ||
|
var employeeList = _context.Employees.Where(x =>
|
||||||
(!string.IsNullOrEmpty(x.LName) && x.LName.StartsWith(searchModel.EmployeeName))).Select(x => x.id).ToList();
|
(!string.IsNullOrEmpty(x.FName) && x.FName.StartsWith(searchModel.EmployeeName)) ||
|
||||||
|
(!string.IsNullOrEmpty(x.LName) && x.LName.StartsWith(searchModel.EmployeeName))).Select(x => x.id)
|
||||||
|
.ToList();
|
||||||
checkouts = checkouts.Where(x => employeeList.Contains(x.ch.EmployeeId));
|
checkouts = checkouts.Where(x => employeeList.Contains(x.ch.EmployeeId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
if (!hasSearch && !hasEmployeeOrWorkshpSearch)
|
if (!hasSearch && !hasEmployeeOrWorkshpSearch)
|
||||||
{
|
{
|
||||||
|
|
||||||
return checkouts.Select(x => new CheckoutViewModel()
|
return checkouts.Select(x => new CheckoutViewModel()
|
||||||
{
|
{
|
||||||
|
|
||||||
Id = x.ch.id,
|
Id = x.ch.id,
|
||||||
EmployeeFullName = x.ch.EmployeeFullName,
|
EmployeeFullName = x.ch.EmployeeFullName,
|
||||||
ContractStart = x.ch.ContractStart.ToFarsi(),
|
ContractStart = x.ch.ContractStart.ToFarsi(),
|
||||||
@@ -2281,26 +2282,21 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
IsBlockCantracingParty = x.contractingParty.IsBlock,
|
IsBlockCantracingParty = x.contractingParty.IsBlock,
|
||||||
HasSignCheckout = x.option != null ? x.option.SignCheckout : x.workshop.SignCheckout,
|
HasSignCheckout = x.option != null ? x.option.SignCheckout : x.workshop.SignCheckout,
|
||||||
IsUpdateNeeded = x.ch.IsUpdateNeeded,
|
IsUpdateNeeded = x.ch.IsUpdateNeeded,
|
||||||
CheckoutWarningMessageList = x.ch.CheckoutWarningMessageList.Select(wm=> new CheckoutWarningMessageModel
|
CheckoutWarningMessageList = x.ch.CheckoutWarningMessageList.Select(wm =>
|
||||||
|
new CheckoutWarningMessageModel
|
||||||
{
|
{
|
||||||
WarningMessage = wm.WarningMessage,
|
WarningMessage = wm.WarningMessage,
|
||||||
TypeOfCheckoutWarning = wm.TypeOfCheckoutWarning,
|
TypeOfCheckoutWarning = wm.TypeOfCheckoutWarning,
|
||||||
|
|
||||||
}).ToList()
|
}).ToList()
|
||||||
|
|
||||||
|
|
||||||
}).OrderByDescending(x => x.Id).Take(3000).ToList().DistinctBy(x => x.Id)
|
}).OrderByDescending(x => x.Id).Take(3000).ToList().DistinctBy(x => x.Id)
|
||||||
.OrderByDescending(x => x.Id).ThenByDescending(x => x.Year)
|
.OrderByDescending(x => x.Id).ThenByDescending(x => x.Year)
|
||||||
.ThenBy(x => x.PersonnelCodeInt)
|
.ThenBy(x => x.PersonnelCodeInt)
|
||||||
.Take(50).ToList();
|
.Take(50).ToList();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (hasSearch && !hasEmployeeOrWorkshpSearch)
|
else if (hasSearch && !hasEmployeeOrWorkshpSearch)
|
||||||
{
|
{
|
||||||
|
|
||||||
var result = checkouts.Select(x => new CheckoutViewModel()
|
var result = checkouts.Select(x => new CheckoutViewModel()
|
||||||
{
|
{
|
||||||
|
|
||||||
Id = x.ch.id,
|
Id = x.ch.id,
|
||||||
EmployeeFullName = x.ch.EmployeeFullName,
|
EmployeeFullName = x.ch.EmployeeFullName,
|
||||||
ContractStart = x.ch.ContractStart.ToFarsi(),
|
ContractStart = x.ch.ContractStart.ToFarsi(),
|
||||||
@@ -2326,19 +2322,17 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
IsBlockCantracingParty = x.contractingParty.IsBlock,
|
IsBlockCantracingParty = x.contractingParty.IsBlock,
|
||||||
HasSignCheckout = x.option != null ? x.option.SignCheckout : x.workshop.SignCheckout,
|
HasSignCheckout = x.option != null ? x.option.SignCheckout : x.workshop.SignCheckout,
|
||||||
IsUpdateNeeded = x.ch.IsUpdateNeeded,
|
IsUpdateNeeded = x.ch.IsUpdateNeeded,
|
||||||
CheckoutWarningMessageList = x.ch.CheckoutWarningMessageList.Select(wm => new CheckoutWarningMessageModel
|
CheckoutWarningMessageList = x.ch.CheckoutWarningMessageList.Select(wm =>
|
||||||
|
new CheckoutWarningMessageModel
|
||||||
{
|
{
|
||||||
WarningMessage = wm.WarningMessage,
|
WarningMessage = wm.WarningMessage,
|
||||||
TypeOfCheckoutWarning = wm.TypeOfCheckoutWarning,
|
TypeOfCheckoutWarning = wm.TypeOfCheckoutWarning,
|
||||||
|
|
||||||
}).ToList()
|
}).ToList()
|
||||||
|
|
||||||
}).OrderByDescending(x => x.Id)
|
}).OrderByDescending(x => x.Id)
|
||||||
.GroupBy(x => x.Id)
|
.GroupBy(x => x.Id)
|
||||||
.Select(x => x.First());
|
.Select(x => x.First());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if ((string.IsNullOrWhiteSpace(searchModel.ContractStart) ||
|
if ((string.IsNullOrWhiteSpace(searchModel.ContractStart) ||
|
||||||
string.IsNullOrWhiteSpace(searchModel.ContractEnd)) && string.IsNullOrWhiteSpace(searchModel.Month))
|
string.IsNullOrWhiteSpace(searchModel.ContractEnd)) && string.IsNullOrWhiteSpace(searchModel.Month))
|
||||||
{
|
{
|
||||||
@@ -2348,7 +2342,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
.OrderByDescending(x => x.ContractStartGr).ToList();
|
.OrderByDescending(x => x.ContractStartGr).ToList();
|
||||||
}
|
}
|
||||||
else if ((string.IsNullOrWhiteSpace(searchModel.ContractStart) ||
|
else if ((string.IsNullOrWhiteSpace(searchModel.ContractStart) ||
|
||||||
string.IsNullOrWhiteSpace(searchModel.ContractEnd)) && !string.IsNullOrWhiteSpace(searchModel.Month) && !string.IsNullOrWhiteSpace(searchModel.Year))
|
string.IsNullOrWhiteSpace(searchModel.ContractEnd)) &&
|
||||||
|
!string.IsNullOrWhiteSpace(searchModel.Month) && !string.IsNullOrWhiteSpace(searchModel.Year))
|
||||||
{
|
{
|
||||||
//اگر فقط سال و ماه رو سرچ کرد
|
//اگر فقط سال و ماه رو سرچ کرد
|
||||||
return result.Take(300)
|
return result.Take(300)
|
||||||
@@ -2366,14 +2361,11 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
|
|
||||||
return result.ToList().OrderByDescending(x => x.Id)
|
return result.ToList().OrderByDescending(x => x.Id)
|
||||||
.ThenByDescending(x => x.Year).ThenBy(x => x.PersonnelCodeInt).ToList();
|
.ThenByDescending(x => x.Year).ThenBy(x => x.PersonnelCodeInt).ToList();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (hasEmployeeOrWorkshpSearch && !hasSearch)
|
else if (hasEmployeeOrWorkshpSearch && !hasSearch)
|
||||||
{
|
{
|
||||||
|
|
||||||
return checkouts.Select(x => new CheckoutViewModel()
|
return checkouts.Select(x => new CheckoutViewModel()
|
||||||
{
|
{
|
||||||
|
|
||||||
Id = x.ch.id,
|
Id = x.ch.id,
|
||||||
EmployeeFullName = x.ch.EmployeeFullName,
|
EmployeeFullName = x.ch.EmployeeFullName,
|
||||||
ContractStart = x.ch.ContractStart.ToFarsi(),
|
ContractStart = x.ch.ContractStart.ToFarsi(),
|
||||||
@@ -2399,13 +2391,12 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
IsBlockCantracingParty = x.contractingParty.IsBlock,
|
IsBlockCantracingParty = x.contractingParty.IsBlock,
|
||||||
HasSignCheckout = x.option != null ? x.option.SignCheckout : x.workshop.SignCheckout,
|
HasSignCheckout = x.option != null ? x.option.SignCheckout : x.workshop.SignCheckout,
|
||||||
IsUpdateNeeded = x.ch.IsUpdateNeeded,
|
IsUpdateNeeded = x.ch.IsUpdateNeeded,
|
||||||
CheckoutWarningMessageList = x.ch.CheckoutWarningMessageList.Select(wm => new CheckoutWarningMessageModel
|
CheckoutWarningMessageList = x.ch.CheckoutWarningMessageList.Select(wm =>
|
||||||
|
new CheckoutWarningMessageModel
|
||||||
{
|
{
|
||||||
WarningMessage = wm.WarningMessage,
|
WarningMessage = wm.WarningMessage,
|
||||||
TypeOfCheckoutWarning = wm.TypeOfCheckoutWarning,
|
TypeOfCheckoutWarning = wm.TypeOfCheckoutWarning,
|
||||||
|
|
||||||
}).ToList()
|
}).ToList()
|
||||||
|
|
||||||
}).GroupBy(x => x.Id).Select(x => x.First()).ToList()
|
}).GroupBy(x => x.Id).Select(x => x.First()).ToList()
|
||||||
.OrderByDescending(x => x.ContractStartGr).ToList();
|
.OrderByDescending(x => x.ContractStartGr).ToList();
|
||||||
}
|
}
|
||||||
@@ -2413,7 +2404,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
{
|
{
|
||||||
return checkouts.Select(x => new CheckoutViewModel()
|
return checkouts.Select(x => new CheckoutViewModel()
|
||||||
{
|
{
|
||||||
|
|
||||||
Id = x.ch.id,
|
Id = x.ch.id,
|
||||||
EmployeeFullName = x.ch.EmployeeFullName,
|
EmployeeFullName = x.ch.EmployeeFullName,
|
||||||
ContractStart = x.ch.ContractStart.ToFarsi(),
|
ContractStart = x.ch.ContractStart.ToFarsi(),
|
||||||
@@ -2439,26 +2429,21 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
IsBlockCantracingParty = x.contractingParty.IsBlock,
|
IsBlockCantracingParty = x.contractingParty.IsBlock,
|
||||||
HasSignCheckout = x.option != null ? x.option.SignCheckout : x.workshop.SignCheckout,
|
HasSignCheckout = x.option != null ? x.option.SignCheckout : x.workshop.SignCheckout,
|
||||||
IsUpdateNeeded = x.ch.IsUpdateNeeded,
|
IsUpdateNeeded = x.ch.IsUpdateNeeded,
|
||||||
CheckoutWarningMessageList = x.ch.CheckoutWarningMessageList.Select(wm => new CheckoutWarningMessageModel
|
CheckoutWarningMessageList = x.ch.CheckoutWarningMessageList.Select(wm =>
|
||||||
|
new CheckoutWarningMessageModel
|
||||||
{
|
{
|
||||||
WarningMessage = wm.WarningMessage,
|
WarningMessage = wm.WarningMessage,
|
||||||
TypeOfCheckoutWarning = wm.TypeOfCheckoutWarning,
|
TypeOfCheckoutWarning = wm.TypeOfCheckoutWarning,
|
||||||
|
|
||||||
}).ToList()
|
}).ToList()
|
||||||
|
|
||||||
}).GroupBy(x => x.Id)
|
}).GroupBy(x => x.Id)
|
||||||
.Select(x => x.First()).ToList()
|
.Select(x => x.First()).ToList()
|
||||||
.OrderByDescending(x => x.Id)
|
.OrderByDescending(x => x.Id)
|
||||||
.ThenByDescending(x => x.Year).ThenBy(x => x.PersonnelCodeInt).ToList();
|
.ThenByDescending(x => x.Year).ThenBy(x => x.PersonnelCodeInt).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
public async Task<List<CheckoutViewModel>> SearchForMainCheckout(CheckoutSearchModel searchModel)
|
public async Task<List<CheckoutViewModel>> SearchForMainCheckout(CheckoutSearchModel searchModel)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
bool hasSearch = false;
|
bool hasSearch = false;
|
||||||
bool hasEmployeeOrWorkshpSearch = false;
|
bool hasEmployeeOrWorkshpSearch = false;
|
||||||
//List<CheckoutViewModel> query = null;
|
//List<CheckoutViewModel> query = null;
|
||||||
@@ -2476,11 +2461,8 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
.Select(x => x.WorkshopId).ToList();
|
.Select(x => x.WorkshopId).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var query = _context.CheckoutSet.Select(x => new CheckoutViewModel()
|
var query = _context.CheckoutSet.Select(x => new CheckoutViewModel()
|
||||||
{
|
{
|
||||||
|
|
||||||
Id = x.id,
|
Id = x.id,
|
||||||
EmployeeFullName = x.EmployeeFullName,
|
EmployeeFullName = x.EmployeeFullName,
|
||||||
//var start = ;
|
//var start = ;
|
||||||
@@ -2503,13 +2485,9 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
IsActiveString = x.IsActiveString,
|
IsActiveString = x.IsActiveString,
|
||||||
Signature = x.Signature,
|
Signature = x.Signature,
|
||||||
CreationDate = x.CreationDate,
|
CreationDate = x.CreationDate,
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(searchModel.ContractNo) && searchModel.ContractId != 0)
|
if (!string.IsNullOrWhiteSpace(searchModel.ContractNo) && searchModel.ContractId != 0)
|
||||||
query = query.Where(x =>
|
query = query.Where(x =>
|
||||||
x.ContractNo == searchModel.ContractNo && x.ContractId == searchModel.ContractId);
|
x.ContractNo == searchModel.ContractNo && x.ContractId == searchModel.ContractId);
|
||||||
@@ -2518,11 +2496,13 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
hasEmployeeOrWorkshpSearch = true;
|
hasEmployeeOrWorkshpSearch = true;
|
||||||
query = query.Where(x => x.WorkshopId == searchModel.WorkshopId);
|
query = query.Where(x => x.WorkshopId == searchModel.WorkshopId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchModel.EmployeeId != 0)
|
if (searchModel.EmployeeId != 0)
|
||||||
{
|
{
|
||||||
hasEmployeeOrWorkshpSearch = true;
|
hasEmployeeOrWorkshpSearch = true;
|
||||||
query = query.Where(x => x.EmployeeId == searchModel.EmployeeId);
|
query = query.Where(x => x.EmployeeId == searchModel.EmployeeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchModel.EmployerId != 0)
|
if (searchModel.EmployerId != 0)
|
||||||
{
|
{
|
||||||
hasEmployeeOrWorkshpSearch = true;
|
hasEmployeeOrWorkshpSearch = true;
|
||||||
@@ -2566,7 +2546,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
query = query.Where(x => x.ContractStartGr >= startyearGr && x.ContractEndGr <= endYearGr);
|
query = query.Where(x => x.ContractStartGr >= startyearGr && x.ContractEndGr <= endYearGr);
|
||||||
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
||||||
query = query.OrderByDescending(x => x.ContractEndGr).ThenBy(x => x.PersonnelCodeInt);
|
query = query.OrderByDescending(x => x.ContractEndGr).ThenBy(x => x.PersonnelCodeInt);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrWhiteSpace(searchModel.Year) && !string.IsNullOrWhiteSpace(searchModel.Month) &&
|
else if (!string.IsNullOrWhiteSpace(searchModel.Year) && !string.IsNullOrWhiteSpace(searchModel.Month) &&
|
||||||
string.IsNullOrWhiteSpace(searchModel.ContractStart) &&
|
string.IsNullOrWhiteSpace(searchModel.ContractStart) &&
|
||||||
@@ -2686,7 +2665,6 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
endDate >= x.ContractEndGr && startDate < x.ContractEndGr);
|
endDate >= x.ContractEndGr && startDate < x.ContractEndGr);
|
||||||
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
||||||
query = query.OrderBy(x => x.PersonnelCodeInt);
|
query = query.OrderBy(x => x.PersonnelCodeInt);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrWhiteSpace(searchModel.ContractStart) &&
|
else if (!string.IsNullOrWhiteSpace(searchModel.ContractStart) &&
|
||||||
!string.IsNullOrWhiteSpace(searchModel.ContractEnd) &&
|
!string.IsNullOrWhiteSpace(searchModel.ContractEnd) &&
|
||||||
@@ -2701,16 +2679,18 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
|
|
||||||
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
if (searchModel.WorkshopId > 0 || searchModel.EmployeeId > 0 || searchModel.EmployerId > 0)
|
||||||
query = query.OrderByDescending(x => x.ContractEndGr).ThenBy(x => x.PersonnelCodeInt);
|
query = query.OrderByDescending(x => x.ContractEndGr).ThenBy(x => x.PersonnelCodeInt);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(searchModel.EmployeeName))
|
if (!string.IsNullOrEmpty(searchModel.EmployeeName))
|
||||||
{
|
{
|
||||||
hasSearch = true;
|
hasSearch = true;
|
||||||
var employeeList = _context.Employees.Where(x => (!string.IsNullOrEmpty(x.FName) && x.FName.StartsWith(searchModel.EmployeeName)) ||
|
var employeeList = _context.Employees.Where(x =>
|
||||||
(!string.IsNullOrEmpty(x.LName) && x.LName.StartsWith(searchModel.EmployeeName))).Select(x => x.id).ToList();
|
(!string.IsNullOrEmpty(x.FName) && x.FName.StartsWith(searchModel.EmployeeName)) ||
|
||||||
|
(!string.IsNullOrEmpty(x.LName) && x.LName.StartsWith(searchModel.EmployeeName))).Select(x => x.id)
|
||||||
|
.ToList();
|
||||||
query = query.Where(x => employeeList.Contains(x.EmployeeId));
|
query = query.Where(x => employeeList.Contains(x.EmployeeId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSearch)
|
if (hasSearch)
|
||||||
return query.OrderByDescending(x => x.Id)
|
return query.OrderByDescending(x => x.Id)
|
||||||
.ThenByDescending(x => x.Year).ThenBy(x => x.PersonnelCodeInt).ToList();
|
.ThenByDescending(x => x.Year).ThenBy(x => x.PersonnelCodeInt).ToList();
|
||||||
@@ -2721,22 +2701,17 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
.ThenByDescending(x => x.Year).ThenBy(x => x.PersonnelCodeInt).Take(50).ToList();
|
.ThenByDescending(x => x.Year).ThenBy(x => x.PersonnelCodeInt).Take(50).ToList();
|
||||||
|
|
||||||
// Console.WriteLine("return" + watch.Elapsed);
|
// Console.WriteLine("return" + watch.Elapsed);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Pooya
|
#region Pooya
|
||||||
|
|
||||||
|
public List<(long EmployeeId, DateTime CheckoutStart, DateTime CheckoutEnd)>
|
||||||
public List<(long EmployeeId, DateTime CheckoutStart, DateTime CheckoutEnd)> GetLastCheckoutsByWorkshopIdForWorkFlow(long workshopId, DateTime start, DateTime end)
|
GetLastCheckoutsByWorkshopIdForWorkFlow(long workshopId, DateTime start, DateTime end)
|
||||||
{
|
{
|
||||||
|
return _context.CheckoutSet.AsSplitQuery().Where(x =>
|
||||||
|
x.ContractEnd.Date >= start && x.ContractStart.Date <= end && x.WorkshopId == workshopId).Select(x => new
|
||||||
|
|
||||||
return _context.CheckoutSet.AsSplitQuery().Where(x => x.ContractEnd.Date >= start && x.ContractStart.Date <= end && x.WorkshopId == workshopId).Select(x => new
|
|
||||||
{
|
{
|
||||||
EmployeeId = x.EmployeeId,
|
EmployeeId = x.EmployeeId,
|
||||||
CheckoutEnd = x.ContractEnd,
|
CheckoutEnd = x.ContractEnd,
|
||||||
@@ -2751,5 +2726,88 @@ public class CheckoutRepository : RepositoryBase<long, Checkout>, ICheckoutRepos
|
|||||||
x.ContractEnd >= inDate);
|
x.ContractEnd >= inDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<PagedResult<CheckoutListClientDto>> GetListForClient(long workshopId,
|
||||||
|
CheckoutListClientSearchModel searchModel)
|
||||||
|
{
|
||||||
|
var query = _context.CheckoutSet.Where(x => x.WorkshopId == workshopId);
|
||||||
|
if (searchModel.EmployeeId is > 0)
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.EmployeeId == searchModel.EmployeeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(searchModel.StartDate) && !string.IsNullOrWhiteSpace(searchModel.EndDate))
|
||||||
|
{
|
||||||
|
if (!searchModel.StartDate.TryToGeorgianDateTime(out var startDateGr))
|
||||||
|
throw new BadRequestException("تاریخ شروع جستجو نامعتبر است");
|
||||||
|
|
||||||
|
if (!searchModel.EndDate.TryToGeorgianDateTime(out var endDateGr))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("تاریخ پایان جستجو نامعتبر است");
|
||||||
|
}
|
||||||
|
|
||||||
|
query = query.Where(x => x.ContractStart <= endDateGr && x.ContractEnd >= startDateGr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(searchModel.Year))
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.Year == searchModel.Year);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(searchModel.Month))
|
||||||
|
{
|
||||||
|
var searchedMonth = Convert.ToInt32(searchModel.Month).ToFarsiMonthByIntNumber();
|
||||||
|
|
||||||
|
query = query.Where(x => x.Month == searchedMonth);
|
||||||
|
}
|
||||||
|
|
||||||
|
query = searchModel.OrderType switch
|
||||||
|
{
|
||||||
|
CheckoutClientListOrderType.ByCheckoutCreationDate =>
|
||||||
|
query.OrderBy(x => x.CreationDate),
|
||||||
|
|
||||||
|
CheckoutClientListOrderType.ByCheckoutStartDate =>
|
||||||
|
query.OrderBy(x => x.ContractStart),
|
||||||
|
|
||||||
|
CheckoutClientListOrderType.ByCheckoutStartDateDescending =>
|
||||||
|
query.OrderByDescending(x => x.ContractStart),
|
||||||
|
|
||||||
|
CheckoutClientListOrderType.ByPersonnelCode =>
|
||||||
|
query.OrderBy(x => x.PersonnelCode),
|
||||||
|
|
||||||
|
CheckoutClientListOrderType.ByPersonnelCodeDescending =>
|
||||||
|
query.OrderByDescending(x => x.PersonnelCode),
|
||||||
|
|
||||||
|
CheckoutClientListOrderType.BySignedCheckout =>
|
||||||
|
query.OrderByDescending(x => x.Signature == "1"),
|
||||||
|
|
||||||
|
CheckoutClientListOrderType.ByUnSignedCheckout =>
|
||||||
|
query.OrderBy(x => x.Signature == "1"),
|
||||||
|
|
||||||
|
_ => query.OrderByDescending(x => x.id)
|
||||||
|
};
|
||||||
|
|
||||||
|
var list =await query.ApplyPagination(searchModel.PageIndex, searchModel.PageSize).ToListAsync();
|
||||||
|
|
||||||
|
var resList = list.Select(x => new CheckoutListClientDto()
|
||||||
|
{
|
||||||
|
Id = x.id,
|
||||||
|
ContractStart = x.ContractStart.ToFarsi(),
|
||||||
|
ContractEnd = x.ContractEnd.ToFarsi(),
|
||||||
|
Year = x.Year,
|
||||||
|
Month = x.Month,
|
||||||
|
ContractNo = x.ContractNo,
|
||||||
|
EmployeeName = x.EmployeeFullName,
|
||||||
|
Signature = x.Signature == "1"
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
var res = new PagedResult<CheckoutListClientDto>
|
||||||
|
{
|
||||||
|
TotalCount = await query.CountAsync(),
|
||||||
|
List = resList
|
||||||
|
};
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,16 @@
|
|||||||
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;
|
||||||
|
|
||||||
@@ -15,6 +22,260 @@ 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)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -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 = "";
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ EndProject
|
|||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackgroundInstitutionContract.Task", "BackgroundInstitutionContract\BackgroundInstitutionContract.Task\BackgroundInstitutionContract.Task.csproj", "{F78FBB92-294B-88BA-168D-F0C578B0D7D6}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackgroundInstitutionContract.Task", "BackgroundInstitutionContract\BackgroundInstitutionContract.Task\BackgroundInstitutionContract.Task.csproj", "{F78FBB92-294B-88BA-168D-F0C578B0D7D6}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProgramManager", "ProgramManager", "{67AFF7B6-4C4F-464C-A90D-9BDB644D83A9}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProgramManager", "ProgramManager", "{67AFF7B6-4C4F-464C-A90D-9BDB644D83A9}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
ProgramManager\appsettings.FileStorage.json = ProgramManager\appsettings.FileStorage.json
|
||||||
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{48F6F6A5-7340-42F8-9216-BEB7A4B7D5A1}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{48F6F6A5-7340-42F8-9216-BEB7A4B7D5A1}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ using Company.Domain.HolidayItemAgg;
|
|||||||
using Company.Domain.InstitutionContractAgg;
|
using Company.Domain.InstitutionContractAgg;
|
||||||
using Company.Domain.InstitutionContractContactInfoAgg;
|
using Company.Domain.InstitutionContractContactInfoAgg;
|
||||||
using Company.Domain.InstitutionContractExtensionTempAgg;
|
using Company.Domain.InstitutionContractExtensionTempAgg;
|
||||||
|
using Company.Domain.InstitutionContractSendFlagAgg;
|
||||||
using Company.Domain.InstitutionPlanAgg;
|
using Company.Domain.InstitutionPlanAgg;
|
||||||
using Company.Domain.InsuranceAgg;
|
using Company.Domain.InsuranceAgg;
|
||||||
using Company.Domain.InsuranceEmployeeInfoAgg;
|
using Company.Domain.InsuranceEmployeeInfoAgg;
|
||||||
@@ -123,6 +124,7 @@ using Company.Domain.ZoneAgg;
|
|||||||
using CompanyManagement.Infrastructure.Excel.SalaryAid;
|
using CompanyManagement.Infrastructure.Excel.SalaryAid;
|
||||||
using CompanyManagement.Infrastructure.Mongo.EmployeeFaceEmbeddingRepo;
|
using CompanyManagement.Infrastructure.Mongo.EmployeeFaceEmbeddingRepo;
|
||||||
using CompanyManagement.Infrastructure.Mongo.InstitutionContractInsertTempRepo;
|
using CompanyManagement.Infrastructure.Mongo.InstitutionContractInsertTempRepo;
|
||||||
|
using CompanyManagement.Infrastructure.Mongo.InstitutionContractSendFlagRepo;
|
||||||
using CompanyManagment.App.Contracts.AdminMonthlyOverview;
|
using CompanyManagment.App.Contracts.AdminMonthlyOverview;
|
||||||
using CompanyManagment.App.Contracts.AndroidApkVersion;
|
using CompanyManagment.App.Contracts.AndroidApkVersion;
|
||||||
using CompanyManagment.App.Contracts.AuthorizedPerson;
|
using CompanyManagment.App.Contracts.AuthorizedPerson;
|
||||||
@@ -561,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
|
||||||
|
|
||||||
|
|
||||||
@@ -658,6 +661,9 @@ public class PersonalBootstrapper
|
|||||||
services.AddTransient<ICameraBugReportApplication, CameraBugReportApplication>();
|
services.AddTransient<ICameraBugReportApplication, CameraBugReportApplication>();
|
||||||
services.AddTransient<ICameraBugReportRepository, CameraBugReportRepository>(); // MongoDB Implementation
|
services.AddTransient<ICameraBugReportRepository, CameraBugReportRepository>(); // MongoDB Implementation
|
||||||
|
|
||||||
|
// InstitutionContractSendFlag - MongoDB
|
||||||
|
services.AddTransient<IInstitutionContractSendFlagRepository, InstitutionContractSendFlagRepository>();
|
||||||
|
|
||||||
services.AddDbContext<CompanyContext>(x => x.UseSqlServer(connectionString));
|
services.AddDbContext<CompanyContext>(x => x.UseSqlServer(connectionString));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentValidation" Version="12.1.1" />
|
<PackageReference Include="FluentValidation" Version="12.1.1" />
|
||||||
<PackageReference Include="MediatR" Version="14.0.0" />
|
<PackageReference Include="MediatR" Version="14.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -18,4 +19,10 @@
|
|||||||
<ProjectReference Include="..\..\Domain\GozareshgirProgramManager.Domain\GozareshgirProgramManager.Domain.csproj" />
|
<ProjectReference Include="..\..\Domain\GozareshgirProgramManager.Domain\GozareshgirProgramManager.Domain.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.AspNetCore.Http.Features">
|
||||||
|
<HintPath>C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\10.0.1\Microsoft.AspNetCore.Http.Features.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public record AddTaskToPhaseCommand(
|
|||||||
Guid PhaseId,
|
Guid PhaseId,
|
||||||
string Name,
|
string Name,
|
||||||
string? Description = null,
|
string? Description = null,
|
||||||
TaskPriority Priority = TaskPriority.Medium,
|
ProjectTaskPriority Priority = ProjectTaskPriority.Medium,
|
||||||
int OrderIndex = 0,
|
int OrderIndex = 0,
|
||||||
DateTime? DueDate = null
|
DateTime? DueDate = null
|
||||||
) : IBaseCommand;
|
) : IBaseCommand;
|
||||||
|
|||||||
@@ -6,35 +6,103 @@ using GozareshgirProgramManager.Domain.ProjectAgg.Repositories;
|
|||||||
|
|
||||||
namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeTaskPriority;
|
namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeTaskPriority;
|
||||||
|
|
||||||
/// <summary>
|
public record ChangeTaskPriorityCommand(
|
||||||
/// Command to change a task priority.
|
Guid Id,
|
||||||
/// </summary>
|
ProjectHierarchyLevel Level,
|
||||||
public record ChangeTaskPriorityCommand(Guid TaskId, TaskPriority Priority) : IBaseCommand;
|
ProjectTaskPriority Priority
|
||||||
|
) : IBaseCommand;
|
||||||
|
|
||||||
public class ChangeTaskPriorityCommandHandler : IBaseCommandHandler<ChangeTaskPriorityCommand>
|
public class ChangeTaskPriorityCommandHandler : IBaseCommandHandler<ChangeTaskPriorityCommand>
|
||||||
{
|
{
|
||||||
private readonly IProjectTaskRepository _taskRepository;
|
private readonly IProjectTaskRepository _taskRepository;
|
||||||
|
private readonly IProjectPhaseRepository _phaseRepository;
|
||||||
|
private readonly IProjectRepository _projectRepository;
|
||||||
private readonly IUnitOfWork _unitOfWork;
|
private readonly IUnitOfWork _unitOfWork;
|
||||||
|
|
||||||
public ChangeTaskPriorityCommandHandler(IProjectTaskRepository taskRepository, IUnitOfWork unitOfWork)
|
public ChangeTaskPriorityCommandHandler(
|
||||||
|
IProjectTaskRepository taskRepository,
|
||||||
|
IProjectPhaseRepository phaseRepository,
|
||||||
|
IProjectRepository projectRepository,
|
||||||
|
IUnitOfWork unitOfWork)
|
||||||
{
|
{
|
||||||
_taskRepository = taskRepository;
|
_taskRepository = taskRepository;
|
||||||
|
_phaseRepository = phaseRepository;
|
||||||
|
_projectRepository = projectRepository;
|
||||||
_unitOfWork = unitOfWork;
|
_unitOfWork = unitOfWork;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<OperationResult> Handle(ChangeTaskPriorityCommand request, CancellationToken cancellationToken)
|
public async Task<OperationResult> Handle(ChangeTaskPriorityCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var task = await _taskRepository.GetByIdAsync(request.TaskId, cancellationToken);
|
switch (request.Level)
|
||||||
|
{
|
||||||
|
case ProjectHierarchyLevel.Task:
|
||||||
|
return await HandleTaskLevelAsync(request.Id, request.Priority, cancellationToken);
|
||||||
|
case ProjectHierarchyLevel.Phase:
|
||||||
|
return await HandlePhaseLevelAsync(request.Id, request.Priority, cancellationToken);
|
||||||
|
case ProjectHierarchyLevel.Project:
|
||||||
|
return await HandleProjectLevelAsync(request.Id, request.Priority, cancellationToken);
|
||||||
|
default:
|
||||||
|
return OperationResult.Failure("سطح نامعتبر است");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task-level priority update
|
||||||
|
private async Task<OperationResult> HandleTaskLevelAsync(Guid taskId, ProjectTaskPriority priority, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var task = await _taskRepository.GetByIdAsync(taskId, ct);
|
||||||
if (task is null)
|
if (task is null)
|
||||||
return OperationResult.NotFound("تسک یافت نشد");
|
return OperationResult.NotFound("تسک یافت نشد");
|
||||||
|
|
||||||
// Idempotent: if already same priority, skip extra work
|
if (task.Priority != priority)
|
||||||
if (task.Priority != request.Priority)
|
|
||||||
{
|
{
|
||||||
task.SetPriority(request.Priority);
|
task.SetPriority(priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _unitOfWork.SaveChangesAsync(cancellationToken);
|
await _unitOfWork.SaveChangesAsync(ct);
|
||||||
|
return OperationResult.Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase-level bulk priority update
|
||||||
|
private async Task<OperationResult> HandlePhaseLevelAsync(Guid phaseId, ProjectTaskPriority priority, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var phase = await _phaseRepository.GetWithTasksAsync(phaseId);
|
||||||
|
if (phase is null)
|
||||||
|
return OperationResult.NotFound("فاز یافت نشد");
|
||||||
|
|
||||||
|
var tasks = phase.Tasks?.ToList() ?? new List<Domain.ProjectAgg.Entities.ProjectTask>();
|
||||||
|
foreach (var t in tasks)
|
||||||
|
{
|
||||||
|
if (t.Priority != priority)
|
||||||
|
{
|
||||||
|
t.SetPriority(priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _unitOfWork.SaveChangesAsync(ct);
|
||||||
|
return OperationResult.Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Project-level bulk priority update across all phases
|
||||||
|
private async Task<OperationResult> HandleProjectLevelAsync(Guid projectId, ProjectTaskPriority priority, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var project = await _projectRepository.GetWithFullHierarchyAsync(projectId);
|
||||||
|
if (project is null)
|
||||||
|
return OperationResult.NotFound("پروژه یافت نشد");
|
||||||
|
|
||||||
|
var phases = project.Phases?.ToList() ?? new List<Domain.ProjectAgg.Entities.ProjectPhase>();
|
||||||
|
foreach (var phase in phases)
|
||||||
|
{
|
||||||
|
var tasks = phase.Tasks?.ToList() ?? new List<Domain.ProjectAgg.Entities.ProjectTask>();
|
||||||
|
foreach (var t in tasks)
|
||||||
|
{
|
||||||
|
if (t.Priority != priority)
|
||||||
|
{
|
||||||
|
t.SetPriority(priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _unitOfWork.SaveChangesAsync(ct);
|
||||||
return OperationResult.Success();
|
return OperationResult.Success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class GetTaskDto
|
|||||||
// Task-specific fields
|
// Task-specific fields
|
||||||
public TimeSpan SpentTime { get; init; }
|
public TimeSpan SpentTime { get; init; }
|
||||||
public TimeSpan RemainingTime { get; init; }
|
public TimeSpan RemainingTime { get; init; }
|
||||||
public TaskPriority Priority { get; set; }
|
public ProjectTaskPriority Priority { get; set; }
|
||||||
public List<GetTaskSectionDto> Sections { get; init; }
|
public List<GetTaskSectionDto> Sections { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,5 +6,7 @@ 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 string? SearchText { get; set; }
|
||||||
public TaskSectionStatus? Status { get; set; }
|
public TaskSectionStatus? Status { get; set; }
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
@@ -41,9 +41,22 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
|
|||||||
queryable = queryable.Where(x => x.Status == request.Status);
|
queryable = queryable.Where(x => x.Status == request.Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.UserId is > 0)
|
||||||
|
{
|
||||||
|
queryable = queryable.Where(x => x.CurrentAssignedUserId == request.UserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(request.SearchText))
|
||||||
|
{
|
||||||
|
queryable = queryable.Where(x=>x.Task.Name.Contains(request.SearchText)
|
||||||
|
|| x.Task.Phase.Name.Contains(request.SearchText)
|
||||||
|
|| x.Task.Phase.Project.Name.Contains(request.SearchText));
|
||||||
|
}
|
||||||
|
|
||||||
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();
|
||||||
@@ -53,7 +66,9 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
|
|||||||
.ToDictionaryAsync(x => x.Id, x => x.FullName, cancellationToken);
|
.ToDictionaryAsync(x => x.Id, x => x.FullName, cancellationToken);
|
||||||
|
|
||||||
|
|
||||||
var result = data .OrderByDescending(x => x.CurrentAssignedUserId == currentUserId)
|
var result = data
|
||||||
|
.OrderByDescending(x => x.CurrentAssignedUserId == currentUserId)
|
||||||
|
.ThenByDescending(x=>x.Task.Priority)
|
||||||
.ThenBy(x => GetStatusOrder(x.Status))
|
.ThenBy(x => GetStatusOrder(x.Status))
|
||||||
.Select(x =>
|
.Select(x =>
|
||||||
{
|
{
|
||||||
@@ -65,7 +80,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();
|
||||||
@@ -103,6 +118,7 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
|
|||||||
ProjectName = x.Task.Phase.Project.Name,
|
ProjectName = x.Task.Phase.Project.Name,
|
||||||
TaskName = x.Task.Name,
|
TaskName = x.Task.Name,
|
||||||
SectionStatus = x.Status,
|
SectionStatus = x.Status,
|
||||||
|
TaskPriority = x.Task.Priority,
|
||||||
Progress = new ProjectProgressDto()
|
Progress = new ProjectProgressDto()
|
||||||
{
|
{
|
||||||
CompleteSecond = x.FinalEstimatedHours.TotalSeconds,
|
CompleteSecond = x.FinalEstimatedHours.TotalSeconds,
|
||||||
@@ -114,6 +130,7 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
|
|||||||
AssignedUser = x.CurrentAssignedUserId == x.OriginalAssignedUserId ? null
|
AssignedUser = x.CurrentAssignedUserId == x.OriginalAssignedUserId ? null
|
||||||
: users.GetValueOrDefault(x.CurrentAssignedUserId, "ناشناس"),
|
: users.GetValueOrDefault(x.CurrentAssignedUserId, "ناشناس"),
|
||||||
SkillName = x.Skill?.Name??"-",
|
SkillName = x.Skill?.Name??"-",
|
||||||
|
TaskId = x.TaskId
|
||||||
};
|
};
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ public class ProjectBoardListResponse
|
|||||||
public string? AssignedUser { get; set; }
|
public string? AssignedUser { get; set; }
|
||||||
public string OriginalUser { get; set; }
|
public string OriginalUser { get; set; }
|
||||||
public string SkillName { get; set; }
|
public string SkillName { get; set; }
|
||||||
|
public ProjectTaskPriority TaskPriority { get; set; }
|
||||||
|
public Guid TaskId { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
public class ProjectProgressDto
|
public class ProjectProgressDto
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ public class
|
|||||||
|
|
||||||
var doneTime = t.Sections.Aggregate(TimeSpan.Zero,
|
var doneTime = t.Sections.Aggregate(TimeSpan.Zero,
|
||||||
(sum, next) => sum.Add(next.GetTotalTimeSpent()));
|
(sum, next) => sum.Add(next.GetTotalTimeSpent()));
|
||||||
|
|
||||||
var skills = t.Sections
|
var skills = t.Sections
|
||||||
.Select(s =>
|
.Select(s =>
|
||||||
{
|
{
|
||||||
@@ -88,7 +89,17 @@ public class
|
|||||||
skillName,
|
skillName,
|
||||||
timePercentage);
|
timePercentage);
|
||||||
}).ToList();
|
}).ToList();
|
||||||
var taskPercentage = (int)Math.Round(skills.Average(x => x.TimePercentage));
|
|
||||||
|
int taskPercentage;
|
||||||
|
|
||||||
|
if (skills.Count == 0)
|
||||||
|
{
|
||||||
|
taskPercentage = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
taskPercentage = (int)Math.Round(skills.Average(x => x.TimePercentage));
|
||||||
|
}
|
||||||
|
|
||||||
return new ProjectDeployBoardDetailTaskItem(
|
return new ProjectDeployBoardDetailTaskItem(
|
||||||
t.Name,
|
t.Name,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using GozareshgirProgramManager.Application._Common.Models;
|
||||||
|
using GozareshgirProgramManager.Application._Common.Interfaces;
|
||||||
|
using GozareshgirProgramManager.Domain._Common.Exceptions;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Repositories;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Application.Modules.TaskChat.Commands.DeleteMessage;
|
||||||
|
|
||||||
|
public record DeleteMessageCommand(Guid MessageId) : IBaseCommand;
|
||||||
|
|
||||||
|
public class DeleteMessageCommandHandler : IBaseCommandHandler<DeleteMessageCommand>
|
||||||
|
{
|
||||||
|
private readonly ITaskChatMessageRepository _repository;
|
||||||
|
private readonly IAuthHelper _authHelper;
|
||||||
|
|
||||||
|
public DeleteMessageCommandHandler(ITaskChatMessageRepository repository, IAuthHelper authHelper)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
_authHelper = authHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OperationResult> Handle(DeleteMessageCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var currentUserId = _authHelper.GetCurrentUserId()??
|
||||||
|
throw new UnAuthorizedException("کاربر احراز هویت نشده است");
|
||||||
|
|
||||||
|
var message = await _repository.GetByIdAsync(request.MessageId);
|
||||||
|
if (message == null)
|
||||||
|
{
|
||||||
|
return OperationResult.NotFound("پیام یافت نشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
message.DeleteMessage(currentUserId);
|
||||||
|
await _repository.UpdateAsync(message);
|
||||||
|
await _repository.SaveChangesAsync();
|
||||||
|
|
||||||
|
// TODO: SignalR notification
|
||||||
|
|
||||||
|
return OperationResult.Success();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return OperationResult.ValidationError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
using GozareshgirProgramManager.Application._Common.Interfaces;
|
||||||
|
using GozareshgirProgramManager.Application._Common.Models;
|
||||||
|
using GozareshgirProgramManager.Domain._Common.Exceptions;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Repositories;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Application.Modules.TaskChat.Commands.EditMessage;
|
||||||
|
|
||||||
|
public record EditMessageCommand(
|
||||||
|
Guid MessageId,
|
||||||
|
string NewTextContent
|
||||||
|
) : IBaseCommand;
|
||||||
|
|
||||||
|
public class EditMessageCommandHandler : IBaseCommandHandler<EditMessageCommand>
|
||||||
|
{
|
||||||
|
private readonly ITaskChatMessageRepository _repository;
|
||||||
|
private readonly IAuthHelper _authHelper;
|
||||||
|
|
||||||
|
public EditMessageCommandHandler(ITaskChatMessageRepository repository, IAuthHelper authHelper)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
_authHelper = authHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OperationResult> Handle(EditMessageCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var currentUserId = _authHelper.GetCurrentUserId()??
|
||||||
|
throw new UnAuthorizedException("کاربر احراز هویت نشده است");
|
||||||
|
|
||||||
|
var message = await _repository.GetByIdAsync(request.MessageId);
|
||||||
|
if (message == null)
|
||||||
|
{
|
||||||
|
return OperationResult.NotFound("پیام یافت نشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
message.EditMessage(request.NewTextContent, currentUserId);
|
||||||
|
await _repository.UpdateAsync(message);
|
||||||
|
await _repository.SaveChangesAsync();
|
||||||
|
|
||||||
|
// TODO: SignalR notification
|
||||||
|
|
||||||
|
return OperationResult.Success();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return OperationResult.ValidationError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using GozareshgirProgramManager.Application._Common.Interfaces;
|
||||||
|
using GozareshgirProgramManager.Application._Common.Models;
|
||||||
|
using GozareshgirProgramManager.Domain._Common.Exceptions;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Repositories;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Application.Modules.TaskChat.Commands.PinMessage;
|
||||||
|
|
||||||
|
public record PinMessageCommand(Guid MessageId) : IBaseCommand;
|
||||||
|
|
||||||
|
public class PinMessageCommandHandler : IBaseCommandHandler<PinMessageCommand>
|
||||||
|
{
|
||||||
|
private readonly ITaskChatMessageRepository _repository;
|
||||||
|
private readonly IAuthHelper _authHelper;
|
||||||
|
|
||||||
|
public PinMessageCommandHandler(ITaskChatMessageRepository repository, IAuthHelper authHelper)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
_authHelper = authHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OperationResult> Handle(PinMessageCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var currentUserId = _authHelper.GetCurrentUserId()??
|
||||||
|
throw new UnAuthorizedException("کاربر احراز هویت نشده است");
|
||||||
|
|
||||||
|
var message = await _repository.GetByIdAsync(request.MessageId);
|
||||||
|
if (message == null)
|
||||||
|
{
|
||||||
|
return OperationResult.NotFound("پیام یافت نشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
message.PinMessage(currentUserId);
|
||||||
|
await _repository.UpdateAsync(message);
|
||||||
|
await _repository.SaveChangesAsync();
|
||||||
|
|
||||||
|
return OperationResult.Success();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return OperationResult.ValidationError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
using GozareshgirProgramManager.Application._Common.Interfaces;
|
||||||
|
using GozareshgirProgramManager.Application._Common.Models;
|
||||||
|
using GozareshgirProgramManager.Application.Modules.TaskChat.DTOs;
|
||||||
|
using GozareshgirProgramManager.Application.Services.FileManagement;
|
||||||
|
using GozareshgirProgramManager.Domain._Common.Exceptions;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Entities;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Repositories;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Enums;
|
||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Entities;
|
||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Repositories;
|
||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Enums;
|
||||||
|
using GozareshgirProgramManager.Domain.ProjectAgg.Repositories;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Application.Modules.TaskChat.Commands.SendMessage;
|
||||||
|
|
||||||
|
public record SendMessageCommand(
|
||||||
|
Guid TaskId,
|
||||||
|
MessageType MessageType,
|
||||||
|
string? TextContent,
|
||||||
|
IFormFile? File,
|
||||||
|
Guid? ReplyToMessageId
|
||||||
|
) : IBaseCommand<MessageDto>;
|
||||||
|
|
||||||
|
public class SendMessageCommandHandler : IBaseCommandHandler<SendMessageCommand, MessageDto>
|
||||||
|
{
|
||||||
|
private readonly ITaskChatMessageRepository _messageRepository;
|
||||||
|
private readonly IUploadedFileRepository _fileRepository;
|
||||||
|
private readonly IProjectTaskRepository _taskRepository;
|
||||||
|
private readonly IFileStorageService _fileStorageService;
|
||||||
|
private readonly IThumbnailGeneratorService _thumbnailService;
|
||||||
|
private readonly IAuthHelper _authHelper;
|
||||||
|
|
||||||
|
public SendMessageCommandHandler(
|
||||||
|
ITaskChatMessageRepository messageRepository,
|
||||||
|
IUploadedFileRepository fileRepository,
|
||||||
|
IProjectTaskRepository taskRepository,
|
||||||
|
IFileStorageService fileStorageService,
|
||||||
|
IThumbnailGeneratorService thumbnailService, IAuthHelper authHelper)
|
||||||
|
{
|
||||||
|
_messageRepository = messageRepository;
|
||||||
|
_fileRepository = fileRepository;
|
||||||
|
_taskRepository = taskRepository;
|
||||||
|
_fileStorageService = fileStorageService;
|
||||||
|
_thumbnailService = thumbnailService;
|
||||||
|
_authHelper = authHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OperationResult<MessageDto>> Handle(SendMessageCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var currentUserId = _authHelper.GetCurrentUserId()
|
||||||
|
?? throw new UnAuthorizedException("کاربر احراز هویت نشده است");
|
||||||
|
|
||||||
|
var task = await _taskRepository.GetByIdAsync(request.TaskId, cancellationToken);
|
||||||
|
if (task == null)
|
||||||
|
{
|
||||||
|
return OperationResult<MessageDto>.NotFound("تسک یافت نشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
Guid? uploadedFileId = null;
|
||||||
|
if (request.File != null)
|
||||||
|
{
|
||||||
|
if (request.File.Length == 0)
|
||||||
|
{
|
||||||
|
return OperationResult<MessageDto>.ValidationError("فایل خالی است");
|
||||||
|
}
|
||||||
|
|
||||||
|
const long maxFileSize = 100 * 1024 * 1024;
|
||||||
|
if (request.File.Length > maxFileSize)
|
||||||
|
{
|
||||||
|
return OperationResult<MessageDto>.ValidationError("حجم فایل بیش از حد مجاز است (حداکثر 100MB)");
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileType = DetectFileType(request.File.ContentType, Path.GetExtension(request.File.FileName));
|
||||||
|
|
||||||
|
var uploadedFile = new UploadedFile(
|
||||||
|
originalFileName: request.File.FileName,
|
||||||
|
fileSizeBytes: request.File.Length,
|
||||||
|
mimeType: request.File.ContentType,
|
||||||
|
fileType: fileType,
|
||||||
|
category: FileCategory.TaskChatMessage,
|
||||||
|
uploadedByUserId: currentUserId,
|
||||||
|
storageProvider: StorageProvider.LocalFileSystem
|
||||||
|
);
|
||||||
|
|
||||||
|
await _fileRepository.AddAsync(uploadedFile);
|
||||||
|
await _fileRepository.SaveChangesAsync();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var stream = request.File.OpenReadStream();
|
||||||
|
var uploadResult = await _fileStorageService.UploadAsync(
|
||||||
|
stream,
|
||||||
|
uploadedFile.UniqueFileName,
|
||||||
|
"TaskChatMessage"
|
||||||
|
);
|
||||||
|
|
||||||
|
uploadedFile.CompleteUpload(uploadResult.StoragePath, uploadResult.StorageUrl);
|
||||||
|
|
||||||
|
if (fileType == FileType.Image)
|
||||||
|
{
|
||||||
|
var dimensions = await _thumbnailService.GetImageDimensionsAsync(uploadResult.StoragePath);
|
||||||
|
if (dimensions.HasValue)
|
||||||
|
{
|
||||||
|
uploadedFile.SetImageDimensions(dimensions.Value.Width, dimensions.Value.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
var thumbnail = await _thumbnailService
|
||||||
|
.GenerateImageThumbnailAsync(uploadResult.StoragePath, category: "TaskChatMessage");
|
||||||
|
if (thumbnail.HasValue)
|
||||||
|
{
|
||||||
|
uploadedFile.SetThumbnail(thumbnail.Value.ThumbnailUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _fileRepository.UpdateAsync(uploadedFile);
|
||||||
|
await _fileRepository.SaveChangesAsync();
|
||||||
|
|
||||||
|
uploadedFileId = uploadedFile.Id;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await _fileRepository.DeleteAsync(uploadedFile);
|
||||||
|
await _fileRepository.SaveChangesAsync();
|
||||||
|
|
||||||
|
return OperationResult<MessageDto>.ValidationError($"خطا در آپلود فایل: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = new TaskChatMessage(
|
||||||
|
taskId: request.TaskId,
|
||||||
|
senderUserId: currentUserId,
|
||||||
|
messageType: request.MessageType,
|
||||||
|
textContent: request.TextContent,
|
||||||
|
uploadedFileId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (request.ReplyToMessageId.HasValue)
|
||||||
|
{
|
||||||
|
message.SetReplyTo(request.ReplyToMessageId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _messageRepository.AddAsync(message);
|
||||||
|
await _messageRepository.SaveChangesAsync();
|
||||||
|
|
||||||
|
if (uploadedFileId.HasValue)
|
||||||
|
{
|
||||||
|
var file = await _fileRepository.GetByIdAsync(uploadedFileId.Value);
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
file.SetReference("TaskChatMessage", message.Id.ToString());
|
||||||
|
await _fileRepository.UpdateAsync(file);
|
||||||
|
await _fileRepository.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dto = new MessageDto
|
||||||
|
{
|
||||||
|
Id = message.Id,
|
||||||
|
TaskId = message.TaskId,
|
||||||
|
SenderUserId = message.SenderUserId,
|
||||||
|
SenderName = "کاربر",
|
||||||
|
MessageType = message.MessageType.ToString(),
|
||||||
|
TextContent = message.TextContent,
|
||||||
|
ReplyToMessageId = message.ReplyToMessageId,
|
||||||
|
IsEdited = message.IsEdited,
|
||||||
|
IsPinned = message.IsPinned,
|
||||||
|
CreationDate = message.CreationDate,
|
||||||
|
IsMine = true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (uploadedFileId.HasValue)
|
||||||
|
{
|
||||||
|
var file = await _fileRepository.GetByIdAsync(uploadedFileId.Value);
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
dto.File = new MessageFileDto
|
||||||
|
{
|
||||||
|
Id = file.Id,
|
||||||
|
FileName = file.OriginalFileName,
|
||||||
|
FileUrl = file.StorageUrl ?? "",
|
||||||
|
FileSizeBytes = file.FileSizeBytes,
|
||||||
|
FileType = file.FileType.ToString(),
|
||||||
|
ThumbnailUrl = file.ThumbnailUrl,
|
||||||
|
ImageWidth = file.ImageWidth,
|
||||||
|
ImageHeight = file.ImageHeight,
|
||||||
|
DurationSeconds = file.DurationSeconds
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OperationResult<MessageDto>.Success(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileType DetectFileType(string mimeType, string extension)
|
||||||
|
{
|
||||||
|
if (mimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return FileType.Image;
|
||||||
|
|
||||||
|
if (mimeType.StartsWith("video/", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return FileType.Video;
|
||||||
|
|
||||||
|
if (mimeType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return FileType.Audio;
|
||||||
|
|
||||||
|
if (new[] { ".zip", ".rar", ".7z", ".tar", ".gz" }.Contains(extension.ToLower()))
|
||||||
|
return FileType.Archive;
|
||||||
|
|
||||||
|
return FileType.Document;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using GozareshgirProgramManager.Application._Common.Interfaces;
|
||||||
|
using GozareshgirProgramManager.Application._Common.Models;
|
||||||
|
using GozareshgirProgramManager.Domain._Common.Exceptions;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Repositories;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Application.Modules.TaskChat.Commands.UnpinMessage;
|
||||||
|
|
||||||
|
public record UnpinMessageCommand(Guid MessageId) : IBaseCommand;
|
||||||
|
|
||||||
|
public class UnpinMessageCommandHandler : IBaseCommandHandler<UnpinMessageCommand>
|
||||||
|
{
|
||||||
|
private readonly ITaskChatMessageRepository _repository;
|
||||||
|
private readonly IAuthHelper _authHelper;
|
||||||
|
|
||||||
|
public UnpinMessageCommandHandler(ITaskChatMessageRepository repository, IAuthHelper authHelper)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
_authHelper = authHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OperationResult> Handle(UnpinMessageCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var currentUserId = _authHelper.GetCurrentUserId()??
|
||||||
|
throw new UnAuthorizedException("کاربر احراز هویت نشده است");
|
||||||
|
|
||||||
|
var message = await _repository.GetByIdAsync(request.MessageId);
|
||||||
|
if (message == null)
|
||||||
|
{
|
||||||
|
return OperationResult.NotFound("پیام یافت نشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
message.UnpinMessage(currentUserId);
|
||||||
|
await _repository.UpdateAsync(message);
|
||||||
|
await _repository.SaveChangesAsync();
|
||||||
|
|
||||||
|
return OperationResult.Success();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return OperationResult.ValidationError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
namespace GozareshgirProgramManager.Application.Modules.TaskChat.DTOs;
|
||||||
|
|
||||||
|
public class SendMessageDto
|
||||||
|
{
|
||||||
|
public Guid TaskId { get; set; }
|
||||||
|
public string MessageType { get; set; } = string.Empty; // "Text", "File", "Image", "Voice", "Video"
|
||||||
|
public string? TextContent { get; set; }
|
||||||
|
public Guid? FileId { get; set; }
|
||||||
|
public Guid? ReplyToMessageId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MessageDto
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid TaskId { get; set; }
|
||||||
|
public long SenderUserId { get; set; }
|
||||||
|
public string SenderName { get; set; } = string.Empty;
|
||||||
|
public string MessageType { get; set; } = string.Empty;
|
||||||
|
public string? TextContent { get; set; }
|
||||||
|
public MessageFileDto? File { get; set; }
|
||||||
|
public Guid? ReplyToMessageId { get; set; }
|
||||||
|
public MessageDto? ReplyToMessage { get; set; }
|
||||||
|
public bool IsEdited { get; set; }
|
||||||
|
public DateTime? EditedDate { get; set; }
|
||||||
|
public bool IsPinned { get; set; }
|
||||||
|
public DateTime? PinnedDate { get; set; }
|
||||||
|
public long? PinnedByUserId { get; set; }
|
||||||
|
public DateTime CreationDate { get; set; }
|
||||||
|
public bool IsMine { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MessageFileDto
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string FileName { get; set; } = string.Empty;
|
||||||
|
public string FileUrl { get; set; } = string.Empty;
|
||||||
|
public long FileSizeBytes { get; set; }
|
||||||
|
public string FileType { get; set; } = string.Empty;
|
||||||
|
public string? ThumbnailUrl { get; set; }
|
||||||
|
public int? ImageWidth { get; set; }
|
||||||
|
public int? ImageHeight { get; set; }
|
||||||
|
public int? DurationSeconds { get; set; }
|
||||||
|
|
||||||
|
public string FileSizeFormatted
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
const long kb = 1024;
|
||||||
|
const long mb = kb * 1024;
|
||||||
|
const long gb = mb * 1024;
|
||||||
|
|
||||||
|
if (FileSizeBytes >= gb)
|
||||||
|
return $"{FileSizeBytes / (double)gb:F2} GB";
|
||||||
|
if (FileSizeBytes >= mb)
|
||||||
|
return $"{FileSizeBytes / (double)mb:F2} MB";
|
||||||
|
if (FileSizeBytes >= kb)
|
||||||
|
return $"{FileSizeBytes / (double)kb:F2} KB";
|
||||||
|
|
||||||
|
return $"{FileSizeBytes} Bytes";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
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>>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class GetMessagesQueryHandler : IBaseQueryHandler<GetMessagesQuery, PaginationResult<MessageDto>>
|
||||||
|
{
|
||||||
|
private readonly IProgramManagerDbContext _context;
|
||||||
|
private readonly IAuthHelper _authHelper;
|
||||||
|
|
||||||
|
public GetMessagesQueryHandler(IProgramManagerDbContext context, IAuthHelper authHelper)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_authHelper = authHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MessageDto> CreateAdditionalTimeNotes(
|
||||||
|
IEnumerable<Domain.ProjectAgg.Entities.TaskSectionAdditionalTime> additionalTimes,
|
||||||
|
Dictionary<long, string> users,
|
||||||
|
Guid taskId)
|
||||||
|
{
|
||||||
|
var notes = new List<MessageDto>();
|
||||||
|
|
||||||
|
foreach (var additionalTime in additionalTimes)
|
||||||
|
{
|
||||||
|
var addedByUserName = additionalTime.AddedByUserId.HasValue && users.TryGetValue(additionalTime.AddedByUserId.Value, out var user)
|
||||||
|
? user
|
||||||
|
: "سیستم";
|
||||||
|
|
||||||
|
var noteContent = $"⏱️ زمان اضافی: {additionalTime.Hours.TotalHours.ToString("F2")} ساعت - {(string.IsNullOrWhiteSpace(additionalTime.Reason) ? "بدون علت" : additionalTime.Reason)} - توسط {addedByUserName}";
|
||||||
|
|
||||||
|
var noteDto = new MessageDto
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
TaskId = taskId,
|
||||||
|
SenderUserId = 0,
|
||||||
|
SenderName = "سیستم",
|
||||||
|
MessageType = "Note",
|
||||||
|
TextContent = noteContent,
|
||||||
|
CreationDate = additionalTime.CreationDate,
|
||||||
|
IsMine = false
|
||||||
|
};
|
||||||
|
|
||||||
|
notes.Add(noteDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
return notes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OperationResult<PaginationResult<MessageDto>>> Handle(GetMessagesQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var currentUserId = _authHelper.GetCurrentUserId();
|
||||||
|
|
||||||
|
var skip = (request.Page - 1) * request.PageSize;
|
||||||
|
|
||||||
|
var query = _context.TaskChatMessages
|
||||||
|
.Where(m => m.TaskId == request.TaskId && !m.IsDeleted)
|
||||||
|
.Include(m => m.ReplyToMessage)
|
||||||
|
.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 messages = await query
|
||||||
|
.Skip(skip)
|
||||||
|
.Take(request.PageSize)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
// ✅ گرفتن تمامی کاربران برای نمایش نام کامل فرستنده به جای "کاربر"
|
||||||
|
var senderUserIds = messages.Select(m => m.SenderUserId).Distinct().ToList();
|
||||||
|
var users = await _context.Users
|
||||||
|
.Where(u => senderUserIds.Contains(u.Id))
|
||||||
|
.ToDictionaryAsync(u => u.Id, u => u.FullName, cancellationToken);
|
||||||
|
|
||||||
|
// ✅ گرفتن تمامی زمانهای اضافی (Additional Times) برای نمایش به صورت نوت
|
||||||
|
var taskSections = await _context.TaskSections
|
||||||
|
.Where(ts => ts.TaskId == request.TaskId)
|
||||||
|
.Include(ts => ts.AdditionalTimes)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
// ✅ تمام زمانهای اضافی را یکجا بگیر و مرتب کن
|
||||||
|
var allAdditionalTimes = taskSections
|
||||||
|
.SelectMany(ts => ts.AdditionalTimes)
|
||||||
|
.OrderBy(at => at.CreationDate)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var messageDtos = new List<MessageDto>();
|
||||||
|
|
||||||
|
// ✅ ابتدا زمانهای اضافی قبل از اولین پیام را اضافه کن (اگر پیامی وجود داشته باشد)
|
||||||
|
if (messages.Any())
|
||||||
|
{
|
||||||
|
var firstMessageDate = messages.First().CreationDate;
|
||||||
|
var additionalTimesBeforeFirstMessage = allAdditionalTimes
|
||||||
|
.Where(at => at.CreationDate < firstMessageDate)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
messageDtos.AddRange(CreateAdditionalTimeNotes(additionalTimesBeforeFirstMessage, users, request.TaskId));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ✅ اگر هیچ پیامی وجود ندارد، همه زمانهای اضافی را نمایش بده
|
||||||
|
messageDtos.AddRange(CreateAdditionalTimeNotes(allAdditionalTimes, users, request.TaskId));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var message in messages)
|
||||||
|
{
|
||||||
|
// ✅ نام فرستنده را از Dictionary Users بگیر، در صورت عدم وجود "کاربر ناشناس" نمایش بده
|
||||||
|
var senderName = users.GetValueOrDefault(message.SenderUserId, "کاربر ناشناس");
|
||||||
|
|
||||||
|
var dto = new MessageDto
|
||||||
|
{
|
||||||
|
Id = message.Id,
|
||||||
|
TaskId = message.TaskId,
|
||||||
|
SenderUserId = message.SenderUserId,
|
||||||
|
SenderName = senderName,
|
||||||
|
MessageType = message.MessageType.ToString(),
|
||||||
|
TextContent = message.TextContent,
|
||||||
|
ReplyToMessageId = message.ReplyToMessageId,
|
||||||
|
IsEdited = message.IsEdited,
|
||||||
|
EditedDate = message.EditedDate,
|
||||||
|
IsPinned = message.IsPinned,
|
||||||
|
PinnedDate = message.PinnedDate,
|
||||||
|
PinnedByUserId = message.PinnedByUserId,
|
||||||
|
CreationDate = message.CreationDate,
|
||||||
|
IsMine = message.SenderUserId == currentUserId
|
||||||
|
};
|
||||||
|
|
||||||
|
if (message.ReplyToMessage != null)
|
||||||
|
{
|
||||||
|
var replySenderName = users.GetValueOrDefault(message.ReplyToMessage.SenderUserId, "کاربر ناشناس");
|
||||||
|
|
||||||
|
dto.ReplyToMessage = new MessageDto
|
||||||
|
{
|
||||||
|
Id = message.ReplyToMessage.Id,
|
||||||
|
SenderUserId = message.ReplyToMessage.SenderUserId,
|
||||||
|
SenderName = replySenderName,
|
||||||
|
TextContent = message.ReplyToMessage.TextContent,
|
||||||
|
CreationDate = message.ReplyToMessage.CreationDate
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.FileId.HasValue)
|
||||||
|
{
|
||||||
|
var file = await _context.UploadedFiles.FirstOrDefaultAsync(f => f.Id == message.FileId.Value, cancellationToken);
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
dto.File = new MessageFileDto
|
||||||
|
{
|
||||||
|
Id = file.Id,
|
||||||
|
FileName = file.OriginalFileName,
|
||||||
|
FileUrl = file.StorageUrl ?? "",
|
||||||
|
FileSizeBytes = file.FileSizeBytes,
|
||||||
|
FileType = file.FileType.ToString(),
|
||||||
|
ThumbnailUrl = file.ThumbnailUrl,
|
||||||
|
ImageWidth = file.ImageWidth,
|
||||||
|
ImageHeight = file.ImageHeight,
|
||||||
|
DurationSeconds = file.DurationSeconds
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
messageDtos.Add(dto);
|
||||||
|
|
||||||
|
// ✅ پیدا کردن پیام بعدی (اگر وجود داشته باشد)
|
||||||
|
var currentIndex = messages.IndexOf(message);
|
||||||
|
var nextMessage = currentIndex < messages.Count - 1 ? messages[currentIndex + 1] : null;
|
||||||
|
|
||||||
|
if (nextMessage != null)
|
||||||
|
{
|
||||||
|
// ✅ زمانهای اضافی بین این پیام و پیام بعدی
|
||||||
|
var additionalTimesBetween = allAdditionalTimes
|
||||||
|
.Where(at => at.CreationDate > message.CreationDate && at.CreationDate < nextMessage.CreationDate)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
messageDtos.AddRange(CreateAdditionalTimeNotes(additionalTimesBetween, users, request.TaskId));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ✅ این آخرین پیام است، زمانهای اضافی بعد از آن را اضافه کن
|
||||||
|
var additionalTimesAfterLastMessage = allAdditionalTimes
|
||||||
|
.Where(at => at.CreationDate > message.CreationDate)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
messageDtos.AddRange(CreateAdditionalTimeNotes(additionalTimesAfterLastMessage, users, request.TaskId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ مرتب کردن نهایی تمام پیامها (معمولی + نوتها) بر اساس زمان ایجاد
|
||||||
|
messageDtos = messageDtos.OrderBy(m => m.CreationDate).ToList();
|
||||||
|
|
||||||
|
var response = new PaginationResult<MessageDto>()
|
||||||
|
{
|
||||||
|
List = messageDtos,
|
||||||
|
TotalCount = totalCount,
|
||||||
|
};
|
||||||
|
|
||||||
|
return OperationResult<PaginationResult<MessageDto>>.Success(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
using GozareshgirProgramManager.Application._Common.Interfaces;
|
||||||
|
using GozareshgirProgramManager.Application._Common.Models;
|
||||||
|
using GozareshgirProgramManager.Application.Modules.TaskChat.DTOs;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Application.Modules.TaskChat.Queries.GetPinnedMessages;
|
||||||
|
|
||||||
|
public record GetPinnedMessagesQuery(Guid TaskId) : IBaseQuery<List<MessageDto>>;
|
||||||
|
|
||||||
|
public class GetPinnedMessagesQueryHandler : IBaseQueryHandler<GetPinnedMessagesQuery, List<MessageDto>>
|
||||||
|
{
|
||||||
|
private readonly IProgramManagerDbContext _context;
|
||||||
|
private readonly IAuthHelper _authHelper;
|
||||||
|
|
||||||
|
public GetPinnedMessagesQueryHandler(IProgramManagerDbContext context, IAuthHelper authHelper)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_authHelper = authHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OperationResult<List<MessageDto>>> Handle(GetPinnedMessagesQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var currentUserId = _authHelper.GetCurrentUserId();
|
||||||
|
|
||||||
|
var messages = await _context.TaskChatMessages
|
||||||
|
.Where(m => m.TaskId == request.TaskId && m.IsPinned && !m.IsDeleted)
|
||||||
|
.Include(m => m.ReplyToMessage)
|
||||||
|
.OrderByDescending(m => m.PinnedDate)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
// ✅ گرفتن تمامی کاربران برای نمایش نام کامل فرستنده
|
||||||
|
var senderUserIds = messages.Select(m => m.SenderUserId).Distinct().ToList();
|
||||||
|
var users = await _context.Users
|
||||||
|
.Where(u => senderUserIds.Contains(u.Id))
|
||||||
|
.ToDictionaryAsync(u => u.Id, u => u.FullName, cancellationToken);
|
||||||
|
|
||||||
|
var messageDtos = new List<MessageDto>();
|
||||||
|
|
||||||
|
foreach (var message in messages)
|
||||||
|
{
|
||||||
|
// ✅ نام فرستنده را از User واقعی بگیر (به جای "کاربر" ثابت)
|
||||||
|
var senderName = users.GetValueOrDefault(message.SenderUserId, "کاربر ناشناس");
|
||||||
|
|
||||||
|
var dto = new MessageDto
|
||||||
|
{
|
||||||
|
Id = message.Id,
|
||||||
|
TaskId = message.TaskId,
|
||||||
|
SenderUserId = message.SenderUserId,
|
||||||
|
SenderName = senderName,
|
||||||
|
MessageType = message.MessageType.ToString(),
|
||||||
|
TextContent = message.TextContent,
|
||||||
|
IsPinned = message.IsPinned,
|
||||||
|
PinnedDate = message.PinnedDate,
|
||||||
|
PinnedByUserId = message.PinnedByUserId,
|
||||||
|
CreationDate = message.CreationDate,
|
||||||
|
IsMine = message.SenderUserId == currentUserId
|
||||||
|
};
|
||||||
|
|
||||||
|
if (message.FileId.HasValue)
|
||||||
|
{
|
||||||
|
var file = await _context.UploadedFiles.FirstOrDefaultAsync(f => f.Id == message.FileId.Value, cancellationToken);
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
dto.File = new MessageFileDto
|
||||||
|
{
|
||||||
|
Id = file.Id,
|
||||||
|
FileName = file.OriginalFileName,
|
||||||
|
FileUrl = file.StorageUrl ?? "",
|
||||||
|
FileSizeBytes = file.FileSizeBytes,
|
||||||
|
FileType = file.FileType.ToString(),
|
||||||
|
ThumbnailUrl = file.ThumbnailUrl
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
messageDtos.Add(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OperationResult<List<MessageDto>>.Success(messageDtos);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
using GozareshgirProgramManager.Application._Common.Interfaces;
|
||||||
|
using GozareshgirProgramManager.Application._Common.Models;
|
||||||
|
using GozareshgirProgramManager.Application.Modules.TaskChat.DTOs;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Application.Modules.TaskChat.Queries.SearchMessages;
|
||||||
|
|
||||||
|
public record SearchMessagesQuery(
|
||||||
|
Guid TaskId,
|
||||||
|
string SearchText,
|
||||||
|
int Page = 1,
|
||||||
|
int PageSize = 20
|
||||||
|
) : IBaseQuery<List<MessageDto>>;
|
||||||
|
|
||||||
|
public class SearchMessagesQueryHandler : IBaseQueryHandler<SearchMessagesQuery, List<MessageDto>>
|
||||||
|
{
|
||||||
|
private readonly IProgramManagerDbContext _context;
|
||||||
|
private readonly IAuthHelper _authHelper;
|
||||||
|
|
||||||
|
public SearchMessagesQueryHandler(IProgramManagerDbContext context, IAuthHelper authHelper)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_authHelper = authHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OperationResult<List<MessageDto>>> Handle(SearchMessagesQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var currentUserId = _authHelper.GetCurrentUserId();
|
||||||
|
var skip = (request.Page - 1) * request.PageSize;
|
||||||
|
|
||||||
|
var messages = await _context.TaskChatMessages
|
||||||
|
.Where(m => m.TaskId == request.TaskId &&
|
||||||
|
m.TextContent != null &&
|
||||||
|
m.TextContent.Contains(request.SearchText) &&
|
||||||
|
!m.IsDeleted)
|
||||||
|
.Include(m => m.ReplyToMessage)
|
||||||
|
.OrderByDescending(m => m.CreationDate)
|
||||||
|
.Skip(skip)
|
||||||
|
.Take(request.PageSize)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
// ✅ گرفتن تمامی کاربران برای نمایش نام کامل فرستنده
|
||||||
|
var senderUserIds = messages.Select(m => m.SenderUserId).Distinct().ToList();
|
||||||
|
var users = await _context.Users
|
||||||
|
.Where(u => senderUserIds.Contains(u.Id))
|
||||||
|
.ToDictionaryAsync(u => u.Id, u => u.FullName, cancellationToken);
|
||||||
|
|
||||||
|
var messageDtos = new List<MessageDto>();
|
||||||
|
foreach (var message in messages)
|
||||||
|
{
|
||||||
|
// ✅ نام فرستنده را از User واقعی بگیر
|
||||||
|
var senderName = users.GetValueOrDefault(message.SenderUserId, "کاربر ناشناس");
|
||||||
|
|
||||||
|
var dto = new MessageDto
|
||||||
|
{
|
||||||
|
Id = message.Id,
|
||||||
|
TaskId = message.TaskId,
|
||||||
|
SenderUserId = message.SenderUserId,
|
||||||
|
SenderName = senderName,
|
||||||
|
MessageType = message.MessageType.ToString(),
|
||||||
|
TextContent = message.TextContent,
|
||||||
|
CreationDate = message.CreationDate,
|
||||||
|
IsMine = message.SenderUserId == currentUserId
|
||||||
|
};
|
||||||
|
|
||||||
|
messageDtos.Add(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OperationResult<List<MessageDto>>.Success(messageDtos);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Entities;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Application.Services.FileManagement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// سرویس ذخیرهسازی فایل
|
||||||
|
/// </summary>
|
||||||
|
public interface IFileStorageService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// آپلود فایل
|
||||||
|
/// </summary>
|
||||||
|
Task<(string StoragePath, string StorageUrl)> UploadAsync(
|
||||||
|
Stream fileStream,
|
||||||
|
string uniqueFileName,
|
||||||
|
string category);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// حذف فایل
|
||||||
|
/// </summary>
|
||||||
|
Task DeleteAsync(string storagePath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت فایل
|
||||||
|
/// </summary>
|
||||||
|
Task<Stream?> GetFileStreamAsync(string storagePath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بررسی وجود فایل
|
||||||
|
/// </summary>
|
||||||
|
Task<bool> ExistsAsync(string storagePath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت URL فایل
|
||||||
|
/// </summary>
|
||||||
|
string GetFileUrl(string storagePath);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
namespace GozareshgirProgramManager.Application.Services.FileManagement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// سرویس تولید thumbnail برای تصاویر و ویدیوها
|
||||||
|
/// </summary>
|
||||||
|
public interface IThumbnailGeneratorService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// تولید thumbnail برای تصویر
|
||||||
|
/// </summary>
|
||||||
|
Task<(string ThumbnailPath, string ThumbnailUrl)?> GenerateImageThumbnailAsync(
|
||||||
|
string imagePath,
|
||||||
|
string category,
|
||||||
|
int width = 200,
|
||||||
|
int height = 200);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تولید thumbnail برای ویدیو
|
||||||
|
/// </summary>
|
||||||
|
Task<(string ThumbnailPath, string ThumbnailUrl)?> GenerateVideoThumbnailAsync(
|
||||||
|
string videoPath,
|
||||||
|
string category);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// حذف thumbnail
|
||||||
|
/// </summary>
|
||||||
|
Task DeleteThumbnailAsync(string thumbnailPath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت ابعاد تصویر
|
||||||
|
/// </summary>
|
||||||
|
Task<(int Width, int Height)?> GetImageDimensionsAsync(string imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -7,6 +7,8 @@ using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities;
|
|||||||
using GozareshgirProgramManager.Domain.SkillAgg.Entities;
|
using GozareshgirProgramManager.Domain.SkillAgg.Entities;
|
||||||
using GozareshgirProgramManager.Domain.UserAgg.Entities;
|
using GozareshgirProgramManager.Domain.UserAgg.Entities;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Entities;
|
||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Entities;
|
||||||
|
|
||||||
namespace GozareshgirProgramManager.Application._Common.Interfaces;
|
namespace GozareshgirProgramManager.Application._Common.Interfaces;
|
||||||
|
|
||||||
@@ -26,6 +28,9 @@ public interface IProgramManagerDbContext
|
|||||||
|
|
||||||
DbSet<ProjectTask> ProjectTasks { get; set; }
|
DbSet<ProjectTask> ProjectTasks { get; set; }
|
||||||
|
|
||||||
|
DbSet<TaskChatMessage> TaskChatMessages { get; set; }
|
||||||
|
DbSet<UploadedFile> UploadedFiles { get; set; }
|
||||||
|
|
||||||
DbSet<Skill> Skills { get; set; }
|
DbSet<Skill> Skills { get; set; }
|
||||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
|
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,244 @@
|
|||||||
|
using GozareshgirProgramManager.Domain._Common;
|
||||||
|
using GozareshgirProgramManager.Domain._Common.Exceptions;
|
||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Enums;
|
||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Events;
|
||||||
|
using FileType = GozareshgirProgramManager.Domain.FileManagementAgg.Enums.FileType;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Domain.FileManagementAgg.Entities;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// فایل آپلود شده - Aggregate Root
|
||||||
|
/// مدیریت مرکزی تمام فایلهای سیستم
|
||||||
|
/// </summary>
|
||||||
|
public class UploadedFile : EntityBase<Guid>
|
||||||
|
{
|
||||||
|
private UploadedFile()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public UploadedFile(
|
||||||
|
string originalFileName,
|
||||||
|
long fileSizeBytes,
|
||||||
|
string mimeType,
|
||||||
|
FileType fileType,
|
||||||
|
FileCategory category,
|
||||||
|
long uploadedByUserId,
|
||||||
|
StorageProvider storageProvider = StorageProvider.LocalFileSystem)
|
||||||
|
{
|
||||||
|
OriginalFileName = originalFileName;
|
||||||
|
FileSizeBytes = fileSizeBytes;
|
||||||
|
MimeType = mimeType;
|
||||||
|
FileType = fileType;
|
||||||
|
Category = category;
|
||||||
|
UploadedByUserId = uploadedByUserId;
|
||||||
|
UploadDate = DateTime.Now;
|
||||||
|
StorageProvider = storageProvider;
|
||||||
|
Status = FileStatus.Uploading;
|
||||||
|
|
||||||
|
// Generate unique file name
|
||||||
|
FileExtension = Path.GetExtension(originalFileName);
|
||||||
|
UniqueFileName = $"{Guid.NewGuid()}{FileExtension}";
|
||||||
|
|
||||||
|
ValidateFile();
|
||||||
|
AddDomainEvent(new FileUploadStartedEvent(Id, originalFileName, uploadedByUserId));
|
||||||
|
}
|
||||||
|
|
||||||
|
// اطلاعات فایل
|
||||||
|
public string OriginalFileName { get; private set; } = string.Empty;
|
||||||
|
public string UniqueFileName { get; private set; } = string.Empty;
|
||||||
|
public string FileExtension { get; private set; } = string.Empty;
|
||||||
|
public long FileSizeBytes { get; private set; }
|
||||||
|
public string MimeType { get; private set; } = string.Empty;
|
||||||
|
public FileType FileType { get; private set; }
|
||||||
|
public FileCategory Category { get; private set; }
|
||||||
|
|
||||||
|
// ذخیرهسازی
|
||||||
|
public StorageProvider StorageProvider { get; private set; }
|
||||||
|
public string? StoragePath { get; private set; }
|
||||||
|
public string? StorageUrl { get; private set; }
|
||||||
|
public string? ThumbnailUrl { get; private set; }
|
||||||
|
|
||||||
|
// متادیتا
|
||||||
|
public long UploadedByUserId { get; private set; }
|
||||||
|
public DateTime UploadDate { get; private set; }
|
||||||
|
public FileStatus Status { get; private set; }
|
||||||
|
|
||||||
|
// اطلاعات تصویر (اختیاری - برای Image)
|
||||||
|
public int? ImageWidth { get; private set; }
|
||||||
|
public int? ImageHeight { get; private set; }
|
||||||
|
|
||||||
|
// اطلاعات صوت/ویدیو (اختیاری)
|
||||||
|
public int? DurationSeconds { get; private set; }
|
||||||
|
|
||||||
|
// امنیت
|
||||||
|
public DateTime? VirusScanDate { get; private set; }
|
||||||
|
public bool? IsVirusScanPassed { get; private set; }
|
||||||
|
public string? VirusScanResult { get; private set; }
|
||||||
|
|
||||||
|
// Soft Delete
|
||||||
|
public bool IsDeleted { get; private set; }
|
||||||
|
public DateTime? DeletedDate { get; private set; }
|
||||||
|
public long? DeletedByUserId { get; private set; }
|
||||||
|
|
||||||
|
// Reference tracking (چه entityهایی از این فایل استفاده میکنند)
|
||||||
|
public string? ReferenceEntityType { get; private set; }
|
||||||
|
public string? ReferenceEntityId { get; private set; }
|
||||||
|
|
||||||
|
private void ValidateFile()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(OriginalFileName))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("نام فایل نمیتواند خالی باشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FileSizeBytes <= 0)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("حجم فایل باید بیشتر از صفر باشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(MimeType))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("نوع MIME فایل باید مشخص شود");
|
||||||
|
}
|
||||||
|
|
||||||
|
// محدودیت حجم (مثلاً 100MB)
|
||||||
|
const long maxSizeBytes = 100 * 1024 * 1024; // 100MB
|
||||||
|
if (FileSizeBytes > maxSizeBytes)
|
||||||
|
{
|
||||||
|
throw new BadRequestException($"حجم فایل نباید بیشتر از {maxSizeBytes / (1024 * 1024)} مگابایت باشد");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CompleteUpload(string storagePath, string storageUrl)
|
||||||
|
{
|
||||||
|
if (Status != FileStatus.Uploading)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("فایل قبلاً آپلود شده است");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(storagePath))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("مسیر ذخیرهسازی نمیتواند خالی باشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(storageUrl))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("URL فایل نمیتواند خالی باشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
StoragePath = storagePath;
|
||||||
|
StorageUrl = storageUrl;
|
||||||
|
Status = FileStatus.Active;
|
||||||
|
|
||||||
|
AddDomainEvent(new FileUploadCompletedEvent(Id, OriginalFileName, StorageUrl, UploadedByUserId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetThumbnail(string thumbnailUrl)
|
||||||
|
{
|
||||||
|
if (FileType != FileType.Image && FileType != FileType.Video)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("فقط میتوان برای تصاویر و ویدیوها thumbnail تنظیم کرد");
|
||||||
|
}
|
||||||
|
|
||||||
|
ThumbnailUrl = thumbnailUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetImageDimensions(int width, int height)
|
||||||
|
{
|
||||||
|
if (FileType != FileType.Image)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("فقط میتوان برای تصاویر ابعاد تنظیم کرد");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width <= 0 || height <= 0)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("ابعاد تصویر باید بیشتر از صفر باشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageWidth = width;
|
||||||
|
ImageHeight = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetDuration(int durationSeconds)
|
||||||
|
{
|
||||||
|
if (FileType != FileType.Audio && FileType != FileType.Video)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("فقط میتوان برای فایلهای صوتی و تصویری مدت زمان تنظیم کرد");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (durationSeconds <= 0)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("مدت زمان باید بیشتر از صفر باشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
DurationSeconds = durationSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MarkAsDeleted(long deletedByUserId)
|
||||||
|
{
|
||||||
|
if (IsDeleted)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("فایل قبلاً حذف شده است");
|
||||||
|
}
|
||||||
|
|
||||||
|
IsDeleted = true;
|
||||||
|
DeletedDate = DateTime.Now;
|
||||||
|
DeletedByUserId = deletedByUserId;
|
||||||
|
Status = FileStatus.Deleted;
|
||||||
|
|
||||||
|
AddDomainEvent(new FileDeletedEvent(Id, OriginalFileName, deletedByUserId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetReference(string entityType, string entityId)
|
||||||
|
{
|
||||||
|
ReferenceEntityType = entityType;
|
||||||
|
ReferenceEntityId = entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsImage()
|
||||||
|
{
|
||||||
|
return FileType == FileType.Image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsVideo()
|
||||||
|
{
|
||||||
|
return FileType == FileType.Video;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAudio()
|
||||||
|
{
|
||||||
|
return FileType == FileType.Audio;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDocument()
|
||||||
|
{
|
||||||
|
return FileType == FileType.Document;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsUploadedBy(long userId)
|
||||||
|
{
|
||||||
|
return UploadedByUserId == userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsActive()
|
||||||
|
{
|
||||||
|
return Status == FileStatus.Active && !IsDeleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetFileSizeFormatted()
|
||||||
|
{
|
||||||
|
const long kb = 1024;
|
||||||
|
const long mb = kb * 1024;
|
||||||
|
const long gb = mb * 1024;
|
||||||
|
|
||||||
|
if (FileSizeBytes >= gb)
|
||||||
|
return $"{FileSizeBytes / (double)gb:F2} GB";
|
||||||
|
if (FileSizeBytes >= mb)
|
||||||
|
return $"{FileSizeBytes / (double)mb:F2} MB";
|
||||||
|
if (FileSizeBytes >= kb)
|
||||||
|
return $"{FileSizeBytes / (double)kb:F2} KB";
|
||||||
|
|
||||||
|
return $"{FileSizeBytes} Bytes";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
namespace GozareshgirProgramManager.Domain.FileManagementAgg.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دستهبندی فایل - مشخص میکند فایل در کجا استفاده شده
|
||||||
|
/// </summary>
|
||||||
|
public enum FileCategory
|
||||||
|
{
|
||||||
|
TaskChatMessage = 1, // پیام چت تسک
|
||||||
|
TaskAttachment = 2, // ضمیمه تسک
|
||||||
|
ProjectDocument = 3, // مستندات پروژه
|
||||||
|
UserProfilePhoto = 4, // عکس پروفایل کاربر
|
||||||
|
Report = 5, // گزارش
|
||||||
|
Other = 6 // سایر
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace GozareshgirProgramManager.Domain.FileManagementAgg.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// وضعیت فایل
|
||||||
|
/// </summary>
|
||||||
|
public enum FileStatus
|
||||||
|
{
|
||||||
|
Uploading = 1, // در حال آپلود
|
||||||
|
Active = 2, // فعال و قابل استفاده
|
||||||
|
Deleted = 5, // حذف شده (Soft Delete)
|
||||||
|
Archived = 6 // آرشیو شده
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
namespace GozareshgirProgramManager.Domain.FileManagementAgg.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// نوع فایل
|
||||||
|
/// </summary>
|
||||||
|
public enum FileType
|
||||||
|
{
|
||||||
|
Document = 1, // اسناد (PDF, Word, Excel, etc.)
|
||||||
|
Image = 2, // تصویر
|
||||||
|
Video = 3, // ویدیو
|
||||||
|
Audio = 4, // صوت
|
||||||
|
Archive = 5, // فایل فشرده (ZIP, RAR)
|
||||||
|
Other = 6 // سایر
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace GozareshgirProgramManager.Domain.FileManagementAgg.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// نوع ذخیرهساز فایل
|
||||||
|
/// </summary>
|
||||||
|
public enum StorageProvider
|
||||||
|
{
|
||||||
|
LocalFileSystem = 1, // دیسک محلی سرور
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using GozareshgirProgramManager.Domain._Common;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Domain.FileManagementAgg.Events;
|
||||||
|
|
||||||
|
// File Upload Events
|
||||||
|
public record FileUploadStartedEvent(Guid FileId, string FileName, long UploadedByUserId) : IDomainEvent
|
||||||
|
{
|
||||||
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record FileUploadCompletedEvent(Guid FileId, string FileName, string StorageUrl, long UploadedByUserId) : IDomainEvent
|
||||||
|
{
|
||||||
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record FileDeletedEvent(Guid FileId, string FileName, long DeletedByUserId) : IDomainEvent
|
||||||
|
{
|
||||||
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Virus Scan Events
|
||||||
|
public record FileQuarantinedEvent(Guid FileId, string FileName) : IDomainEvent
|
||||||
|
{
|
||||||
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record FileVirusScanPassedEvent(Guid FileId, string FileName) : IDomainEvent
|
||||||
|
{
|
||||||
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record FileInfectedEvent(Guid FileId, string FileName, string ScanResult) : IDomainEvent
|
||||||
|
{
|
||||||
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Entities;
|
||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Enums;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Domain.FileManagementAgg.Repositories;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Repository برای مدیریت فایلهای آپلود شده
|
||||||
|
/// </summary>
|
||||||
|
public interface IUploadedFileRepository
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت فایل بر اساس شناسه
|
||||||
|
/// </summary>
|
||||||
|
Task<UploadedFile?> GetByIdAsync(Guid fileId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت فایل بر اساس نام یکتا
|
||||||
|
/// </summary>
|
||||||
|
Task<UploadedFile?> GetByUniqueFileNameAsync(string uniqueFileName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت لیست فایلهای یک کاربر
|
||||||
|
/// </summary>
|
||||||
|
Task<List<UploadedFile>> GetUserFilesAsync(long userId, int pageNumber, int pageSize);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت فایلهای یک دسته خاص
|
||||||
|
/// </summary>
|
||||||
|
Task<List<UploadedFile>> GetByCategoryAsync(FileCategory category, int pageNumber, int pageSize);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت فایلهای با وضعیت خاص
|
||||||
|
/// </summary>
|
||||||
|
Task<List<UploadedFile>> GetByStatusAsync(FileStatus status, int pageNumber, int pageSize);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت فایلهای یک Reference خاص
|
||||||
|
/// </summary>
|
||||||
|
Task<List<UploadedFile>> GetByReferenceAsync(string entityType, string entityId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// جستجو در فایلها بر اساس نام
|
||||||
|
/// </summary>
|
||||||
|
Task<List<UploadedFile>> SearchByNameAsync(string searchTerm, int pageNumber, int pageSize);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت تعداد کل فایلهای یک کاربر
|
||||||
|
/// </summary>
|
||||||
|
Task<int> GetUserFilesCountAsync(long userId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت مجموع حجم فایلهای یک کاربر (به بایت)
|
||||||
|
/// </summary>
|
||||||
|
Task<long> GetUserTotalFileSizeAsync(long userId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت فایلهای منقضی شده برای پاکسازی
|
||||||
|
/// </summary>
|
||||||
|
Task<List<UploadedFile>> GetExpiredFilesAsync(DateTime olderThan);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// اضافه کردن فایل جدید
|
||||||
|
/// </summary>
|
||||||
|
Task<UploadedFile> AddAsync(UploadedFile file);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بهروزرسانی فایل
|
||||||
|
/// </summary>
|
||||||
|
Task UpdateAsync(UploadedFile file);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// حذف فیزیکی فایل (فقط برای cleanup)
|
||||||
|
/// </summary>
|
||||||
|
Task DeleteAsync(UploadedFile file);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ذخیره تغییرات
|
||||||
|
/// </summary>
|
||||||
|
Task<int> SaveChangesAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بررسی وجود فایل
|
||||||
|
/// </summary>
|
||||||
|
Task<bool> ExistsAsync(Guid fileId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بررسی وجود فایل با نام یکتا
|
||||||
|
/// </summary>
|
||||||
|
Task<bool> ExistsByUniqueFileNameAsync(string uniqueFileName);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ public class ProjectTask : ProjectHierarchyNode
|
|||||||
{
|
{
|
||||||
PhaseId = phaseId;
|
PhaseId = phaseId;
|
||||||
_sections = new List<TaskSection>();
|
_sections = new List<TaskSection>();
|
||||||
Priority = TaskPriority.Medium;
|
Priority = ProjectTaskPriority.Low;
|
||||||
AddDomainEvent(new TaskCreatedEvent(Id, phaseId, name));
|
AddDomainEvent(new TaskCreatedEvent(Id, phaseId, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ public class ProjectTask : ProjectHierarchyNode
|
|||||||
|
|
||||||
// Task-specific properties
|
// Task-specific properties
|
||||||
public Enums.TaskStatus Status { get; private set; } = Enums.TaskStatus.NotStarted;
|
public Enums.TaskStatus Status { get; private set; } = Enums.TaskStatus.NotStarted;
|
||||||
public TaskPriority Priority { get; private set; }
|
public ProjectTaskPriority Priority { get; private set; }
|
||||||
public DateTime? StartDate { get; private set; }
|
public DateTime? StartDate { get; private set; }
|
||||||
public DateTime? EndDate { get; private set; }
|
public DateTime? EndDate { get; private set; }
|
||||||
public DateTime? DueDate { get; private set; }
|
public DateTime? DueDate { get; private set; }
|
||||||
@@ -119,7 +119,7 @@ public class ProjectTask : ProjectHierarchyNode
|
|||||||
AddDomainEvent(new TaskStatusUpdatedEvent(Id, status));
|
AddDomainEvent(new TaskStatusUpdatedEvent(Id, status));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPriority(TaskPriority priority)
|
public void SetPriority(ProjectTaskPriority priority)
|
||||||
{
|
{
|
||||||
Priority = priority;
|
Priority = priority;
|
||||||
AddDomainEvent(new TaskPriorityUpdatedEvent(Id, priority));
|
AddDomainEvent(new TaskPriorityUpdatedEvent(Id, priority));
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ namespace GozareshgirProgramManager.Domain.ProjectAgg.Enums;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// اولویت تسک
|
/// اولویت تسک
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum TaskPriority
|
public enum ProjectTaskPriority
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// پایین
|
/// پایین
|
||||||
@@ -78,7 +78,7 @@ public record TaskStatusUpdatedEvent(Guid TaskId, TaskStatus Status) : IDomainEv
|
|||||||
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
public record TaskPriorityUpdatedEvent(Guid TaskId, TaskPriority Priority) : IDomainEvent
|
public record TaskPriorityUpdatedEvent(Guid TaskId, ProjectTaskPriority Priority) : IDomainEvent
|
||||||
{
|
{
|
||||||
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public interface IProjectTaskRepository : IRepository<Guid, ProjectTask>
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get tasks by priority
|
/// Get tasks by priority
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task<List<ProjectTask>> GetByPriorityAsync(ProjectAgg.Enums.TaskPriority priority);
|
Task<List<ProjectTask>> GetByPriorityAsync(ProjectAgg.Enums.ProjectTaskPriority priority);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get tasks assigned to user
|
/// Get tasks assigned to user
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
using GozareshgirProgramManager.Domain._Common;
|
||||||
|
using GozareshgirProgramManager.Domain._Common.Exceptions;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Events;
|
||||||
|
using MessageType = GozareshgirProgramManager.Domain.TaskChatAgg.Enums.MessageType;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Domain.TaskChatAgg.Entities;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// پیام چت تسک - Aggregate Root
|
||||||
|
/// هر کسی که به تسک دسترسی داشته باشد میتواند پیامها را ببیند و ارسال کند
|
||||||
|
/// نیازی به مدیریت گروه و ممبر نیست چون دسترسی از طریق خود تسک کنترل میشود
|
||||||
|
/// </summary>
|
||||||
|
public class TaskChatMessage : EntityBase<Guid>
|
||||||
|
{
|
||||||
|
private TaskChatMessage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskChatMessage(Guid taskId, long senderUserId, MessageType messageType,
|
||||||
|
string? textContent = null,Guid? fileId = null)
|
||||||
|
{
|
||||||
|
TaskId = taskId;
|
||||||
|
SenderUserId = senderUserId;
|
||||||
|
MessageType = messageType;
|
||||||
|
TextContent = textContent;
|
||||||
|
IsEdited = false;
|
||||||
|
IsDeleted = false;
|
||||||
|
IsPinned = false;
|
||||||
|
if (fileId.HasValue)
|
||||||
|
{
|
||||||
|
SetFile(fileId.Value);
|
||||||
|
}
|
||||||
|
ValidateMessage();
|
||||||
|
AddDomainEvent(new TaskChatMessageSentEvent(Id, taskId, senderUserId, messageType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference به Task (Foreign Key فقط - بدون Navigation Property برای جلوگیری از coupling)
|
||||||
|
public Guid TaskId { get; private set; }
|
||||||
|
|
||||||
|
public long SenderUserId { get; private set; }
|
||||||
|
|
||||||
|
public MessageType MessageType { get; private set; }
|
||||||
|
|
||||||
|
// محتوای متنی (برای پیامهای Text و Caption برای فایل/تصویر)
|
||||||
|
public string? TextContent { get; private set; }
|
||||||
|
|
||||||
|
// ارجاع به فایل (برای پیامهای File, Voice, Image, Video)
|
||||||
|
public Guid? FileId { get; private set; }
|
||||||
|
|
||||||
|
// پیام Reply
|
||||||
|
public Guid? ReplyToMessageId { get; private set; }
|
||||||
|
public TaskChatMessage? ReplyToMessage { get; private set; }
|
||||||
|
|
||||||
|
// وضعیت پیام
|
||||||
|
public bool IsEdited { get; private set; }
|
||||||
|
public DateTime? EditedDate { get; private set; }
|
||||||
|
public bool IsDeleted { get; private set; }
|
||||||
|
public DateTime? DeletedDate { get; private set; }
|
||||||
|
public bool IsPinned { get; private set; }
|
||||||
|
public DateTime? PinnedDate { get; private set; }
|
||||||
|
public long? PinnedByUserId { get; private set; }
|
||||||
|
|
||||||
|
private void ValidateMessage()
|
||||||
|
{
|
||||||
|
// ✅ بررسی پیامهای متنی
|
||||||
|
if (MessageType == MessageType.Text && string.IsNullOrWhiteSpace(TextContent))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("پیام متنی نمیتواند خالی باشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ بررسی پیامهای فایلی - باید FileId داشته باشند
|
||||||
|
if ((MessageType == MessageType.File || MessageType == MessageType.Voice ||
|
||||||
|
MessageType == MessageType.Image || MessageType == MessageType.Video)
|
||||||
|
&& FileId == null)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("پیامهای فایلی باید شناسه فایل داشته باشند");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ بررسی یادداشتهای سیستم - باید محتوای متنی داشته باشند
|
||||||
|
if (MessageType == MessageType.Note && string.IsNullOrWhiteSpace(TextContent))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("یادداشت نمیتواند خالی باشد");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetFile(Guid fileId)
|
||||||
|
{
|
||||||
|
if (MessageType != MessageType.File && MessageType != MessageType.Image &&
|
||||||
|
MessageType != MessageType.Video && MessageType != MessageType.Voice)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("فقط میتوان برای پیامهای فایل، تصویر، ویدیو و صدا شناسه فایل تنظیم کرد");
|
||||||
|
}
|
||||||
|
|
||||||
|
FileId = fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EditMessage(string newTextContent, long editorUserId)
|
||||||
|
{
|
||||||
|
if (IsDeleted)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("نمیتوان پیام حذف شده را ویرایش کرد");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editorUserId != SenderUserId)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("فقط فرستنده میتواند پیام را ویرایش کند");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((MessageType != MessageType.Text && !string.IsNullOrWhiteSpace(TextContent)))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("فقط پیامهای متنی قابل ویرایش هستند");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(newTextContent))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("محتوای پیام نمیتواند خالی باشد");
|
||||||
|
}
|
||||||
|
|
||||||
|
TextContent = newTextContent;
|
||||||
|
IsEdited = true;
|
||||||
|
EditedDate = DateTime.Now;
|
||||||
|
AddDomainEvent(new TaskChatMessageEditedEvent(Id, TaskId, editorUserId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteMessage(long deleterUserId)
|
||||||
|
{
|
||||||
|
if (IsDeleted)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("پیام قبلاً حذف شده است");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deleterUserId != SenderUserId)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("فقط فرستنده میتواند پیام را حذف کند");
|
||||||
|
}
|
||||||
|
|
||||||
|
IsDeleted = true;
|
||||||
|
DeletedDate = DateTime.Now;
|
||||||
|
AddDomainEvent(new TaskChatMessageDeletedEvent(Id, TaskId, deleterUserId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PinMessage(long pinnerUserId)
|
||||||
|
{
|
||||||
|
if (IsDeleted)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("نمیتوان پیام حذف شده را پین کرد");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsPinned)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("این پیام قبلاً پین شده است");
|
||||||
|
}
|
||||||
|
|
||||||
|
IsPinned = true;
|
||||||
|
PinnedDate = DateTime.Now;
|
||||||
|
PinnedByUserId = pinnerUserId;
|
||||||
|
AddDomainEvent(new TaskChatMessagePinnedEvent(Id, TaskId, pinnerUserId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnpinMessage(long unpinnerUserId)
|
||||||
|
{
|
||||||
|
if (!IsPinned)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("این پیام پین نشده است");
|
||||||
|
}
|
||||||
|
|
||||||
|
IsPinned = false;
|
||||||
|
PinnedDate = null;
|
||||||
|
PinnedByUserId = null;
|
||||||
|
AddDomainEvent(new TaskChatMessageUnpinnedEvent(Id, TaskId, unpinnerUserId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetReplyTo(Guid replyToMessageId)
|
||||||
|
{
|
||||||
|
ReplyToMessageId = replyToMessageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSentBy(long userId)
|
||||||
|
{
|
||||||
|
return SenderUserId == userId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
namespace GozareshgirProgramManager.Domain.TaskChatAgg.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// نوع پیام در چت تسک
|
||||||
|
/// </summary>
|
||||||
|
public enum MessageType
|
||||||
|
{
|
||||||
|
Text = 1, // پیام متنی
|
||||||
|
File = 2, // فایل (اسناد، PDF، و غیره)
|
||||||
|
Image = 3, // تصویر
|
||||||
|
Voice = 4, // پیام صوتی
|
||||||
|
Video = 5, // ویدیو
|
||||||
|
Note = 6, // ✅ یادداشت سیستم (برای زمان اضافی و اطلاعات خودکار)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using GozareshgirProgramManager.Domain._Common;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Enums;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Domain.TaskChatAgg.Events;
|
||||||
|
|
||||||
|
// Message Events
|
||||||
|
public record TaskChatMessageSentEvent(Guid MessageId, Guid TaskId, long SenderUserId, MessageType MessageType) : IDomainEvent
|
||||||
|
{
|
||||||
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record TaskChatMessageEditedEvent(Guid MessageId, Guid TaskId, long EditorUserId) : IDomainEvent
|
||||||
|
{
|
||||||
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record TaskChatMessageDeletedEvent(Guid MessageId, Guid TaskId, long DeleterUserId) : IDomainEvent
|
||||||
|
{
|
||||||
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record TaskChatMessagePinnedEvent(Guid MessageId, Guid TaskId, long PinnerUserId) : IDomainEvent
|
||||||
|
{
|
||||||
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record TaskChatMessageUnpinnedEvent(Guid MessageId, Guid TaskId, long UnpinnerUserId) : IDomainEvent
|
||||||
|
{
|
||||||
|
public DateTime OccurredOn { get; init; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Entities;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Domain.TaskChatAgg.Repositories;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Repository برای مدیریت پیامهای چت تسک
|
||||||
|
/// </summary>
|
||||||
|
public interface ITaskChatMessageRepository
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت پیام بر اساس شناسه
|
||||||
|
/// </summary>
|
||||||
|
Task<TaskChatMessage?> GetByIdAsync(Guid messageId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت لیست پیامهای یک تسک (با صفحهبندی)
|
||||||
|
/// </summary>
|
||||||
|
Task<List<TaskChatMessage>> GetTaskMessagesAsync(Guid taskId, int pageNumber, int pageSize);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت تعداد کل پیامهای یک تسک
|
||||||
|
/// </summary>
|
||||||
|
Task<int> GetTaskMessageCountAsync(Guid taskId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت پیامهای پین شده یک تسک
|
||||||
|
/// </summary>
|
||||||
|
Task<List<TaskChatMessage>> GetPinnedMessagesAsync(Guid taskId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت آخرین پیام یک تسک
|
||||||
|
/// </summary>
|
||||||
|
Task<TaskChatMessage?> GetLastMessageAsync(Guid taskId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// جستجو در پیامهای یک تسک
|
||||||
|
/// </summary>
|
||||||
|
Task<List<TaskChatMessage>> SearchMessagesAsync(Guid taskId, string searchText, int pageNumber, int pageSize);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت پیامهای یک کاربر خاص در یک تسک
|
||||||
|
/// </summary>
|
||||||
|
Task<List<TaskChatMessage>> GetUserMessagesAsync(Guid taskId, long userId, int pageNumber, int pageSize);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت پیامهای با فایل (تصویر، ویدیو، فایل و...) - پیامهایی که FileId دارند
|
||||||
|
/// </summary>
|
||||||
|
Task<List<TaskChatMessage>> GetMediaMessagesAsync(Guid taskId, int pageNumber, int pageSize);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// اضافه کردن پیام جدید
|
||||||
|
/// </summary>
|
||||||
|
Task<TaskChatMessage> AddAsync(TaskChatMessage message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بهروزرسانی پیام
|
||||||
|
/// </summary>
|
||||||
|
Task UpdateAsync(TaskChatMessage message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// حذف فیزیکی پیام (در صورت نیاز - معمولاً استفاده نمیشود)
|
||||||
|
/// </summary>
|
||||||
|
Task DeleteAsync(TaskChatMessage message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ذخیره تغییرات
|
||||||
|
/// </summary>
|
||||||
|
Task<int> SaveChangesAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بررسی وجود پیام
|
||||||
|
/// </summary>
|
||||||
|
Task<bool> ExistsAsync(Guid messageId);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,9 +4,11 @@
|
|||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using GozareshgirProgramManager.Application._Common.Behaviors;
|
using GozareshgirProgramManager.Application._Common.Behaviors;
|
||||||
using GozareshgirProgramManager.Application._Common.Interfaces;
|
using GozareshgirProgramManager.Application._Common.Interfaces;
|
||||||
|
using GozareshgirProgramManager.Application.Services.FileManagement;
|
||||||
using GozareshgirProgramManager.Domain._Common;
|
using GozareshgirProgramManager.Domain._Common;
|
||||||
using GozareshgirProgramManager.Domain.CheckoutAgg.Repositories;
|
using GozareshgirProgramManager.Domain.CheckoutAgg.Repositories;
|
||||||
using GozareshgirProgramManager.Domain.CustomerAgg.Repositories;
|
using GozareshgirProgramManager.Domain.CustomerAgg.Repositories;
|
||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Repositories;
|
||||||
using GozareshgirProgramManager.Domain.ProjectAgg.Repositories;
|
using GozareshgirProgramManager.Domain.ProjectAgg.Repositories;
|
||||||
using GozareshgirProgramManager.Domain.RoleAgg.Repositories;
|
using GozareshgirProgramManager.Domain.RoleAgg.Repositories;
|
||||||
using GozareshgirProgramManager.Domain.RoleAgg.Repositories;
|
using GozareshgirProgramManager.Domain.RoleAgg.Repositories;
|
||||||
@@ -14,6 +16,7 @@ using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Repositories;
|
|||||||
using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Repositories;
|
using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Repositories;
|
||||||
using GozareshgirProgramManager.Domain.SkillAgg.Repositories;
|
using GozareshgirProgramManager.Domain.SkillAgg.Repositories;
|
||||||
using GozareshgirProgramManager.Domain.SkillAgg.Repositories;
|
using GozareshgirProgramManager.Domain.SkillAgg.Repositories;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Repositories;
|
||||||
using GozareshgirProgramManager.Domain.UserAgg.Repositories;
|
using GozareshgirProgramManager.Domain.UserAgg.Repositories;
|
||||||
using GozareshgirProgramManager.Infrastructure.Persistence;
|
using GozareshgirProgramManager.Infrastructure.Persistence;
|
||||||
using GozareshgirProgramManager.Infrastructure.Persistence.Context;
|
using GozareshgirProgramManager.Infrastructure.Persistence.Context;
|
||||||
@@ -82,6 +85,14 @@ public static class DependencyInjection
|
|||||||
|
|
||||||
services.AddScoped<IUserRefreshTokenRepository, UserRefreshTokenRepository>();
|
services.AddScoped<IUserRefreshTokenRepository, UserRefreshTokenRepository>();
|
||||||
|
|
||||||
|
// File Management & Task Chat
|
||||||
|
services.AddScoped<IUploadedFileRepository, Persistence.Repositories.FileManagement.UploadedFileRepository>();
|
||||||
|
services.AddScoped<ITaskChatMessageRepository, Persistence.Repositories.TaskChat.TaskChatMessageRepository>();
|
||||||
|
|
||||||
|
// File Storage Services
|
||||||
|
services.AddScoped<IFileStorageService, Services.FileManagement.LocalFileStorageService>();
|
||||||
|
services.AddScoped<IThumbnailGeneratorService, Services.FileManagement.ThumbnailGeneratorService>();
|
||||||
|
|
||||||
// JWT Settings
|
// JWT Settings
|
||||||
services.Configure<JwtSettings>(configuration.GetSection("JwtSettings"));
|
services.Configure<JwtSettings>(configuration.GetSection("JwtSettings"));
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,21 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.1" />
|
||||||
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
|
||||||
<!--<PackageReference Include="System.Text.Encodings.Web" Version="10.0.0" />-->
|
<!--<PackageReference Include="System.Text.Encodings.Web" Version="10.0.0" />-->
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Application\GozareshgirProgramManager.Application\GozareshgirProgramManager.Application.csproj" />
|
<ProjectReference Include="..\..\Application\GozareshgirProgramManager.Application\GozareshgirProgramManager.Application.csproj" />
|
||||||
<ProjectReference Include="..\..\Domain\GozareshgirProgramManager.Domain\GozareshgirProgramManager.Domain.csproj" />
|
<ProjectReference Include="..\..\Domain\GozareshgirProgramManager.Domain\GozareshgirProgramManager.Domain.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.AspNetCore.Hosting.Abstractions">
|
||||||
|
<HintPath>C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\10.0.1\Microsoft.AspNetCore.Hosting.Abstractions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Extensions.Hosting.Abstractions">
|
||||||
|
<HintPath>C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\10.0.1\Microsoft.Extensions.Hosting.Abstractions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Infrastructure.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class addtaskchatuploadedfile : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "TaskChatMessages",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TaskId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
SenderUserId = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
MessageType = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||||
|
TextContent = table.Column<string>(type: "nvarchar(4000)", maxLength: 4000, nullable: true),
|
||||||
|
FileId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
ReplyToMessageId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
IsEdited = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||||
|
EditedDate = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||||
|
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||||
|
DeletedDate = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||||
|
IsPinned = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||||
|
PinnedDate = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||||
|
PinnedByUserId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
CreationDate = table.Column<DateTime>(type: "datetime2", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_TaskChatMessages", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TaskChatMessages_TaskChatMessages_ReplyToMessageId",
|
||||||
|
column: x => x.ReplyToMessageId,
|
||||||
|
principalTable: "TaskChatMessages",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "UploadedFiles",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
OriginalFileName = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
|
||||||
|
UniqueFileName = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
|
||||||
|
FileExtension = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||||
|
FileSizeBytes = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
MimeType = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||||
|
FileType = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||||
|
Category = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||||
|
StorageProvider = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||||
|
StoragePath = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
|
||||||
|
StorageUrl = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
|
||||||
|
ThumbnailUrl = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
|
||||||
|
UploadedByUserId = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
UploadDate = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||||
|
Status = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||||
|
ImageWidth = table.Column<int>(type: "int", nullable: true),
|
||||||
|
ImageHeight = table.Column<int>(type: "int", nullable: true),
|
||||||
|
DurationSeconds = table.Column<int>(type: "int", nullable: true),
|
||||||
|
VirusScanDate = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||||
|
IsVirusScanPassed = table.Column<bool>(type: "bit", nullable: true),
|
||||||
|
VirusScanResult = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||||
|
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||||
|
DeletedDate = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||||
|
DeletedByUserId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
ReferenceEntityType = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||||
|
ReferenceEntityId = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||||
|
CreationDate = table.Column<DateTime>(type: "datetime2", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_UploadedFiles", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TaskChatMessages_CreationDate",
|
||||||
|
table: "TaskChatMessages",
|
||||||
|
column: "CreationDate");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TaskChatMessages_FileId",
|
||||||
|
table: "TaskChatMessages",
|
||||||
|
column: "FileId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TaskChatMessages_IsDeleted",
|
||||||
|
table: "TaskChatMessages",
|
||||||
|
column: "IsDeleted");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TaskChatMessages_ReplyToMessageId",
|
||||||
|
table: "TaskChatMessages",
|
||||||
|
column: "ReplyToMessageId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TaskChatMessages_SenderUserId",
|
||||||
|
table: "TaskChatMessages",
|
||||||
|
column: "SenderUserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TaskChatMessages_TaskId",
|
||||||
|
table: "TaskChatMessages",
|
||||||
|
column: "TaskId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TaskChatMessages_TaskId_IsPinned",
|
||||||
|
table: "TaskChatMessages",
|
||||||
|
columns: new[] { "TaskId", "IsPinned" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_UploadedFiles_Category",
|
||||||
|
table: "UploadedFiles",
|
||||||
|
column: "Category");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_UploadedFiles_IsDeleted",
|
||||||
|
table: "UploadedFiles",
|
||||||
|
column: "IsDeleted");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_UploadedFiles_ReferenceEntityType_ReferenceEntityId",
|
||||||
|
table: "UploadedFiles",
|
||||||
|
columns: new[] { "ReferenceEntityType", "ReferenceEntityId" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_UploadedFiles_Status",
|
||||||
|
table: "UploadedFiles",
|
||||||
|
column: "Status");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_UploadedFiles_UniqueFileName",
|
||||||
|
table: "UploadedFiles",
|
||||||
|
column: "UniqueFileName",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_UploadedFiles_UploadedByUserId",
|
||||||
|
table: "UploadedFiles",
|
||||||
|
column: "UploadedByUserId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "TaskChatMessages");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "UploadedFiles");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -102,6 +102,131 @@ namespace GozareshgirProgramManager.Infrastructure.Migrations
|
|||||||
b.ToTable("Customers", (string)null);
|
b.ToTable("Customers", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GozareshgirProgramManager.Domain.FileManagementAgg.Entities.UploadedFile", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("Category")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(100)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreationDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedByUserId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<int?>("DurationSeconds")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("FileExtension")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(50)");
|
||||||
|
|
||||||
|
b.Property<long>("FileSizeBytes")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("FileType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(50)");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageHeight")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageWidth")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("IsDeleted")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool?>("IsVirusScanPassed")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<string>("MimeType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("nvarchar(200)");
|
||||||
|
|
||||||
|
b.Property<string>("OriginalFileName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("nvarchar(500)");
|
||||||
|
|
||||||
|
b.Property<string>("ReferenceEntityId")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(100)");
|
||||||
|
|
||||||
|
b.Property<string>("ReferenceEntityType")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(100)");
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(50)");
|
||||||
|
|
||||||
|
b.Property<string>("StoragePath")
|
||||||
|
.HasMaxLength(1000)
|
||||||
|
.HasColumnType("nvarchar(1000)");
|
||||||
|
|
||||||
|
b.Property<string>("StorageProvider")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(50)");
|
||||||
|
|
||||||
|
b.Property<string>("StorageUrl")
|
||||||
|
.HasMaxLength(1000)
|
||||||
|
.HasColumnType("nvarchar(1000)");
|
||||||
|
|
||||||
|
b.Property<string>("ThumbnailUrl")
|
||||||
|
.HasMaxLength(1000)
|
||||||
|
.HasColumnType("nvarchar(1000)");
|
||||||
|
|
||||||
|
b.Property<string>("UniqueFileName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("nvarchar(500)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UploadDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<long>("UploadedByUserId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("VirusScanDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<string>("VirusScanResult")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("nvarchar(500)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Category");
|
||||||
|
|
||||||
|
b.HasIndex("IsDeleted");
|
||||||
|
|
||||||
|
b.HasIndex("Status");
|
||||||
|
|
||||||
|
b.HasIndex("UniqueFileName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("UploadedByUserId");
|
||||||
|
|
||||||
|
b.HasIndex("ReferenceEntityType", "ReferenceEntityId");
|
||||||
|
|
||||||
|
b.ToTable("UploadedFiles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b =>
|
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
@@ -495,6 +620,81 @@ namespace GozareshgirProgramManager.Infrastructure.Migrations
|
|||||||
b.ToTable("Skills", (string)null);
|
b.ToTable("Skills", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GozareshgirProgramManager.Domain.TaskChatAgg.Entities.TaskChatMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreationDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("EditedDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<Guid?>("FileId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<bool>("IsDeleted")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsEdited")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsPinned")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<string>("MessageType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("nvarchar(50)");
|
||||||
|
|
||||||
|
b.Property<long?>("PinnedByUserId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("PinnedDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<Guid?>("ReplyToMessageId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<long>("SenderUserId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<Guid>("TaskId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("TextContent")
|
||||||
|
.HasMaxLength(4000)
|
||||||
|
.HasColumnType("nvarchar(4000)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CreationDate");
|
||||||
|
|
||||||
|
b.HasIndex("FileId");
|
||||||
|
|
||||||
|
b.HasIndex("IsDeleted");
|
||||||
|
|
||||||
|
b.HasIndex("ReplyToMessageId");
|
||||||
|
|
||||||
|
b.HasIndex("SenderUserId");
|
||||||
|
|
||||||
|
b.HasIndex("TaskId");
|
||||||
|
|
||||||
|
b.HasIndex("TaskId", "IsPinned");
|
||||||
|
|
||||||
|
b.ToTable("TaskChatMessages", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b =>
|
modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("Id")
|
b.Property<long>("Id")
|
||||||
@@ -779,6 +979,16 @@ namespace GozareshgirProgramManager.Infrastructure.Migrations
|
|||||||
b.Navigation("WorkingHoursList");
|
b.Navigation("WorkingHoursList");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GozareshgirProgramManager.Domain.TaskChatAgg.Entities.TaskChatMessage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GozareshgirProgramManager.Domain.TaskChatAgg.Entities.TaskChatMessage", "ReplyToMessage")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ReplyToMessageId")
|
||||||
|
.OnDelete(DeleteBehavior.NoAction);
|
||||||
|
|
||||||
|
b.Navigation("ReplyToMessage");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b =>
|
modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b =>
|
||||||
{
|
{
|
||||||
b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 =>
|
b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 =>
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
using GozareshgirProgramManager.Application._Common.Interfaces;
|
using GozareshgirProgramManager.Application._Common.Interfaces;
|
||||||
using GozareshgirProgramManager.Domain.CheckoutAgg.Entities;
|
using GozareshgirProgramManager.Domain.CheckoutAgg.Entities;
|
||||||
using GozareshgirProgramManager.Domain.CustomerAgg;
|
using GozareshgirProgramManager.Domain.CustomerAgg;
|
||||||
using GozareshgirProgramManager.Application._Common.Interfaces;
|
using GozareshgirProgramManager.Application._Common.Interfaces;
|
||||||
using GozareshgirProgramManager.Domain.CustomerAgg;
|
using GozareshgirProgramManager.Domain.CustomerAgg;
|
||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Entities;
|
||||||
using GozareshgirProgramManager.Domain.ProjectAgg.Entities;
|
using GozareshgirProgramManager.Domain.ProjectAgg.Entities;
|
||||||
using GozareshgirProgramManager.Domain.RoleAgg.Entities;
|
using GozareshgirProgramManager.Domain.RoleAgg.Entities;
|
||||||
using GozareshgirProgramManager.Domain.RoleUserAgg;
|
using GozareshgirProgramManager.Domain.RoleUserAgg;
|
||||||
using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities;
|
using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities;
|
||||||
using GozareshgirProgramManager.Domain.UserAgg.Entities;
|
using GozareshgirProgramManager.Domain.UserAgg.Entities;
|
||||||
using GozareshgirProgramManager.Domain.SkillAgg.Entities;
|
using GozareshgirProgramManager.Domain.SkillAgg.Entities;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Entities;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace GozareshgirProgramManager.Infrastructure.Persistence.Context;
|
namespace GozareshgirProgramManager.Infrastructure.Persistence.Context;
|
||||||
@@ -40,6 +42,13 @@ public class ProgramManagerDbContext : DbContext, IProgramManagerDbContext
|
|||||||
public DbSet<Role> Roles { get; set; } = null!;
|
public DbSet<Role> Roles { get; set; } = null!;
|
||||||
|
|
||||||
public DbSet<Skill> Skills { get; set; } = null!;
|
public DbSet<Skill> Skills { get; set; } = null!;
|
||||||
|
|
||||||
|
// File Management
|
||||||
|
public DbSet<UploadedFile> UploadedFiles { get; set; } = null!;
|
||||||
|
|
||||||
|
// Task Chat
|
||||||
|
public DbSet<TaskChatMessage> TaskChatMessages { get; set; } = null!;
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
modelBuilder.ApplyConfigurationsFromAssembly(typeof(ProgramManagerDbContext).Assembly);
|
modelBuilder.ApplyConfigurationsFromAssembly(typeof(ProgramManagerDbContext).Assembly);
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Entities;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings;
|
||||||
|
|
||||||
|
public class TaskChatMessageMapping : IEntityTypeConfiguration<TaskChatMessage>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<TaskChatMessage> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable("TaskChatMessages");
|
||||||
|
|
||||||
|
builder.HasKey(x => x.Id);
|
||||||
|
|
||||||
|
builder.Property(x => x.Id)
|
||||||
|
.ValueGeneratedNever();
|
||||||
|
|
||||||
|
// Task Reference
|
||||||
|
builder.Property(x => x.TaskId)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.HasIndex(x => x.TaskId);
|
||||||
|
|
||||||
|
// Sender
|
||||||
|
builder.Property(x => x.SenderUserId)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.HasIndex(x => x.SenderUserId);
|
||||||
|
|
||||||
|
// Message Type
|
||||||
|
builder.Property(x => x.MessageType)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConversion<string>()
|
||||||
|
.HasMaxLength(50);
|
||||||
|
|
||||||
|
// Content
|
||||||
|
builder.Property(x => x.TextContent)
|
||||||
|
.HasMaxLength(4000);
|
||||||
|
|
||||||
|
// File Reference
|
||||||
|
builder.Property(x => x.FileId);
|
||||||
|
|
||||||
|
builder.HasIndex(x => x.FileId);
|
||||||
|
|
||||||
|
// Reply
|
||||||
|
builder.Property(x => x.ReplyToMessageId);
|
||||||
|
|
||||||
|
builder.HasOne(x => x.ReplyToMessage)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(x => x.ReplyToMessageId)
|
||||||
|
.OnDelete(DeleteBehavior.NoAction);
|
||||||
|
|
||||||
|
// Status
|
||||||
|
builder.Property(x => x.IsEdited)
|
||||||
|
.IsRequired()
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
builder.Property(x => x.EditedDate);
|
||||||
|
|
||||||
|
builder.Property(x => x.IsDeleted)
|
||||||
|
.IsRequired()
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
builder.Property(x => x.DeletedDate);
|
||||||
|
|
||||||
|
builder.HasIndex(x => x.IsDeleted);
|
||||||
|
|
||||||
|
// Pin
|
||||||
|
builder.Property(x => x.IsPinned)
|
||||||
|
.IsRequired()
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
builder.Property(x => x.PinnedDate);
|
||||||
|
builder.Property(x => x.PinnedByUserId);
|
||||||
|
|
||||||
|
builder.HasIndex(x => new { x.TaskId, x.IsPinned });
|
||||||
|
|
||||||
|
// Audit
|
||||||
|
builder.Property(x => x.CreationDate)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.HasIndex(x => x.CreationDate);
|
||||||
|
|
||||||
|
// Query Filter - پیامهای حذف نشده
|
||||||
|
builder.HasQueryFilter(x => !x.IsDeleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Entities;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings;
|
||||||
|
|
||||||
|
public class UploadedFileMapping : IEntityTypeConfiguration<UploadedFile>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<UploadedFile> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable("UploadedFiles");
|
||||||
|
|
||||||
|
builder.HasKey(x => x.Id);
|
||||||
|
|
||||||
|
builder.Property(x => x.Id)
|
||||||
|
.ValueGeneratedNever();
|
||||||
|
|
||||||
|
// اطلاعات فایل
|
||||||
|
builder.Property(x => x.OriginalFileName)
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(500);
|
||||||
|
|
||||||
|
builder.Property(x => x.UniqueFileName)
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(500);
|
||||||
|
|
||||||
|
builder.HasIndex(x => x.UniqueFileName)
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
builder.Property(x => x.FileExtension)
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50);
|
||||||
|
|
||||||
|
builder.Property(x => x.FileSizeBytes)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(x => x.MimeType)
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200);
|
||||||
|
|
||||||
|
builder.Property(x => x.FileType)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConversion<string>()
|
||||||
|
.HasMaxLength(50);
|
||||||
|
|
||||||
|
builder.Property(x => x.Category)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConversion<string>()
|
||||||
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
// ذخیرهسازی
|
||||||
|
builder.Property(x => x.StorageProvider)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConversion<string>()
|
||||||
|
.HasMaxLength(50);
|
||||||
|
|
||||||
|
builder.Property(x => x.StoragePath)
|
||||||
|
.HasMaxLength(1000);
|
||||||
|
|
||||||
|
builder.Property(x => x.StorageUrl)
|
||||||
|
.HasMaxLength(1000);
|
||||||
|
|
||||||
|
builder.Property(x => x.ThumbnailUrl)
|
||||||
|
.HasMaxLength(1000);
|
||||||
|
|
||||||
|
// متادیتا
|
||||||
|
builder.Property(x => x.UploadedByUserId)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(x => x.UploadDate)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(x => x.Status)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConversion<string>()
|
||||||
|
.HasMaxLength(50);
|
||||||
|
|
||||||
|
builder.HasIndex(x => x.Status);
|
||||||
|
builder.HasIndex(x => x.UploadedByUserId);
|
||||||
|
builder.HasIndex(x => x.Category);
|
||||||
|
|
||||||
|
// اطلاعات تصویر
|
||||||
|
builder.Property(x => x.ImageWidth);
|
||||||
|
builder.Property(x => x.ImageHeight);
|
||||||
|
|
||||||
|
// اطلاعات صوت/ویدیو
|
||||||
|
builder.Property(x => x.DurationSeconds);
|
||||||
|
|
||||||
|
// امنیت
|
||||||
|
builder.Property(x => x.VirusScanDate);
|
||||||
|
builder.Property(x => x.IsVirusScanPassed);
|
||||||
|
builder.Property(x => x.VirusScanResult)
|
||||||
|
.HasMaxLength(500);
|
||||||
|
|
||||||
|
// Soft Delete
|
||||||
|
builder.Property(x => x.IsDeleted)
|
||||||
|
.IsRequired()
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
builder.Property(x => x.DeletedDate);
|
||||||
|
builder.Property(x => x.DeletedByUserId);
|
||||||
|
|
||||||
|
builder.HasIndex(x => x.IsDeleted);
|
||||||
|
|
||||||
|
// Reference Tracking
|
||||||
|
builder.Property(x => x.ReferenceEntityType)
|
||||||
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
builder.Property(x => x.ReferenceEntityId)
|
||||||
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
builder.HasIndex(x => new { x.ReferenceEntityType, x.ReferenceEntityId });
|
||||||
|
|
||||||
|
// Audit
|
||||||
|
builder.Property(x => x.CreationDate)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
// Query Filter - فایلهای حذف نشده
|
||||||
|
builder.HasQueryFilter(x => !x.IsDeleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Entities;
|
||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Enums;
|
||||||
|
using GozareshgirProgramManager.Domain.FileManagementAgg.Repositories;
|
||||||
|
using GozareshgirProgramManager.Infrastructure.Persistence.Context;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories.FileManagement;
|
||||||
|
|
||||||
|
public class UploadedFileRepository : IUploadedFileRepository
|
||||||
|
{
|
||||||
|
private readonly ProgramManagerDbContext _context;
|
||||||
|
|
||||||
|
public UploadedFileRepository(ProgramManagerDbContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<UploadedFile?> GetByIdAsync(Guid fileId)
|
||||||
|
{
|
||||||
|
return await _context.UploadedFiles
|
||||||
|
.FirstOrDefaultAsync(x => x.Id == fileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<UploadedFile?> GetByUniqueFileNameAsync(string uniqueFileName)
|
||||||
|
{
|
||||||
|
return await _context.UploadedFiles
|
||||||
|
.FirstOrDefaultAsync(x => x.UniqueFileName == uniqueFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<UploadedFile>> GetUserFilesAsync(long userId, int pageNumber, int pageSize)
|
||||||
|
{
|
||||||
|
return await _context.UploadedFiles
|
||||||
|
.Where(x => x.UploadedByUserId == userId)
|
||||||
|
.OrderByDescending(x => x.UploadDate)
|
||||||
|
.Skip((pageNumber - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<UploadedFile>> GetByCategoryAsync(FileCategory category, int pageNumber, int pageSize)
|
||||||
|
{
|
||||||
|
return await _context.UploadedFiles
|
||||||
|
.Where(x => x.Category == category)
|
||||||
|
.OrderByDescending(x => x.UploadDate)
|
||||||
|
.Skip((pageNumber - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<UploadedFile>> GetByStatusAsync(FileStatus status, int pageNumber, int pageSize)
|
||||||
|
{
|
||||||
|
return await _context.UploadedFiles
|
||||||
|
.Where(x => x.Status == status)
|
||||||
|
.OrderByDescending(x => x.UploadDate)
|
||||||
|
.Skip((pageNumber - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<UploadedFile>> GetByReferenceAsync(string entityType, string entityId)
|
||||||
|
{
|
||||||
|
return await _context.UploadedFiles
|
||||||
|
.Where(x => x.ReferenceEntityType == entityType && x.ReferenceEntityId == entityId)
|
||||||
|
.OrderByDescending(x => x.UploadDate)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<UploadedFile>> SearchByNameAsync(string searchTerm, int pageNumber, int pageSize)
|
||||||
|
{
|
||||||
|
return await _context.UploadedFiles
|
||||||
|
.Where(x => x.OriginalFileName.Contains(searchTerm))
|
||||||
|
.OrderByDescending(x => x.UploadDate)
|
||||||
|
.Skip((pageNumber - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> GetUserFilesCountAsync(long userId)
|
||||||
|
{
|
||||||
|
return await _context.UploadedFiles
|
||||||
|
.CountAsync(x => x.UploadedByUserId == userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<long> GetUserTotalFileSizeAsync(long userId)
|
||||||
|
{
|
||||||
|
return await _context.UploadedFiles
|
||||||
|
.Where(x => x.UploadedByUserId == userId)
|
||||||
|
.SumAsync(x => x.FileSizeBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<UploadedFile>> GetExpiredFilesAsync(DateTime olderThan)
|
||||||
|
{
|
||||||
|
return await _context.UploadedFiles
|
||||||
|
.IgnoreQueryFilters() // Include deleted files
|
||||||
|
.Where(x => x.IsDeleted && x.DeletedDate < olderThan)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<UploadedFile> AddAsync(UploadedFile file)
|
||||||
|
{
|
||||||
|
await _context.UploadedFiles.AddAsync(file);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task UpdateAsync(UploadedFile file)
|
||||||
|
{
|
||||||
|
_context.UploadedFiles.Update(file);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteAsync(UploadedFile file)
|
||||||
|
{
|
||||||
|
_context.UploadedFiles.Remove(file);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> SaveChangesAsync()
|
||||||
|
{
|
||||||
|
return await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ExistsAsync(Guid fileId)
|
||||||
|
{
|
||||||
|
return await _context.UploadedFiles
|
||||||
|
.AnyAsync(x => x.Id == fileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ExistsByUniqueFileNameAsync(string uniqueFileName)
|
||||||
|
{
|
||||||
|
return await _context.UploadedFiles
|
||||||
|
.AnyAsync(x => x.UniqueFileName == uniqueFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ public class ProjectTaskRepository : RepositoryBase<Guid, ProjectTask>, IProject
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<List<ProjectTask>> GetByPriorityAsync(TaskPriority priority)
|
public Task<List<ProjectTask>> GetByPriorityAsync(ProjectTaskPriority priority)
|
||||||
{
|
{
|
||||||
return _context.ProjectTasks
|
return _context.ProjectTasks
|
||||||
.Where(t => t.Priority == priority)
|
.Where(t => t.Priority == priority)
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Entities;
|
||||||
|
using GozareshgirProgramManager.Domain.TaskChatAgg.Repositories;
|
||||||
|
using GozareshgirProgramManager.Infrastructure.Persistence.Context;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories.TaskChat;
|
||||||
|
|
||||||
|
public class TaskChatMessageRepository : ITaskChatMessageRepository
|
||||||
|
{
|
||||||
|
private readonly ProgramManagerDbContext _context;
|
||||||
|
|
||||||
|
public TaskChatMessageRepository(ProgramManagerDbContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TaskChatMessage?> GetByIdAsync(Guid messageId)
|
||||||
|
{
|
||||||
|
return await _context.TaskChatMessages
|
||||||
|
.Include(x => x.ReplyToMessage)
|
||||||
|
.FirstOrDefaultAsync(x => x.Id == messageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<TaskChatMessage>> GetTaskMessagesAsync(Guid taskId, int pageNumber, int pageSize)
|
||||||
|
{
|
||||||
|
return await _context.TaskChatMessages
|
||||||
|
.Where(x => x.TaskId == taskId)
|
||||||
|
.Include(x => x.ReplyToMessage)
|
||||||
|
.OrderBy(x => x.CreationDate)
|
||||||
|
.Skip((pageNumber - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> GetTaskMessageCountAsync(Guid taskId)
|
||||||
|
{
|
||||||
|
return await _context.TaskChatMessages
|
||||||
|
.CountAsync(x => x.TaskId == taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<TaskChatMessage>> GetPinnedMessagesAsync(Guid taskId)
|
||||||
|
{
|
||||||
|
return await _context.TaskChatMessages
|
||||||
|
.Where(x => x.TaskId == taskId && x.IsPinned)
|
||||||
|
.Include(x => x.ReplyToMessage)
|
||||||
|
.OrderByDescending(x => x.PinnedDate)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TaskChatMessage?> GetLastMessageAsync(Guid taskId)
|
||||||
|
{
|
||||||
|
return await _context.TaskChatMessages
|
||||||
|
.Where(x => x.TaskId == taskId)
|
||||||
|
.OrderByDescending(x => x.CreationDate)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<TaskChatMessage>> SearchMessagesAsync(Guid taskId, string searchText, int pageNumber, int pageSize)
|
||||||
|
{
|
||||||
|
return await _context.TaskChatMessages
|
||||||
|
.Where(x => x.TaskId == taskId &&
|
||||||
|
x.TextContent != null &&
|
||||||
|
x.TextContent.Contains(searchText))
|
||||||
|
.Include(x => x.ReplyToMessage)
|
||||||
|
.OrderByDescending(x => x.CreationDate)
|
||||||
|
.Skip((pageNumber - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<TaskChatMessage>> GetUserMessagesAsync(Guid taskId, long userId, int pageNumber, int pageSize)
|
||||||
|
{
|
||||||
|
return await _context.TaskChatMessages
|
||||||
|
.Where(x => x.TaskId == taskId && x.SenderUserId == userId)
|
||||||
|
.Include(x => x.ReplyToMessage)
|
||||||
|
.OrderByDescending(x => x.CreationDate)
|
||||||
|
.Skip((pageNumber - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<TaskChatMessage>> GetMediaMessagesAsync(Guid taskId, int pageNumber, int pageSize)
|
||||||
|
{
|
||||||
|
return await _context.TaskChatMessages
|
||||||
|
.Where(x => x.TaskId == taskId && x.FileId != null)
|
||||||
|
.Include(x => x.ReplyToMessage)
|
||||||
|
.OrderByDescending(x => x.CreationDate)
|
||||||
|
.Skip((pageNumber - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TaskChatMessage> AddAsync(TaskChatMessage message)
|
||||||
|
{
|
||||||
|
await _context.TaskChatMessages.AddAsync(message);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task UpdateAsync(TaskChatMessage message)
|
||||||
|
{
|
||||||
|
_context.TaskChatMessages.Update(message);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteAsync(TaskChatMessage message)
|
||||||
|
{
|
||||||
|
_context.TaskChatMessages.Remove(message);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> SaveChangesAsync()
|
||||||
|
{
|
||||||
|
return await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ExistsAsync(Guid messageId)
|
||||||
|
{
|
||||||
|
return await _context.TaskChatMessages
|
||||||
|
.AnyAsync(x => x.Id == messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
using GozareshgirProgramManager.Application.Services.FileManagement;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Infrastructure.Services.FileManagement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// سرویس ذخیرهسازی فایل در سیستم فایل محلی
|
||||||
|
/// </summary>
|
||||||
|
public class LocalFileStorageService : IFileStorageService
|
||||||
|
{
|
||||||
|
private readonly string _uploadBasePath;
|
||||||
|
private readonly string _baseUrl;
|
||||||
|
|
||||||
|
public LocalFileStorageService(IConfiguration configuration,
|
||||||
|
IHttpContextAccessor httpContextAccessor, IHostEnvironment env)
|
||||||
|
{
|
||||||
|
// محاسبه مسیر پایه: اگر env نبود، از مسیر فعلی استفاده کن
|
||||||
|
var contentRoot = env.ContentRootPath;
|
||||||
|
_uploadBasePath = Path.Combine(contentRoot, "Storage");
|
||||||
|
// Base URL برای دسترسی به فایلها
|
||||||
|
var request = httpContextAccessor.HttpContext?.Request;
|
||||||
|
if (request != null)
|
||||||
|
{
|
||||||
|
_baseUrl = $"{request.Scheme}://{request.Host}/storage";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_baseUrl = configuration["FileStorage:BaseUrl"] ?? "http://localhost:5000/storage";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ایجاد پوشه اگر وجود نداشت
|
||||||
|
if (!Directory.Exists(_uploadBasePath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(_uploadBasePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(string StoragePath, string StorageUrl)> UploadAsync(
|
||||||
|
Stream fileStream,
|
||||||
|
string uniqueFileName,
|
||||||
|
string category)
|
||||||
|
{
|
||||||
|
// ایجاد پوشه دستهبندی (مثلاً: Uploads/TaskChatMessage)
|
||||||
|
var categoryPath = Path.Combine(_uploadBasePath, category);
|
||||||
|
if (!Directory.Exists(categoryPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(categoryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ایجاد زیرپوشه بر اساس تاریخ (مثلاً: Uploads/TaskChatMessage/2026/01)
|
||||||
|
var datePath = Path.Combine(categoryPath, DateTime.Now.Year.ToString(),
|
||||||
|
DateTime.Now.Month.ToString("00"));
|
||||||
|
if (!Directory.Exists(datePath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(datePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// مسیر کامل فایل
|
||||||
|
var storagePath = Path.Combine(datePath, uniqueFileName);
|
||||||
|
|
||||||
|
// ذخیره فایل
|
||||||
|
await using var fileStreamOutput = new FileStream(storagePath, FileMode.Create, FileAccess.Write);
|
||||||
|
await fileStream.CopyToAsync(fileStreamOutput);
|
||||||
|
|
||||||
|
// URL فایل
|
||||||
|
var relativePath = Path.GetRelativePath(_uploadBasePath, storagePath)
|
||||||
|
.Replace("\\", "/");
|
||||||
|
var storageUrl = $"{_baseUrl}/{relativePath}";
|
||||||
|
|
||||||
|
return (storagePath, storageUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteAsync(string storagePath)
|
||||||
|
{
|
||||||
|
if (File.Exists(storagePath))
|
||||||
|
{
|
||||||
|
File.Delete(storagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Stream?> GetFileStreamAsync(string storagePath)
|
||||||
|
{
|
||||||
|
if (!File.Exists(storagePath))
|
||||||
|
{
|
||||||
|
return Task.FromResult<Stream?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var stream = new FileStream(storagePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||||
|
return Task.FromResult<Stream?>(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> ExistsAsync(string storagePath)
|
||||||
|
{
|
||||||
|
return Task.FromResult(File.Exists(storagePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetFileUrl(string storagePath)
|
||||||
|
{
|
||||||
|
var relativePath = Path.GetRelativePath(_uploadBasePath, storagePath)
|
||||||
|
.Replace("\\", "/");
|
||||||
|
return $"{_baseUrl}/{relativePath}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
using GozareshgirProgramManager.Application.Services.FileManagement;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using SixLabors.ImageSharp;
|
||||||
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||||
|
|
||||||
|
namespace GozareshgirProgramManager.Infrastructure.Services.FileManagement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// سرویس تولید thumbnail با استفاده از ImageSharp
|
||||||
|
/// </summary>
|
||||||
|
public class ThumbnailGeneratorService : IThumbnailGeneratorService
|
||||||
|
{
|
||||||
|
private readonly string _thumbnailBasePath;
|
||||||
|
private readonly string _baseUrl;
|
||||||
|
|
||||||
|
public ThumbnailGeneratorService(IConfiguration configuration,
|
||||||
|
IHttpContextAccessor httpContextAccessor)
|
||||||
|
{
|
||||||
|
_thumbnailBasePath = configuration["FileStorage:ThumbnailPath"]
|
||||||
|
?? Path.Combine(Directory.GetCurrentDirectory(), "storage", "Thumbnails");
|
||||||
|
var request = httpContextAccessor.HttpContext?.Request;
|
||||||
|
|
||||||
|
if (request != null)
|
||||||
|
{
|
||||||
|
_baseUrl = $"{request.Scheme}://{request.Host}/storage";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_baseUrl = configuration["FileStorage:BaseUrl"] ?? "http://localhost:5000/storage";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Directory.Exists(_thumbnailBasePath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(_thumbnailBasePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(string ThumbnailPath, string ThumbnailUrl)?> GenerateImageThumbnailAsync(
|
||||||
|
string imagePath,
|
||||||
|
string category,
|
||||||
|
int width = 200,
|
||||||
|
int height = 200)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!File.Exists(imagePath))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// بارگذاری تصویر
|
||||||
|
using var image = await Image.LoadAsync(imagePath);
|
||||||
|
|
||||||
|
// Resize با حفظ نسبت
|
||||||
|
image.Mutate(x => x.Resize(new ResizeOptions
|
||||||
|
{
|
||||||
|
Size = new Size(width, height),
|
||||||
|
Mode = ResizeMode.Max
|
||||||
|
}));
|
||||||
|
|
||||||
|
// نام فایل thumbnail
|
||||||
|
var fileName = Path.GetFileNameWithoutExtension(imagePath);
|
||||||
|
var extension = Path.GetExtension(imagePath);
|
||||||
|
var thumbnailFileName = $"{fileName}_thumb{extension}";
|
||||||
|
|
||||||
|
// دریافت مسیر و URL توسط متد private
|
||||||
|
var (thumbnailPath, thumbnailUrl) = GetThumbnailPathAndUrl(thumbnailFileName, category);
|
||||||
|
|
||||||
|
// ذخیره thumbnail با کیفیت 80
|
||||||
|
await image.SaveAsync(thumbnailPath, new JpegEncoder { Quality = 80 });
|
||||||
|
|
||||||
|
|
||||||
|
return (thumbnailPath, thumbnailUrl);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// در صورت خطا null برمیگردانیم
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(string ThumbnailPath, string ThumbnailUrl)?> GenerateVideoThumbnailAsync(string videoPath, string category = "general")
|
||||||
|
{
|
||||||
|
// TODO: برای Video thumbnail باید از FFmpeg استفاده کنیم
|
||||||
|
// فعلاً یک placeholder image برمیگردانیم
|
||||||
|
await Task.CompletedTask;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteThumbnailAsync(string thumbnailPath)
|
||||||
|
{
|
||||||
|
if (File.Exists(thumbnailPath))
|
||||||
|
{
|
||||||
|
File.Delete(thumbnailPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(int Width, int Height)?> GetImageDimensionsAsync(string imagePath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!File.Exists(imagePath))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageInfo = await Image.IdentifyAsync(imagePath);
|
||||||
|
return (imageInfo.Width, imageInfo.Height);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت مسیر فیزیکی و URL برای thumbnail بر اساس category
|
||||||
|
/// </summary>
|
||||||
|
private (string ThumbnailPath, string ThumbnailUrl) GetThumbnailPathAndUrl(string thumbnailFileName, string category)
|
||||||
|
{
|
||||||
|
var categoryFolder = string.IsNullOrWhiteSpace(category) ? "general" : category;
|
||||||
|
var categoryPath = Path.Combine(Directory.GetCurrentDirectory(), "storage", categoryFolder);
|
||||||
|
|
||||||
|
if (!Directory.Exists(categoryPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(categoryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
var thumbnailSubPath = Path.Combine(categoryPath, "Thumbnails");
|
||||||
|
if (!Directory.Exists(thumbnailSubPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(thumbnailSubPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
var thumbnailPath = Path.Combine(thumbnailSubPath, thumbnailFileName);
|
||||||
|
var thumbnailUrl = $"{_baseUrl}/{categoryFolder}/thumbnails/{thumbnailFileName}";
|
||||||
|
|
||||||
|
return (thumbnailPath, thumbnailUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
using GozareshgirProgramManager.Application._Common.Models;
|
||||||
|
using GozareshgirProgramManager.Application.Modules.TaskChat.Commands.DeleteMessage;
|
||||||
|
using GozareshgirProgramManager.Application.Modules.TaskChat.Commands.EditMessage;
|
||||||
|
using GozareshgirProgramManager.Application.Modules.TaskChat.Commands.PinMessage;
|
||||||
|
using GozareshgirProgramManager.Application.Modules.TaskChat.Commands.SendMessage;
|
||||||
|
using GozareshgirProgramManager.Application.Modules.TaskChat.Commands.UnpinMessage;
|
||||||
|
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;
|
||||||
|
|
||||||
|
namespace ServiceHost.Areas.Admin.Controllers.ProgramManager;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// کنترلر مدیریت چت تسک
|
||||||
|
/// </summary>
|
||||||
|
public class TaskChatController : ProgramManagerBaseController
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
|
public TaskChatController(IMediator mediator)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت لیست پیامهای یک تسک
|
||||||
|
/// </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,messageType, page, pageSize);
|
||||||
|
var result = await _mediator.Send(query);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت پیامهای پین شده یک تسک
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="taskId">شناسه تسک</param>
|
||||||
|
[HttpGet("{taskId:guid}/messages/pinned")]
|
||||||
|
public async Task<ActionResult<OperationResult<List<MessageDto>>>> GetPinnedMessages(Guid taskId)
|
||||||
|
{
|
||||||
|
var query = new GetPinnedMessagesQuery(taskId);
|
||||||
|
var result = await _mediator.Send(query);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// جستجو در پیامهای یک تسک
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="taskId">شناسه تسک</param>
|
||||||
|
/// <param name="search">متن جستجو</param>
|
||||||
|
/// <param name="page">صفحه</param>
|
||||||
|
/// <param name="pageSize">تعداد در هر صفحه</param>
|
||||||
|
[HttpGet("{taskId:guid}/messages/search")]
|
||||||
|
public async Task<ActionResult<OperationResult<List<MessageDto>>>> SearchMessages(
|
||||||
|
Guid taskId,
|
||||||
|
[FromQuery] string search,
|
||||||
|
[FromQuery] int page = 1,
|
||||||
|
[FromQuery] int pageSize = 20)
|
||||||
|
{
|
||||||
|
var query = new SearchMessagesQuery(taskId, search, page, pageSize);
|
||||||
|
var result = await _mediator.Send(query);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ارسال پیام جدید (با یا بدون فایل)
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost("messages")]
|
||||||
|
public async Task<ActionResult<OperationResult<MessageDto>>> SendMessage(
|
||||||
|
[FromForm] SendMessageCommand command)
|
||||||
|
{
|
||||||
|
var result = await _mediator.Send(command);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ویرایش پیام (فقط متن)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="messageId">شناسه پیام</param>
|
||||||
|
/// <param name="request">محتوای جدید</param>
|
||||||
|
[HttpPut("messages/{messageId:guid}")]
|
||||||
|
public async Task<ActionResult<OperationResult>> EditMessage(
|
||||||
|
Guid messageId,
|
||||||
|
[FromBody] EditMessageRequest request)
|
||||||
|
{
|
||||||
|
var command = new EditMessageCommand(messageId, request.NewTextContent);
|
||||||
|
var result = await _mediator.Send(command);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// حذف پیام
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="messageId">شناسه پیام</param>
|
||||||
|
[HttpDelete("messages/{messageId:guid}")]
|
||||||
|
public async Task<ActionResult<OperationResult>> DeleteMessage(Guid messageId)
|
||||||
|
{
|
||||||
|
var command = new DeleteMessageCommand(messageId);
|
||||||
|
var result = await _mediator.Send(command);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// پین کردن پیام
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="messageId">شناسه پیام</param>
|
||||||
|
[HttpPost("messages/{messageId:guid}/pin")]
|
||||||
|
public async Task<ActionResult<OperationResult>> PinMessage(Guid messageId)
|
||||||
|
{
|
||||||
|
var command = new PinMessageCommand(messageId);
|
||||||
|
var result = await _mediator.Send(command);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// برداشتن پین پیام
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="messageId">شناسه پیام</param>
|
||||||
|
[HttpPost("messages/{messageId:guid}/unpin")]
|
||||||
|
public async Task<ActionResult<OperationResult>> UnpinMessage(Guid messageId)
|
||||||
|
{
|
||||||
|
var command = new UnpinMessageCommand(messageId);
|
||||||
|
var result = await _mediator.Send(command);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EditMessageRequest
|
||||||
|
{
|
||||||
|
public string NewTextContent { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
59
ServiceHost/Areas/Admin/Controllers/SmsReportController.cs
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -916,6 +916,17 @@ public class institutionContractController : AdminBaseController
|
|||||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
$"قرارداد های مالی.xlsx");
|
$"قرارداد های مالی.xlsx");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تنظیم وضعیت ارسال قرارداد
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost("set-is-sent")]
|
||||||
|
public async Task<ActionResult<OperationResult>> SetIsSent([FromBody] SetInstitutionContractSendFlagRequest request)
|
||||||
|
{
|
||||||
|
var result = await _institutionContractApplication.SetContractSendFlag(request);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InstitutionContractCreationGetRepresentativeIdResponse
|
public class InstitutionContractCreationGetRepresentativeIdResponse
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
25
ServiceHost/Areas/Client/Controllers/CheckoutController.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using _0_Framework.Application;
|
||||||
|
using CompanyManagment.App.Contracts.Checkout;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using ServiceHost.BaseControllers;
|
||||||
|
|
||||||
|
namespace ServiceHost.Areas.Client.Controllers;
|
||||||
|
|
||||||
|
public class CheckoutController:ClientBaseController
|
||||||
|
{
|
||||||
|
private readonly ICheckoutApplication _checkoutApplication;
|
||||||
|
private readonly long _workshopId;
|
||||||
|
|
||||||
|
public CheckoutController(ICheckoutApplication checkoutApplication,IAuthHelper authHelper)
|
||||||
|
{
|
||||||
|
_checkoutApplication = checkoutApplication;
|
||||||
|
_workshopId = authHelper.GetWorkshopId();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<PagedResult<CheckoutListClientDto>>> GetList(CheckoutListClientSearchModel searchModel)
|
||||||
|
{
|
||||||
|
var res =await _checkoutApplication.GetListForClient(_workshopId, searchModel);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,10 +63,17 @@ if (!Directory.Exists(logDirectory))
|
|||||||
Directory.CreateDirectory(logDirectory);
|
Directory.CreateDirectory(logDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
// فقط برای فایل از Serilog استفاده میشود
|
|
||||||
// تنظیمات MinimumLevel از appsettings.json خوانده میشود
|
|
||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
.Enrich.FromLogContext()
|
//NO EF Core log
|
||||||
|
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
|
||||||
|
|
||||||
|
//NO DbCommand log
|
||||||
|
.MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", LogEventLevel.Warning)
|
||||||
|
|
||||||
|
//NO Microsoft Public log
|
||||||
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
|
||||||
|
|
||||||
|
//.MinimumLevel.Information()
|
||||||
.WriteTo.File(
|
.WriteTo.File(
|
||||||
path: Path.Combine(logDirectory, "gozareshgir_log.txt"),
|
path: Path.Combine(logDirectory, "gozareshgir_log.txt"),
|
||||||
rollingInterval: RollingInterval.Day,
|
rollingInterval: RollingInterval.Day,
|
||||||
@@ -373,7 +380,8 @@ builder.Services.AddParbad().ConfigureGateways(gateways =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// فقط Serilog برای File استفاده میشه، کنسول از لاگر پیشفرض ASP.NET استفاده میکنه
|
if (builder.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
builder.Host.UseSerilog((context, services, configuration) =>
|
builder.Host.UseSerilog((context, services, configuration) =>
|
||||||
{
|
{
|
||||||
var logConfig = configuration
|
var logConfig = configuration
|
||||||
@@ -391,6 +399,12 @@ builder.Host.UseSerilog((context, services, configuration) =>
|
|||||||
);
|
);
|
||||||
}, writeToProviders: true); // این باعث میشه کنسول پیشفرض هم کار کنه
|
}, writeToProviders: true); // این باعث میشه کنسول پیشفرض هم کار کنه
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.Host.UseSerilog();
|
||||||
|
}
|
||||||
|
|
||||||
Log.Information("SERILOG STARTED SUCCESSFULLY");
|
Log.Information("SERILOG STARTED SUCCESSFULLY");
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
@@ -486,6 +500,24 @@ app.UseHttpsRedirection();
|
|||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
|
||||||
|
// Static files برای فایلهای آپلود شده
|
||||||
|
var uploadsPath = builder.Configuration["FileStorage:LocalPath"] ?? Path.Combine(Directory.GetCurrentDirectory(), "Storage");
|
||||||
|
if (!Directory.Exists(uploadsPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(uploadsPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseStaticFiles(new StaticFileOptions
|
||||||
|
{
|
||||||
|
FileProvider = new Microsoft.Extensions.FileProviders.PhysicalFileProvider(uploadsPath),
|
||||||
|
RequestPath = "/storage",
|
||||||
|
OnPrepareResponse = ctx =>
|
||||||
|
{
|
||||||
|
// Cache برای فایلها (30 روز)
|
||||||
|
ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=2592000");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.UseCookiePolicy();
|
app.UseCookiePolicy();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"sqlDebugging": true,
|
"sqlDebugging": true,
|
||||||
"dotnetRunMessages": "true",
|
"dotnetRunMessages": "true",
|
||||||
"nativeDebugging": true,
|
"nativeDebugging": true,
|
||||||
"applicationUrl": "https://localhost:5004;http://localhost:5003;https://192.168.0.117:5006",
|
"applicationUrl": "https://localhost:5004;http://localhost:5003;",
|
||||||
"jsWebView2Debugging": false,
|
"jsWebView2Debugging": false,
|
||||||
"hotReloadEnabled": true
|
"hotReloadEnabled": true
|
||||||
},
|
},
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
"sqlDebugging": true,
|
"sqlDebugging": true,
|
||||||
"dotnetRunMessages": "true",
|
"dotnetRunMessages": "true",
|
||||||
"nativeDebugging": true,
|
"nativeDebugging": true,
|
||||||
"applicationUrl": "https://localhost:5004;http://localhost:5003;https://192.168.0.117:5006;",
|
"applicationUrl": "https://localhost:5004;http://localhost:5003;",
|
||||||
"jsWebView2Debugging": false,
|
"jsWebView2Debugging": false,
|
||||||
"hotReloadEnabled": true
|
"hotReloadEnabled": true
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 312 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 328 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 312 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 312 KiB |