AppendixNotificationPlugin.cs 21 KB

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