This commit is contained in:
Daniel Schick 2016-01-17 15:00:26 +00:00
parent 8d93750655
commit e3de127046
30 changed files with 941 additions and 72 deletions

Binary file not shown.

View File

@ -68,11 +68,19 @@ namespace bsmd.ExcelReadService
using (BSMDPopClient bsmdPopClient = new BSMDPopClient())
{
if (!bsmdPopClient.IsConnected)
{
_log.Error("cannot connect to pop3 server, aborting!");
this.Stop();
}
// if (!bsmdPopClient.IsConnected)
//{
// _log.Error("cannot connect to pop3 server, aborting!");
// this.Stop();
//}
// just for testing
ExcelReader er = new ExcelReader(@"E:\work\bsmd\nsw\Source\bsmd.ExcelReadService\2016_01_08_BMSD - EUNoAD Tool Rev 3.0_mit Testdaten.xls");
string amsg;
MessageCore aCore;
bool aReadResult = Util.ProcessSheet(er, out amsg, out aCore);
er.Dispose();
// check and download next e-Mail, saving attachment
while (bsmdPopClient.ReceiveSingleMail(out attachmentLocalPath, out messageId, out mailSender))
@ -90,7 +98,7 @@ namespace bsmd.ExcelReadService
_log.Error("Excel sheet could not be interpreted");
}
// set messagecore to createreport and let reportGenerator create a reply
// set messagecore to createreport and let reportGenerator create a reply?
// remove e-Mail
_log.InfoFormat("deleting mail with messageId {0}", messageId);
@ -100,6 +108,11 @@ namespace bsmd.ExcelReadService
_log.InfoFormat("removing local file {0}", attachmentLocalPath);
// File.Delete(attachmentLocalPath);
// create a reply sheet (template + scanned highlighted content for verification
// send reply sheet back to sender
}
}

View File

