add task job

This commit is contained in:
MahanCh
2025-08-09 12:40:31 +03:30
parent 4d45ee36b6
commit 9d9f0e14d3
20 changed files with 330 additions and 147 deletions

View File

@@ -26,6 +26,7 @@ public interface ISmsService
#region Mahan
Task<double> GetCreditAmount();
SmsResult TaskReminderSms(string number, string taskCount);
#endregion

View File

@@ -0,0 +1,32 @@
namespace _0_Framework.Application.Sms;
public class SmsResult
{
public SmsResult()
{
IsSuccedded = false;
}
public bool IsSuccedded { get; set; }
public string Message { get; set; }
public byte StatusCode { get; set; }
public int MessageId { get; set; }
public SmsResult Succedded(byte statusCode, string message, int messageId)
{
IsSuccedded = true;
Message = message;
StatusCode = statusCode;
MessageId = messageId;
return this;
}
public SmsResult Failed(byte statusCode, string message, int messageId)
{
IsSuccedded = false;
Message = message;
StatusCode = statusCode;
MessageId = messageId;
return this;
}
}

View File

@@ -332,6 +332,34 @@ public class SmsService : ISmsService
}
public SmsResult TaskReminderSms(string number, string taskCount)
{
var tamplateId = 909433;
var result = new SmsResult();
var smsIr = new SmsIr("Og5M562igmzJRhQPnq0GdtieYdLgtfikjzxOmeQBPxJjZtyge5Klc046Lfw1mxSa");
var sendResult = smsIr.VerifySendAsync(number, tamplateId,
new VerifySendParameter[]
{
new("TASKCOUNT", taskCount),
});
Thread.Sleep(500);
if (sendResult.IsCompletedSuccessfully)
{
var status = sendResult.Result.Status;
var message = sendResult.Result.Message;
var messaeId = sendResult.Result.Data.MessageId;
return result.Succedded(status, message, messaeId);
}
else
{
var status = sendResult.Result.Status;
var message = sendResult.Result.Message;
var messaeId = sendResult.Result.Data.MessageId;
return result.Failed(status, message, messaeId);
}
}
#endregion
}

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\0_Framework\0_Framework.csproj" />
<ProjectReference Include="..\..\AccountManagement.Configuration\AccountManagement.Configuration.csproj" />
<ProjectReference Include="..\..\PersonalContractingParty.Config\PersonalContractingParty.Config.csproj" />
<ProjectReference Include="..\..\Query.Bootstrapper\Query.Bootstrapper.csproj" />
<ProjectReference Include="..\..\WorkFlow\Infrastructure\WorkFlow.Infrastructure.Config\WorkFlow.Infrastructure.Config.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,6 +1,6 @@
using _0_Framework.Application;
namespace BackgroundService
namespace BackgroundJobs.Task
{
public class FileUploader : IFileUploader
{

View File

@@ -0,0 +1,63 @@
using Hangfire;
namespace BackgroundJobs.Task.Jobs;
public class JobSchedulerRegistrator
{
private readonly IBackgroundJobClient _backgroundJobClient;
private readonly SmsReminder _smsReminder;
private static DateTime? _lastRunDateMorning;
private static DateTime? _lastRunDateEvening;
public JobSchedulerRegistrator(SmsReminder smsReminder, IBackgroundJobClient backgroundJobClient)
{
_smsReminder = smsReminder;
_backgroundJobClient = backgroundJobClient;
}
public void Register()
{
RecurringJob.AddOrUpdate(
"Task.SmsReminderChecker",
() => SmsReminderCheckAndSchedule(),
Cron.Minutely() // هر 5 دقیقه یکبار چک کن
);
}
private void SmsReminderCheckAndSchedule()
{
var now = DateTime.Now;
var startMorning = new TimeSpan(9, 0, 0);
var endMorning = new TimeSpan(9, 40, 0);
var startEvening = new TimeSpan(15, 30, 0);
var endEvening = new TimeSpan(15, 40, 0);
// صبح
if (now.DayOfWeek != DayOfWeek.Friday &&
now.TimeOfDay >= startMorning &&
now.TimeOfDay < endMorning)
{
if (_lastRunDateMorning?.Date != now.Date)
{
_backgroundJobClient.Enqueue(() => _smsReminder.Execute());
_lastRunDateMorning = now;
}
}
// عصر
if (now.DayOfWeek != DayOfWeek.Friday &&
now.DayOfWeek != DayOfWeek.Thursday &&
now.TimeOfDay >= startEvening &&
now.TimeOfDay < endEvening)
{
if (_lastRunDateEvening?.Date != now.Date)
{
_backgroundJobClient.Enqueue(() => _smsReminder.Execute());
_lastRunDateEvening = now;
}
}
}
}

View File

@@ -0,0 +1,119 @@
using _0_Framework.Application.Sms;
using AccountManagement.Application.Contracts.Account;
using AccountMangement.Infrastructure.EFCore;
using Company.Domain.SmsResultAgg;
using Microsoft.EntityFrameworkCore;
using SmsResult = Company.Domain.SmsResultAgg.SmsResult;
namespace BackgroundJobs.Task.Jobs;
public class SmsReminder
{
private readonly AccountContext _accountContext;
private readonly ISmsService _smsService;
private readonly ISmsResultRepository _smsResultRepository;
public SmsReminder(ISmsService smsService, AccountContext accountContext, ISmsResultRepository smsResultRepository)
{
_smsService = smsService;
_accountContext = accountContext;
_smsResultRepository = smsResultRepository;
}
public void Execute()
{
//var accounts = _accountContext.Accounts.Where(x => x.PositionId > 0 && x.IsActiveString == "true").Select(x => new AccountViewModel() { Id = x.id, Mobile = x.Mobile, Fullname = x.Fullname }).ToList();
//Thread.Sleep(300);
//var accounts = new List<AccountViewModel>() { new AccountViewModel() { Mobile = "09114221321", Id = 2 } };
var accounts= _accountContext.Accounts.Where(x => x.Username.ToLower()=="mahan").Select(x => new AccountViewModel() { Id = x.id, Mobile = x.Mobile, Fullname = x.Fullname }).ToList();
var smsVM = accounts.Select(x => new AccountSmsTaskViewModel()
{
Mobile = x.Mobile,
AccountId = x.Id,
FullName = x.Fullname,
TaskCount = GetLateTasksCount(x.Id)
}).Where(x => x.TaskCount > 0 && !string.IsNullOrEmpty(x.Mobile) && x.Mobile.Length == 11).ToList();
Thread.Sleep(300);
foreach (var viewmodel in smsVM)
{
var smsResult = _smsService.TaskReminderSms(viewmodel.Mobile, $"{viewmodel.TaskCount}");
Thread.Sleep(1000);
var createSmsResult = new SmsResult(smsResult.MessageId, smsResult.Message, "یادآور وظایف",
viewmodel.FullName, viewmodel.Mobile, viewmodel.AccountId, viewmodel.AccountId);
_smsResultRepository.Create(createSmsResult);
_smsResultRepository.SaveChanges();
Thread.Sleep(1000);
}
}
private int GetLateTasksCount(long accountId)
{
var positionValue = _accountContext.Accounts
.Where(x => x.id == accountId)
.Include(p => p.Position)
.Select(x => x.Position.PositionValue)
.FirstOrDefault();
if (positionValue == 0)
return 0;
DateTime now = DateTime.Now;
int overdueTasksCount;
if (positionValue == 1)
{
overdueTasksCount = _accountContext.Assigns.Include(x => x.Task).Where(x => x.AssignedId == accountId &&
x.AssignerId == accountId && x.Task.Assigns.Count == 1 &&
!x.IsCancel && !x.IsCanceledRequest &&
!x.IsDone && !x.TimeRequest && !x.IsDoneRequest && x.EndTaskDate.Date <= DateTime.Now.Date && x.Task.IsActiveString == "true")
.GroupBy(x => x.TaskId).Select(x => x.First()).Count();
//overdueTasksCount = _accountContext.Tasks.Include(x =>
// x.Assigns).Count(x => !x.Assigns.Any(a => a.IsCancel) && !x.Assigns.Any(a => a.IsCanceledRequest) &&
// !x.Assigns.Any(a => a.IsDone) && !x.Assigns.Any(a => a.IsDoneRequest) &&
// !x.Assigns.Any(a => a.TimeRequest)
// && x.Assigns.Any(a => a.AssignedId == accountId && a.AssignerId == accountId) &&
// (x.Assigns.First(a => a.AssignedId == accountId && a.AssignerId == accountId)
// .EndTaskDate.Date <= DateTime.Now.Date) && x.Assigns.Count == 1);
}
else
{
overdueTasksCount = _accountContext.Assigns
.Include(x => x.Task)
.Where(x => x.AssignedId == accountId &&
!x.IsCancel && !x.IsCanceledRequest &&
!x.IsDone && !x.TimeRequest && !x.IsDoneRequest && x.EndTaskDate.Date <= DateTime.Now.Date && x.Task.IsActiveString == "true")
.GroupBy(x => x.TaskId).Select(x => x.First()).Count();
}
//overdueTasksCount = _accountContext.Tasks.Include(x =>
// x.Assigns).Count(x => !x.Assigns.Any(a => a.IsCancel) && !x.Assigns.Any(a => a.IsCanceledRequest) &&
// !x.Assigns.Any(a => a.IsDone) && !x.Assigns.Any(a => a.IsDoneRequest) &&
// !x.Assigns.Any(a => a.TimeRequest)
// && x.Assigns.Any(a => a.AssignedId == accountId) &&
// (x.Assigns.First(a => a.AssignedId == accountId).EndTaskDate.Date <= DateTime.Now.Date));
var overdueRequestsCount = _accountContext.Assigns.Include(x => x.Task)
.Where(x => (x.IsCanceledRequest
|| x.IsDoneRequest || x.TimeRequest) && !x.IsCancel && !x.IsDone &&
x.Task.IsActiveString == "true" &&
x.Task.SenderId == accountId).GroupBy(x => x.TaskId).Select(x => x.First()).Count();
return overdueTasksCount + overdueRequestsCount;
}
}
public class AccountSmsTaskViewModel
{
public int TaskCount { get; set; }
public long AccountId { get; set; }
public string Mobile { get; set; }
public string FullName { get; set; }
}

View File

@@ -0,0 +1,24 @@
using BackgroundJobs.Task.Jobs;
namespace BackgroundJobs.Task;
public class JobsBootstrapper
{
public static void Configure(IServiceCollection services)
{
var currentNamespace = typeof(JobSchedulerRegistrator).Namespace; // همون namespace کلاس
var assembly = typeof(JobSchedulerRegistrator).Assembly;
var jobTypes = assembly.GetTypes()
.Where(t =>
t is { IsClass: true, IsAbstract: false, Namespace: not null } &&
t.Namespace.StartsWith(currentNamespace, StringComparison.Ordinal))
.ToList();
foreach (var jobType in jobTypes)
{
services.AddTransient(jobType);
}
}
}

View File

@@ -2,10 +2,10 @@ using _0_Framework.Application;
using _0_Framework.Application.Sms;
using _0_Framework.Application.UID;
using AccountManagement.Configuration;
using BackgroundService;
using BackgroundService.Jobs;
using BackgroundService.Services;
using BackgroundJobs.Task;
using BackgroundJobs.Task.Jobs;
using Hangfire;
using Microsoft.AspNetCore.Identity;
using PersonalContractingParty.Config;
using Query.Bootstrapper;
using WorkFlow.Infrastructure.Config;

View File

@@ -4,8 +4,8 @@
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:38468",
"sslPort": 44358
"applicationUrl": "http://localhost:56492",
"sslPort": 44378
}
},
"profiles": {
@@ -13,7 +13,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5105",
"applicationUrl": "http://localhost:5216",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
@@ -22,7 +22,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7000;http://localhost:5105",
"applicationUrl": "https://localhost:7222;http://localhost:5216",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}

