// // Class: ExcelReader // Current CLR: 4.0.30319.34209 // System: Microsoft Visual Studio 10.0 // Author: dani // Created: 6/15/2015 10:03:40 PM // // Copyright (c) 2015 Informatikbüro Daniel Schick. All rights reserved. using log4net; using Microsoft.Office.Interop.Excel; using System; using System.Collections.Generic; using System.Data; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using bsmd.database; namespace bsmd.ExcelReadService { internal class ExcelReader : ExcelBase { internal enum ReadState { NONE, OK, WARN, FAIL }; internal Dictionary ImportValues { get; } = new Dictionary(); public ExcelReader(string filePath) { _log = LogManager.GetLogger(typeof(ExcelReader)); this._excelApp = new Application(); this._excelApp.DisplayAlerts = false; this._excelWorkbooks = _excelApp.Workbooks; this._portcall = _excelWorkbooks.Open(filePath, 0, true, 5, "", "", false, XlPlatform.xlWindows, "", false, false, 0, false, false, false); _nameDict = new Dictionary(); int bookCnt = 0; foreach(Name name in _portcall.Names) { string theValue = name.Value; // Namensbezug: =SheetZelle. Leere Referenzen überspringen (kommt immer mal wieder vor!) string nameKey = name.Name; try { if (nameKey.Contains("!")) nameKey = nameKey.Substring(nameKey.IndexOf('!') + 1); } catch(Exception) { _log.DebugFormat("Strange name in Sheet: {0}", nameKey); continue; } if ((theValue != "=#REF!#REF!") && (theValue != "=#BEZUG!#BEZUG!")) { _nameDict[nameKey] = name; bookCnt++; } } _log.DebugFormat("{0} named ranges found at Workbook level", bookCnt); foreach(Worksheet ws in _portcall.Worksheets) { int wsCnt = 0; foreach(Name name in ws.Names) { string theValue = name.Value; // Namensbezug: =SheetZelle. Leere Referenzen überspringen (kommt immer mal wieder vor!) if (!_nameDict.ContainsKey(name.Name)) { if ((theValue != "=#REF!#REF!") && (theValue != "=#BEZUG!#BEZUG!")) { _nameDict[name.Name] = name; wsCnt++; } } } if (wsCnt > 0) _log.DebugFormat("{0} named ranges found in Worksheet {1}", wsCnt, ws.Name); } } internal Confirmation Conf { get; set; } internal void SetConfirmation(System.Collections.Specialized.StringCollection templatePaths) { if (templatePaths == Properties.Settings.Default.ConfirmationDE) _countryMode = CountryMode.DE; if (templatePaths == Properties.Settings.Default.ConfirmationDK) _countryMode = CountryMode.DK; this.Conf = new Confirmation(templatePaths, _excelApp); } internal List SaveConfirmationSheets(string attachmentLocalPath) { return this.Conf.SaveConfirmationSheets(attachmentLocalPath); } internal string ReadText(string lookup) { string result = null; if (_nameDict.ContainsKey(lookup)) { try { var val = _nameDict[lookup].RefersToRange.Value; var val2 = _nameDict[lookup].RefersToRange.Value2; if (val != null) result = val.ToString().Trim(); else if (val2 != null) result = val2.ToString().Trim(); } catch (COMException ex) { _log.WarnFormat("COMException reading field {0}: {1}", lookup, ex.ErrorCode); } } if (result != null) { result = result.Trim(); this.ImportValues[lookup] = result; } return result; } internal string ReadTextNoWhitespace(string lookup) { string val = this.ReadText(lookup); if (val == null) return val; return new string(val.Where(c => !Char.IsWhiteSpace(c)).ToArray()); } internal string ReadLoCode(string lookup) { string val = this.ReadText(lookup); if(!val.IsNullOrEmpty()) { val = val.ToUpper(); string portName = LocodeDB.PortNameFromLocode(val); if(portName == null) { this.Conf.ConfirmText(lookup, val, ReadState.WARN); } else { this.Conf.ConfirmText(lookup, val, ReadState.OK); } } else { this.Conf.ConfirmText(lookup, null, ReadState.FAIL); } return val; } internal int? ReadCargoLACode(string lookup) { string val = ReadText(lookup); if (val.IsNullOrEmpty()) return null; if(int.TryParse(val, out int result)) { if ((result >= 10) && (result <= 99)) this.Conf.ConfirmText(lookup, val, ReadState.OK); else this.Conf.ConfirmText(lookup, val, ReadState.WARN); return result; } else { this.Conf.ConfirmText(lookup, val, ReadState.FAIL); return null; } } internal byte? ReadGender(string lookup) { byte? result = null; string val = this.ReadText(lookup); if (val != null) { if (val.Equals("m", StringComparison.CurrentCultureIgnoreCase) || val.Equals("male", StringComparison.CurrentCultureIgnoreCase)) { this.Conf.ConfirmText(lookup, val, ReadState.OK); result = 0; } else if (val.Equals("f", StringComparison.CurrentCultureIgnoreCase) || val.Equals("female", StringComparison.CurrentCultureIgnoreCase)) { this.Conf.ConfirmText(lookup, val, ReadState.OK); result = 1; } else { result = 2; this.Conf.ConfirmText(lookup, val, ReadState.WARN); } } if(result == null) { this.Conf.ConfirmText(lookup, null, ReadState.FAIL); } return result; } internal byte? ReadIdentityDocumentType(string lookup) { byte? result = null; string val = this.ReadText(lookup); if (val != null) { if (val.Equals("identity_card", StringComparison.CurrentCultureIgnoreCase) || val.Equals("1")) result = 0; if (val.Equals("passport", StringComparison.CurrentCultureIgnoreCase) || val.Equals("2")) result = 1; if (val.Equals("muster_book", StringComparison.CurrentCultureIgnoreCase) || val.Equals("3")) result = 2; if (val.Equals("picture_id", StringComparison.CurrentCultureIgnoreCase) || val.Equals("4")) result = 3; if (val.Equals("residental_permit", StringComparison.CurrentCultureIgnoreCase) || val.Equals("5")) result = 4; if (val.Equals("other_legal_identity_document", StringComparison.CurrentCultureIgnoreCase) || val.Equals("6")) result = 5; if (val.Equals("ic", StringComparison.CurrentCultureIgnoreCase)) result = 0; if (result == null) this.Conf.ConfirmText(lookup, val, ReadState.WARN); else this.Conf.ConfirmText(lookup, val, ReadState.OK); } else { this.Conf.ConfirmText(lookup, null, ReadState.FAIL); } return result; } internal byte? ReadShippingArea(string lookup) { string val = this.ReadText(lookup); byte? result = null; if (val != null) { if ((val.IndexOf("baltic", StringComparison.OrdinalIgnoreCase) >= 0) || (val.Equals("1"))) result = 0; if ((val.IndexOf("europe", StringComparison.OrdinalIgnoreCase) >= 0) || (val.Equals("2"))) result = 1; if ((val.IndexOf("overseas", StringComparison.OrdinalIgnoreCase) >= 0) || (val.Equals("3"))) result = 2; if (result == null) this.Conf.ConfirmText(lookup, val, ReadState.WARN); else this.Conf.ConfirmText(lookup, val, ReadState.OK); } else { this.Conf.ConfirmText(lookup, null, ReadState.FAIL); } return result; } internal byte? ReadGeneralDescriptionOfCargo(string lookup) { string val = this.ReadText(lookup); byte? result = null; if(val != null) { if (val.Contains("container", StringComparison.OrdinalIgnoreCase) || val.Equals("1")) result = 0; if (val.Contains("vehicles", StringComparison.OrdinalIgnoreCase) || val.Equals("2")) result = 1; if (val.Contains("convent", StringComparison.OrdinalIgnoreCase) || val.Equals("3")) result = 2; if (val.Contains("dry", StringComparison.OrdinalIgnoreCase) || val.Equals("4")) result = 3; if (val.Contains("liquid", StringComparison.OrdinalIgnoreCase) || val.Equals("5")) result = 4; if (val.Contains("empty", StringComparison.OrdinalIgnoreCase) || val.Equals("6")) result = 5; if (result == null) this.Conf.ConfirmText(lookup, val, ReadState.WARN); else this.Conf.ConfirmText(lookup, val, ReadState.OK); } else { this.Conf.ConfirmText(lookup, null, ReadState.FAIL); } return result; } internal byte? ReadCargoHandlingType(string lookup) { string val = this.ReadText(lookup); byte? result = null; if(val != null) { if ((val.IndexOf("load", StringComparison.OrdinalIgnoreCase) >= 0) || val.Equals("1")) result = 0; if ((val.IndexOf("discharge", StringComparison.OrdinalIgnoreCase) >= 0) || val.Equals("2")) result = 1; if ((val.IndexOf("transit", StringComparison.OrdinalIgnoreCase) >= 0) || val.Equals("3")) result = 2; if (result == null) this.Conf.ConfirmText(lookup, val, ReadState.WARN); else this.Conf.ConfirmText(lookup, val, ReadState.OK); } return result; } /// /// read nationality field an returns 2 Char ISO code (optional lookup) and "confirms" /// the field /// internal string ReadNationality(string lookup) { string val = this.ReadText(lookup); if (val.IsNullOrEmpty()) { this.Conf.ConfirmText(lookup, null, ReadState.FAIL); } else { if (val.Length > 2) { string isoCode = LocodeDB.CountryCodeFromName(val); if (isoCode != null) { this.Conf.ConfirmText(lookup, val, ReadState.OK); val = isoCode; } else { this.Conf.ConfirmText(lookup, val, ReadState.WARN); } } if (val.Length == 2) { val = val.ToUpper(); this.Conf.ConfirmText(lookup, val, ReadState.OK); } } return val; } internal byte? ReadHullConfiguration(string lookup) { string val = this.ReadText(lookup); byte? result = null; if (val != null) { if (val.IndexOf("sbt", StringComparison.OrdinalIgnoreCase) >= 0) result = 1; if (val.IndexOf("single", StringComparison.OrdinalIgnoreCase) >= 0) result = 0; if (val.IndexOf("double", StringComparison.OrdinalIgnoreCase) >= 0) result = 2; if (result == null) this.Conf.ConfirmText(lookup, val, ReadState.WARN); else this.Conf.ConfirmText(lookup, val, ReadState.OK); } else { this.Conf.ConfirmText(lookup, null, ReadState.FAIL); } return result; } internal byte? ReadPackingGroup(string lookup) { string val = this.ReadText(lookup); byte? result = null; if(val!= null) { if (val == "I") result = 1; if (val == "II") result = 2; if (val == "III") result = 3; if (val.Equals("NONE", StringComparison.OrdinalIgnoreCase)) result = 0; this.Conf.ConfirmText(lookup, val, result.HasValue ? ReadState.OK : ReadState.FAIL); } return result; } internal string ReadShip2ShipActivityType(string lookup) { string val = this.ReadText(lookup); bool isValid = false; if(!val.IsNullOrEmpty()) { if (int.TryParse(val, out int typeVal)) { if ((typeVal >= 1) && (typeVal <= 23)) isValid = true; } } this.Conf.ConfirmText(lookup, val, isValid ? ReadState.OK : ReadState.FAIL); return val; } internal byte? ReadConditionTanks(string lookup) { string val = this.ReadText(lookup); byte? result = null; if (val != null) { if (val.IndexOf("full", StringComparison.OrdinalIgnoreCase) >= 0) result = 0; if (val.IndexOf("empty", StringComparison.OrdinalIgnoreCase) >= 0) result = 1; if (val.IndexOf("inerted", StringComparison.OrdinalIgnoreCase) >= 0) result = 2; if (result == null) this.Conf.ConfirmText(lookup, val, ReadState.WARN); else this.Conf.ConfirmText(lookup, val, ReadState.OK); } else { this.Conf.ConfirmText(lookup, null, ReadState.FAIL); } return result; } internal byte? ReadDelivery(string lookup) { string val = this.ReadText(lookup); byte? result = null; if (val != null) { if ((val.IndexOf("all", StringComparison.OrdinalIgnoreCase) >= 0) || val.Equals("1")) result = 0; if ((val.IndexOf("some", StringComparison.OrdinalIgnoreCase) >= 0) || val.Equals("2")) result = 1; if ((val.IndexOf("none", StringComparison.OrdinalIgnoreCase) >= 0) || val.Equals("3")) result = 2; if (result == null) this.Conf.ConfirmText(lookup, val, ReadState.WARN); else this.Conf.ConfirmText(lookup, val, ReadState.OK); } else { this.Conf.ConfirmText(lookup, val, ReadState.FAIL); } return result; } internal DateTime? ReadBirthDate(string lookup) { DateTime? result = this.ReadDate(lookup); // mark fail if date is in the future if(result.HasValue) { if (result.Value > DateTime.Now) this.Conf.ConfirmDate(lookup, result, ReadState.FAIL); } return result; } internal DateTime? ReadDate(string lookup, bool noHighlight = false) { try { DateTime? date = null; if (_nameDict.ContainsKey(lookup)) { var val = _nameDict[lookup].RefersToRange.Value; if (val is DateTime) { this.Conf.ConfirmDate(lookup, val, noHighlight ? ReadState.NONE : ReadState.OK); date = val; } else if (val is double) { try { date = DateTime.FromOADate(val); } catch (ArgumentException) { /* .. */ } if(date == null) { CultureInfo provider = CultureInfo.InvariantCulture; string dateString = val.ToString(); const string format = "yyyyMMdd"; if (DateTime.TryParseExact(dateString, format, provider, DateTimeStyles.None, out DateTime tmpDate)) date = tmpDate; } } if (date == null) { if (DateTime.TryParse(val, out DateTime tmpDate)) date = tmpDate; } // TODO: weitere varianten ausprobieren if (date != null) { if ((date.Value < new DateTime(1899, 1, 1)) || (date.Value > new DateTime(2030, 1, 1))) { date = null; this.Conf.ConfirmDate(lookup, date, noHighlight ? ReadState.NONE : ReadState.WARN); } else { this.Conf.ConfirmDate(lookup, date, noHighlight? ReadState.NONE : ReadState.OK); } } else { this.Conf.ConfirmDate(lookup, null, noHighlight ? ReadState.NONE : ReadState.FAIL); } } return date; } catch (Exception) { this.Conf.ConfirmDate(lookup, null, noHighlight ? ReadState.NONE : ReadState.FAIL); _log.WarnFormat("error parsing datetime for lookup {0}", lookup); return null; } } internal DateTime? ReadDateTime(string dateField, string timeField, bool noHighlight = false) { DateTime? result = null; DateTime? etaDate = this.ReadDate(dateField, noHighlight); DateTime? etaTime = this.ReadTime(timeField, noHighlight); if (etaDate != null) { result = new DateTime(etaDate.Value.Year, etaDate.Value.Month, etaDate.Value.Day); if (etaTime != null) { result = new DateTime(etaDate.Value.Year, etaDate.Value.Month, etaDate.Value.Day, etaTime.Value.Hour, etaTime.Value.Minute, etaTime.Value.Second, DateTimeKind.Local); } } if(result.HasValue) { // wir haben local time gelesen, wird jetzt in UTC konvertiert result = result.Value.ToUniversalTime(); } return result; } internal DateTime? ReadTime(string lookup, bool noHighlight = false) { DateTime? result = null; try { if (_nameDict.ContainsKey(lookup)) { var val = _nameDict[lookup].RefersToRange.Value; if (val is DateTime) { result = val; } if (val is double) { try { result = DateTime.FromOADate(val); } catch(ArgumentException) { } if (result == null) { CultureInfo provider = CultureInfo.InvariantCulture; string dateString = val.ToString(); if (!dateString.Contains(":")) { const string format = "HHmm"; if (DateTime.TryParseExact(dateString, format, provider, DateTimeStyles.None, out DateTime tmpDate)) result = tmpDate; } } } if (result == null) { if (DateTime.TryParseExact(val, "HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out DateTime date)) result = date; } if (result == null) { if (DateTime.TryParseExact(val, "HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out DateTime date)) result = date; } if ((result == null) && (val != null)) { CultureInfo provider = CultureInfo.InvariantCulture; string dateString = val.ToString(); if (!dateString.Contains(":")) { const string format = "HHmm"; if (DateTime.TryParseExact(dateString, format, provider, DateTimeStyles.None, out DateTime tmpDate)) result = tmpDate; } } if (result != null) { this.Conf.ConfirmTime(lookup, result, noHighlight ? ReadState.NONE : ReadState.OK); } else { this.Conf.ConfirmTime(lookup, result, noHighlight ? ReadState.NONE : ReadState.WARN); } } } catch (Exception) { this.Conf.ConfirmTime(lookup, null, noHighlight ? ReadState.NONE : ReadState.FAIL); _log.WarnFormat("error reading time for lookup {0}", lookup); } return result; } internal double? ReadNumber(string lookup) { double? result = null; try { if (_nameDict.ContainsKey(lookup)) { var val = _nameDict[lookup].RefersToRange.Value; if (val is double) result = val; if (val is string) { if (double.TryParse(val, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, CultureInfo.InvariantCulture, out double tmpDouble)) result = tmpDouble; if (result == null) { if (double.TryParse(val, out tmpDouble)) // current language style (==GER, mit , statt .) result = tmpDouble; } } if ((result == null) && (val != null)) { try { { double tmpDouble2 = val[1, 1]; result = tmpDouble2; } } catch (Exception) { // .. } } if (result != null) { this.Conf.ConfirmNumber(lookup, result, ReadState.OK); } else { this.Conf.ConfirmNumber(lookup, result, ReadState.FAIL); } } } catch (Exception) { this.Conf.ConfirmNumber(lookup, null, ReadState.FAIL); _log.WarnFormat("error reading number for lookup {0}", lookup); } return result; } internal double ReadNumberDefaultZero(string lookup) { double? result = this.ReadNumber(lookup); if(!result.HasValue) { result = 0; this.Conf.ConfirmNumber(lookup, 0, ReadState.WARN); } return result.Value; } internal bool? ReadBoolean(string lookup, bool noHighlight = false) { string val = this.ReadText(lookup); if (val == null) { this.Conf.ConfirmText(lookup, val, noHighlight ? ReadState.NONE : ReadState.FAIL); return null; } this.Conf.ConfirmText(lookup, val, ReadState.OK); if ((val == "y") || (val == "Y") || val.Equals("yes", StringComparison.OrdinalIgnoreCase) || (val == "1") || (val == "x") || (val == "X")) return true; return false; } } }