@ -10,50 +10,120 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using log4net;
using Excel.Core;
using Excel;
using Microsoft.Office.Interop.Excel;
namespace bsmd.ExcelReadService
{
public class ExcelReader : IDisposable
{
private IExcelDataReader dataReader;
private ILog _log = LogManager.GetLogger(typeof(ExcelReader));
private Workbooks _excelWorkbooks;
private Application _excelApp;
private Dictionary<string, Name> _nameDict;
public ExcelReader(string filePath)
{
using (FileStream fs = File.Open(filePath, FileMode.Open, FileAccess.Read))
this._excelApp = new Application();
this._excelWorkbooks = _excelApp.Workbooks;
Workbook portcall = _excelWorkbooks.Open(filePath, 0, true, 5, "", "", false, XlPlatform.xlWindows, "", false, false, 0, false, false, false);
_nameDict = new Dictionary<string, Name>();
foreach(Name name in portcall.Names)
{
if (filePath.EndsWith(".xls", StringComparison.InvariantCultureIgnoreCase))
dataReader = ExcelReaderFactory.CreateBinaryReader(fs);
else if (filePath.EndsWith(".xlsx", StringComparison.InvariantCultureIgnoreCase))
dataReader = ExcelReaderFactory.CreateOpenXmlReader(fs);
else
throw new ArgumentException(string.Format("saved file {0} is not an excel file", filePath));
_nameDict[name.Name] = name;
}
}
public object GetCell(string workSheetName, int row, int col)
public string ReadText(string lookup)
{
this.dataReader.IsFirstRowAsColumnNames = false;
DataSet dataSet = dataReader.AsDataSet();
DataTable workSheet = dataSet.Tables[workSheetName];
var cellValue = workSheet.Rows[row][col];
return cellValue;
if (!_nameDict.ContainsKey(lookup)) return null;
var val = _nameDict[lookup].RefersToRange.Value;
var val2 = _nameDict[lookup].RefersToRange.Value2;
if(val != null)
return val.ToString();
if (val2 != null)
return val2.ToString();
return null;
}
public void Dispose()
{
if (this.dataReader != null)
this.dataReader.Dispose();
if (this._excelWorkbooks != null)
this._excelWorkbooks.Close();
if (this._excelApp != null)
this._excelApp.Quit();
}
internal DateTime? ReadDate(string lookup)
{
try
{
var val = _nameDict[lookup].RefersToRange.Value;
if (val is DateTime) return val;
if (val is double)
return DateTime.FromOADate(val);
DateTime date;
if (DateTime.TryParse(val, out date))
return date;
// TODO: weitere varianten ausprobieren
return null;
}
catch (Exception)
{
_log.WarnFormat("error parsing datetime for lookup {0}", lookup);
return null;
}
}
internal DateTime? ReadTime(string lookup)
{
try
{
var val = _nameDict[lookup].RefersToRange.Value;
if (val is DateTime) return val;
if (val is double)
return DateTime.FromOADate(val);
DateTime date;
if (DateTime.TryParseExact(val, "HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out date))
return date;
if (DateTime.TryParseExact(val, "HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out date))
return date;
return null;
}
catch (Exception)
{
_log.WarnFormat("error reading time for lookup {0}", lookup);
return null;
}
}
internal double? ReadNumber(string lookup)
{
double result;
try
{
var val = _nameDict[lookup].RefersToRange.Value;
if (val is double) return val;
if (val is string)
{
if (double.TryParse(val, NumberStyles.None, CultureInfo.InvariantCulture, out result))
return result;
if (double.TryParse(val, out result))
return result;
}
return null;
}
catch (Exception)
{
_log.WarnFormat("error reading number for lookup {0}", lookup);
return null;
}
}
}
}

View File

@ -0,0 +1,87 @@
//
// Class: LocodeDB
// Current CLR: 4.0.30319.42000
// System: Microsoft Visual Studio 10.0
// Author: dani
// Created: 1/9/2016 10:10:20 PM
//
// Copyright (c) 2016 Informatikbüro Daniel Schick. All rights reserved.
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
namespace bsmd.ExcelReadService
{
/// <summary>
/// Locodes suchen (zu Orten), die DB ist aus einem github Projekt:
/// https://github.com/kabisa/un_locode
/// </summary>
public class LocodeDB
{
private static SQLiteConnection _con;
private const string _locode_DB_NAME = "db.sqlite";
static LocodeDB()
{
_con = new SQLiteConnection(string.Format("data source={0}; Version=3;", _locode_DB_NAME));
_con.Open();
}
#region public static methods
public static string LocodeGERFromCity(string city)
{
return LocodeDB.LocodeFromCity(city, "DE");
}
/// <summary>
/// Lookup and create locode from local sqlite database
/// </summary>
public static string LocodeFromCity(string city, string country)
{
string result = null;
string query = string.Format("SELECT city_code FROM locodes JOIN countries ON locodes.country_id = countries.ID WHERE countries.code = '{0}' AND locodes.port='t' AND locodes.name like '{1}'",
country, city);
SQLiteCommand cmd = new SQLiteCommand(query, _con);
IDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
result = reader.GetString(0);
break;
}
reader.Close();
if (result != null)
result = string.Format("{0}{1}", country, result);
return result;
}
/// <summary>
/// Lookup 2CHAR Country Code from country name (like search). Hopefully this will result in many hits
/// </summary>
public static string CountryCodeFromName(string countryName)
{
string result = null;
string query = string.Format("SELECT code FROM countries WHERE countries.name like '{0}'", countryName);
SQLiteCommand cmd = new SQLiteCommand(query, _con);
IDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
result = reader.GetString(0);
break;
}
reader.Close();
return result;
}
public static void CloseDB()
{
_con.Close();
}
#endregion
}
}

View File

@ -9,6 +9,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using log4net;
using bsmd.database;
@ -21,43 +24,487 @@ namespace bsmd.ExcelReadService
public static bool ProcessSheet(ExcelReader reader, out string readMessage, out MessageCore messageCore)
{
readMessage = "ok";
messageCore = Util.LookupMessageCore(reader);
messageCore = Util.LookupMessageCore(reader, out readMessage);
if (messageCore == null) return false; // cannot work with this sheet or create one
// load messages if already present
List<Message> messages = DBManager.Instance.GetMessagesForCore(messageCore);
// start parsing fields
string sheetVersion = reader.GetCell("Portcall", 2, 1) as string;
messageCore.SietasSheetVersion = sheetVersion;
if (messageCore.IsTransit)
{
// scan for transit messages
// AGNT
// NOA_NOD
// SEC
// POBA
// POBD
ScanTIEFA(messages, messageCore, reader);
ScanBKRA(messages, messageCore, reader);
ScanSTAT(messages, messageCore, reader);
// MDH
// CREW
// PAS
// BPOL
// TOWA
// HAZA
// HAZD
}
else
{
// scan for visit messages
// AGNT
// NOA_NOD
ScanATA(messages, messageCore, reader);
ScanATD(messages, messageCore, reader);
// SEC
// POBA
// POBD
ScanNAME(messages, messageCore, reader);
ScanTIEFA(messages, messageCore, reader);
ScanTIEFD(messages, messageCore, reader);
ScanBKRA(messages, messageCore, reader);
ScanBKRD(messages, messageCore, reader);
ScanSTAT(messages, messageCore, reader);
// LADG
// INFO
// SERV
// PRE72H
// MDH
// WAS
// CREW
// PAS
// BPOL
// TOWA
// TOWD
// HAZA
// HAZD
}
//string sheetVersion = reader.GetCell("Portcall", 2, 1) as string;
//messageCore.SietasSheetVersion = sheetVersion;
// save all messages now
foreach(Message message in messages)
{
DBManager.Instance.Save(message);
// TODO: Die abhängigen Listen müssen auch gespeichert werden
}
DBManager.Instance.Save(messageCore);
return true;
}
#region ATA
static void ScanATA(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message ataMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.ATA);
if (ataMessage.Elements.Count == 0)
{
ATA newATA = new ATA();
newATA.MessageHeader = ataMessage;
ataMessage.Elements.Add(newATA);
}
ATA ata = ataMessage.Elements[0] as ATA;
Util.ScanMessage(ata, reader);
if (!ata.ATAPortOfCall.HasValue && ataMessage.IsNew)
messages.Remove(ataMessage);
}
#endregion
#region ATD
static void ScanATD(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message atdMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.ATD);
if (atdMessage.Elements.Count == 0)
{
ATD newATD = new ATD();
newATD.MessageHeader = atdMessage;
atdMessage.Elements.Add(newATD);
}
ATD atd = atdMessage.Elements[0] as ATD;
Util.ScanMessage(atd, reader);
if (!atd.ATDPortOfCall.HasValue && atdMessage.IsNew)
messages.Remove(atdMessage);
}
#endregion
#region TIEFA
static void ScanTIEFA(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message tiefaMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.TIEFA);
if (tiefaMessage.Elements.Count == 0)
{
TIEFA newTIEFA = new TIEFA();
newTIEFA.MessageHeader = tiefaMessage;
tiefaMessage.Elements.Add(newTIEFA);
}
TIEFA tiefa = tiefaMessage.Elements[0] as TIEFA;
Util.ScanMessage(tiefa, reader);
if (!tiefa.DraughtUponArrival_DMT.HasValue && tiefaMessage.IsNew)
messages.Remove(tiefaMessage);
}
#endregion
#region TIEFD
static void ScanTIEFD(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message tiefdMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.TIEFD);
if(tiefdMessage.Elements.Count == 0)
{
TIEFD newTIEFD = new TIEFD();
newTIEFD.MessageHeader = tiefdMessage;
tiefdMessage.Elements.Add(newTIEFD);
}
TIEFD tiefd = tiefdMessage.Elements[0] as TIEFD;
Util.ScanMessage(tiefd, reader);
if (!tiefd.DraughtUponDeparture_DMT.HasValue && tiefdMessage.IsNew)
messages.Remove(tiefdMessage);
}
#endregion
#region NAME
static void ScanNAME(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message nameMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.NAME);
if (nameMessage.Elements.Count == 0)
{
NAME newNAME = new NAME();
newNAME.MessageHeader = nameMessage;
nameMessage.Elements.Add(newNAME);
}
NAME name = nameMessage.Elements[0] as NAME;
Util.ScanMessage(name, reader);
if (name.NameOfMaster.IsNullOrEmpty() && name.IsNew)
messages.Remove(nameMessage);
}
#endregion
#region STAT
static void ScanSTAT(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message statMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.STAT);
if(statMessage.Elements.Count == 0)
{
STAT newSTAT = new STAT();
newSTAT.MessageHeader = statMessage;
statMessage.Elements.Add(newSTAT);
}
STAT stat = statMessage.Elements[0] as STAT;
Util.ScanMessage(stat, reader);
if (!stat.Flag.IsNullOrEmpty() && stat.Flag.Length > 2)
stat.Flag = LocodeDB.CountryCodeFromName(stat.Flag);
if (!stat.Flag.IsNullOrEmpty() && stat.Flag.Length == 2)
{
if (!stat.PortOfRegistry.IsNullOrEmpty() && stat.PortOfRegistry.Length != 5)
stat.PortOfRegistry = LocodeDB.LocodeFromCity(stat.PortOfRegistry, stat.Flag);
}
// wird nicht wieder entfernt (core ist auch da!)
}
#endregion
#region BKRA
static void ScanBKRA(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message bkraMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.BKRA);
for (int i = 0; i < bkraMessage.NumberOfExcelRows; i++)
{
string lnQuantity = string.Format("BKRA.BunkerFuelQuantity_TNE_{0}", i + 1);
string lnType = string.Format("BKRA.BunkerFuelType_{0}", i + 1);
BRKA bkra = bkraMessage.GetSublistElementWithIdentifier((i + 1).ToString()) as BRKA;
if (bkra == null)
{
bkra = new BRKA();
bkra.Identifier = (i + 1).ToString();
bkra.MessageHeader = bkraMessage;
bkraMessage.Elements.Add(bkra);
}
bkra.BunkerFuelQuantity_TNE = reader.ReadNumber(lnQuantity);
bkra.BunkerFuelType = reader.ReadText(lnType);
// dont save empty element
if(bkra.IsNew && !bkra.BunkerFuelQuantity_TNE.HasValue && bkra.BunkerFuelType.IsNullOrEmpty())
bkraMessage.Elements.Remove(bkra);
}
}
#endregion
#region BKRD
static void ScanBKRD(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message bkrdMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.BKRD);
for (int i = 0; i < bkrdMessage.NumberOfExcelRows; i++)
{
string lnQuantity = string.Format("BKRD.BunkerFuelQuantity_TNE_{0}", i + 1);
string lnType = string.Format("BKRD.BunkerFuelType_{0}", i + 1);
BRKD bkrd = bkrdMessage.GetSublistElementWithIdentifier((i + 1).ToString()) as BRKD;
if (bkrd == null)
{
bkrd = new BRKD();
bkrd.Identifier = (i + 1).ToString();
bkrd.MessageHeader = bkrdMessage;
bkrdMessage.Elements.Add(bkrd);
}
bkrd.BunkerFuelQuantity_TNE = reader.ReadNumber(lnQuantity);
bkrd.BunkerFuelType = reader.ReadText(lnType);
// dont save empty element
if(bkrd.IsNew && !bkrd.BunkerFuelQuantity_TNE.HasValue && bkrd.BunkerFuelType.IsNullOrEmpty())
bkrdMessage.Elements.Remove(bkrd);
}
}
#endregion
#region LADG
static void ScanLADG(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message ladgMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.LADG);
for (int i = 0; i < ladgMessage.NumberOfExcelRows; i++)
{
string lnCHT = string.Format("LADG.CargoHandlingType_{0}", i + 1);
string lnType = string.Format("LADG.CargoType_{0}", i + 1);
string lnCNOI = string.Format("LADG.CargoNumberOfItems_{0}", i + 1);
string lnCGQ = string.Format("LADG.CargoGrossQuantity_TNE_{0}", i + 1);
LADG ladg = ladgMessage.GetSublistElementWithIdentifier((i + 1).ToString()) as LADG;
if (ladg == null)
{
ladg = new LADG();
ladg.Identifier = (i + 1).ToString();
ladg.MessageHeader = ladgMessage;
ladgMessage.Elements.Add(ladg);
}
string handlingTypeString = reader.ReadText(lnCHT);
if (!handlingTypeString.IsNullOrEmpty())
{
// irgendwas mit "*load*" drin wird load, alles andere discharge
ladg.CargoHandlingType = handlingTypeString.Contains("load", StringComparison.InvariantCultureIgnoreCase) ? (byte) 0 : (byte) 1;
}
ladg.CargoCodeNST = reader.ReadText(lnType);
if (ladg.CargoCodeNST.Length != 2) ladg.CargoCodeNST = null; // stupid validation
ladg.CargoNumberOfItems = (int?) reader.ReadNumber(lnCNOI);
ladg.CargoGrossQuantity_TNE = reader.ReadNumber(lnCGQ);
// dont save empty element
if (ladg.IsNew && !ladg.CargoHandlingType.HasValue)
ladgMessage.Elements.Remove(ladg);
}
}
#endregion
private static void ScanMessage(DatabaseEntity dbEntity, ExcelReader reader)
{
Type objType = dbEntity.GetType();
List<PropertyInfo> props = new List<PropertyInfo>();
// add lookup properties to scan list
props.AddRange(objType.GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(LookupNameAttribute))));
foreach (PropertyInfo property in props)
{
object propValue = property.GetValue(dbEntity, null);
string value = (propValue == null) ? string.Empty : propValue.ToString();
LookupNameAttribute lookupNameAttribute = Attribute.GetCustomAttribute(property, typeof(LookupNameAttribute)) as LookupNameAttribute;
if (property.PropertyType == typeof(DateTime?))
{
DateTime? sheetValue = reader.ReadDate(lookupNameAttribute.LookupName);
if (sheetValue != null)
property.SetValue(dbEntity, sheetValue);
}
else if (property.PropertyType == typeof(double?))
{
double? sheetValue = reader.ReadNumber(lookupNameAttribute.LookupName);
if (sheetValue != null)
property.SetValue(dbEntity, sheetValue);
}
else if (property.PropertyType == typeof(string))
{
string sheetValue = reader.ReadText(lookupNameAttribute.LookupName);
if (sheetValue != null)
property.SetValue(dbEntity, sheetValue);
} else {
}
}
}
/// <summary>
/// Check with cell values if this message core is already in our DB
/// </summary>
private static MessageCore LookupMessageCore(ExcelReader reader)
private static MessageCore LookupMessageCore(ExcelReader reader, out string message)
{
// lookup using field values
double imoDouble = (double) reader.GetCell("SHIP", 13, 6);
string imo = Convert.ToInt32(imoDouble).ToString();
string etaDateString = reader.GetCell("Portcall", 16, 8).ToString();
string etaTime = reader.GetCell("Portcall", 16, 10).ToString();
DateTime dt = Util.ConstructDate(etaDateString, etaTime);
string poc = reader.GetCell("Portcall", 16, 1) as string;
MessageCore result = null;
DateTime? eta = null;
string poc = null;
string imo = null;
message = string.Empty;
bool isTransit = false;
if (DBManager.Instance.GetMessageCoreByShipInfos(imo, dt, poc) == null)
// first check with visit/transit ID
string visitTransitId = reader.ReadText("ID");
if (visitTransitId != null)
{
if (bsmd.database.Util.IsVisitId(visitTransitId))
{
result = DBManager.Instance.GetMessageCoreByVisitId(visitTransitId);
}
else if (bsmd.database.Util.IsTransitId(visitTransitId))
{
result = DBManager.Instance.GetMessageCoreByTransitId(visitTransitId);
}
}
else
{
// lookup poc, imo, eta
poc = reader.ReadText("Visit.PortOfCall");
// Prüfen auf Transit
if (poc.ToUpper().Contains("CANAL"))
{
poc = "ZZNOK";
isTransit = true;
}
else
{
// Im Sheet könnte der Name statt des LOCODES stehen!
if (!RuleEngine.IsGermanLocode(poc))
{
// somehow lookup LOCODE from the port's name!
poc = LocodeDB.LocodeGERFromCity(poc);
}
}
imo = reader.ReadText("Visit.IMONumber");
// ETA
DateTime? etaDate = reader.ReadDate("NOA_NOD.ETADateToPortOfCall");
DateTime? etaTime = reader.ReadTime("NOA_NOD.ETATimeToPortOfCall");
if (etaDate != null)
{
eta = new DateTime(etaDate.Value.Year, etaDate.Value.Month, etaDate.Value.Day);
if (etaTime != null)
{
eta = new DateTime(etaDate.Value.Year, etaDate.Value.Month, etaDate.Value.Day, etaTime.Value.Hour, etaTime.Value.Minute, etaTime.Value.Second);
}
}
result = DBManager.Instance.GetMessageCoreByShipInfos(imo, eta.Value, poc);
if (result.IsNew)
result.IsTransit = isTransit;
}
if (result == null)
{
if (imo == null)
{
message = "IMO number missing or not found";
return null;
}
if(poc == null)
{
message = string.Format("Port of call missing or not found for IMO {0}", imo);
return null;
}
if(eta == null)
{
message = string.Format("ETA missing or not found for IMO {0}", imo);
return null;
}
result = new MessageCore();
result.IMO = imo;
result.ReportStatus = MessageCore.ReportStatusEnum.COMPLETE;
result.Portname = poc;
result.ETA = dt;
result.ETA = eta;
if (result.IMO.Length > 7)
{
_log.WarnFormat("IMO {0} is longer than 7 chars, truncating!", result.IMO);
@ -66,7 +513,6 @@ namespace bsmd.ExcelReadService
DBManager.Instance.Save(result);
}
return result;
}
@ -82,5 +528,18 @@ namespace bsmd.ExcelReadService
return result;
}
private static Message GetMessageWithType(List<Message> messages, MessageCore core, Message.NotificationClass type)
{
foreach(Message message in messages)
if (message.MessageNotificationClass == type) return message;
Message newMessage = new Message();
newMessage.MessageNotificationClass = type;
messages.Add(newMessage);
newMessage.MessageCore = core;
return newMessage;
}
}
}