View File

@@ -1,8 +1,10 @@
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
@@ -16,11 +18,25 @@
//local
"MesbahDb": "Data Source=.;Initial Catalog=mesbah_db;Integrated Security=True;TrustServerCertificate=true;",
"TestDb": "Data Source=.;Initial Catalog=TestDb;Integrated Security=True;TrustServerCertificate=true;"
//dad-mehr
//"MesbahDb": "Data Source=.;Initial Catalog=teamWork;Integrated Security=True;TrustServerCertificate=true;",
"TestDb": "Data Source=.;Initial Catalog=TestDb;Integrated Security=True;TrustServerCertificate=true;",
//mahan Docker
//"MesbahDb": "Data Source=localhost,5069;Initial Catalog=mesbah_db;User ID=sa;Password=YourPassword123;TrustServerCertificate=True;"
//"MesbahDb": "Data Source=localhost,5069;Initial Catalog=mesbah_db;User ID=sa;Password=YourPassword123;TrustServerCertificate=True;",
"HangfireDb": "Data Source=.;Initial Catalog=hangfire_db;Integrated Security=True;TrustServerCertificate=true;"
},
"GoogleRecaptchaV3": {
"SiteKey": "6Lfhp_AnAAAAAB79WkrMoHd1k8ir4m8VvfjE7FTH",
"SecretKey": "6Lfhp_AnAAAAANjDDY6DPrbbUQS7k6ZCRmrVP5Lb"
},
"SmsSecrets": {
"ApiKey": "Og5M562igmzJRhQPnq0GdtieYdLgtfikjzxOmeQBPxJjZtyge5Klc046Lfw1mxSa",
"SecretKey": "dadmehr"
},
"Domain": ".gozareshgir.ir",
"AllowedHosts": "*"
}
}

