using GreenTree.Nachtragsmanagement.Core.Plugins; using System; using System.Collections.Generic; using System.Linq; using System.Web; using GreenTree.Nachtragsmanagement.Core.Domain.Misc; using GreenTree.Nachtragsmanagement.Services.User; using GreenTree.Nachtragsmanagement.Services.Configuration; using GreenTree.Nachtragsmanagement.Services.Appendix; using GreenTree.Nachtragsmanagement.Core.Domain.Appendix; using System.Net.Mail; using System.Net; using System.Globalization; using Quartz; namespace GreenTree.Nachtragsmanagement.Web.Implementations { public class AppendixNotificationPlugin : INotificationPlugin, IJob { #region Services private readonly IUserService _userService; private readonly IConfigurationService _configurationService; private readonly IAppendixService _appendixService; #endregion #region Properties /// /// Id /// public Guid Id { get { return Guid.Parse("E99CA4A1-B3A9-4AA6-BBAD-9254CEED0A45"); } } /// /// System name /// public string SystemName { get { return "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin"; } } /// /// List of available notification jobs /// public List AvailableNotificationJobs { get { return new List { new NotificationJob ( Guid.Parse("2F3642E0-259D-466D-8629-CB279F740313"), "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate", "Verhandlungstermine überprüfen", "Erstellt automatisch Benachrichtigungen für Nachträge, die nach 8 Wochen nach Einreichung noch keinen " + "Verhandlungstermin gesetzt haben und ändert den entsprechenden Status ab" ), new NotificationJob ( Guid.Parse("2E46B32A-1912-47F9-951E-C8188AA9BA50"), "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol", "Verhandlungsprotokolle überprüfen", "Erstellt automatisch Benachrichtigungen für Nachträge, die nach 2 Wochen zwar verhandelt sind, " + "jedoch noch kein Protokoll aufweisen." ) }; } } /// /// Displayed name /// public string Name { get { return "Nachtragsbenachrichtigung"; } } /// /// Further description on how this plugin works /// public string Description { get { return "Erstellt automatisch Benachrichtigungen für Nachträge, die nach 8 Wochen nach Einreichung noch keinen " + "Verhandlungstermin gesetzt haben und ändert den entsprechenden Status ab. Außerdem werden alle 2 Wochen " + "Benachrichtigungen für Nachträge erstellt, die zwar verhandelt sind, jedoch noch kein Protokoll aufweisen."; } } #endregion /// /// Initializes a new instance of the AppendixNotificationPlugin class /// public AppendixNotificationPlugin() { } /// /// Initializes a new instance of the AppendixNotificationPlugin class /// public AppendixNotificationPlugin( IUserService userService, IConfigurationService configurationService, IAppendixService appendixService) { _userService = userService; _configurationService = configurationService; _appendixService = appendixService; } #region Quartz implmentation /// /// Executes the current job /// /// public void Execute(IJobExecutionContext context) { if (!context.JobDetail.JobDataMap.ContainsKey("MailNotifications")) return; var mailNotifications = context.JobDetail.JobDataMap.Get("MailNotifications") as IEnumerable; if (mailNotifications == null) return; ProcessNotifications(mailNotifications); } #endregion #region Processing /// /// Process all mail notifications registered for that plugin /// /// The notifications which shall be generated. public void ProcessNotifications(IEnumerable mailNotifications) { if (mailNotifications == null || !mailNotifications.Any()) return; foreach (var notification in mailNotifications) { switch (notification.NotificationJobSystemName) { case "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate": { ProcessNegotiationDateNotification(notification); } break; case "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol": { ProcessNegotiationProtocolNotification(notification); } break; default: continue; } } } /// /// Sets the corresponding status for appendices which offering date is older than N weeks and notifies /// the correspondig recipients /// /// The notification which shall be generated. private void ProcessNegotiationDateNotification(MailNotification mailNotification) { var ageDays = _configurationService.TryGetConfigItemValue( "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate.AgeDays", 56); var stateSetId = _configurationService.TryGetConfigItemValue( "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate.StateSet", 2); var interval = _configurationService.TryGetConfigItemValue( "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate.Interval", 2); interval = interval == 0 ? 1 : interval; var finishStateId = _appendixService.GetFinishState().Id; var appendices = _appendixService.GetAllAppendices() .Where(a => a.OfferingDate.HasValue && (DateTime.Now - a.OfferingDate).Value.Days >= ageDays && a.StateId != stateSetId && a.StateId != finishStateId && a.NegotiationDate == null) .ToList(); var currentCalendarWeek = GetCalendarWeek(DateTime.Now); appendices = appendices .Where(a => ((currentCalendarWeek - GetCalendarWeek(a.OfferingDate.Value) % interval == 0))) .ToList(); if (appendices.Any()) { var mailBody = GenerateNegotiationDateMailBody(appendices); foreach (var appendix in appendices) { appendix.StateId = stateSetId; _appendixService.UpdateAppendix(appendix); } SendNotification(mailNotification, "Autom. Übersicht nicht verhandelte Nachträge", mailBody); } } /// /// Sets the corresponding status for appendices which negotiation date is older than N weeks and notifies /// the correspondig recipients /// /// The notification which shall be generated. private void ProcessNegotiationProtocolNotification(MailNotification mailNotification) { var ageDays = _configurationService.TryGetConfigItemValue( "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol.AgeDays", 14); var stateConditionId = _configurationService.TryGetConfigItemValue( "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol.StateCondition", 3); var interval = _configurationService.TryGetConfigItemValue( "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol.Interval", 2); interval = interval == 0 ? 1 : interval; var finishStateId = _appendixService.GetFinishState().Id; var appendices = _appendixService.GetAllAppendices() .Where(a => a.NegotiationDate.HasValue && (DateTime.Now - a.NegotiationDate).Value.Days >= ageDays && !a.ProtocolExists && a.StateId != finishStateId) .ToList(); var currentCalendarWeek = GetCalendarWeek(DateTime.Now); appendices = appendices .Where(a => ((currentCalendarWeek - GetCalendarWeek(a.OfferingDate.Value) % interval == 0))) .ToList(); if (appendices.Any()) { var mailBody = GenerateNegotiationProtocolMailBody(appendices); SendNotification(mailNotification, "Autom. Übersicht verhandelte Nachträge o. Protokoll", mailBody); } } #endregion #region Mail body generation /// /// Generates a mail body with a list of all appendices with a offering date later than N weeks /// /// Appendices matching that criteria. public string GenerateNegotiationDateMailBody(IEnumerable appendices) { var template = "" + " " + "

Übersicht \"Nicht verhandelte Nachträge\"

" + "

Folgende Nachträge haben ein Einreichdatum älter als 8 Wochen, jedoch noch kein Verhandlungstermin" + " gesetzt:

" + "
    " + " {0}" + "
" + " " + ""; if (!appendices.Any()) return String.Format(template, String.Empty); var appendicesList = String.Empty; foreach (var appendix in appendices) { appendicesList += String.Format( "
  • Nachtrag \"{0}\" in Baustelle \"{1}\" - Einreichdatum: {2:dd.MM.yyyy}", appendix.CustomNumber, appendix.Site.CustomNumber, appendix.OfferingDate); } return String.Format(template, appendicesList); } /// /// Generates a mail body with a list of all appendices with a negotiation date later than N weeks /// /// Appendices matching that criteria. public string GenerateNegotiationProtocolMailBody(IEnumerable appendices) { var template = "" + " " + "

    Übersicht \"Verhandelte Nachträge ohne Protokoll\"

    " + "

    Folgende Nachträge haben ein Verhandlungstermin älter als zwei Wochen, jedoch noch kein Protokoll:" + "

      " + " {0}" + "
    " + " " + ""; if (!appendices.Any()) return String.Format(template, String.Empty); var appendicesList = String.Empty; foreach (var appendix in appendices) { appendicesList += String.Format( "
  • Nachtrag \"{0}\" in Baustelle \"{1}\" - Verhandlungsdatum: {2:dd.MM.yyyy}", appendix.CustomNumber, appendix.Site.CustomNumber, appendix.NegotiationDate); } return String.Format(template, appendicesList); } #endregion #region Mail sending /// /// Sends a generated mail body to the specified recipients in the mail notification /// /// The mail notification. /// The mail subject. /// The mail body. public void SendNotification(MailNotification mailNotification, string subject, string body) { if (mailNotification == null) return; var mailServerConfig = _configurationService.GetCurrentConfiguration().MailServerElement; var smptClient = new SmtpClient(mailServerConfig.SmtpServer, mailServerConfig.Port) { EnableSsl = mailServerConfig.UseSsl, Credentials = new NetworkCredential( mailServerConfig.Username, mailServerConfig.Password, mailServerConfig.Domain) }; var recipients = mailNotification.Users .Select(u => u.MailAddress); var mailMessage = new MailMessage { IsBodyHtml = true, Subject = subject, Body = body, From = new MailAddress("Nachtragsbenachrichtigung@schweerbau.de") }; foreach (var recipient in recipients) mailMessage.To.Add(recipient); smptClient.Send(mailMessage); } #endregion #region Helper /// /// Determines the calendar week of a specific datetime /// /// The datetime which calendarweek should be calculated. public static int GetCalendarWeek(DateTime date) { var currentCulture = CultureInfo.CurrentCulture; var calendar = currentCulture.Calendar; var calendarWeek = calendar.GetWeekOfYear( date, currentCulture.DateTimeFormat.CalendarWeekRule, currentCulture.DateTimeFormat.FirstDayOfWeek); if (calendarWeek > 52) { date = date.AddDays(7); var testCalendarWeek = calendar.GetWeekOfYear(date, currentCulture.DateTimeFormat.CalendarWeekRule, currentCulture.DateTimeFormat.FirstDayOfWeek); if (testCalendarWeek == 2) calendarWeek = 1; } return calendarWeek; } #endregion } }