View File

@ -32,18 +32,18 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Excel">
<HintPath>..\packages\ExcelDataReader.2.1.2.3\lib\net45\Excel.dll</HintPath>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib">
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="log4net">
<HintPath>..\packages\log4net.2.0.3\lib\net40-full\log4net.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Office.Interop.Excel, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c, processorArchitecture=MSIL">
<EmbedInteropTypes>True</EmbedInteropTypes>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Core" />
<Reference Include="System.Data.SQLite">
<HintPath>..\packages\System.Data.SQLite.Core.1.0.99.0\lib\net45\System.Data.SQLite.dll</HintPath>
</Reference>
<Reference Include="System.Management" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
@ -69,6 +69,7 @@
<Compile Include="ExcelReadService.Designer.cs">
<DependentUpon>ExcelReadService.cs</DependentUpon>
</Compile>
<Compile Include="LocodeDB.cs" />
<Compile Include="Program.cs" />
<Compile Include="ProjectInstaller.cs">
<SubType>Component</SubType>
@ -85,6 +86,10 @@
<Compile Include="Util.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\misc\db.sqlite">
<Link>db.sqlite</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="App.config" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
@ -114,6 +119,7 @@
<WCFMetadata Include="Service References\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\System.Data.SQLite.Core.1.0.99.0\build\net45\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.99.0\build\net45\System.Data.SQLite.Core.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ExcelDataReader" version="2.1.2.3" targetFramework="net45" />
<package id="log4net" version="2.0.3" targetFramework="net45" />
<package id="OpenPop.NET" version="2.0.6.1112" targetFramework="net45" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net45" />
<package id="System.Data.SQLite.Core" version="1.0.99.0" targetFramework="net45" />
</packages>