View File

@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@@ -1,22 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Hangfire" Version="1.8.20" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.20" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AccountManagement.Configuration\AccountManagement.Configuration.csproj" />
<ProjectReference Include="..\PersonalContractingParty.Config\PersonalContractingParty.Config.csproj" />
<ProjectReference Include="..\Query.Bootstrapper\Query.Bootstrapper.csproj" />
<ProjectReference Include="..\WorkFlow\Infrastructure\WorkFlow.Infrastructure.Config\WorkFlow.Infrastructure.Config.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,23 +0,0 @@
using BackgroundService.Services;
using Hangfire;
namespace BackgroundService.Jobs;
public class JobSchedulerRegistrator
{
private readonly ITestService _testService;
public JobSchedulerRegistrator(ITestService testService)
{
_testService = testService;
}
public void Register()
{
RecurringJob.AddOrUpdate(
"job1",
() => _testService.Execute(),
Cron.Hourly
);
}
}

View File

@@ -1,27 +0,0 @@
using _0_Framework.Application;
using _0_Framework.Application.PaymentGateway;
using CompanyManagment.App.Contracts.PaymentTransaction;
using CompanyManagment.EFCore;
using Microsoft.Extensions.Options;
namespace BackgroundService.Jobs.PaymentTransactions;
public class PaymentTransactionValidatePending
{
private readonly CompanyContext _companyContext;
private readonly IPaymentGateway _paymentGateway;
public PaymentTransactionValidatePending(CompanyContext companyContext, IHttpClientFactory httpClientFactory,IOptions<AppSettingConfiguration> appSetting)
{
_companyContext = companyContext;
_paymentGateway = new AqayePardakhtPaymentGateway(httpClientFactory,appSetting);
}
public async Task Execute()
{
var paymentTransactions = _companyContext.PaymentTransactions.Where(x =>
x.Status == PaymentTransactionStatus.Pending && x.CreationDate.AddMinutes(30) <= DateTime.Now);
//Todo: وریفای تراکنش
}
}

