278 lines
13 KiB
C#
278 lines
13 KiB
C#
// Copyright (c) 2020-present schick Informatik
|
|
// Description:
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Globalization;
|
|
using System.ServiceProcess;
|
|
using System.Text.RegularExpressions;
|
|
using System.Timers;
|
|
using bsmd.email;
|
|
using bsmd.database;
|
|
using log4net;
|
|
|
|
namespace bsmd.POService
|
|
{
|
|
public partial class POService : ServiceBase
|
|
{
|
|
|
|
#region Fields
|
|
|
|
private Timer _timer;
|
|
private readonly ILog _log = LogManager.GetLogger(typeof(POService));
|
|
|
|
#endregion
|
|
|
|
#region Construction
|
|
|
|
public POService()
|
|
{
|
|
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
|
|
InitializeComponent();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Start/Stop Service
|
|
|
|
protected override void OnStart(string[] args)
|
|
{
|
|
this.EventLog.Source = this.ServiceName;
|
|
this.EventLog.Log = "Application";
|
|
this.Init();
|
|
this.EventLog.WriteEntry("NSW PO Number Service started.", EventLogEntryType.Information);
|
|
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
|
|
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
|
|
string version = fvi.FileVersion;
|
|
_log.InfoFormat("Starting PO Number Service. v.{0} -------------- ", version);
|
|
this.DoOnce();
|
|
}
|
|
|
|
protected override void OnStop()
|
|
{
|
|
this._log.Info("Stopping PO Number Service");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region helper
|
|
|
|
private void Init()
|
|
{
|
|
this._timer = new Timer
|
|
{
|
|
Interval = Properties.Settings.Default.SleepSeconds * 1000
|
|
};
|
|
this._timer.Elapsed += _timer_Elapsed;
|
|
this._timer.Enabled = true;
|
|
}
|
|
|
|
internal void DoOnce()
|
|
{
|
|
this._timer_Elapsed(null, null);
|
|
}
|
|
|
|
internal static bool ParsePO(string inputValue, ref string poNumber, ref string port,
|
|
ref string shipname, ref string something, ref string dateString)
|
|
{
|
|
bool result = false;
|
|
|
|
if (inputValue.IsNullOrEmpty()) return result;
|
|
|
|
// WuselString parsen. Ein Beispiel:
|
|
// "WG: PO:8204730095 DEWVNTM-ADELINA D-005E-310120";
|
|
// Hier kann man designen: https://regex101.com/
|
|
const string poPattern = @"PO:(\d+) ([A-Z]+)-(.*?)-(.*?)-(\d{6})";
|
|
Regex poRegex = new Regex(poPattern);
|
|
Match aMatch = poRegex.Match(inputValue);
|
|
if (aMatch.Success)
|
|
{
|
|
poNumber = aMatch.Groups[1].Captures[0].Value;
|
|
port = aMatch.Groups[2].Captures[0].Value;
|
|
shipname = aMatch.Groups[3].Captures[0].Value;
|
|
something = aMatch.Groups[4].Captures[0].Value;
|
|
dateString = aMatch.Groups[5].Captures[0].Value;
|
|
result = true;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region timer loop handler
|
|
|
|
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
|
|
{
|
|
|
|
if (DBManager.Instance.Connect(Properties.Settings.Default.ConnectionString))
|
|
{
|
|
|
|
try
|
|
{
|
|
string messageId = "";
|
|
string mailSender = "";
|
|
const string receiptSubject = "PO number service INFO";
|
|
string mailSubject = "";
|
|
string body = "";
|
|
|
|
using (BSMDPopClient bsmdPopClient = new BSMDPopClient())
|
|
{
|
|
if (bsmdPopClient.IsConnected)
|
|
{
|
|
// check and download next e-Mail, saving attachment
|
|
while (bsmdPopClient.ReceiveSingleMailText(out messageId, out mailSender, out mailSubject, out body))
|
|
{
|
|
string receiptText = "";
|
|
|
|
|
|
// only a valid sender gets a reply
|
|
bool isValidSender = false;
|
|
foreach (string aValidSender in Properties.Settings.Default.ValidSender)
|
|
{
|
|
if (mailSender.Equals(aValidSender, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
isValidSender = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!isValidSender)
|
|
{
|
|
receiptText = string.Format("ignored e - mail from illegal sender: {0}", mailSender);
|
|
_log.Warn(receiptText);
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
string poNumber = null;
|
|
string port = null;
|
|
string dateString = null;
|
|
string shipname = null;
|
|
string something = null;
|
|
|
|
// Mail nach dem PO Nummerntext durchsuchen
|
|
// Der Nummerstring ist vielleicht im Betreff, im Body oder im Dateinamen des
|
|
// PDF Attachments. In den PDF's selbst habe ich den (kompletten) String aktuell nicht gefunden.
|
|
|
|
try
|
|
{
|
|
|
|
if (!ParsePO(mailSubject, ref poNumber, ref port, ref shipname, ref something, ref dateString))
|
|
{
|
|
if (!ParsePO(body, ref poNumber, ref port, ref shipname, ref something, ref dateString))
|
|
{
|
|
string attachmentFileName = bsmdPopClient.GetNameOfFirstMailEmailPDFAttachment(messageId);
|
|
if (attachmentFileName != null)
|
|
ParsePO(attachmentFileName, ref poNumber, ref port, ref shipname, ref something, ref dateString);
|
|
}
|
|
}
|
|
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
_log.WarnFormat("Exception looking for PO number: {0}", ex.ToString());
|
|
}
|
|
|
|
|
|
if (poNumber != null)
|
|
{
|
|
// aus (ungefährem) Datum, Name und Hafen den MessageCore suchen
|
|
uint? from = null, to = null;
|
|
if (DateTime.TryParseExact(dateString, "ddMMyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime etaDate))
|
|
{
|
|
// Alle Anmeldungen des betreffenden Tages laden
|
|
Dictionary<MessageCore.SearchFilterType, string> filterDict = new Dictionary<MessageCore.SearchFilterType, string>();
|
|
|
|
// Datum filtern
|
|
from = etaDate.ToUniversalTime().Subtract(new TimeSpan(2, 0, 0)).ToUnixTimeStamp(); // 2 Tage vorher
|
|
to = etaDate.ToUniversalTime().Add(new TimeSpan(23, 59, 59)).ToUnixTimeStamp(); // 1 Tag später
|
|
|
|
filterDict.Add(MessageCore.SearchFilterType.FILTER_ETA, string.Format("{0}:{1}", from?.ToString() ?? "", to?.ToString() ?? ""));
|
|
List<MessageCore> anmeldungen = DBManager.GetSingleCon(Properties.Settings.Default.ConnectionString).GetMessageCoresWithFilters(filterDict, 100);
|
|
|
|
List<MessageCore> possibleMatches = new List<MessageCore>();
|
|
// nach Hafen und Schiffsnamen ausfiltern
|
|
if (port.Length > 5) port = port.Substring(0, 5);
|
|
foreach (MessageCore foundCore in anmeldungen)
|
|
{
|
|
if (foundCore.PoC.Equals(port) && foundCore.Shipname.Equals(shipname, StringComparison.OrdinalIgnoreCase))
|
|
possibleMatches.Add(foundCore);
|
|
}
|
|
if (possibleMatches.Count == 0)
|
|
{
|
|
// nix gefunden
|
|
receiptText = string.Format("no match found for PO number {0} ship {1} date {2} port {3}",
|
|
poNumber, shipname, etaDate, port);
|
|
_log.Warn(receiptText);
|
|
}
|
|
else if (possibleMatches.Count > 1)
|
|
{
|
|
// nicht eindeutig
|
|
receiptText = string.Format("{0} matches found for PO number {1} ship {2} date {3} port {4}",
|
|
possibleMatches.Count, poNumber, shipname, etaDate, port);
|
|
_log.Warn(receiptText);
|
|
}
|
|
else
|
|
{
|
|
// PO-Nummer und Schiffs/Anlaufklassifizierung eintragen
|
|
possibleMatches[0].PONumber = poNumber;
|
|
DBManager.GetSingleCon(Properties.Settings.Default.ConnectionString).Save(possibleMatches[0]);
|
|
_log.InfoFormat("MessageCore {0} updated with po number {1}", possibleMatches[0].Id, poNumber);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_log.WarnFormat("Error parsing date component of PO string: {0}", dateString);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_log.Warn("incoming e-mail did not contain a po number");
|
|
}
|
|
}
|
|
catch (Exception someException)
|
|
{
|
|
receiptText = string.Format("Error processing po mail: {0}", someException.Message);
|
|
_log.Error(receiptText);
|
|
}
|
|
|
|
}
|
|
|
|
if (receiptText.Length > 0)
|
|
{
|
|
_log.Debug("sending system info email");
|
|
BSMDMail.SendSystemInfo(receiptSubject, receiptText, mailSender);
|
|
}
|
|
|
|
|
|
// remove e-Mail
|
|
_log.InfoFormat("deleting mail with messageId {0}", messageId);
|
|
_log.InfoFormat("mail delete {0}", bsmdPopClient.DeleteMessageByMessageId(messageId) ? "successful" : "failed");
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
DBManager.Instance.Disconnect();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_log.ErrorFormat("Exception occurred: {0}", ex.ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_log.Error("DB Connection failure");
|
|
}
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|