diff --git a/Kaizen/Extensions/ServiceCollectionExtensions.cs b/Kaizen/Extensions/ServiceCollectionExtensions.cs index 4c8d47e8..03853c1a 100644 --- a/Kaizen/Extensions/ServiceCollectionExtensions.cs +++ b/Kaizen/Extensions/ServiceCollectionExtensions.cs @@ -2,6 +2,7 @@ using Kaizen.DomainEvents; using Kaizen.Filters; using Kaizen.HostedServices; +using Kaizen.HostedServices.ProcessingServices; using Microsoft.Extensions.DependencyInjection; namespace Kaizen.Extensions @@ -21,6 +22,10 @@ public static void ConfigureHostedServices(this IServiceCollection services) services.AddHostedService(); services.AddHostedService(); services.AddHostedService(); + + services.AddScoped(typeof(EmployeeContract)); + services.AddScoped(typeof(OverdueBills)); + services.AddScoped(typeof(PendingActivitiesToConfirmed)); } public static void ConfigureDomainEventDispatcher(this IServiceCollection services) diff --git a/Kaizen/HostedServices/BackgroundService.cs b/Kaizen/HostedServices/BackgroundService.cs index 534c74f9..5913293f 100644 --- a/Kaizen/HostedServices/BackgroundService.cs +++ b/Kaizen/HostedServices/BackgroundService.cs @@ -1,53 +1,14 @@ using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; namespace Kaizen.HostedServices { - public abstract class BackgroundService : IHostedService, IDisposable + public abstract class BackgroundService : Microsoft.Extensions.Hosting.BackgroundService { - private Task _executingTask; - private readonly CancellationTokenSource _stoppingCts = new(); + protected IServiceProvider ServiceProvider { get; set; } - protected abstract Task ExecuteAsync(CancellationToken cancellationToken); - - public virtual Task StartAsync(CancellationToken cancellationToken) - { - _executingTask = ExecuteAsync(_stoppingCts.Token); - - return _executingTask.IsCompleted ? _executingTask : Task.CompletedTask; - } - - public virtual async Task StopAsync(CancellationToken cancellationToken) - { - if (_executingTask == null) - { - return; - } - - try - { - _stoppingCts.Cancel(); - } - catch (Exception) - { - await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken)); - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) + protected BackgroundService(IServiceProvider serviceProvider) { - if (disposing) - { - _stoppingCts?.Cancel(); - } + ServiceProvider = serviceProvider; } } } diff --git a/Kaizen/HostedServices/EmployeeContractHostedService.cs b/Kaizen/HostedServices/EmployeeContractHostedService.cs index baa12012..80ae890e 100644 --- a/Kaizen/HostedServices/EmployeeContractHostedService.cs +++ b/Kaizen/HostedServices/EmployeeContractHostedService.cs @@ -1,45 +1,29 @@ using System; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Kaizen.Core.Services; -using Kaizen.Domain.Entities; -using Kaizen.Domain.Repositories; +using Kaizen.HostedServices.ProcessingServices; +using Microsoft.Extensions.DependencyInjection; namespace Kaizen.HostedServices { public class EmployeeContractHostedService : BackgroundService { - private static readonly int DelayTime = TimeSpan.FromDays(1.0).Milliseconds; - - private readonly IEmployeesRepository _employeesRepository; - private readonly IMailService _mailService; - private readonly IMailTemplate _mailTemplate; - - public EmployeeContractHostedService(IEmployeesRepository employeesRepository, IMailService mailService, - IMailTemplate mailTemplate) + public EmployeeContractHostedService(IServiceProvider serviceProvider) : base(serviceProvider) { - _employeesRepository = employeesRepository; - _mailService = mailService; - _mailTemplate = mailTemplate; } protected override async Task ExecuteAsync(CancellationToken cancellationToken) { - while (!cancellationToken.IsCancellationRequested) - { - IEnumerable employees = await _employeesRepository.EmployeesWithContractCloseToExpiration(); - foreach (Employee employee in employees) - { - string mailMessage = _mailTemplate.LoadTemplate("ContractCloseToExpiration.html", $"{employee.LastName} {employee.FirstName}", - employee.ContractCode, - employee.EmployeeContract.EndDate.ToShortDateString()); + await DoWork(cancellationToken); + } - await _mailService.SendEmailAsync(employee.User.Email, "Contrato a punto de vencer", mailMessage, true); - } + private async Task DoWork(CancellationToken cancellationToken) + { + using IServiceScope scope = ServiceProvider.CreateScope(); + EmployeeContract employeeContractProcessingService = + scope.ServiceProvider.GetRequiredService(); - await Task.Delay(DelayTime, cancellationToken); - } + await employeeContractProcessingService.DoWork(cancellationToken); } } } diff --git a/Kaizen/HostedServices/OverdueBillsHostedService.cs b/Kaizen/HostedServices/OverdueBillsHostedService.cs index adfe1681..94afcde6 100644 --- a/Kaizen/HostedServices/OverdueBillsHostedService.cs +++ b/Kaizen/HostedServices/OverdueBillsHostedService.cs @@ -1,74 +1,29 @@ using System; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Kaizen.Domain.Entities; -using Kaizen.Domain.Repositories; -using Kaizen.Hubs; -using Microsoft.AspNetCore.SignalR; +using Kaizen.HostedServices.ProcessingServices; +using Microsoft.Extensions.DependencyInjection; namespace Kaizen.HostedServices { public class OverdueBillsHostedService : BackgroundService { - private static readonly int DelayTime = TimeSpan.FromDays(1.0).Milliseconds; - - private readonly IProductInvoicesRepository _productInvoicesRepository; - private readonly IServiceInvoicesRepository _serviceInvoicesRepository; - private readonly IUnitWork _unitWork; - private readonly IHubContext _invoiceHub; - - public OverdueBillsHostedService( - IProductInvoicesRepository productInvoicesRepository, - IServiceInvoicesRepository serviceInvoicesRepository, - IUnitWork unitWork, - IHubContext invoiceHub - ) + public OverdueBillsHostedService(IServiceProvider serviceProvider) : base(serviceProvider) { - _productInvoicesRepository = productInvoicesRepository; - _serviceInvoicesRepository = serviceInvoicesRepository; - _unitWork = unitWork; - _invoiceHub = invoiceHub; } protected override async Task ExecuteAsync(CancellationToken cancellationToken) { - while (!cancellationToken.IsCancellationRequested) - { - await FindAndReportExpiredProductInvoices(cancellationToken); - - await FindAndReportExpiredServiceInvoices(cancellationToken); - - await Task.Delay(DelayTime, cancellationToken); - } - } - - private async Task FindAndReportExpiredProductInvoices(CancellationToken cancellationToken) - { - IEnumerable productInvoices = await _productInvoicesRepository.GetPendingExpiredProductInvoices(); - foreach (ProductInvoice productInvoice in productInvoices) - { - productInvoice.State = InvoiceState.Expired; - _productInvoicesRepository.Update(productInvoice); - } - - await _unitWork.SaveAsync(); - - await _invoiceHub.Clients.Group("Administrator").SendAsync("OverdueProductBills", productInvoices, cancellationToken: cancellationToken); + await DoWork(cancellationToken); } - private async Task FindAndReportExpiredServiceInvoices(CancellationToken cancellationToken) + private async Task DoWork(CancellationToken cancellationToken) { - IEnumerable serviceInvoices = await _serviceInvoicesRepository.GetPendingExpiredServiceInvoices(); - foreach (ServiceInvoice serviceInvoice in serviceInvoices) - { - serviceInvoice.State = InvoiceState.Expired; - _serviceInvoicesRepository.Update(serviceInvoice); - } - - await _unitWork.SaveAsync(); + using IServiceScope scope = ServiceProvider.CreateScope(); + OverdueBills overdueBillsProcessingService = + scope.ServiceProvider.GetRequiredService(); - await _invoiceHub.Clients.Group("Administrator").SendAsync("OverdueServiceBills", serviceInvoices, cancellationToken: cancellationToken); + await overdueBillsProcessingService.DoWork(cancellationToken); } } } diff --git a/Kaizen/HostedServices/PendingActivitiesToBeConfirmedHostedService.cs b/Kaizen/HostedServices/PendingActivitiesToBeConfirmedHostedService.cs index f493f439..728b85ed 100644 --- a/Kaizen/HostedServices/PendingActivitiesToBeConfirmedHostedService.cs +++ b/Kaizen/HostedServices/PendingActivitiesToBeConfirmedHostedService.cs @@ -1,79 +1,29 @@ using System; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Kaizen.Core.Services; -using Kaizen.Domain.Entities; -using Kaizen.Domain.Repositories; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; -using Microsoft.EntityFrameworkCore; +using Kaizen.HostedServices.ProcessingServices; +using Microsoft.Extensions.DependencyInjection; namespace Kaizen.HostedServices { public class PendingActivitiesToBeConfirmedHostedService : BackgroundService { - private static readonly int DelayTime = TimeSpan.FromDays(1.0).Milliseconds; - - private readonly IActivitiesRepository _activitiesRepository; - private readonly IMailService _mailService; - private readonly IMailTemplate _mailTemplate; - private readonly IHttpContextAccessor _accessor; - private readonly LinkGenerator _generator; - - public PendingActivitiesToBeConfirmedHostedService( - IActivitiesRepository activitiesRepository, - IMailService mailService, - IMailTemplate mailTemplate, - IHttpContextAccessor accessor, - LinkGenerator generator - ) + public PendingActivitiesToBeConfirmedHostedService(IServiceProvider serviceProvider) : base(serviceProvider) { - _activitiesRepository = activitiesRepository; - _mailService = mailService; - _mailTemplate = mailTemplate; - _accessor = accessor; - _generator = generator; } protected override async Task ExecuteAsync(CancellationToken cancellationToken) { - while (!cancellationToken.IsCancellationRequested) - { - DateTime today = DateTime.Now; - - List pendingActivities = await _activitiesRepository - .Where(a => a.State == ActivityState.Pending && (a.Date - today).Days <= 3 && (a.Date - today).Days > 0) - .Include(a => a.Client) - .ThenInclude(c => c.User) - .ToListAsync(cancellationToken: cancellationToken); - - foreach (Activity activity in pendingActivities) - { - await SendPendingActivityEmail(activity); - } - - await Task.Delay(DelayTime, cancellationToken); - } + await DoWork(cancellationToken); } - private async Task SendPendingActivityEmail(Activity activity) + private async Task DoWork(CancellationToken cancellationToken) { - string activityConfirmationLink = GetActivityLink("ConfirmActivity", activity.Code); - string activityRejectLink = GetActivityLink("RejectActivity", activity.Code); - string changeDateLink = GetActivityLink("ChangeDate", activity.Code); + using IServiceScope scope = ServiceProvider.CreateScope(); + PendingActivitiesToConfirmed pendingActivitiesToConfirmed = + scope.ServiceProvider.GetRequiredService(); - string mailMessage = _mailTemplate.LoadTemplate("PendingActivityToBeConfirmed.html", - $"{activity.Client.FirstName} {activity.Client.SecondName} {activity.Client.LastName} {activity.Client.SecondLastName}", - $"{activity.Date}", activityConfirmationLink, activityRejectLink, changeDateLink); - - await _mailService.SendEmailAsync(activity.Client.User.Email, "Actividad pendiente a confirmaciĆ³n", mailMessage, - true); - } - - private string GetActivityLink(string action, int activityCode) - { - return _generator.GetUriByAction(_accessor.HttpContext, $"{action}/{activityCode}", "activity_schedule"); + await pendingActivitiesToConfirmed.DoWork(cancellationToken); } } } diff --git a/Kaizen/HostedServices/ProcessingServices/EmployeeContract.cs b/Kaizen/HostedServices/ProcessingServices/EmployeeContract.cs new file mode 100644 index 00000000..2bc37fe5 --- /dev/null +++ b/Kaizen/HostedServices/ProcessingServices/EmployeeContract.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Kaizen.Core.Services; +using Kaizen.Domain.Entities; +using Kaizen.Domain.Repositories; + +namespace Kaizen.HostedServices.ProcessingServices +{ + public class EmployeeContract : IScopedProcessingService + { + private static readonly int DelayTime = (int)TimeSpan.FromDays(1.0).TotalMilliseconds; + + private readonly IEmployeesRepository _employeesRepository; + private readonly IMailService _mailService; + private readonly IMailTemplate _mailTemplate; + + public EmployeeContract(IEmployeesRepository employeesRepository, IMailService mailService, IMailTemplate mailTemplate) + { + _employeesRepository = employeesRepository; + _mailService = mailService; + _mailTemplate = mailTemplate; + } + + public async Task DoWork(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + IEnumerable employees = await _employeesRepository.EmployeesWithContractCloseToExpiration(); + foreach (Employee employee in employees) + { + string mailMessage = _mailTemplate.LoadTemplate("ContractCloseToExpiration.html", $"{employee.LastName} {employee.FirstName}", + employee.ContractCode, + employee.EmployeeContract.EndDate.ToShortDateString()); + + await _mailService.SendEmailAsync(employee.User.Email, "Contrato a punto de vencer", mailMessage, true); + } + + await Task.Delay(DelayTime, cancellationToken); + } + } + } +} diff --git a/Kaizen/HostedServices/ProcessingServices/IScopedProcessingService.cs b/Kaizen/HostedServices/ProcessingServices/IScopedProcessingService.cs new file mode 100644 index 00000000..eb3e42a7 --- /dev/null +++ b/Kaizen/HostedServices/ProcessingServices/IScopedProcessingService.cs @@ -0,0 +1,10 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Kaizen.HostedServices.ProcessingServices +{ + internal interface IScopedProcessingService + { + Task DoWork(CancellationToken cancellationToken); + } +} diff --git a/Kaizen/HostedServices/ProcessingServices/OverdueBills.cs b/Kaizen/HostedServices/ProcessingServices/OverdueBills.cs new file mode 100644 index 00000000..86b9c3df --- /dev/null +++ b/Kaizen/HostedServices/ProcessingServices/OverdueBills.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Kaizen.Domain.Entities; +using Kaizen.Domain.Repositories; +using Kaizen.Hubs; +using Microsoft.AspNetCore.SignalR; + +namespace Kaizen.HostedServices.ProcessingServices +{ + public class OverdueBills : IScopedProcessingService + { + private static readonly int DelayTime = (int)TimeSpan.FromDays(1.0).TotalMilliseconds; + + private readonly IProductInvoicesRepository _productInvoicesRepository; + private readonly IServiceInvoicesRepository _serviceInvoicesRepository; + private readonly IUnitWork _unitWork; + private readonly IHubContext _invoiceHub; + + public OverdueBills( + IProductInvoicesRepository productInvoicesRepository, + IServiceInvoicesRepository serviceInvoicesRepository, + IUnitWork unitWork, + IHubContext invoiceHub) + { + _productInvoicesRepository = productInvoicesRepository; + _serviceInvoicesRepository = serviceInvoicesRepository; + _unitWork = unitWork; + _invoiceHub = invoiceHub; + } + + public async Task DoWork(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + await FindAndReportExpiredProductInvoices(cancellationToken); + + await FindAndReportExpiredServiceInvoices(cancellationToken); + + await Task.Delay(DelayTime, cancellationToken); + } + } + + private async Task FindAndReportExpiredProductInvoices(CancellationToken cancellationToken) + { + IEnumerable productInvoices = await _productInvoicesRepository.GetPendingExpiredProductInvoices(); + foreach (ProductInvoice productInvoice in productInvoices) + { + productInvoice.State = InvoiceState.Expired; + _productInvoicesRepository.Update(productInvoice); + } + + await _unitWork.SaveAsync(); + + await _invoiceHub.Clients.Group("Administrator").SendAsync("OverdueProductBills", productInvoices, cancellationToken); + } + + private async Task FindAndReportExpiredServiceInvoices(CancellationToken cancellationToken) + { + IEnumerable serviceInvoices = await _serviceInvoicesRepository.GetPendingExpiredServiceInvoices(); + foreach (ServiceInvoice serviceInvoice in serviceInvoices) + { + serviceInvoice.State = InvoiceState.Expired; + _serviceInvoicesRepository.Update(serviceInvoice); + } + + await _unitWork.SaveAsync(); + + await _invoiceHub.Clients.Group("Administrator").SendAsync("OverdueServiceBills", serviceInvoices, cancellationToken); + } + } +} diff --git a/Kaizen/HostedServices/ProcessingServices/PendingActivitiesToConfirmed.cs b/Kaizen/HostedServices/ProcessingServices/PendingActivitiesToConfirmed.cs new file mode 100644 index 00000000..4ec840ec --- /dev/null +++ b/Kaizen/HostedServices/ProcessingServices/PendingActivitiesToConfirmed.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Kaizen.Core.Services; +using Kaizen.Domain.Entities; +using Kaizen.Domain.Repositories; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace Kaizen.HostedServices.ProcessingServices +{ + public class PendingActivitiesToConfirmed : IScopedProcessingService + { + private static readonly int DelayTime = (int)TimeSpan.FromDays(1.0).TotalMilliseconds; + + private readonly IActivitiesRepository _activitiesRepository; + private readonly IMailService _mailService; + private readonly IMailTemplate _mailTemplate; + private readonly IHttpContextAccessor _accessor; + private readonly LinkGenerator _generator; + + public PendingActivitiesToConfirmed( + IActivitiesRepository activitiesRepository, + IMailService mailService, + IMailTemplate mailTemplate, + IHttpContextAccessor accessor, + LinkGenerator generator) + { + _activitiesRepository = activitiesRepository; + _mailService = mailService; + _mailTemplate = mailTemplate; + _accessor = accessor; + _generator = generator; + } + + public async Task DoWork(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + IEnumerable pendingActivities = await _activitiesRepository.GetPendingActivitiesToConfirmed(); + + foreach (Activity activity in pendingActivities) + { + await SendPendingActivityEmail(activity); + } + + await Task.Delay(DelayTime, cancellationToken); + } + } + + private async Task SendPendingActivityEmail(Activity activity) + { + string activityConfirmationLink = GetActivityLink("ConfirmActivity", activity.Code); + string activityRejectLink = GetActivityLink("RejectActivity", activity.Code); + string changeDateLink = GetActivityLink("ChangeDate", activity.Code); + + string mailMessage = _mailTemplate.LoadTemplate("PendingActivityToBeConfirmed.html", + $"{activity.Client.FirstName} {activity.Client.SecondName} {activity.Client.LastName} {activity.Client.SecondLastName}", + $"{activity.Date}", activityConfirmationLink, activityRejectLink, changeDateLink); + + await _mailService.SendEmailAsync(activity.Client.User.Email, "Actividad pendiente a confirmaciĆ³n", mailMessage, + true); + } + + private string GetActivityLink(string action, int activityCode) + { + return _generator.GetUriByAction(_accessor.HttpContext, $"{action}/{activityCode}", "activity_schedule"); + } + } +}