View File

@@ -1,6 +0,0 @@
namespace BackgroundService.Services;
public interface ITestService
{
void Execute();
}

View File

@@ -1,11 +0,0 @@
using BackgroundService.Services;
namespace BackgroundService.Jobs.Test;
public class TestService:ITestService
{
public void Execute()
{
Console.WriteLine("Hello World!");
}
}

View File

@@ -1,14 +0,0 @@
using BackgroundService.Jobs;
using BackgroundService.Jobs.Test;
using BackgroundService.Services;
namespace BackgroundService;
public class JobsBootstrapper
{
public static void Configure(IServiceCollection services)
{
services.AddTransient<ITestService, TestService>();
services.AddTransient<JobSchedulerRegistrator>();
}
}

View File

@@ -1,26 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
//تست
//"MesbahDb": "Data Source=DESKTOP-NUE119G\\MSNEW;Initial Catalog=Mesbah_db;Integrated Security=True"
//server
//"MesbahDb": "Data Source=171.22.24.15;Initial Catalog=mesbah_db;Persist Security Info=False;User ID=ir_db;Password=R2rNp[170]18[3019]#@ATt;TrustServerCertificate=true;",
//local
"MesbahDb": "Data Source=.;Initial Catalog=mesbah_db;Integrated Security=True;TrustServerCertificate=true;",
"hangfireDb": "Data Source=.;Initial Catalog=hangfire_db;Integrated Security=True;TrustServerCertificate=true;",
"TestDb": "Data Source=.;Initial Catalog=TestDb;Integrated Security=True;TrustServerCertificate=true;"
//mahan Docker
//"MesbahDb": "Data Source=localhost,5069;Initial Catalog=mesbah_db;User ID=sa;Password=YourPassword123;TrustServerCertificate=True;"
},
"Domain": ".gozareshgir.ir"
}