View File

@ -296,7 +296,8 @@ namespace bsmd.dakosy
vList.Visit[0].MDH = new MDH();
vList.Visit[0].MDH.MdhSimplificationSpecified = mdh.MDHSimplification.HasValue;
vList.Visit[0].MDH.MdhSimplification = mdh.MDHSimplification ?? false;
vList.Visit[0].MDH.PortOfCallWhereCompleteMDHNotified = mdh.PortOfCallWhereCompleteMDHNotified;
if(mdh.MDHSimplification ?? false)
vList.Visit[0].MDH.PortOfCallWhereCompleteMDHNotified = mdh.PortOfCallWhereCompleteMDHNotified;
vList.Visit[0].MDH.NonAccidentialDeathsDuringVoyageSpecified = mdh.NonAccidentalDeathsDuringVoyage.HasValue;
vList.Visit[0].MDH.NonAccidentialDeathsDuringVoyage = mdh.NonAccidentalDeathsDuringVoyage ?? false;
vList.Visit[0].MDH.NonAccidentialDeathsDuringVoyageCountSpecified = mdh.NonAccidentalDeathsDuringVoyageCount.HasValue;
@ -315,11 +316,14 @@ namespace bsmd.dakosy
vList.Visit[0].MDH.AwareOfConditionsForFurtherInfections = mdh.AwareOfFurtherInfections ?? false;
vList.Visit[0].MDH.SanitaryMeasuresAppliedSpecified = mdh.SanitaryMeasuresApplied.HasValue;
vList.Visit[0].MDH.SanitaryMeasuresApplied = mdh.SanitaryMeasuresApplied ?? false;
vList.Visit[0].MDH.SanitaryMeasuresDetails = new SanitaryMeasuresDetails();
vList.Visit[0].MDH.SanitaryMeasuresDetails.SanitaryMeasuresType = mdh.SanitaryMeasuresType;
vList.Visit[0].MDH.SanitaryMeasuresDetails.SanitaryMeasuresLocation = mdh.SanitaryMeasuresLocation;
if (mdh.SanitaryMeasuresDate.HasValue)
vList.Visit[0].MDH.SanitaryMeasuresDetails.SanitaryMeasuresDate = mdh.SanitaryMeasuresDate.Value;
if (mdh.SanitaryMeasuresApplied ?? false)
{
vList.Visit[0].MDH.SanitaryMeasuresDetails = new SanitaryMeasuresDetails();
vList.Visit[0].MDH.SanitaryMeasuresDetails.SanitaryMeasuresType = mdh.SanitaryMeasuresType;
vList.Visit[0].MDH.SanitaryMeasuresDetails.SanitaryMeasuresLocation = mdh.SanitaryMeasuresLocation;
if (mdh.SanitaryMeasuresDate.HasValue)
vList.Visit[0].MDH.SanitaryMeasuresDetails.SanitaryMeasuresDate = mdh.SanitaryMeasuresDate.Value;
}
vList.Visit[0].MDH.StowawaysDetectedSpecified = mdh.StowawaysDetected.HasValue;
vList.Visit[0].MDH.StowawaysDetected = mdh.StowawaysDetected ?? false;
vList.Visit[0].MDH.StowawaysJoiningLocation = mdh.StowawaysJoiningLocation;
@ -335,10 +339,13 @@ namespace bsmd.dakosy
vList.Visit[0].MDH.SanitaryControlReinspectionRequired = mdh.SanitaryControlReinspectionRequired ?? false;
vList.Visit[0].MDH.InfectedAreaVisitedSpecified = mdh.InfectedAreaVisited.HasValue;
vList.Visit[0].MDH.InfectedAreaVisited = mdh.InfectedAreaVisited ?? false;
vList.Visit[0].MDH.InfectedArea = new InfectedArea();
if (mdh.InfectedAreaDate.HasValue)
vList.Visit[0].MDH.InfectedArea.InfectedAreaDate = mdh.InfectedAreaDate.Value;
vList.Visit[0].MDH.InfectedArea.InfectedAreaPort = mdh.InfectedAreaPort;
if (mdh.InfectedAreaVisited ?? false)
{
vList.Visit[0].MDH.InfectedArea = new InfectedArea();
if (mdh.InfectedAreaDate.HasValue)
vList.Visit[0].MDH.InfectedArea.InfectedAreaDate = mdh.InfectedAreaDate.Value;
vList.Visit[0].MDH.InfectedArea.InfectedAreaPort = mdh.InfectedAreaPort;
}
if (mdh.PortOfCallLast30Days.Count > 0)
{
vList.Visit[0].MDH.PortsOfCallLast30Days = new PortOfCallLast30Days[mdh.PortOfCallLast30Days.Count];
@ -459,7 +466,8 @@ namespace bsmd.dakosy
vList.Visit[0].SEC = new SEC();
vList.Visit[0].SEC.SecSimplificationSpecified = sec.SECSimplification.HasValue;
vList.Visit[0].SEC.SecSimplification = sec.SECSimplification ?? false;
vList.Visit[0].SEC.PortOfCallWhereCompleteSECNotified = sec.PortOfCallWhereCompleteSECNotified;
if(sec.SECSimplification ?? false)
vList.Visit[0].SEC.PortOfCallWhereCompleteSECNotified = sec.PortOfCallWhereCompleteSECNotified;
vList.Visit[0].SEC.CsoLastName = sec.CSOLastName;
vList.Visit[0].SEC.CsoFirstName = sec.CSOFirstName;
vList.Visit[0].SEC.CsoPhone = sec.CSOPhone;

View File

@ -9,6 +9,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
@ -84,6 +85,12 @@ namespace bsmd.dakosy
MessageCore core = DBManager.Instance.GetMessageCoreById(localReferenceId);
DatabaseEntity dbEntity = DBManager.Instance.GetMessageById(messageReferenceId);
if (dbEntity == null)
{
_log.WarnFormat("Message not found for reference Id {0}", messageReferenceId);
continue;
}
// Objekte aktualisieren und speichern
Message aMessage = null;
@ -163,6 +170,15 @@ namespace bsmd.dakosy
catch (Exception ex)
{
_log.ErrorFormat("error parsing response:{0}", ex.ToString());
/*
* Zum Debuggen. Das funktioniert nur, wenn die PDB's mitkopiert werden
StackTrace st = new StackTrace(ex, true);
StackFrame sf = st.GetFrame(0);
string method = sf.GetMethod().Name;
int line = sf.GetFileLineNumber();
int col = sf.GetFileColumnNumber();
_log.ErrorFormat("Method {0} Line {1} Col{2}", method, line, col);
*/
retval = false;
}

View File

@ -26,6 +26,7 @@ namespace bsmd.database
[ShowReport]
[Validation(ValidationCode.TIME_IMPLAUSIBLE)]
[LookupName("ATA.ATAPortOfCall")]
public DateTime? ATAPortOfCall { get; set; }
#endregion

View File

@ -26,6 +26,7 @@ namespace bsmd.database
[ShowReport]
[Validation(ValidationCode.TIME_IMPLAUSIBLE)]
[LookupName("ATD.ATDPortOfCall")]
public DateTime? ATDPortOfCall { get; set; }
#endregion

View File

@ -105,6 +105,11 @@ namespace bsmd.database
return null;
}
public int NumberOfExcelRows
{
get { return 1; }
}
#endregion
#region IMessageParagraph implementation

