// Copyright (c) 2015-2017 schick Informatik // Service entry point using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.ServiceProcess; using System.Timers; using log4net; using MigraDoc.DocumentObjectModel; using bsmd.database; using bsmd.email; using System.Text; namespace bsmd.ReportGenerator { public partial class ReportService : ServiceBase { private Timer _timer; private object _timerlock = new object(); private bool processRunning = false; private ILog _log = LogManager.GetLogger(typeof(ReportService)); public ReportService() { Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); InitializeComponent(); } #region windows service overrides protected override void OnStart(string[] args) { this.EventLog.Source = this.ServiceName; this.EventLog.Log = "Application"; this.Init(args); this.EventLog.WriteEntry("Report Service started.", EventLogEntryType.Information); System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location); string version = fvi.FileVersion; _log.InfoFormat("Report Service started. v.{0}", version); this.DoOnce(); } protected override void OnStop() { _log.Info("Report Service stopping."); } #endregion #region timer functions private void Init(string[] args) { this._timer = new Timer(); this._timer.Interval = Properties.Settings.Default.SleepSeconds * 1000; this._timer.Elapsed += _timer_Elapsed; this._timer.Enabled = true; } private void _timer_Elapsed(object sender, ElapsedEventArgs e) { lock (this._timerlock) { if (this.processRunning) return; else this.processRunning = true; } if (DBManager.Instance.Connect(Properties.Settings.Default.ConnectionString)) { try { // load all messages with report flag set List reportCores = DBManager.Instance.GetMessageCoresByReportStatus(MessageCore.ReportStatusEnum.COMPLETE); reportCores.AddRange(DBManager.Instance.GetMessageCoresByReportStatus(MessageCore.ReportStatusEnum.HE_REPORTTYPE)); reportCores.AddRange(DBManager.Instance.GetMessageCoresByReportStatus(MessageCore.ReportStatusEnum.HE_REVISION)); // create report documents for each of the messages foreach (MessageCore reportCore in reportCores) { this.CreateReport(reportCore); } // new ENI-2 Mode reportCores = DBManager.Instance.GetMessageCoresByReportStatus(MessageCore.ReportStatusEnum.SINGLE); foreach(MessageCore reportCore in reportCores) { this.CreateSingleReport(reportCore); } DBManager.Instance.Disconnect(); } catch (Exception ex) { _log.ErrorFormat("Exception occurred: {0}", ex.ToString()); } } else { this.EventLog.WriteEntry("ReportService DB connection failed", EventLogEntryType.Error); } lock (this._timerlock) { this.processRunning = false; } } internal void DoOnce() { this._timer_Elapsed(null, null); } #endregion #region create and send "old" EU-NOAD report private void CreateReport(MessageCore reportCore) { List messages = DBManager.Instance.GetMessagesForCore(reportCore, DBManager.MessageLoad.ALL); messages.Sort(new ANSWMessageComparer()); Dictionary coverInfos = new Dictionary(); bool isReportUpdate = reportCore.ReportStatus != MessageCore.ReportStatusEnum.COMPLETE; coverInfos.Add("Type", reportCore.HerbergReportType); coverInfos.Add("Ship", DBManager.Instance.GetShipNameFromCore(reportCore)); coverInfos.Add("E-Mail Ship", reportCore.HerbergEmailContactReportingVessel); coverInfos.Add("IMO", reportCore.IMO); DateTime eta = reportCore.ETA ?? (reportCore.ETAKielCanal ?? new DateTime(0)); coverInfos.Add("ETA", eta.ToShortDateString()); coverInfos.Add("Port", reportCore.Portname); coverInfos.Add("", ""); if (reportCore.Customer != null) { coverInfos.Add("Name", reportCore.Customer.Name); coverInfos.Add("Contact first name", reportCore.Customer.ContactFirstName); coverInfos.Add("Contact last name", reportCore.Customer.ContactLastName); coverInfos.Add("Customer number", reportCore.Customer.CustomerNumber); coverInfos.Add("Street", reportCore.Customer.StreetAndNumber); coverInfos.Add("Postal code", reportCore.Customer.PostalCode); coverInfos.Add("City", reportCore.Customer.City); coverInfos.Add("Country", reportCore.Customer.Country); coverInfos.Add("Phone", reportCore.Customer.Phone); coverInfos.Add("E-Mail", reportCore.Customer.Email); } // create document and print header area (with message core data) Document migraDocument = BSMDDocument.CreateDocument( string.Format("NSW Eingangsdatenübersicht für IMO {0}, ETA {1}", reportCore.IMO, reportCore.ETA), "NSW Meldung", Properties.Settings.Default.ReportAuthor, coverInfos, isReportUpdate); // print messages in subsequent tables foreach (Message message in messages) { BSMDDocument.AddNSWMessageParagraph(migraDocument, message); } // prepare and send E-Mail with generated attachment string fullPath = string.Format("{0}\\{1}.pdf", Properties.Settings.Default.OutputDirectory, reportCore.Id); BSMDDocument.RenderDocument(migraDocument, fullPath); _log.InfoFormat("Document created for MessageCoreId {0}, IMO {1}", reportCore.Id, reportCore.IMO); string subject = string.Format("NEW EU-NOAD message IMO {0}", reportCore.IMO); if(isReportUpdate) subject = string.Format("UPDATE EU-NOAD message IMO {0}", reportCore.IMO); List attachments = new List(); attachments.Add(fullPath); #region 10.7.15: Check PAS/CREW messages to create extra csv files and add them as well Message pas = messages.Find(x => x.MessageNotificationClass == Message.NotificationClass.PAS); string passengerCSV = null; if ((pas != null) && (pas.Elements.Count > 0)) { passengerCSV = CrewPasHelper.CreateCSV(pas); attachments.Add(passengerCSV); } Message crew = messages.Find(x => x.MessageNotificationClass == Message.NotificationClass.CREW); string crewCSV = null; if ((crew != null) && (crew.Elements.Count > 0)) { crewCSV = CrewPasHelper.CreateCSV(crew); attachments.Add(crewCSV); } #endregion BSMDMail.SendNSWReportWithAttachments(subject, attachments, null); // reset report status reportCore.ReportStatus = MessageCore.ReportStatusEnum.NONE; DBManager.Instance.Save(reportCore); if (passengerCSV != null) { try { File.Delete(passengerCSV); } catch(Exception ex) { _log.WarnFormat("Exception trying to delete passenger csv:{0}", ex.Message); } } if (crewCSV != null) { try { File.Delete(crewCSV); } catch(Exception ex) { _log.WarnFormat("Exception trying to delete crew csv:{0}", ex.Message); } } } #endregion #region create (and send) "single" report (a report per message class) internal void CreateSingleReport(MessageCore reportCore) { List messages = DBManager.Instance.GetMessagesForCore(reportCore, DBManager.MessageLoad.ALL); List reportMessages = new List(); messages.Sort(new ANSWMessageComparer()); StringBuilder sb = new StringBuilder(); Guid reportingPartyId = Guid.Empty; foreach (Message aMessage in messages) { if (aMessage.InternalStatus == Message.BSMDStatus.REPORT) { if ((aMessage.MessageNotificationClass != Message.NotificationClass.VISIT) && (aMessage.MessageNotificationClass != Message.NotificationClass.TRANSIT)) reportMessages.Add(aMessage); aMessage.InternalStatus = Message.BSMDStatus.PREPARE; DBManager.Instance.Save(aMessage); sb.Append(aMessage.MessageNotificationClassDisplay); sb.Append("_"); if (aMessage.ReportingPartyId.HasValue) reportingPartyId = aMessage.ReportingPartyId.Value; } } if (sb.Length > 0) sb.Remove(sb.Length - 1, 1); string classes = sb.ToString(); if (!classes.IsNullOrEmpty()) { ReportingParty rp = null; if (DBManager.Instance.GetReportingPartyDict().ContainsKey(reportingPartyId)) { rp = DBManager.Instance.GetReportingPartyDict()[reportingPartyId]; Dictionary coverInfos = new Dictionary(); coverInfos.Add("Ship", DBManager.Instance.GetShipNameFromCore(reportCore)); coverInfos.Add("ETA", reportCore.ETA_NOA_NOD.HasValue ? reportCore.ETA_NOA_NOD.Value.ToLocalTime().ToString() : ""); coverInfos.Add("Port of call", reportCore.Portname); coverInfos.Add("Visit-ID", reportCore.DisplayId); coverInfos.Add("Class", classes); string subject = string.Format("PDF report IMO {0} class(es) {1}", reportCore.IMO, classes); Document migraDocument = BSMDDocument.CreateSingleClassDocument(reportCore, reportMessages, coverInfos, classes, rp); // print messages to document foreach (Message message in reportMessages) { BSMDDocument.AddNSWMessageParagraph(migraDocument, message); } // prepare and send E-Mail with generated attachment // Schiffsname_ID_Meldeklassen.pdf string shipName = DBManager.Instance.GetShipNameFromCore(reportCore); if (shipName.IsNullOrEmpty()) shipName = "UNKNOWN"; // INSANITY CHECK!!! string invalid = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars()); foreach (char c in invalid) shipName = shipName.Replace(c.ToString(), ""); shipName = shipName.Replace(' ', '_'); string fullPath = string.Format("{0}\\{1}_{2}_{3}.pdf", Properties.Settings.Default.OutputDirectory, shipName, reportCore.DisplayId, classes); BSMDDocument.RenderDocument(migraDocument, fullPath); _log.InfoFormat("Document created for MessageCoreId {0}, IMO {1}", reportCore.Id, reportCore.IMO); List attachments = new List(); attachments.Add(fullPath); BSMDMail.SendNSWReportWithAttachments(subject, attachments, rp.UserEMail); // remove if (Properties.Settings.Default.DeleteFileAfterSend) { try { File.Delete(fullPath); } catch (Exception ex) { _log.ErrorFormat("Cannot delete {0}: {1}", fullPath, ex.Message); } } } else { _log.WarnFormat("Default reporting party not set on core {0}", reportCore.Id); } } else { _log.WarnFormat("Core {0} set for report, but no message classes!", reportCore.Id); } // reset report status reportCore.ReportStatus = MessageCore.ReportStatusEnum.NONE; DBManager.Instance.Save(reportCore); } #endregion } }