View File

@@ -80,7 +80,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Query.Bootstrapper", "Query
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompanyManagement.Infrastructure.Excel", "CompanyManagement.Infrastructure.Excel\CompanyManagement.Infrastructure.Excel.csproj", "{BF98173C-42AF-4897-A7CB-4CACEB2B52A2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackgroundService", "BackgroundService\BackgroundService.csproj", "{6C97118D-0497-48A6-846B-E44402FB824F}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackgroundJobs.Task", "BackgroundJobs\BackgroundJobs.Task\BackgroundJobs.Task.csproj", "{97E148FA-3C36-40DD-B121-D90C1C0F3B47}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BackgroundJobs", "BackgroundJobs", "{C10E256D-7E7D-4C77-B416-E577A34AF924}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -180,10 +182,10 @@ Global
{BF98173C-42AF-4897-A7CB-4CACEB2B52A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF98173C-42AF-4897-A7CB-4CACEB2B52A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF98173C-42AF-4897-A7CB-4CACEB2B52A2}.Release|Any CPU.Build.0 = Release|Any CPU
{6C97118D-0497-48A6-846B-E44402FB824F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C97118D-0497-48A6-846B-E44402FB824F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C97118D-0497-48A6-846B-E44402FB824F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C97118D-0497-48A6-846B-E44402FB824F}.Release|Any CPU.Build.0 = Release|Any CPU
{97E148FA-3C36-40DD-B121-D90C1C0F3B47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{97E148FA-3C36-40DD-B121-D90C1C0F3B47}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97E148FA-3C36-40DD-B121-D90C1C0F3B47}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97E148FA-3C36-40DD-B121-D90C1C0F3B47}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -218,6 +220,7 @@ Global
{339E05B6-E99F-4403-AFDF-CD0540E96C8D} = {708E8D7E-F190-47C5-B78E-F43131FB7D6D}
{02892882-2A02-484B-BAF9-7E63F6BDCFA0} = {708E8D7E-F190-47C5-B78E-F43131FB7D6D}
{BF98173C-42AF-4897-A7CB-4CACEB2B52A2} = {86921E1B-2AFA-4B8A-9403-EE16D58B5B26}
{97E148FA-3C36-40DD-B121-D90C1C0F3B47} = {C10E256D-7E7D-4C77-B416-E577A34AF924}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E6CFB3A7-A7C8-4E82-8F06-F750408F0BA9}