View File

@ -227,6 +227,66 @@ namespace bsmd.database
return result;
}
public MessageCore GetMessageCoreByVisitId(string visitId)
{
MessageCore aCore = new MessageCore();
SqlCommand cmd = new SqlCommand();
Message.LoadFilter filter = Message.LoadFilter.BY_VISITID;
aCore.PrepareLoadCommand(cmd, filter, visitId);
SqlDataReader reader = this.PerformCommand(cmd);
List<DatabaseEntity> cores = aCore.LoadList(reader);
MessageCore result = null;
if (cores.Count > 0)
{
if (cores.Count > 1) _log.WarnFormat("more than one core in DB for VISIT ID {0}", visitId);
result = cores[0] as MessageCore;
if (result.CustomerId.HasValue)
{
Customer c = new Customer();
SqlCommand cCmd = new SqlCommand();
c.PrepareLoadCommand(cCmd, Message.LoadFilter.BY_ID, result.CustomerId.Value);
reader = this.PerformCommand(cCmd);
List<DatabaseEntity> customers = c.LoadList(reader);
if (customers.Count > 0)
result.Customer = customers[0] as Customer;
}
}
return result;
}
public MessageCore GetMessageCoreByTransitId(string transitId)
{
MessageCore aCore = new MessageCore();
SqlCommand cmd = new SqlCommand();
Message.LoadFilter filter = Message.LoadFilter.BY_TRANSITID;
aCore.PrepareLoadCommand(cmd, filter, transitId);
SqlDataReader reader = this.PerformCommand(cmd);
List<DatabaseEntity> cores = aCore.LoadList(reader);
MessageCore result = null;
if (cores.Count > 0)
{
if (cores.Count > 1) _log.WarnFormat("more than one core in DB for TRANSIT ID {0}", transitId);
result = cores[0] as MessageCore;
if (result.CustomerId.HasValue)
{
Customer c = new Customer();
SqlCommand cCmd = new SqlCommand();
c.PrepareLoadCommand(cCmd, Message.LoadFilter.BY_ID, result.CustomerId.Value);
reader = this.PerformCommand(cCmd);
List<DatabaseEntity> customers = c.LoadList(reader);
if (customers.Count > 0)
result.Customer = customers[0] as Customer;
}
}
return result;
}
public MessageCore GetMessageCoreByShipInfos(string imo, DateTime eta, string poc)
{
MessageCore aCore = new MessageCore();

View File

@ -204,6 +204,8 @@ namespace bsmd.database
return null;
}
public int NumberOfExcelRows { get { return 0; } }
public IGCPosition GetIGCPositionWithIdentifier(string identifier)
{
foreach (IGCPosition igcPosition in this.IGCPositions)

View File

@ -7,11 +7,22 @@ using System.Threading.Tasks;
namespace bsmd.database
{
/// <summary>
/// Dieses Interface wird von DatabaseEntities implementiert, die 1:n Sublisten haben
/// Dieses Interface wird von DatabaseEntities implementiert, die 1:n Sublisten haben, m
/// mit anderen Worten, alles, was n-fach vorkommen kann
/// </summary>
public interface ISublistContainer
{
ISublistElement GetSublistElementWithIdentifier(string identifier);
/// <summary>
/// Liefert die maximale Anzahl an Excelzeilen, die für das n-fache Element eingelesen werden
/// sollen. TODO: Das könnte ggf auch an Bord geändert werden?, wird aber i.d.R. über die Names-Konvention
/// definiert. d.h. wenn keine passenden Name-Ranges angegeben sind wird das ohnehin nicht eingelesen werden
/// können
/// </summary>
int NumberOfExcelRows { get; }
}
/// <summary>

View File

@ -0,0 +1,45 @@
//
// Class: LookupNameAttribute
// Current CLR: 4.0.30319.42000
// System: Microsoft Visual Studio 10.0
// Author: dani
// Created: 1/9/2016 9:34:19 AM
//
// Copyright (c) 2016 Informatikbüro Daniel Schick. All rights reserved.
using System;
using System.Collections.Generic;
namespace bsmd.database
{
/// <summary>
/// Marker, der den Lookup-String (NAME) beim Einlesen aus Excel liefert
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class LookupNameAttribute : Attribute
{
private string _lookupName;
public LookupNameAttribute(string lookupName)
{
_lookupName = lookupName;
}
public string LookupName
{
get { return this._lookupName; }
set { this._lookupName = value; }
}
}
/// <summary>
/// Dieser Marker zeigt an, dass das Property aus mehreren Excel-Feldern (Date + Time)
/// zusammengesetzt wird
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class SpecialLookupAttribute : Attribute
{
public SpecialLookupAttribute() { }
}
}

View File

@ -217,7 +217,7 @@ namespace bsmd.database
#endregion
#region ISublistElement implementation
#region ISublistContainer implementation
public ISublistElement GetSublistElementWithIdentifier(string identifier)
{
@ -228,6 +228,11 @@ namespace bsmd.database
return null;
}
public int NumberOfExcelRows
{
get { return 15; }
}
#endregion
#region IMessageParagraph implementation

View File

@ -123,7 +123,9 @@ namespace bsmd.database
HAZ_ID,
IMDG_ID,
REPORTSTATUS,
IMO_ETA_POC
IMO_ETA_POC,
BY_VISITID,
BY_TRANSITID
}
/// <summary>
@ -408,6 +410,22 @@ namespace bsmd.database
return null;
}
public int NumberOfExcelRows
{
get
{
switch (this.MessageNotificationClass)
{
case NotificationClass.BKRA: return 5;
case NotificationClass.BKRD: return 5;
case NotificationClass.LADG: return 5;
default:
return 0;
}
}
}
#endregion
#region IMessageParagraph implementation

