AppendixNotificationPlugin.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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. foreach (var notification in mailNotifications)
  148. {
  149. try
  150. {
  151. switch (notification.NotificationJobSystemName)
  152. {
  153. case "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate":
  154. {
  155. ProcessNegotiationDateNotification(notification);
  156. }
  157. break;
  158. case "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol":
  159. {
  160. ProcessNegotiationProtocolNotification(notification);
  161. }
  162. break;
  163. case "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationOrder":
  164. {
  165. ProcessNegotiationOrderNotification(notification);
  166. }
  167. break;
  168. default:
  169. continue;
  170. }
  171. }
  172. catch (Exception ex)
  173. {
  174. _logger.Error(
  175. String.Format(
  176. "Fehler bei Mail-Benachrichtigung in \"{0}\" für \"{1}", SystemName, notification.NotificationJobSystemName), ex);
  177. }
  178. }
  179. }
  180. /// <summary>
  181. /// Sets the corresponding status for appendices which offering date is older than N weeks and notifies
  182. /// the correspondig recipients
  183. /// </summary>
  184. /// <param name="mailNotification">The notification which shall be generated.</param>
  185. private void ProcessNegotiationDateNotification(MailNotification mailNotification)
  186. {
  187. var ageDays = _configurationService.TryGetConfigItemValue<int>(
  188. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate.AgeDays", 56);
  189. var stateSetId = _configurationService.TryGetConfigItemValue<int[]>(
  190. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate.StateSet", new[] { 13 })[0];
  191. var stateConditionIds = _configurationService.TryGetConfigItemValue<int[]>(
  192. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate.StateCondition", new[] { 1, 5, 6, 12 });
  193. var interval = _configurationService.TryGetConfigItemValue<int>(
  194. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationDate.Interval", 2);
  195. interval = interval == 0
  196. ? 1
  197. : interval;
  198. var finishStateId = _appendixService.GetFinishState().Id;
  199. var appendices = _appendixService.GetAllAppendices()
  200. .Where(a => a.OfferingDate.HasValue &&
  201. (DateTime.Now - a.OfferingDate).Value.Days >= ageDays &&
  202. a.StateId != stateSetId && a.StateId != finishStateId &&
  203. stateConditionIds.Contains(a.StateId.Value) && a.NegotiationDate == null)
  204. .ToList();
  205. var currentCalendarWeek = GetCalendarWeek(DateTime.Now);
  206. appendices = appendices
  207. .Where(a => (currentCalendarWeek - GetCalendarWeek(a.OfferingDate.Value) % interval == 0) ||
  208. (currentCalendarWeek - GetCalendarWeek(a.OfferingDate.Value) < 0))
  209. .ToList();
  210. if (appendices.Any())
  211. {
  212. var mailBody = GenerateNegotiationDateMailBody(appendices);
  213. foreach (var appendix in appendices)
  214. {
  215. appendix.StateId = stateSetId;
  216. _appendixService.UpdateAppendix(appendix);
  217. }
  218. SendNotification(mailNotification, "Autom. Übersicht nicht verhandelte Nachträge", mailBody);
  219. }
  220. }
  221. /// <summary>
  222. /// Sets the corresponding status for appendices which negotiation date is older than N weeks and notifies
  223. /// the correspondig recipients when the protocol does not exist
  224. /// </summary>
  225. /// <param name="mailNotification">The notification which shall be generated.</param>
  226. private void ProcessNegotiationProtocolNotification(MailNotification mailNotification)
  227. {
  228. var ageDays = _configurationService.TryGetConfigItemValue<int>(
  229. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol.AgeDays", 14);
  230. var interval = _configurationService.TryGetConfigItemValue<int>(
  231. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationProtocol.Interval", 2);
  232. interval = interval == 0
  233. ? 1
  234. : interval;
  235. var finishStateId = _appendixService.GetFinishState().Id;
  236. var appendices = _appendixService.GetAllAppendices()
  237. .Where(a => a.NegotiationDate.HasValue &&
  238. (DateTime.Now - a.NegotiationDate).Value.Days >= ageDays &&
  239. !a.ProtocolExists && a.StateId != finishStateId)
  240. .ToList();
  241. var currentCalendarWeek = GetCalendarWeek(DateTime.Now);
  242. appendices = appendices
  243. .Where(a => (currentCalendarWeek - GetCalendarWeek(a.OfferingDate.Value) % interval == 0) ||
  244. (currentCalendarWeek - GetCalendarWeek(a.OfferingDate.Value) < 0))
  245. .ToList();
  246. if (appendices.Any())
  247. {
  248. var mailBody = GenerateNegotiationProtocolMailBody(appendices);
  249. SendNotification(mailNotification, "Autom. Übersicht verhandelte Nachträge o. Protokoll", mailBody);
  250. }
  251. }
  252. /// <summary>
  253. /// Sets the corresponding status for appendices which negotiation date is older than N weeks and notifies
  254. /// the correspondig recipients when the order number is still missing
  255. /// </summary>
  256. /// <param name="mailNotification">The notification which shall be generated.</param>
  257. private void ProcessNegotiationOrderNotification(MailNotification mailNotification)
  258. {
  259. var ageDays = _configurationService.TryGetConfigItemValue<int>(
  260. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationOrder.AgeDays", 14);
  261. var interval = _configurationService.TryGetConfigItemValue<int>(
  262. "GreenTree.Nachtragsmanagement.AppendixNotificationPlugin.ProcessNegotiationOrder.Interval", 2);
  263. interval = interval == 0
  264. ? 1
  265. : interval;
  266. var finishStateId = _appendixService.GetFinishState().Id;
  267. var appendices = _appendixService.GetAllAppendices()
  268. .Where(a => a.NegotiationDate.HasValue &&
  269. (DateTime.Now - a.NegotiationDate).Value.Days >= ageDays &&
  270. String.IsNullOrEmpty(a.OrderNumber) && a.StateId != finishStateId)
  271. .ToList();
  272. var currentCalendarWeek = GetCalendarWeek(DateTime.Now);
  273. appendices = appendices
  274. .Where(a => (currentCalendarWeek - GetCalendarWeek(a.OfferingDate.Value) % interval == 0) ||
  275. (currentCalendarWeek - GetCalendarWeek(a.OfferingDate.Value) < 0))
  276. .ToList();
  277. if (appendices.Any())
  278. {
  279. var mailBody = GenerateNegotiationOrderMailBody(appendices);
  280. SendNotification(mailNotification, "Autom. Übersicht verhandelte Nachträge o. Bestellnummer", mailBody);
  281. }
  282. }
  283. #endregion
  284. #region Mail body generation
  285. /// <summary>
  286. /// Generates a mail body with a list of all appendices with a offering date later than N weeks
  287. /// </summary>
  288. /// <param name="appendices">Appendices matching that criteria.</param>
  289. public string GenerateNegotiationDateMailBody(IEnumerable<Appendix> appendices)
  290. {
  291. var template =
  292. "<html>" +
  293. " <body>" +
  294. " <h3>Übersicht \"Nicht verhandelte Nachträge\"</h3>" +
  295. " <p>Folgende Nachträge haben ein Einreichdatum älter als 8 Wochen, jedoch noch kein Verhandlungstermin" +
  296. " gesetzt:</p>" +
  297. " <ul>" +
  298. " {0}" +
  299. " </ul>" +
  300. " </body>" +
  301. "</html>";
  302. if (!appendices.Any()) return String.Format(template, String.Empty);
  303. var appendicesList = String.Empty;
  304. foreach (var appendix in appendices)
  305. {
  306. appendicesList += String.Format(
  307. "<li>Nachtrag <b>\"{0}\"</b> in Baustelle <b>\"{1}\"</b> - Einreichdatum: <b>{2:dd.MM.yyyy}</b>",
  308. appendix.CustomNumber, appendix.Site.CustomNumber, appendix.OfferingDate);
  309. }
  310. return String.Format(template, appendicesList);
  311. }
  312. /// <summary>
  313. /// Generates a mail body with a list of all appendices with a negotiation date later than N weeks and not existing protocol
  314. /// </summary>
  315. /// <param name="appendices">Appendices matching that criteria.</param>
  316. public string GenerateNegotiationProtocolMailBody(IEnumerable<Appendix> appendices)
  317. {
  318. var template =
  319. "<html>" +
  320. " <body>" +
  321. " <h3>Übersicht \"Verhandelte Nachträge ohne Protokoll\"</h3>" +
  322. " <p>Folgende Nachträge haben ein Verhandlungstermin älter als zwei Wochen, jedoch noch kein Protokoll:" +
  323. " <ul>" +
  324. " {0}" +
  325. " </ul>" +
  326. " </body>" +
  327. "</html>";
  328. if (!appendices.Any()) return String.Format(template, String.Empty);
  329. var appendicesList = String.Empty;
  330. foreach (var appendix in appendices)
  331. {
  332. appendicesList += String.Format(
  333. "<li>Nachtrag <b>\"{0}\"</b> in Baustelle <b>\"{1}\"</b> - Verhandlungsdatum: <b>{2:dd.MM.yyyy}</b>",
  334. appendix.CustomNumber,
  335. appendix.Site == null
  336. ? String.Empty
  337. : appendix.Site.CustomNumber,
  338. appendix.NegotiationDate);
  339. }
  340. return String.Format(template, appendicesList);
  341. }
  342. /// <summary>
  343. /// Generates a mail body with a list of all appendices with a negotiation date later than N weeks and not existing order number
  344. /// </summary>
  345. /// <param name="appendices">Appendices matching that criteria.</param>
  346. public string GenerateNegotiationOrderMailBody(IEnumerable<Appendix> appendices)
  347. {
  348. var template =
  349. "<html>" +
  350. " <body>" +
  351. " <h3>Übersicht \"Verhandelte Nachträge ohne Bestellnummer\"</h3>" +
  352. " <p>Folgende Nachträge haben ein Verhandlungstermin älter als zwei Wochen, jedoch noch keine Bestellnummer:" +
  353. " <ul>" +
  354. " {0}" +
  355. " </ul>" +
  356. " </body>" +
  357. "</html>";
  358. if (!appendices.Any()) return String.Format(template, String.Empty);
  359. var appendicesList = String.Empty;
  360. foreach (var appendix in appendices)
  361. {
  362. appendicesList += String.Format(
  363. "<li>Nachtrag <b>\"{0}\"</b> in Baustelle <b>\"{1}\"</b> - Verhandlungsdatum: <b>{2:dd.MM.yyyy}</b>",
  364. appendix.CustomNumber,
  365. appendix.Site == null
  366. ? String.Empty
  367. : appendix.Site.CustomNumber,
  368. appendix.NegotiationDate);
  369. }
  370. return String.Format(template, appendicesList);
  371. }
  372. #endregion
  373. #region Mail sending
  374. /// <summary>
  375. /// Sends a generated mail body to the specified recipients in the mail notification
  376. /// </summary>
  377. /// <param name="mailNotification">The mail notification.</param>
  378. /// <param name="subject">The mail subject.</param>
  379. /// <param name="body">The mail body.</param>
  380. public void SendNotification(MailNotification mailNotification, string subject, string body)
  381. {
  382. if (mailNotification == null) return;
  383. var mailServerConfig = _configurationService.GetCurrentConfiguration().MailServerElement;
  384. var smptClient = new SmtpClient(mailServerConfig.SmtpServer, mailServerConfig.Port)
  385. {
  386. EnableSsl = mailServerConfig.UseSsl,
  387. Credentials = new NetworkCredential(
  388. mailServerConfig.Username,
  389. mailServerConfig.Password,
  390. mailServerConfig.Domain)
  391. };
  392. var recipients =
  393. mailNotification.Users
  394. .Select(u => u.MailAddress);
  395. var mailMessage = new MailMessage
  396. {
  397. IsBodyHtml = true,
  398. Subject = subject,
  399. Body = body,
  400. From = new MailAddress("Nachtragsbenachrichtigung@schweerbau.de")
  401. };
  402. foreach (var recipient in recipients)
  403. mailMessage.To.Add(recipient);
  404. smptClient.Send(mailMessage);
  405. }
  406. #endregion
  407. #region Helper
  408. /// <summary>
  409. /// Determines the calendar week of a specific datetime
  410. /// </summary>
  411. /// <param name="date">The datetime which calendarweek should be calculated.</param>
  412. public static int GetCalendarWeek(DateTime date)
  413. {
  414. var currentCulture = CultureInfo.CurrentCulture;
  415. var calendar = currentCulture.Calendar;
  416. var calendarWeek = calendar.GetWeekOfYear(
  417. date,
  418. currentCulture.DateTimeFormat.CalendarWeekRule,
  419. currentCulture.DateTimeFormat.FirstDayOfWeek);
  420. if (calendarWeek > 52)
  421. {
  422. date = date.AddDays(7);
  423. var testCalendarWeek = calendar.GetWeekOfYear(date,
  424. currentCulture.DateTimeFormat.CalendarWeekRule,
  425. currentCulture.DateTimeFormat.FirstDayOfWeek);
  426. if (testCalendarWeek == 2)
  427. calendarWeek = 1;
  428. }
  429. return calendarWeek;
  430. }
  431. #endregion
  432. }
  433. }