AppendixNotificationPlugin.cs 21 KB

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