View File

@ -221,6 +221,18 @@ namespace bsmd.database
((SqlCommand)cmd).Parameters.AddWithValue("@POC", criteria[2]);
break;
}
case Message.LoadFilter.BY_VISITID:
{
query += "WHERE VisitId = @VISITID";
((SqlCommand)cmd).Parameters.AddWithValue("@VISITID", criteria[0]);
break;
}
case Message.LoadFilter.BY_TRANSITID:
{
query += "WHERE TransitId = @TRANSITID";
((SqlCommand)cmd).Parameters.AddWithValue("@TRANSITID", criteria[0]);
break;
}
case Message.LoadFilter.ALL:
default:
break;

View File

@ -26,6 +26,7 @@ namespace bsmd.database
[ShowReport]
[Validation(ValidationCode.NOT_NULL)]
[LookupName("NAME.NameOfMaster")]
public string NameOfMaster { get; set; }
#endregion

View File

@ -140,6 +140,11 @@ namespace bsmd.database
return null;
}
public int NumberOfExcelRows
{
get { return 1; }
}
#endregion
#region IMessageParagraph implementation

View File

@ -111,7 +111,7 @@ namespace bsmd.database
#endregion
#region ISublistElement implementation
#region ISublistContainer implementation
public ISublistElement GetSublistElementWithIdentifier(string identifier)
{
@ -121,6 +121,11 @@ namespace bsmd.database
return null;
}
public int NumberOfExcelRows
{
get { return 1; }
}
#endregion
#region IMessageParagraph implementation

