AppendixNotificationPlugin.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. using GreenTree.Nachtragsmanagement.Core.Plugins;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Web;
  6. using GreenTree.Nachtragsmanagement.Core.Domain.Misc;
  7. using GreenTree.Nachtragsmanagement.Services.User;
  8. using GreenTree.Nachtragsmanagement.Services.Configuration;
  9. using GreenTree.Nachtragsmanagement.Services.Appendix;
  10. using GreenTree.Nachtragsmanagement.Core.Domain.Appendix;
  11. using System.Net.Mail;
  12. using System.Net;
  13. using System.Globalization;
  14. using Quartz;
  15. namespace GreenTree.Nachtragsmanagement.Web.Implementations
  16. {
  17. public class AppendixNotificationPlugin : INotificationPlugin, IJob
  18. {
  19. #region Services
  20. private readonly IUserService _userService;
  21. private readonly IConfigurationService _configurationService;
  22. private readonly IAppendixService _appendixService;
  23. #endregion
  24. #region Properties
  25. /// <summary>
  26. /// Id
  27. /// </summary>
  28. public Guid Id
  29. {
  30. get
  31. {
  32. return Guid.Parse("E99CA4A1-B3A9-4AA6-BBAD-9254CEED0A45");
  33. }
  34. }
  35. /// <summary>
  36. /// System name
  37. /// </summary>
  38. public string SystemName
  39. {
  40. get
  41. {
  42. return "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin";
  43. }
  44. }
  45. /// <summary>
  46. /// List of available notification jobs
  47. /// </summary>
  48. public List<NotificationJob> AvailableNotificationJobs
  49. {
  50. get
  51. {
  52. return new List<NotificationJob>
  53. {
  54. new NotificationJob
  55. (
  56. Guid.Parse("2F3642E0-259D-466D-8629-CB279F740313"),
  57. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate",
  58. "Verhandlungstermine überprüfen",
  59. "Erstellt automatisch Benachrichtigungen für Nachträge, die nach 8 Wochen nach Einreichung noch keinen " +
  60. "Verhandlungstermin gesetzt haben und ändert den entsprechenden Status ab"
  61. ),
  62. new NotificationJob
  63. (
  64. Guid.Parse("2E46B32A-1912-47F9-951E-C8188AA9BA50"),
  65. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol",
  66. "Verhandlungsprotokolle überprüfen",
  67. "Erstellt automatisch Benachrichtigungen für Nachträge, die nach 2 Wochen zwar verhandelt sind, " +
  68. "jedoch noch kein Protokoll aufweisen."
  69. )
  70. };
  71. }
  72. }
  73. /// <summary>
  74. /// Displayed name
  75. /// </summary>
  76. public string Name
  77. {
  78. get
  79. {
  80. return "Nachtragsbenachrichtigung";
  81. }
  82. }
  83. /// <summary>
  84. /// Further description on how this plugin works
  85. /// </summary>
  86. public string Description
  87. {
  88. get
  89. {
  90. return
  91. "Erstellt automatisch Benachrichtigungen für Nachträge, die nach 8 Wochen nach Einreichung noch keinen " +
  92. "Verhandlungstermin gesetzt haben und ändert den entsprechenden Status ab. Außerdem werden alle 2 Wochen " +
  93. "Benachrichtigungen für Nachträge erstellt, die zwar verhandelt sind, jedoch noch kein Protokoll aufweisen.";
  94. }
  95. }
  96. #endregion
  97. /// <summary>
  98. /// Initializes a new instance of the AppendixNotificationPlugin class
  99. /// </summary>
  100. public AppendixNotificationPlugin() { }
  101. /// <summary>
  102. /// Initializes a new instance of the AppendixNotificationPlugin class
  103. /// </summary>
  104. public AppendixNotificationPlugin(
  105. IUserService userService,
  106. IConfigurationService configurationService,
  107. IAppendixService appendixService)
  108. {
  109. _userService = userService;
  110. _configurationService = configurationService;
  111. _appendixService = appendixService;
  112. }
  113. #region Quartz implmentation
  114. /// <summary>
  115. /// Executes the current job
  116. /// </summary>
  117. /// <param name="context"></param>
  118. public void Execute(IJobExecutionContext context)
  119. {
  120. if (!context.JobDetail.JobDataMap.ContainsKey("MailNotifications"))
  121. return;
  122. var mailNotifications = context.JobDetail.JobDataMap.Get("MailNotifications") as IEnumerable<MailNotification>;
  123. if (mailNotifications == null) return;
  124. ProcessNotifications(mailNotifications);
  125. }
  126. #endregion
  127. #region Processing
  128. /// <summary>
  129. /// Process all mail notifications registered for that plugin
  130. /// </summary>
  131. /// <param name="mailNotifications">The notifications which shall be generated.</param>
  132. public void ProcessNotifications(IEnumerable<MailNotification> mailNotifications)
  133. {
  134. if (mailNotifications == null || !mailNotifications.Any()) return;
  135. foreach (var notification in mailNotifications)
  136. {
  137. switch (notification.NotificationJobSystemName)
  138. {
  139. case "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate":
  140. {
  141. ProcessNegotiationDateNotification(notification);
  142. }
  143. break;
  144. case "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol":
  145. {
  146. ProcessNegotiationProtocolNotification(notification);
  147. }
  148. break;
  149. default:
  150. continue;
  151. }
  152. }
  153. }
  154. /// <summary>
  155. /// Sets the corresponding status for appendices which offering date is older than N weeks and notifies
  156. /// the correspondig recipients
  157. /// </summary>
  158. /// <param name="mailNotification">The notification which shall be generated.</param>
  159. private void ProcessNegotiationDateNotification(MailNotification mailNotification)
  160. {
  161. var ageDays = _configurationService.TryGetConfigItemValue<int>(
  162. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate.AgeDays", 56);
  163. var stateConditionId = _configurationService.TryGetConfigItemValue<int>(
  164. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate.StateCondition", 1);
  165. var stateSetId = _configurationService.TryGetConfigItemValue<int>(
  166. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate.StateSet", 2);
  167. var interval = _configurationService.TryGetConfigItemValue<int>(
  168. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate.Interval", 2);
  169. interval = interval == 0
  170. ? 1
  171. : interval;
  172. var finishStateId = _appendixService.GetFinishState().Id;
  173. var appendices = _appendixService.GetAllAppendices()
  174. .Where(a => a.OfferingDate.HasValue &&
  175. (DateTime.Now - a.OfferingDate).Value.Days >= ageDays &&
  176. a.StateId != stateSetId && a.StateId != finishStateId &&
  177. a.NegotiationDate == null)
  178. .ToList();
  179. var currentCalendarWeek = GetCalendarWeek(DateTime.Now);
  180. appendices = appendices
  181. .Where(a => ((currentCalendarWeek - GetCalendarWeek(a.OfferingDate.Value) % interval == 0)))
  182. .ToList();
  183. if (appendices.Any())
  184. {
  185. var mailBody = GenerateNegotiationDateMailBody(appendices);
  186. foreach (var appendix in appendices)
  187. {
  188. appendix.StateId = stateSetId;
  189. _appendixService.UpdateAppendix(appendix);
  190. }
  191. SendNotification(mailNotification, "Autom. Übersicht nicht verhandelte Nachträge", mailBody);
  192. }
  193. }
  194. /// <summary>
  195. /// Sets the corresponding status for appendices which negotiation date is older than N weeks and notifies
  196. /// the correspondig recipients
  197. /// </summary>
  198. /// <param name="mailNotification">The notification which shall be generated.</param>
  199. private void ProcessNegotiationProtocolNotification(MailNotification mailNotification)
  200. {
  201. var ageDays = _configurationService.TryGetConfigItemValue<int>(
  202. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol.AgeDays", 14);
  203. var stateConditionId = _configurationService.TryGetConfigItemValue<int>(
  204. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol.StateCondition", 3);
  205. var interval = _configurationService.TryGetConfigItemValue<int>(
  206. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol.Interval", 2);
  207. interval = interval == 0
  208. ? 1
  209. : interval;
  210. var finishStateId = _appendixService.GetFinishState().Id;
  211. var appendices = _appendixService.GetAllAppendices()
  212. .Where(a => a.NegotiationDate.HasValue &&
  213. (DateTime.Now - a.NegotiationDate).Value.Days >= ageDays &&
  214. !a.ProtocolExists && a.StateId != finishStateId)
  215. .ToList();
  216. var currentCalendarWeek = GetCalendarWeek(DateTime.Now);
  217. appendices = appendices
  218. .Where(a => ((currentCalendarWeek - GetCalendarWeek(a.OfferingDate.Value) % interval == 0)))
  219. .ToList();
  220. if (appendices.Any())
  221. {
  222. var mailBody = GenerateNegotiationProtocolMailBody(appendices);
  223. SendNotification(mailNotification, "Autom. Übersicht verhandelte Nachträge o. Protokoll", mailBody);
  224. }
  225. }
  226. #endregion
  227. #region Mail body generation
  228. /// <summary>
  229. /// Generates a mail body with a list of all appendices with a offering date later than N weeks
  230. /// </summary>
  231. /// <param name="appendices">Appendices matching that criteria.</param>
  232. public string GenerateNegotiationDateMailBody(IEnumerable<Appendix> appendices)
  233. {
  234. var template =
  235. "<html>" +
  236. " <body>" +
  237. " <h3>Übersicht \"Nicht verhandelte Nachträge\"</h3>" +
  238. " <p>Folgende Nachträge haben ein Einreichdatum älter als 8 Wochen, jedoch noch kein Verhandlungstermin" +
  239. " gesetzt:</p>" +
  240. " <ul>" +
  241. " {0}" +
  242. " </ul>" +
  243. " </body>" +
  244. "</html>";
  245. if (!appendices.Any()) return String.Format(template, String.Empty);
  246. var appendicesList = String.Empty;
  247. foreach (var appendix in appendices)
  248. {
  249. appendicesList += String.Format(
  250. "<li>Nachtrag <b>\"{0}\"</b> in Baustelle <b>\"{1}\"</b> - Einreichdatum: <b>{2:dd.MM.yyyy}</b>",
  251. appendix.CustomNumber, appendix.Site.CustomNumber, appendix.OfferingDate);
  252. }
  253. return String.Format(template, appendicesList);
  254. }
  255. /// <summary>
  256. /// Generates a mail body with a list of all appendices with a negotiation date later than N weeks
  257. /// </summary>
  258. /// <param name="appendices">Appendices matching that criteria.</param>
  259. public string GenerateNegotiationProtocolMailBody(IEnumerable<Appendix> appendices)
  260. {
  261. var template =
  262. "<html>" +
  263. " <body>" +
  264. " <h3>Übersicht \"Verhandelte Nachträge ohne Protokoll\"</h3>" +
  265. " <p>Folgende Nachträge haben ein Verhandlungstermin älter als zwei Wochen, jedoch noch kein Protokoll:" +
  266. " <ul>" +
  267. " {0}" +
  268. " </ul>" +
  269. " </body>" +
  270. "</html>";
  271. if (!appendices.Any()) return String.Format(template, String.Empty);
  272. var appendicesList = String.Empty;
  273. foreach (var appendix in appendices)
  274. {
  275. appendicesList += String.Format(
  276. "<li>Nachtrag <b>\"{0}\"</b> in Baustelle <b>\"{1}\"</b> - Verhandlungsdatum: <b>{2:dd.MM.yyyy}</b>",
  277. appendix.CustomNumber, appendix.Site.CustomNumber, appendix.NegotiationDate);
  278. }
  279. return String.Format(template, appendicesList);
  280. }
  281. #endregion
  282. #region Mail sending
  283. /// <summary>
  284. /// Sends a generated mail body to the specified recipients in the mail notification
  285. /// </summary>
  286. /// <param name="mailNotification">The mail notification.</param>
  287. /// <param name="subject">The mail subject.</param>
  288. /// <param name="body">The mail body.</param>
  289. public void SendNotification(MailNotification mailNotification, string subject, string body)
  290. {
  291. if (mailNotification == null) return;
  292. var mailServerConfig = _configurationService.GetCurrentConfiguration().MailServerElement;
  293. var smptClient = new SmtpClient(mailServerConfig.SmtpServer, mailServerConfig.Port)
  294. {
  295. EnableSsl = mailServerConfig.UseSsl,
  296. Credentials = new NetworkCredential(
  297. mailServerConfig.Username,
  298. mailServerConfig.Password,
  299. mailServerConfig.Domain)
  300. };
  301. var recipients =
  302. mailNotification.Users
  303. .Select(u => u.MailAddress);
  304. var mailMessage = new MailMessage
  305. {
  306. IsBodyHtml = true,
  307. Subject = subject,
  308. Body = body,
  309. From = new MailAddress("Nachtragsbenachrichtigung@schweerbau.de")
  310. };
  311. foreach (var recipient in recipients)
  312. mailMessage.To.Add(recipient);
  313. smptClient.Send(mailMessage);
  314. }
  315. #endregion
  316. #region Helper
  317. /// <summary>
  318. /// Determines the calendar week of a specific datetime
  319. /// </summary>
  320. /// <param name="date">The datetime which calendarweek should be calculated.</param>
  321. public static int GetCalendarWeek(DateTime date)
  322. {
  323. var currentCulture = CultureInfo.CurrentCulture;
  324. var calendar = currentCulture.Calendar;
  325. var calendarWeek = calendar.GetWeekOfYear(
  326. date,
  327. currentCulture.DateTimeFormat.CalendarWeekRule,
  328. currentCulture.DateTimeFormat.FirstDayOfWeek);
  329. if (calendarWeek > 52)
  330. {
  331. date = date.AddDays(7);
  332. var testCalendarWeek = calendar.GetWeekOfYear(date,
  333. currentCulture.DateTimeFormat.CalendarWeekRule,
  334. currentCulture.DateTimeFormat.FirstDayOfWeek);
  335. if (testCalendarWeek == 2)
  336. calendarWeek = 1;
  337. }
  338. return calendarWeek;
  339. }
  340. #endregion
  341. }
  342. }