View File

@ -329,6 +329,11 @@ namespace bsmd.database
}
public static bool IsGermanLocode(string val)
{
return (gerLocodeList.Contains(val.ToUpper()));
}
#endregion
#region private helper

View File

@ -26,34 +26,42 @@ namespace bsmd.database
[ShowReport]
[Validation(ValidationCode.NOT_NULL)]
[LookupName("STAT.ShipName")]
public string ShipName { get; set; }
[ShowReport]
[Validation(ValidationCode.NOT_NULL)]
[LookupName("STAT.CallSign")]
public string CallSign { get; set; }
[ShowReport]
[Validation(ValidationCode.NOT_NULL)]
[LookupName("STAT.MMSINumber")]
public string MMSINumber { get; set; }
[ShowReport]
[Validation(ValidationCode.FLAG_CODE)]
[LookupName("STAT.Flag")]
public string Flag { get; set; }
[ShowReport]
[Validation(ValidationCode.DOUBLE_GT_ZERO)]
[LookupName("STAT.LengthOverall_MTR")]
public double? LengthOverall_MTR { get; set; }
[ShowReport]
[Validation(ValidationCode.DOUBLE_GT_ZERO)]
[LookupName("STAT.Beam_MTR")]
public double? Beam_MTR { get; set; }
[ShowReport]
[Validation(ValidationCode.DOUBLE_GT_ZERO)]
[LookupName("STAT.GrossTonnage")]
public int? GrossTonnage { get; set; }
[ShowReport]
[Validation(ValidationCode.LOCODE)]
[LookupName("STAT.PortOfRegistry")]
public string PortOfRegistry { get; set; }
[ShowReport]
@ -61,13 +69,16 @@ namespace bsmd.database
[ShowReport]
[Validation(ValidationCode.NOT_NULL)]
[LookupName("STAT.ShipType")]
public string ShipType { get; set; }
[ShowReport]
[LookupName("STAT.ISMCompanyName")]
public string ISMCompanyName { get; set; }
[ShowReport]
[Validation(ValidationCode.STRING_EXACT_LEN, 7)]
[LookupName("STAT.ISMCompanyId")]
public string ISMCompanyId { get; set; }
[ShowReport]

View File

@ -25,6 +25,7 @@ namespace bsmd.database
#region Properties
[ShowReport]
[Validation(ValidationCode.DRAUGHT_IMPLAUSIBLE)]
[LookupName("TIEFA.DraughtUponArrival_DMT")]
public double? DraughtUponArrival_DMT { get; set; }
public override string Subtitle

View File

@ -25,6 +25,7 @@ namespace bsmd.database
#region Properties
[ShowReport]
[Validation(ValidationCode.DRAUGHT_IMPLAUSIBLE)]
[LookupName("TIEFA.DraughtUponDeparture_DMT")]
public double? DraughtUponDeparture_DMT { get; set; }
public override string Subtitle

View File

@ -10,11 +10,15 @@
using System;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace bsmd.database
{
public static class Util
{
private static Regex regexVisit = new Regex("(DE)([A-Z]{3})-([0-9]{4})-([A-Z]{6})", RegexOptions.IgnoreCase);
private static Regex regexTransit = new Regex("(ZZNOK)-([0-9]{4})-([A-Z]{6})", RegexOptions.IgnoreCase);
/// <summary>
/// Extension helper to add values that can be null:
/// http://stackoverflow.com/questions/13451085/exception-when-addwithvalue-parameter-is-null
@ -100,5 +104,17 @@ namespace bsmd.database
}
}
public static bool IsVisitId(string val)
{
if (val.IsNullOrEmpty()) return false;
return regexVisit.IsMatch(val);
}
public static bool IsTransitId(string val)
{
if (val.IsNullOrEmpty()) return false;
return regexTransit.IsMatch(val);
}
}
}

View File

@ -133,6 +133,11 @@ namespace bsmd.database
return null;
}
public int NumberOfExcelRows
{
get { return 9; }
}
#endregion
#region IMessageParagraph implementation

View File

@ -65,6 +65,7 @@
<Compile Include="IMSBCPosition.cs" />
<Compile Include="ISublistContainer.cs" />
<Compile Include="LastTenPortFacilitiesCalled.cs" />
<Compile Include="LookupNameAttribute.cs" />
<Compile Include="MARPOL_Annex_I_Position.cs" />
<Compile Include="Properties\AssemblyProductInfo.cs" />
<Compile Include="Properties\AssemblyProjectInfo.cs" />

BIN
nsw/Source/misc/db.sqlite Normal file

Binary file not shown.