2025 lines
78 KiB
C#
2025 lines
78 KiB
C#
using System.Data;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
using Gremlin_BlazorServer.Data.EntityClasses;
|
|
using Gremlin_BlazorServer.Services;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.VisualBasic.FileIO;
|
|
using MySqlConnector;
|
|
using static Gremlin_BlazorServer.Data.EntityClasses.Enums;
|
|
|
|
namespace Gremlin_BlazorServer.Data.DBClasses;
|
|
|
|
internal static class DbHelper
|
|
{
|
|
private static readonly DateTime farInTheFuture = DateTime.Parse("2050-12-31t00:00:00.000000z", CultureInfo.CurrentCulture);
|
|
private static readonly ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = Environment.ProcessorCount * 4 };
|
|
private static readonly Random random = new();
|
|
|
|
public static bool CheckDatabaseConnection(string connectionString)
|
|
{
|
|
bool isConnected = false;
|
|
MySqlConnection mySqlConnection = new();
|
|
|
|
try
|
|
{
|
|
mySqlConnection = new(connectionString);
|
|
mySqlConnection.Open();
|
|
isConnected = true;
|
|
}
|
|
|
|
catch (ArgumentException aEx)
|
|
{
|
|
Console.WriteLine(aEx.Message);
|
|
}
|
|
|
|
catch (MySqlException ex)
|
|
{
|
|
Console.WriteLine($"Message: {ex.Message}\nSource: {ex.Source}\nNumber: {ex.Number}", "Connection Failed!");
|
|
|
|
isConnected = false;
|
|
|
|
switch (ex.Number)
|
|
{
|
|
case 1042: // Unable to connect to any of the specified MySQL hosts (Check Server,Port)
|
|
break;
|
|
case 0: // Access denied (Check DB name,username,password)
|
|
break;
|
|
}
|
|
}
|
|
|
|
finally
|
|
{
|
|
if (mySqlConnection.State == ConnectionState.Open)
|
|
{
|
|
mySqlConnection.Close();
|
|
}
|
|
}
|
|
|
|
return isConnected;
|
|
}
|
|
|
|
public static void DbBuilder()
|
|
{
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
_ = gremlinDb.Database.EnsureDeleted();
|
|
_ = gremlinDb.Database.EnsureCreated();
|
|
}
|
|
}
|
|
|
|
public static void DbInitializer()
|
|
{
|
|
//PRODUCT LINES
|
|
string[] productLineAbbreviations = {
|
|
"XF", "LM", "XA", "RB", "GE",
|
|
"9Z", "9P", "9M", "9K", "9H",
|
|
"9F", "9E", "9C", "ZZ", "ZF",
|
|
"V1", "MB", "MA", "LI", "JW",
|
|
"CA", "BZ", "BC", "AZ", "AJ",
|
|
"AB", "AA", "8P", "89", "74",
|
|
"6P", "6G", "58", "29", "AM",
|
|
"RP", "CD", "PT", "XB", "RM",
|
|
"GS", "AT", "SR", "FS", "BD",
|
|
"UF", "3P"
|
|
};
|
|
string[] productLineDescriptions = {
|
|
"Cell Analysis", "Lab Management", "Flow Cell", "Remarketed Instruments", " Genomics",
|
|
"Drugs of Abuse", "Sample Prep/Resins", "Research Products", "Dissolution & Other", "Vacuum Products",
|
|
"AA/OES", "Drugs of Abuse", "Micro GC", "Common PL & Default", "Expedite Freight",
|
|
"Automation", "Particle Analysis", "Molecular Spectroscopy", "Software and Informatics", "GC Columns",
|
|
"Mid Range GC", "GC-MS", "LC Columns", "Gas Phase Analysis", "ICPMS",
|
|
"Bio-consumables", "Instrument Supplies", "Analytical Parts Sup", "LC-MS", "Support Services",
|
|
"Software and Professinal Services", "Other Local Products", "Competitive Supplies", "LC", "Amplicon Sequencing",
|
|
"Reagent Partnership", "Companion Diagnostic", "Pathology", "Biotek", "Raman Spectroscopy",
|
|
"Genomics Systems", "Parallel CE Instrument", "Bio Reagents", "Flexible Spending", "Nucleic Acid",
|
|
"Microfluidics", "3rd Party Product"
|
|
};
|
|
|
|
int length = productLineAbbreviations.Length;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
ProductLine plToBeAdded = new()
|
|
{
|
|
ProductLineCode = productLineAbbreviations[i],
|
|
ProductLineDescription = productLineDescriptions[i],
|
|
DataStatus = Status.Active.ToString(),
|
|
DataModificationByUser = "DbInitializer"
|
|
};
|
|
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
|
|
_ = gremlinDb.ProductLines.Add(plToBeAdded);
|
|
|
|
_ = gremlinDb.SaveChanges();
|
|
}
|
|
}
|
|
|
|
//ACCOUNT TYPES
|
|
string[] accountTypes = {
|
|
"FPC", "FPR", "FPT", "FPV", "FPN",
|
|
"FPP", "FPG", "FPX", "FPS", "FPA",
|
|
"FPO", "FPW", "NPU", "NPR", "NPG",
|
|
"NPH", "SUP"
|
|
};
|
|
string[] accountTypeDescription = {
|
|
"Commercial", "Contract Manufacturing CRM & Contract Research CRO", "Contract Testing", "Instrument IDR Distributor", "Instrument National Distributor",
|
|
"Foreign Trade Org", "Genomics/CSD Distributor", "Regulated Distributor", "Transactional Reseller", "Value Added Reseller",
|
|
"OEM", "Occasional resellers", "University", "Research Institute", "Government",
|
|
"Hospital", "Supplier"
|
|
};
|
|
|
|
length = accountTypes.Length;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
AccountType aTtoBeAdded = new()
|
|
{
|
|
AccountTypeCode = accountTypes[i],
|
|
AccountTypeDescription = accountTypeDescription[i],
|
|
DataStatus = Status.Active.ToString()
|
|
};
|
|
_ = MetaDataSetter.ForImport(aTtoBeAdded, "DbInitializer", "DbInitializer");
|
|
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
|
|
_ = gremlinDb.AccountTypes.Add(aTtoBeAdded);
|
|
|
|
_ = gremlinDb.SaveChanges();
|
|
}
|
|
}
|
|
|
|
//SubMarkets
|
|
string[] subMarketCodes = {
|
|
"CCH", "CEN", "CFD", "CFR", "CMS",
|
|
"COT", "LPH", "LBT", "LGN", "LRS",
|
|
"DCT", "LOT", "VEN", "VAR", "SUP"
|
|
};
|
|
|
|
string[] subMarketDescriptions = {
|
|
"Chemical & Energy", "Environmental", "Food", "Forensics", "Material Science",
|
|
"CA Other", "Pharmaceutical", "BioPharma", "Generics", "LS Research",
|
|
"Clinical Testing", "LS Other", "Analytical Instrument Vendor", "VAR-Partner", "Supplier"
|
|
};
|
|
|
|
length = subMarketCodes.Length;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
SubMarket sMtoBeAdded = new()
|
|
{
|
|
SubMarketCode = subMarketCodes[i],
|
|
SubMarketDescription = subMarketDescriptions[i],
|
|
DataStatus = Status.Active.ToString()
|
|
};
|
|
_ = MetaDataSetter.ForImport(sMtoBeAdded, "DbInitializer", "DbInitializer");
|
|
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
|
|
_ = gremlinDb.SubMarkets.Add(sMtoBeAdded);
|
|
|
|
_ = gremlinDb.SaveChanges();
|
|
}
|
|
}
|
|
|
|
List<Account> seedAccounts = new();
|
|
Account agilent = new()
|
|
{
|
|
AccountName = "Agilent Technologies",
|
|
AccountId = 1,
|
|
Street = "Hewlett-Packard-Str. 8",
|
|
Zip = 76337,
|
|
City = "Waldbronn",
|
|
SapAccountNumber = 00000001,
|
|
EMail = "CustomerCare_Germany@agilent.com",
|
|
PhoneNumber = "+49 800 6031000",
|
|
DataStatus = Status.Active.ToString(),
|
|
AccountType = new()
|
|
{
|
|
AccountTypeCode = "SUP"
|
|
},
|
|
SubMarket = new()
|
|
{
|
|
SubMarketCode = "VEN"
|
|
}
|
|
};
|
|
seedAccounts.Add(agilent);
|
|
|
|
Account bios = new()
|
|
{
|
|
AccountName = "Bios Analytical Ltd.",
|
|
AccountId = 2,
|
|
Street = "7 South Fens Enterprise Park//Fenton Way//PE16 6WA Chatteris//Cambridgeshire//United Kingdom",
|
|
Zip = 0,
|
|
City = "Chatteris, UNITED KINGDOM",
|
|
SapAccountNumber = 00000002,
|
|
EMail = "",
|
|
PhoneNumber = "+44 1354 694377",
|
|
DataStatus = Status.Active.ToString(),
|
|
AccountType = new()
|
|
{
|
|
AccountTypeCode = "SUP"
|
|
},
|
|
SubMarket = new()
|
|
{
|
|
SubMarketCode = "VAR"
|
|
}
|
|
};
|
|
seedAccounts.Add(bios);
|
|
|
|
Account huber = new()
|
|
{
|
|
AccountName = "Huber Kältemaschinenbau AG",
|
|
AccountId = 3,
|
|
Street = "Werner-von-Siemens-Straße 1",
|
|
Zip = 77656,
|
|
City = "Offenburg",
|
|
SapAccountNumber = 00000003,
|
|
EMail = "sales@huber-online.com",
|
|
PhoneNumber = "0781 96030",
|
|
DataStatus = Status.Active.ToString(),
|
|
AccountType = new()
|
|
{
|
|
AccountTypeCode = "SUP"
|
|
},
|
|
SubMarket = new()
|
|
{
|
|
SubMarketCode = "SUP"
|
|
}
|
|
};
|
|
seedAccounts.Add(huber);
|
|
|
|
Account vanderheijden = new()
|
|
{
|
|
AccountName = "Van der Heijden Labortechnik GmbH",
|
|
AccountId = 4,
|
|
Street = "Tramsmeiers Berg 2",
|
|
Zip = 32694,
|
|
City = "Dörentrup",
|
|
SapAccountNumber = 00000004,
|
|
EMail = "info@vdh-online.com",
|
|
PhoneNumber = "05265 945520",
|
|
DataStatus = Status.Active.ToString(),
|
|
AccountType = new()
|
|
{
|
|
AccountTypeCode = "SUP"
|
|
},
|
|
SubMarket = new()
|
|
{
|
|
SubMarketCode = "SUP"
|
|
}
|
|
};
|
|
seedAccounts.Add(vanderheijden);
|
|
|
|
Account ole = new()
|
|
{
|
|
AccountName = "OLE DICH Instrumentmakers ApS",
|
|
AccountId = 5,
|
|
Street = "18, Taarnfalkevej",
|
|
Zip = 2650,
|
|
City = "Hvidovre, DENMARK",
|
|
SapAccountNumber = 00000005,
|
|
EMail = "",
|
|
PhoneNumber = "+45 36 78 41 85",
|
|
DataStatus = Status.Active.ToString(),
|
|
AccountType = new()
|
|
{
|
|
AccountTypeCode = "SUP"
|
|
},
|
|
SubMarket = new()
|
|
{
|
|
SubMarketCode = "SUP"
|
|
}
|
|
};
|
|
seedAccounts.Add(ole);
|
|
|
|
Account sprep = new()
|
|
{
|
|
AccountName = "S-prep GmbH",
|
|
AccountId = 6,
|
|
Street = "Im Amann 7",
|
|
Zip = 88662,
|
|
City = "Überlingen",
|
|
SapAccountNumber = 00000006,
|
|
EMail = "info@s-prep.com",
|
|
PhoneNumber = "07551 932696",
|
|
FaxNumber = "07551-932699",
|
|
DataStatus = Status.Active.ToString(),
|
|
AccountType = new()
|
|
{
|
|
AccountTypeCode = "SUP"
|
|
},
|
|
SubMarket = new()
|
|
{
|
|
SubMarketCode = "SUP"
|
|
}
|
|
};
|
|
seedAccounts.Add(sprep);
|
|
|
|
Account hellma = new()
|
|
{
|
|
AccountName = "Hellma GmbH & Co. KG",
|
|
AccountId = 7,
|
|
Street = "Klosterrunsstraße 5",
|
|
Zip = 79379,
|
|
City = "Müllheim",
|
|
SapAccountNumber = 00000007,
|
|
EMail = "info.de@hellma.com",
|
|
PhoneNumber = "07631 1820",
|
|
DataStatus = Status.Active.ToString(),
|
|
AccountType = new()
|
|
{
|
|
AccountTypeCode = "SUP"
|
|
},
|
|
SubMarket = new()
|
|
{
|
|
SubMarketCode = "SUP"
|
|
}
|
|
};
|
|
seedAccounts.Add(hellma);
|
|
|
|
Account glasside = new()
|
|
{
|
|
AccountName = "Glasside Technologies",
|
|
AccountId = 8,
|
|
Street = "Albany House, 82 Avenue Road//PE19 1LH St Neots, Cambridgeshire//United Kingdom",
|
|
Zip = 0,
|
|
City = "St Neots, Cambridgesgire, UNITED KINGDOM",
|
|
SapAccountNumber = 00000008,
|
|
EMail = "",
|
|
PhoneNumber = "-/-",
|
|
DataStatus = Status.Active.ToString(),
|
|
AccountType = new()
|
|
{
|
|
AccountTypeCode = "SUP"
|
|
},
|
|
SubMarket = new()
|
|
{
|
|
SubMarketCode = "SUP"
|
|
}
|
|
};
|
|
seedAccounts.Add(glasside);
|
|
|
|
Account pike = new()
|
|
{
|
|
AccountName = "PIKE Technologies Inc.",
|
|
AccountId = 9,
|
|
Street = "6125 Cottonwood Drive//Madison, WI 53719//USA",
|
|
Zip = 53719,
|
|
City = "Madison (WI), USA",
|
|
SapAccountNumber = 00000009,
|
|
EMail = "info@piketech.com",
|
|
PhoneNumber = "+1 608 274 2721",
|
|
FaxNumber = "+1 608 274 0103",
|
|
DataStatus = Status.Active.ToString(),
|
|
AccountType = new()
|
|
{
|
|
AccountTypeCode = "SUP"
|
|
},
|
|
SubMarket = new()
|
|
{
|
|
SubMarketCode = "SUP"
|
|
}
|
|
};
|
|
seedAccounts.Add(pike);
|
|
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
foreach (Account account in seedAccounts)
|
|
{
|
|
// AccountType und SubMarket aus DB laden, damit der Datensatz vom Context verfolgt wird und EF Core nicht versucht, diesen standardmäßig neu anzulegen.
|
|
|
|
|
|
account.AccountType = ResolveAccountType(gremlinDb, account.AccountType.AccountTypeCode);
|
|
|
|
|
|
|
|
|
|
account.SubMarket = ResolveSubmarket(gremlinDb, account.SubMarket.SubMarketCode);
|
|
|
|
|
|
_ = MetaDataSetter.ForImport(account, "DbInitializer", "Function DbHelper.DbInitializer");
|
|
}
|
|
|
|
|
|
gremlinDb.Accounts.AddRange(seedAccounts);
|
|
|
|
_ = gremlinDb.SaveChanges();
|
|
}
|
|
|
|
//RegisteredUser
|
|
List<RegisteredUser> seedRegisteredUser = new();
|
|
|
|
RegisteredUser userSascha = new()
|
|
{
|
|
UserName = "woitsche",
|
|
PasswordHash = "527646"
|
|
};
|
|
seedRegisteredUser.Add(userSascha);
|
|
|
|
RegisteredUser userSebastian = new()
|
|
{
|
|
UserName = "sewelsch",
|
|
PasswordHash = "123456"
|
|
};
|
|
seedRegisteredUser.Add(userSebastian);
|
|
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
foreach (RegisteredUser userSetting in seedRegisteredUser)
|
|
{
|
|
userSetting.DataCreationDate = DateTime.Now;
|
|
userSetting.DataModificationByUser = "DB Initializer";
|
|
userSetting.DataModificationDate = DateTime.Now;
|
|
}
|
|
|
|
|
|
gremlinDb.RegisteredUser.AddRange(seedRegisteredUser);
|
|
|
|
_ = gremlinDb.SaveChanges();
|
|
}
|
|
|
|
//RUSetting
|
|
List<RuSettings> seedRuSettings = new();
|
|
|
|
using (RuSettings saschaName = new())
|
|
{
|
|
saschaName.RegisteredUserId = 1;
|
|
saschaName.SettingKey = "userName";
|
|
saschaName.SettingValue = "Dr. Sascha Woitschetzki";
|
|
seedRuSettings.Add(saschaName);
|
|
}
|
|
|
|
using (RuSettings saschaPhone = new())
|
|
{
|
|
saschaPhone.RegisteredUserId = 1;
|
|
saschaPhone.SettingKey = "userPhone";
|
|
saschaPhone.SettingValue = "+49 208 74129134";
|
|
seedRuSettings.Add(saschaPhone);
|
|
}
|
|
|
|
using (RuSettings saschaMobile = new())
|
|
{
|
|
saschaMobile.RegisteredUserId = 1;
|
|
saschaMobile.SettingKey = "userMobile";
|
|
saschaMobile.SettingValue = "+49 176 22285334";
|
|
seedRuSettings.Add(saschaMobile);
|
|
}
|
|
|
|
using (RuSettings saschaMail = new())
|
|
{
|
|
saschaMail.RegisteredUserId = 1;
|
|
saschaMail.SettingKey = "userMail";
|
|
saschaMail.SettingValue = "sascha.woitschetzki@non.agilent.com";
|
|
seedRuSettings.Add(saschaMail);
|
|
}
|
|
|
|
using (RuSettings saschaTerritoryId = new())
|
|
{
|
|
saschaTerritoryId.RegisteredUserId = 1;
|
|
saschaTerritoryId.SettingKey = "userTerritoryID";
|
|
saschaTerritoryId.SettingValue = "83PE89";
|
|
seedRuSettings.Add(saschaTerritoryId);
|
|
}
|
|
|
|
using (RuSettings saschaTexRand = new())
|
|
{
|
|
saschaTexRand.RegisteredUserId = 1;
|
|
saschaTexRand.SettingKey = "texRand";
|
|
saschaTexRand.SettingValue = "2";
|
|
seedRuSettings.Add(saschaTexRand);
|
|
}
|
|
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
foreach (RuSettings userSetting in seedRuSettings)
|
|
{
|
|
userSetting.DataCreationDate = DateTime.Now;
|
|
userSetting.DataModificationByUser = "DB Initializer";
|
|
userSetting.DataModificationDate = DateTime.Now;
|
|
}
|
|
|
|
|
|
gremlinDb.RuSettings.AddRange(seedRuSettings);
|
|
|
|
_ = gremlinDb.SaveChanges();
|
|
}
|
|
}
|
|
|
|
public static void InsertTestDataIntoDb()
|
|
{
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
Random r = new();
|
|
|
|
Contact newContact = new()
|
|
{
|
|
AcademicTitle = RandomString(9),
|
|
FirstName = RandomString(5),
|
|
LastName = RandomString(20),
|
|
Gender = (byte)Gender.Male,
|
|
Department = RandomString(9)
|
|
};
|
|
_ = MetaDataSetter.ForImport(newContact, "Tester", "Seeding data for testing.");
|
|
|
|
Account newAccount = new()
|
|
{
|
|
AccountName = RandomString(20),
|
|
Street = RandomString(9),
|
|
Zip = Convert.ToUInt32(r.Next(11111, 99999)),
|
|
City = RandomString(9),
|
|
SapAccountNumber = Convert.ToUInt32(r.Next(1111111, 99999999)),
|
|
EMail = RandomString(9) + "@" + RandomString(9) + "." + RandomString(3),
|
|
PhoneNumber = "+49 " + r.Next()
|
|
};
|
|
_ = MetaDataSetter.ForImport(newAccount, "Tester", "Seeding data for testing.");
|
|
|
|
AccountType? accountType = gremlinDb.AccountTypes.FirstOrDefault(a => a.AccountTypeCode == "FPC")!;
|
|
|
|
newAccount.AccountType = accountType;
|
|
|
|
SubMarket subMarket = gremlinDb.SubMarkets.First(a => a.SubMarketCode == "CEN");
|
|
|
|
newAccount.SubMarket = subMarket;
|
|
newContact.Account = newAccount;
|
|
|
|
try
|
|
{
|
|
_ = gremlinDb.Add(newAccount);
|
|
_ = gremlinDb.SaveChanges();
|
|
_ = gremlinDb.Add(newContact);
|
|
_ = gremlinDb.SaveChanges();
|
|
Console.WriteLine($"Account {newAccount.AccountName} mit Contact {newContact.LastName} wurde angelegt.");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine(e.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static bool ImportContactsFromCsv(string filepath = "", string separator = ";", bool dataHasHeading = true)
|
|
{
|
|
//Wenn keine Datei ausgewählt (Cancel geklickt), dann Abbruch:
|
|
if (filepath == "")
|
|
{
|
|
return false;
|
|
}
|
|
|
|
List<Contact> contactsReadFromFile = new(8000);
|
|
// ENCODING CHANGED TO UNICODE. TO BE TESTED!
|
|
using (TextFieldParser csvParser = new(filepath, FileService.GetEncoding(filepath)))
|
|
{
|
|
//Parser configuration:
|
|
csvParser.Delimiters = new[] { separator };
|
|
csvParser.CommentTokens = new[] { "#" };
|
|
csvParser.HasFieldsEnclosedInQuotes = true;
|
|
|
|
// Skip the row with the column names:
|
|
if (dataHasHeading)
|
|
{
|
|
_ = csvParser.ReadLine();
|
|
}
|
|
|
|
while (!csvParser.EndOfData)
|
|
{
|
|
// Read current line fields, pointer moves to the next line.
|
|
Contact importedContact = new();
|
|
string[] fields = csvParser.ReadFields()!;
|
|
|
|
//No conversion
|
|
importedContact.AcademicTitle = fields[1];
|
|
importedContact.FirstName = fields[3];
|
|
importedContact.LastName = fields[4];
|
|
importedContact.EMail = fields[6];
|
|
importedContact.Department = fields[7];
|
|
importedContact.Room = fields[8];
|
|
importedContact.PhoneNumber = fields[9];
|
|
importedContact.Function = fields[10];
|
|
importedContact.MobileNumber = fields[13];
|
|
|
|
//Convert Gender
|
|
importedContact.Gender = fields[2] == "M" ? (byte)Gender.Male : fields[2] == "F" ? (byte)Gender.Female : (byte)Gender.Unknown;
|
|
|
|
//Convert OptIn Status
|
|
importedContact.OptInStatus = fields[5] switch
|
|
{
|
|
"Opt In" => true,
|
|
"Opt Out" => false,
|
|
_ => false
|
|
};
|
|
|
|
//Convert "SAP Contact Number"
|
|
try
|
|
{
|
|
importedContact.SapContactNumber = Convert.ToUInt32(fields[11], CultureInfo.CurrentCulture);
|
|
}
|
|
catch (FormatException ex)
|
|
{
|
|
//errorhandling here: "Unable to parse input: " + field[0] + " as uint"
|
|
//Zeilennummer, Feld und Wert in Liste speichern, um am Ende gesammelt auszugeben
|
|
string errorRaiser = fields[11];
|
|
if (errorRaiser == "")
|
|
{
|
|
errorRaiser = "No Contact Number in this row!";
|
|
}
|
|
|
|
DisplayErrorDetails(ex, errorRaiser);
|
|
return false;
|
|
}
|
|
catch (OverflowException ex)
|
|
{
|
|
//errorhandling here: "Number cannot fit in an Uint."
|
|
//Zeilennummer, Feld und Wert in Liste speichern, um am Ende gesammelt auszugeben
|
|
string errorRaiser = fields[11];
|
|
if (errorRaiser == "")
|
|
{
|
|
errorRaiser = "No Contact Number in this row!";
|
|
}
|
|
|
|
DisplayErrorDetails(ex, errorRaiser);
|
|
return false;
|
|
}
|
|
|
|
//Convert "Account Created on"
|
|
int year = Convert.ToInt32(fields[12].Substring(0, 4), CultureInfo.CurrentCulture);
|
|
int month = Convert.ToInt32(fields[12].Substring(4, 2), CultureInfo.CurrentCulture);
|
|
int day = Convert.ToInt32(fields[12].Substring(6, 2), CultureInfo.CurrentCulture);
|
|
importedContact.SapContactCreationDate = new(year, month, day);
|
|
|
|
//Convert "No Phone Calls"
|
|
if (fields[26] == "1")
|
|
{
|
|
importedContact.NoPhoneCalls = true;
|
|
}
|
|
|
|
//Convert "No Hardcopy Mailing"
|
|
if (fields[27] == "1")
|
|
{
|
|
importedContact.NoHardcopyMailing = true;
|
|
}
|
|
|
|
//SAPAccountID in Contact.Notes speichern, um den entsprechenden Account aus DB heraussuchen zu können:
|
|
importedContact.Notes = fields[0];
|
|
|
|
contactsReadFromFile.Add(importedContact);
|
|
}
|
|
|
|
//Eingelesenen Account in DB schreiben:
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
foreach (Contact contact in contactsReadFromFile)
|
|
{
|
|
// AccountID aus DB laden, damit der Datensatz vom Context verfolgt wird und EF Core nicht versucht, diesen standardmäßig neu anzulegen.
|
|
|
|
contact.Account = ResolveAccountById(gremlinDb, uint.Parse(contact.Notes));
|
|
|
|
contact.Notes = "";
|
|
_ = MetaDataSetter.ForImport(contact, "CSVImporter", "Initial import by CSV Importer (Function DbHelper.ImportContactsFromCSV)");
|
|
}
|
|
|
|
|
|
gremlinDb.Contacts.AddRange(contactsReadFromFile);
|
|
|
|
_ = gremlinDb.SaveChanges();
|
|
}
|
|
}
|
|
|
|
//Bestätigung senden
|
|
Console.WriteLine($"Es wurden {contactsReadFromFile.Count} Contacts erfolgreich der Datenbank hinzugefügt.");
|
|
return true;
|
|
}
|
|
|
|
private static bool ImportAccountsFromCsv(string filepath = "", string separator = ";", bool dataHasHeading = true)
|
|
{
|
|
//Wenn keine Datei ausgewählt (Cancel geklickt), dann Abbruch:
|
|
if (filepath == "")
|
|
{
|
|
return false;
|
|
}
|
|
|
|
List<Account> accountsReadFromFile = new(2000);
|
|
|
|
//ENCODING CHANGED TO ISO-8859-1 AS EQUIVALENT (?) TO "LATIN1" (unavailable). TO BE TESTED!
|
|
//ich würde mir ja UTF8 als universelles Encoding wünschen
|
|
|
|
using (TextFieldParser csvParser = new(filepath, FileService.GetEncoding(filepath)))
|
|
{
|
|
//Parser configuration:
|
|
csvParser.Delimiters = new[] { separator };
|
|
csvParser.CommentTokens = new[] { "#" };
|
|
csvParser.HasFieldsEnclosedInQuotes = true;
|
|
|
|
// Skip the row with the column names:
|
|
if (dataHasHeading)
|
|
{
|
|
_ = csvParser.ReadLine();
|
|
}
|
|
|
|
while (!csvParser.EndOfData)
|
|
{
|
|
// Read current line fields, pointer moves to the next line.
|
|
Account importedAccount = new();
|
|
{
|
|
importedAccount.SubMarket = new();
|
|
importedAccount.AccountType = new();
|
|
importedAccount.Contacts = new List<Contact>();
|
|
}
|
|
string[] fields = csvParser.ReadFields()!;
|
|
|
|
//Konvertierung erforderlich:
|
|
try
|
|
{
|
|
importedAccount.SapAccountNumber = Convert.ToUInt32(fields[0]);
|
|
}
|
|
catch (FormatException ex)
|
|
{
|
|
//errorhandling here: "Unable to parse input: " + field[0] + " as uint"
|
|
//Zeilennummer, Feld und Wert in Liste speichern, um am Ende gesammelt auszugeben
|
|
string errorRaiser = fields[0];
|
|
if (errorRaiser == "")
|
|
{
|
|
errorRaiser = "No Account Number in this row!";
|
|
}
|
|
|
|
DisplayErrorDetails(ex, errorRaiser);
|
|
return false;
|
|
}
|
|
catch (OverflowException ex)
|
|
{
|
|
//errorhandling here: "Number cannot fit in an Uint."
|
|
//Zeilennummer, Feld und Wert in Liste speichern, um am Ende gesammelt auszugeben
|
|
string errorRaiser = fields[0];
|
|
if (errorRaiser == "")
|
|
{
|
|
errorRaiser = "No Account Number in this row!";
|
|
}
|
|
|
|
DisplayErrorDetails(ex, errorRaiser);
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
importedAccount.Zip = Convert.ToUInt32(fields[2]);
|
|
}
|
|
catch (FormatException ex)
|
|
{
|
|
//errorhandling here: "Unable to parse input: " + field[0] + " as uint"
|
|
//Zeilennummer, Feld und Wert in Liste speichern, um am Ende gesammelt auszugeben
|
|
string errorRaiser = fields[0];
|
|
if (errorRaiser == "")
|
|
{
|
|
errorRaiser = "No ZIP in this row!";
|
|
}
|
|
|
|
DisplayErrorDetails(ex, errorRaiser);
|
|
return false;
|
|
}
|
|
catch (OverflowException ex)
|
|
{
|
|
//errorhandling here: "Number cannot fit in an Uint."
|
|
//Zeilennummer, Feld und Wert in Liste speichern, um am Ende gesammelt auszugeben
|
|
string errorRaiser = fields[0];
|
|
if (errorRaiser == "")
|
|
{
|
|
errorRaiser = "No ZIP in this row!";
|
|
}
|
|
|
|
DisplayErrorDetails(ex, errorRaiser);
|
|
return false;
|
|
}
|
|
|
|
//Konvertierung für AccountCreatedinSAPOn Property:
|
|
//Test auf Inhalt
|
|
if (fields[8].Length != 0)
|
|
{
|
|
int year = Convert.ToInt32(fields[8].Substring(0, 4));
|
|
int month = Convert.ToInt32(fields[8].Substring(4, 2));
|
|
int day = Convert.ToInt32(fields[8].Substring(6, 2));
|
|
importedAccount.AccountCreatedInSapOn = new(year, month, day);
|
|
}
|
|
|
|
//keine Konvertierung nötig:
|
|
importedAccount.AccountName = fields[1];
|
|
importedAccount.City = fields[3];
|
|
importedAccount.Street = fields[4];
|
|
importedAccount.SubMarket.SubMarketCode = fields[5];
|
|
importedAccount.SubMarket.DataStatus = Status.Active.ToString();
|
|
importedAccount.AccountType.AccountTypeCode = fields[6];
|
|
importedAccount.AccountType.DataStatus = Status.Active.ToString();
|
|
importedAccount.PhoneNumber = fields[7];
|
|
importedAccount.DataStatus = Status.Active.ToString();
|
|
|
|
accountsReadFromFile.Add(importedAccount);
|
|
}
|
|
}
|
|
|
|
//Eingelesenen Account in DB schreiben:
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
foreach (Account account in accountsReadFromFile)
|
|
{
|
|
// AccountType aus DB laden, damit der Datensatz vom Context verfolgt wird und EF Core nicht versucht, diesen standardmäßig neu anzulegen.
|
|
|
|
if (account.AccountType.AccountTypeCode != "")
|
|
{
|
|
|
|
AccountType? accountType = gremlinDb.AccountTypes.First(a => a.AccountTypeCode == account.AccountType.AccountTypeCode);
|
|
|
|
account.AccountType = accountType;
|
|
|
|
account.AccountType = ResolveAccountType(gremlinDb, account.AccountType.AccountTypeCode);
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
//Default
|
|
account.AccountType = ResolveAccountType(gremlinDb, "FPC");
|
|
}
|
|
|
|
|
|
if (account.SubMarket.SubMarketCode != "")
|
|
{
|
|
|
|
SubMarket subMarket = gremlinDb.SubMarkets.First(a => a.SubMarketCode == account.SubMarket.SubMarketCode);
|
|
|
|
account.SubMarket = subMarket;
|
|
|
|
|
|
account.AccountType = ResolveAccountType(gremlinDb, account.AccountType.AccountTypeCode);
|
|
|
|
|
|
|
|
account.SubMarket = ResolveSubmarket(gremlinDb, account.SubMarket.SubMarketCode);
|
|
|
|
}
|
|
else
|
|
{
|
|
//Default
|
|
account.SubMarket = ResolveSubmarket(gremlinDb, "COT");
|
|
}
|
|
|
|
_ = MetaDataSetter.ForImport(account, "CSVImporter", "Initial import by CSV Importer (Function DbHelper.ImportAccountsFromCSV)");
|
|
}
|
|
|
|
|
|
gremlinDb.Accounts.AddRange(accountsReadFromFile);
|
|
|
|
_ = gremlinDb.SaveChanges();
|
|
}
|
|
|
|
//Bestätigung senden
|
|
Console.WriteLine($"Es wurden {accountsReadFromFile.Count} Accounts erfolgreich der Datenbank hinzugefügt.");
|
|
|
|
return true;
|
|
}
|
|
|
|
private static bool ImportLsagContactListToolData(string filepath = "", string separator = ";")
|
|
{
|
|
if (filepath == "")
|
|
{
|
|
return false; //Wenn keine Datei ausgewählt (Cancel geklickt), dann Abbruch:
|
|
}
|
|
|
|
List<Contact> contactsReadFromFile = new(8000);
|
|
List<Account> accountsReadFromFile = new(2000);
|
|
|
|
using (TextFieldParser csvParser = new(filepath, FileService.GetEncoding(filepath)))
|
|
{
|
|
//Parser configuration:
|
|
csvParser.Delimiters = new[] { separator };
|
|
csvParser.CommentTokens = new[] { "#" };
|
|
csvParser.HasFieldsEnclosedInQuotes = true;
|
|
|
|
//dynamische Spaltenzuordnung in Dictonary speichern
|
|
string[] fields = csvParser.ReadFields()!;
|
|
Dictionary<string, int> columnNumberOf = ColumnMapping(fields);
|
|
|
|
//Daten einlesen und Accounts und Kontakte in eigene List<Account> bzw List<Contact> extrahieren.
|
|
while (!csvParser.EndOfData)
|
|
{
|
|
bool dataHasError = false;
|
|
Account importedAccount = new();
|
|
Contact importedContact = new();
|
|
importedAccount.SubMarket = new();
|
|
importedAccount.AccountType = new();
|
|
importedContact.Account = new();
|
|
|
|
fields = csvParser.ReadFields()!; // Read current line fields, pointer moves to the next line.
|
|
if (fields[0] == "")
|
|
{
|
|
break; // Am Ende hängt eine leere Zeile, die im Parser einen Fehler auslösen würde.
|
|
}
|
|
|
|
//Account-Daten
|
|
// Konvertierung erforderlich:
|
|
try
|
|
{
|
|
importedAccount.SapAccountNumber = Convert.ToUInt32(fields[columnNumberOf["SAPAccountNumber"]]);
|
|
}
|
|
catch (FormatException ex)
|
|
{
|
|
//errorhandling here: "Unable to parse input: " + field[0] + " as uint"
|
|
//Zeilennummer, Feld und Wert in Liste speichern, um am Ende gesammelt auszugeben
|
|
string errorRaiser = fields[columnNumberOf["SAPContactNumber"]];
|
|
if (errorRaiser == "")
|
|
{
|
|
errorRaiser = "No Contact Number in this row!";
|
|
}
|
|
|
|
DisplayErrorDetails(ex, errorRaiser);
|
|
return false;
|
|
}
|
|
catch (OverflowException ex)
|
|
{
|
|
//errorhandling here: "Number cannot fit in an Uint."
|
|
//Zeilennummer, Feld und Wert in Liste speichern, um am Ende gesammelt auszugeben
|
|
string errorRaiser = fields[columnNumberOf["SAPContactNumber"]];
|
|
if (errorRaiser == "")
|
|
{
|
|
errorRaiser = "No Contact Number in this row!";
|
|
}
|
|
|
|
DisplayErrorDetails(ex, errorRaiser);
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
importedAccount.Zip = Convert.ToUInt32(fields[columnNumberOf["ZIP"]]);
|
|
}
|
|
catch (FormatException ex)
|
|
{
|
|
//errorhandling here: "Unable to parse input: " + field[0] + " as uint"
|
|
//Zeilennummer, Feld und Wert in Liste speichern, um am Ende gesammelt auszugeben
|
|
string errorRaiser = fields[columnNumberOf["SAPContactNumber"]];
|
|
if (errorRaiser == "")
|
|
{
|
|
errorRaiser = "No Contact Number in this row!";
|
|
}
|
|
|
|
DisplayErrorDetails(ex, errorRaiser);
|
|
return false;
|
|
}
|
|
catch (OverflowException ex)
|
|
{
|
|
//errorhandling here: "Number cannot fit in an Uint."
|
|
//Zeilennummer, Feld und Wert in Liste speichern, um am Ende gesammelt auszugeben
|
|
string errorRaiser = fields[columnNumberOf["SAPContactNumber"]];
|
|
if (errorRaiser == "")
|
|
{
|
|
errorRaiser = "No Contact Number in this row!";
|
|
}
|
|
|
|
DisplayErrorDetails(ex, errorRaiser);
|
|
return false;
|
|
}
|
|
|
|
// Konvertierung für AccountCreatedinSAPOn Property:
|
|
int year = Convert.ToInt32(fields[columnNumberOf["AccountCreatedInSAPOn"]].Substring(0, 4));
|
|
int month = Convert.ToInt32(fields[columnNumberOf["AccountCreatedInSAPOn"]].Substring(4, 2));
|
|
int day = Convert.ToInt32(fields[columnNumberOf["AccountCreatedInSAPOn"]].Substring(6, 2));
|
|
importedAccount.AccountCreatedInSapOn = new(year, month, day);
|
|
|
|
//Convert City von Großschreibung zu Normalschreibung
|
|
importedAccount.City = fields[columnNumberOf["City"]].First() + fields[columnNumberOf["City"]].Substring(1).ToLower();
|
|
|
|
// keine Konvertierung nötig:
|
|
importedAccount.AccountName = fields[columnNumberOf["AccountName"]];
|
|
importedAccount.Street = fields[columnNumberOf["Street"]];
|
|
importedAccount.SubMarket.SubMarketCode = fields[columnNumberOf["SubMarketCode"]];
|
|
importedAccount.SubMarket.DataStatus = Status.Active.ToString();
|
|
importedAccount.AccountType.AccountTypeCode = fields[columnNumberOf["AccountTypeCode"]];
|
|
importedAccount.AccountType.DataStatus = Status.Active.ToString();
|
|
importedAccount.PhoneNumber = fields[columnNumberOf["AccountPhoneNumber"]];
|
|
importedAccount.DataStatus = Status.Active.ToString();
|
|
|
|
//Validierungen:
|
|
if (importedAccount.AccountName == "" || importedAccount.City == "" || importedAccount.Street == "" || importedAccount.SubMarket.SubMarketCode == "" || importedAccount.AccountType.AccountTypeCode == "" || importedAccount.SapAccountNumber == 0)
|
|
{
|
|
dataHasError = true;
|
|
}
|
|
|
|
//Validierten Account der Liste hinzufügen:
|
|
if (dataHasError == false)
|
|
{
|
|
_ = importedAccount.AddIfUniqueTo(accountsReadFromFile);
|
|
}
|
|
|
|
//Contact-Daten
|
|
// Ohne Konvertierung
|
|
importedContact.AcademicTitle = fields[columnNumberOf["AcademicTitle"]];
|
|
importedContact.FirstName = fields[columnNumberOf["FirstName"]];
|
|
importedContact.LastName = fields[columnNumberOf["LastName"]];
|
|
importedContact.EMail = fields[columnNumberOf["EMail"]];
|
|
importedContact.Department = fields[columnNumberOf["Department"]];
|
|
importedContact.Room = fields[columnNumberOf["Room"]];
|
|
importedContact.PhoneNumber = fields[columnNumberOf["PhoneNumber"]];
|
|
importedContact.Function = fields[columnNumberOf["Function"]];
|
|
importedContact.MobileNumber = fields[columnNumberOf["MobileNumber"]];
|
|
|
|
//Convert Gender
|
|
importedContact.Gender = fields[columnNumberOf["Gender"]] == "M" ? (byte)Gender.Male : fields[columnNumberOf["Gender"]] == "F" ? (byte)Gender.Female : (byte)Gender.Unknown;
|
|
|
|
//Convert OptIn Status
|
|
importedContact.OptInStatus = fields[columnNumberOf["OptInStatus"]] == "Opt In" || (fields[columnNumberOf["OptInStatus"]] == "Opt Out" && false);
|
|
|
|
//Convert "SAP Contact Number"
|
|
try
|
|
{
|
|
importedContact.SapContactNumber = Convert.ToUInt32(fields[columnNumberOf["SAPContactNumber"]]);
|
|
}
|
|
catch (FormatException ex)
|
|
{
|
|
//errorhandling here: "Unable to parse input: " + field[0] + " as uint"
|
|
//Zeilennummer, Feld und Wert in Liste speichern, um am Ende gesammelt auszugeben
|
|
string errorRaiser = fields[columnNumberOf["SAPContactNumber"]];
|
|
if (errorRaiser == "")
|
|
{
|
|
errorRaiser = "No Contact Number in this row!";
|
|
}
|
|
|
|
DisplayErrorDetails(ex, errorRaiser);
|
|
return false;
|
|
}
|
|
catch (OverflowException ex)
|
|
{
|
|
//errorhandling here: "Number cannot fit in an Uint."
|
|
//Zeilennummer, Feld und Wert in Liste speichern, um am Ende gesammelt auszugeben
|
|
string errorRaiser = fields[columnNumberOf["SAPContactNumber"]];
|
|
if (errorRaiser == "")
|
|
{
|
|
errorRaiser = "No Contact Number in this row!";
|
|
}
|
|
|
|
DisplayErrorDetails(ex, errorRaiser);
|
|
return false;
|
|
}
|
|
|
|
//Convert "Account Created on"
|
|
year = Convert.ToInt32(fields[columnNumberOf["AccountCreatedInSAPOn"]].Substring(0, 4));
|
|
month = Convert.ToInt32(fields[columnNumberOf["AccountCreatedInSAPOn"]].Substring(4, 2));
|
|
day = Convert.ToInt32(fields[columnNumberOf["AccountCreatedInSAPOn"]].Substring(6, 2));
|
|
importedContact.SapContactCreationDate = new(year, month, day);
|
|
|
|
//Convert "No Phone Calls"
|
|
if (fields[columnNumberOf["NoPhoneCalls"]] == "1")
|
|
{
|
|
importedContact.NoPhoneCalls = true;
|
|
}
|
|
|
|
//Convert "No Hardcopy Mailing"
|
|
if (fields[columnNumberOf["NoHardcopyMailing"]] == "1")
|
|
{
|
|
importedContact.NoHardcopyMailing = true;
|
|
}
|
|
|
|
//SAPAccountID in Contact.Notes speichern, um den entsprechenden Account aus DB heraussuchen zu können:
|
|
importedContact.Notes = fields[columnNumberOf["SAPAccountNumber"]];
|
|
|
|
//Validierungen:
|
|
if (importedContact.EmailBounced || importedContact.LastName == "" || importedContact.SapContactNumber == 0)
|
|
{
|
|
dataHasError = true;
|
|
}
|
|
|
|
if (importedContact.EMail.Length > 7 && importedContact.EMail.Substring(0, 8) == "bounced-")
|
|
{
|
|
dataHasError = true;
|
|
}
|
|
|
|
//Validierte Kontakte zu Liste hinzufügen:
|
|
if (dataHasError == false)
|
|
{
|
|
contactsReadFromFile.Add(importedContact);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Eingelesenen Account in DB schreiben:
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
foreach (Account account in accountsReadFromFile)
|
|
{
|
|
// AccountType aus DB laden, damit der Datensatz vom Context verfolgt wird und EF Core nicht versucht, diesen standardmäßig neu anzulegen.
|
|
|
|
|
|
AccountType? accountType = gremlinDb.AccountTypes.First(a => a.AccountTypeCode == account.AccountType.AccountTypeCode);
|
|
|
|
|
|
account.AccountType = accountType;
|
|
|
|
|
|
SubMarket subMarket = gremlinDb.SubMarkets.First(a => a.SubMarketCode == account.SubMarket.SubMarketCode);
|
|
|
|
|
|
account.SubMarket = subMarket;
|
|
|
|
account.AccountType = ResolveAccountType(gremlinDb, account.AccountType.AccountTypeCode);
|
|
|
|
account.SubMarket = ResolveSubmarket(gremlinDb, account.SubMarket.SubMarketCode);
|
|
|
|
_ = MetaDataSetter.ForImport(account, "CSVImporter", "Initial import by CSV Importer (Function DbHelper.ImportAccountsFromCSV)");
|
|
}
|
|
|
|
|
|
gremlinDb.Accounts.AddRange(accountsReadFromFile);
|
|
|
|
_ = gremlinDb.SaveChanges();
|
|
}
|
|
|
|
//Eingelesenen Contacts in DB schreiben:
|
|
using (GremlinDb db = new())
|
|
{
|
|
foreach (Contact contact in contactsReadFromFile)
|
|
{
|
|
|
|
contact.Account = ResolveAccountById(db, uint.Parse(contact.Notes));
|
|
|
|
contact.Notes = "";
|
|
_ = MetaDataSetter.ForImport(contact, "CSVImporter", "Initial import by CSV Importer (Function DbHelper.ImportContactsFromCSV)");
|
|
}
|
|
|
|
|
|
db.Contacts.AddRange(contactsReadFromFile);
|
|
|
|
_ = db.SaveChanges();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static bool ImportProductsFromCsv(string filepath = "", string separator = "|", bool dataHasHeading = true)
|
|
{
|
|
if (filepath == "")
|
|
{
|
|
return false; //Wenn keine Datei ausgewählt (Cancel geklickt), dann Abbruch.
|
|
}
|
|
|
|
List<Product> productsReadFromFile = new(ParseProductFile(filepath, separator, dataHasHeading));
|
|
return InsertProducts(productsReadFromFile);
|
|
}
|
|
|
|
private static bool ImportCustomDescriptionsFromCsv(string filepath = "", string separator = "|", bool dataHasHeading = true)
|
|
{
|
|
if (filepath == "")
|
|
{
|
|
return false; //Wenn keine Datei ausgewählt (Cancel geklickt), dann Abbruch:
|
|
}
|
|
|
|
List<CustomDescription> cDsReadFromFile = new(2500);
|
|
using (TextFieldParser csvParser = new(filepath, Encoding.GetEncoding("UTF-8")))
|
|
{
|
|
//Parser configuration:
|
|
csvParser.Delimiters = new[] { separator };
|
|
csvParser.CommentTokens = new[] { "#" };
|
|
csvParser.HasFieldsEnclosedInQuotes = true;
|
|
|
|
// Skip the row with the column names:
|
|
if (dataHasHeading)
|
|
{
|
|
_ = csvParser.ReadLine();
|
|
}
|
|
|
|
while (!csvParser.EndOfData)
|
|
{
|
|
// Read current line fields, pointer moves to the next line.
|
|
string[] fields = csvParser.ReadFields()!;
|
|
|
|
//string productNumber = fields[0];
|
|
//string? optionNumber = fields[1] == "" ? null : fields[1];
|
|
CustomDescription importedCd = new()
|
|
{
|
|
ProductNumber = fields[0],
|
|
OptionNumber = fields[1],
|
|
Heading = fields[3],
|
|
DescriptionText = fields[4],
|
|
CoverletterText = fields[5],
|
|
Notes = fields[6],
|
|
// Product = new Product()
|
|
// Supplier = new()
|
|
// {
|
|
// AccountName = fields[2] is "" or "RB" ? "Agilent Technologies" : fields[2]
|
|
// }
|
|
};
|
|
|
|
_ = MetaDataSetter.ForImport(importedCd, "Importer", "Initial Importer by CD-ImporterFomCsv");
|
|
cDsReadFromFile.Add(importedCd);
|
|
}
|
|
}
|
|
|
|
//Eingelesenen Custum Desciptions in DB schreiben:
|
|
//Check for 3PPs that not yet in the db.
|
|
//Step 1a: Add 3PP-Products from CD-List to list
|
|
//Step 1b: Add list to db.
|
|
//Step 2: Add CDs to products.
|
|
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
//Step 1a
|
|
List<Product> thirdPartyProductsFromImportedCDs = new();
|
|
foreach (CustomDescription cd in cDsReadFromFile)
|
|
{
|
|
|
|
if (cd.Supplier.AccountName != "Agilent Technologies")
|
|
{
|
|
Product new3PpProduct = new()
|
|
{
|
|
// CustomDescription = cd,
|
|
HasBreakPrices = false,
|
|
ListPrice = 0,
|
|
ProductNumber = cd.ProductNumber,
|
|
OptionNumber = cd.OptionNumber,
|
|
ProductStatus = Status.Active.ToString(),
|
|
SapLongDescription = "",
|
|
SapShortDescription = "",
|
|
Weight = 0,
|
|
IntroductionDate = DateTime.Now.Date,
|
|
BreakRangeFrom = 0,
|
|
BreakRangeTo = 0,
|
|
ProductLine = ResolveProductLine(gremlinDb, "3P")
|
|
};
|
|
|
|
// new3PpProduct.CustomDescription.Supplier = ResolveAccountByName(gremlinDb, new3PpProduct.CustomDescription.Supplier.AccountName);
|
|
|
|
_ = MetaDataSetter.ForImport(new3PpProduct, "Custom Desciption Importer", "Created at import from Custom Descriptions.");
|
|
|
|
thirdPartyProductsFromImportedCDs.Add(new3PpProduct);
|
|
}
|
|
}
|
|
|
|
|
|
//Step 1b
|
|
|
|
gremlinDb.Products.AddRange(thirdPartyProductsFromImportedCDs); //Imports both the products and the associated custom descriptions!
|
|
|
|
_ = gremlinDb.SaveChanges();
|
|
|
|
// Produkt aus DB laden, damit der Datensatz vom Context verfolgt wird und EF Core nicht versucht, diesen standardmäßig neu anzulegen.
|
|
//Step 2
|
|
List<CustomDescription> importedCDsWithEfReferences = new(100000);
|
|
List<CustomDescription> cDsWithoutEfReferences = new(1000); //nur zur Kontrolle, wird nicht verwendet.
|
|
List<Product> productsInDb = gremlinDb.Products.ToList();
|
|
|
|
Account agilent = gremlinDb.Accounts.Single(a => a.AccountName == "Agilent Technologies");
|
|
|
|
// foreach (CustomDescription cd in cDsReadFromFile.Where(cd => !thirdPartyProductsFromImportedCDs.Equals(cd.Product)))
|
|
// {
|
|
// //Establish EF Reference. If no PN/Opt found, then skip this custom description.
|
|
// //CD.Product = GetProduct(db, CD.ProductNumber, CD.OptionNumber); //ResolveXY-functions return null, if no match is found in db.
|
|
// // cd.Product = productsInDb.Where(product => product.ProductNumber == cd.ProductNumber && product.OptionNumber == cd.OptionNumber).FirstOrDefault();
|
|
//
|
|
// //Establish EF Reference: If no Supplier-Account found, then skip this custom description (shouldn't happen), else set Supplier to Agilent (3PP-Supplier have been processed before and their products should not be part of this list).
|
|
// cd.Supplier = agilent;
|
|
// _ = MetaDataSetter.ForImport(cd, "CSVImporter", "Initial import by CSV Importer (Function DbHelper.ImportCustomDescriptionsFromCsv)");
|
|
//
|
|
// //add to final list of CDs, that will go into the db.
|
|
// importedCDsWithEfReferences.Add(cd);
|
|
// }
|
|
|
|
|
|
gremlinDb.CustomDescriptions.AddRange(importedCDsWithEfReferences);
|
|
|
|
_ = gremlinDb.SaveChanges();
|
|
|
|
//Bestätigung senden
|
|
Console.WriteLine($"Es wurden {importedCDsWithEfReferences.Count} eigene Beschreibungen erfolgreich der Datenbank hinzugefügt.{Environment.NewLine}Es wurden {thirdPartyProductsFromImportedCDs.Count} 3PP-Produkte neu angelegt.");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//public static bool ImportCustomDescriptionsFromDocx(string filepath = "")
|
|
/////Importiert Eigene Beschreibungen aus Word-Dokument
|
|
/////Abkürzung: CD = CustomDescriptions
|
|
//{
|
|
// if (filepath == "")
|
|
// {
|
|
// //filepath = FileIO.GetFilepathFromUser("Word-Dokument|*.doc; *.docx; *.docm"); //Pfad abfragen über Dtei-Öffnen-Dialog:
|
|
// }
|
|
|
|
// if (filepath == "")
|
|
// {
|
|
// return false; //Wenn keine Datei ausgewählt (Cancel geklickt), dann Abbruch:
|
|
// }
|
|
|
|
// List<CustomDescription> importedCDs = new(2500);
|
|
// WordprocessingDocument CDDoc = WordprocessingDocument.Open(filepath, false); //alternativ in using-Block packen, dann kann man nicht das Document.Close vergessen.
|
|
// Table CDTable = CDDoc.MainDocumentPart.Document.Body.Elements<Table>().ElementAt(0); //alternativ: Elements<Table>.First()
|
|
// if (CDTable != null)
|
|
// {
|
|
// CDTable.Descendants<TableRow>().First().Remove(); //Überschriften löschen
|
|
// foreach (TableRow aRow in CDTable.Descendants<TableRow>()) //einmal durch den XML-Baum wandern: WordprocessingDocument -> MainDocumentPart -> Document -> Body -> Table -> TableRow -> TableCell -> Paragraph -> Run -> Text
|
|
// {
|
|
// CustomDescription importedCD = new();
|
|
// List<string> stringsRead = new();
|
|
|
|
// foreach (TableCell aCell in aRow.Descendants<TableCell>())
|
|
// {
|
|
// StringBuilder sb = new();
|
|
// StringBuilder note = new();
|
|
// foreach (Paragraph aParagraph in aCell.Descendants<Paragraph>())
|
|
// {
|
|
// foreach (Run aRun in aParagraph.Descendants<Run>())
|
|
// {
|
|
// foreach (Text aText in aRun.Descendants<Text>())
|
|
// {
|
|
// string temp = "";
|
|
// temp = aParagraph.Descendants<Run>()
|
|
// .Where(r => r.RunProperties.Vanish != null)
|
|
// .Aggregate("", (text, r) => text += r.InnerText); //nach hidden Text filtern, diesen in "note" speichern
|
|
// _ = note.Append(temp);
|
|
|
|
// if (temp == "") //true, falls kein hidden Text => normalen Text verketten...
|
|
// {
|
|
// _ = sb.Append(aText.InnerText);
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// stringsRead.Add(sb.ToString()); //...und zellenweise abspeichern
|
|
// if (note.ToString() != "")
|
|
// {
|
|
// importedCD.Notes = note.ToString();
|
|
// }
|
|
// }
|
|
|
|
// importedCD.ProductNumber = stringsRead.ElementAt(0);
|
|
// importedCD.OptionNumber = stringsRead.ElementAt(1) == "" ? null : stringsRead.ElementAt(1);
|
|
// importedCD.Supplier.AccountName = stringsRead.ElementAt(2) is "" or "RB" ? "Agilent Technologies" : stringsRead.ElementAt(2);
|
|
// importedCD.Heading = stringsRead.ElementAt(3);
|
|
// importedCD.DescriptionText = stringsRead.ElementAt(4);
|
|
// importedCD.CoverletterText = stringsRead.ElementAt(5);
|
|
|
|
// importedCDs.Add(importedCD);
|
|
// //if (importedCDs.Count >= 1200 && importedCDs.Count % 100 == 0) MessageBox.Show(importedCDs.Count.ToString()); //DEBUGGING
|
|
|
|
// }
|
|
// }
|
|
// //MessageBox.Show(importedCDs.Count.ToString()); //DEBUGGING
|
|
// CDDoc.Close();
|
|
|
|
// //Eingelesenen Custum Desciptions in DB schreiben:
|
|
// //Check for 3PPs that not yet in the db.
|
|
// //Step 1a: Add 3PP-Products from CD-List to list
|
|
// //Step 1b: Add list to db.
|
|
// //Step 2: Add CDs to products.
|
|
|
|
// using (GremlinContext db = new())
|
|
// {
|
|
// //Step 1a
|
|
// List<Product> thirdPartyProductsFromImportedCDs = new();
|
|
// foreach (CustomDescription CD in importedCDs)
|
|
// {
|
|
// if (CD.Supplier.AccountName != "Agilent Technologies")
|
|
// {
|
|
// Product new3PPProduct = new()
|
|
// {
|
|
// CustomDescription = CD,
|
|
// HasBreakPrices = false,
|
|
// ListPrice = 0,
|
|
// ProductNumber = CD.ProductNumber,
|
|
// OptionNumber = CD.OptionNumber,
|
|
// ProductStatus = Status.Active.ToString(),
|
|
// SapLongDescription = null,
|
|
// SapShortDescription = null,
|
|
// Weight = 0,
|
|
// IntroductionDate = DateTime.Now.Date,
|
|
// BreakRangeFrom = 0,
|
|
// BreakRangeTo = 0,
|
|
// ProductLine = ResolveProductLine(db, "3P")
|
|
// };
|
|
// new3PPProduct.CustomDescription.Supplier = ResolveAccountByName(db, new3PPProduct.CustomDescription.Supplier.AccountName);
|
|
// _ = MetaDataSetter.ForImport(new3PPProduct, "Custom Desciption Importer", "Created at import from Custom Descriptions.");
|
|
|
|
// thirdPartyProductsFromImportedCDs.Add(new3PPProduct);
|
|
// }
|
|
// };
|
|
|
|
// //Step 1b
|
|
// db.Products.AddRange(thirdPartyProductsFromImportedCDs); //Imports both the products and the associated custom descriptions!
|
|
// _ = db.SaveChanges();
|
|
|
|
// // Produkt aus DB laden, damit der Datensatz vom Context verfolgt wird und EF Core nicht versucht, diesen standardmäßig neu anzulegen.
|
|
// //Step 2
|
|
// List<CustomDescription> importedCDsWithEFReferences = new();
|
|
// List<CustomDescription> CDsWithoutEFReferences = new(); //nur zur Kontrolle, wird nicht verwendet.
|
|
// foreach (CustomDescription CD in importedCDs)
|
|
// {
|
|
// //Skip Desciptions, if it has been already imported above (as part from 3PP)
|
|
// if (thirdPartyProductsFromImportedCDs.Intersect(CD.Products).Any())
|
|
// {
|
|
// continue;
|
|
// }
|
|
|
|
// //Establish EF Reference. If no PN/Opt found, then skip this custom description.
|
|
// CD.Products.Add(ResolveProduct(db, CD.ProductNumber, CD.OptionNumber)); //ResolveXY-functions return null, if no match is found in db.
|
|
|
|
// if (CD.Products == null)
|
|
// {
|
|
// CDsWithoutEFReferences.Add(CD);
|
|
// continue;
|
|
// }
|
|
|
|
// //Establish EF Reference. If no Supplier-Account found, then skip this custom description.
|
|
// CD.Supplier = ResolveAccountByName(db, CD.Supplier.AccountName); //ResolveXY-functions return null, if no match is found in db.
|
|
// if (CD.Supplier == null)
|
|
// {
|
|
// CDsWithoutEFReferences.Add(CD);
|
|
// continue;
|
|
// }
|
|
// _ = MetaDataSetter.ForImport(CD, "DocxImporter", "Initial import by CSV Importer (Function DbHelper.ImportCustomDescriptionsFromDocx)");
|
|
|
|
// //add to final list of CDs, that will go into the db.
|
|
// importedCDsWithEFReferences.Add(CD);
|
|
// }
|
|
|
|
// db.CustomDescriptions.AddRange(importedCDsWithEFReferences);
|
|
// _ = db.SaveChanges();
|
|
// }
|
|
// return true;
|
|
//}
|
|
|
|
private static bool UpdateProductsFromCsv(string filepath = "", string separator = "|", bool dataHasHeading = true)
|
|
{
|
|
string fileName = ExtractFileName(filepath);
|
|
if (filepath == "")
|
|
{
|
|
return false; //Wenn keine Datei ausgewählt (Cancel geklickt), dann Abbruch.
|
|
}
|
|
|
|
//Aktiven Produkte aus DB laden
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
//Aktive Produkte aus der DB einlesen
|
|
|
|
List<Product> activeProductsInDb = gremlinDb.Products.Where(p => p.DataStatus == Status.Active.ToString()).Include(p => p.ProductLine).ToList();
|
|
|
|
//Neue CPL einlesen...
|
|
List<Product> productsReadFromFile = new(ParseProductFile(filepath, separator, dataHasHeading));
|
|
|
|
//...Aufteilung in neue und nicht-neue Produkte...
|
|
List<Product> newProducts = new(FilterNewProducts(productsReadFromFile));
|
|
List<Product> nonNewProducts = new(productsReadFromFile.Except(newProducts));
|
|
|
|
//...Letztere wiederum in obsolete Produkte...
|
|
ProductEqualityComparer proEc = new();
|
|
List<Product> obsoleteProducts = new(activeProductsInDb.Except(nonNewProducts, proEc));
|
|
|
|
DateTime now = DateTime.Now;
|
|
|
|
//Obsolete Produkte prozessieren
|
|
foreach (Product product in obsoleteProducts)
|
|
{
|
|
product.ProductStatus = Status.Obsolete.ToString();
|
|
product.DataStatus = Status.Archived.ToString();
|
|
product.DataValidUntil = now;
|
|
product.DataModificationDate = now;
|
|
product.DataModificationByUser = "CPL Updater";
|
|
}
|
|
|
|
//den Rest prozessieren
|
|
List<Product> updatedProducts = new(10000);
|
|
string dataVersionComment = "Data as per " + fileName;
|
|
|
|
////Counter für Debugging
|
|
//int x = 0;
|
|
|
|
//Multithreading
|
|
_ = Parallel.ForEach(nonNewProducts, parallelOptions, product =>
|
|
{
|
|
////Debugging-Counter
|
|
//x++;
|
|
|
|
Product? existingProduct = activeProductsInDb.FirstOrDefault(p => p.ProductNumber == product.ProductNumber && p.OptionNumber == product.OptionNumber && p.BreakRangeFrom == product.BreakRangeFrom && p.BreakRangeTo == product.BreakRangeTo);
|
|
|
|
//Checkpoint, falls ein neues Produkt versehentlich auf "Active" statt auf "New" gesetzt ist.
|
|
if (existingProduct == null)
|
|
{
|
|
newProducts.Add(product);
|
|
return;
|
|
}
|
|
|
|
//Wenn keine Änderung, dann nur DataVersionComment mit CPL-Dateinamen aktualisieren...
|
|
|
|
if (product.ListPrice == existingProduct.ListPrice && product.ProductStatus == existingProduct.ProductStatus && Normalize(product.SapLongDescription) == Normalize(existingProduct.SapLongDescription) && Normalize(product.SapShortDescription) == Normalize(existingProduct.SapShortDescription))
|
|
{
|
|
existingProduct.DataVersionComment = dataVersionComment;
|
|
}
|
|
|
|
//andernfalls die vorhandene Datensatz-Version archivieren und neue Version anlegen
|
|
else //alten Datensatz archivieren:
|
|
{
|
|
existingProduct.DataStatus = Status.Archived.ToString();
|
|
existingProduct.DataModificationByUser = "CPL Updater";
|
|
existingProduct.DataModificationDate = now;
|
|
existingProduct.DataValidUntil = now;
|
|
existingProduct.DataVersionComment = "Archived b/c of data update";
|
|
|
|
if (product.ListPrice != existingProduct.ListPrice)
|
|
{
|
|
existingProduct.ProductStatus = Status.PriceUpdated.ToString();
|
|
}
|
|
else if (Normalize(product.SapLongDescription) != Normalize(existingProduct.SapLongDescription) || Normalize(product.SapShortDescription) != Normalize(existingProduct.SapShortDescription))
|
|
{
|
|
existingProduct.ProductStatus = Status.DescriptionUpdated.ToString();
|
|
}
|
|
else if (product.ProductStatus == existingProduct.ProductStatus)
|
|
{
|
|
existingProduct.ProductStatus = Status.StatusUpdated.ToString();
|
|
}
|
|
|
|
//neuen Datensatz anlegen
|
|
Product updatedProduct = new()
|
|
{
|
|
ProductNumber = product.ProductNumber,
|
|
OptionNumber = product.OptionNumber,
|
|
BreakRangeFrom = product.BreakRangeFrom,
|
|
BreakRangeTo = product.BreakRangeTo,
|
|
HasBreakPrices = product.HasBreakPrices,
|
|
IntroductionDate = existingProduct.IntroductionDate,
|
|
ListPrice = product.ListPrice,
|
|
ProductStatus = Status.Active.ToString(),
|
|
SapLongDescription = product.SapLongDescription,
|
|
SapShortDescription = product.SapShortDescription,
|
|
Weight = product.Weight
|
|
};
|
|
_ = MetaDataSetter.ForImport(updatedProduct, "CPL Updater", "Product Update");
|
|
|
|
updatedProduct.ProductLine = product.ProductLine.ProductLineCode == existingProduct.ProductLine.ProductLineCode ? product.ProductLine : ResolveProductLine(gremlinDb, product.ProductLine.ProductLineCode);
|
|
newProducts.Add(updatedProduct);
|
|
}
|
|
|
|
updatedProducts.Add(existingProduct);
|
|
});
|
|
|
|
_ = InsertProducts(newProducts); //enthält auch ResolvePL()
|
|
gremlinDb.Products.UpdateRange(obsoleteProducts);
|
|
gremlinDb.Products.UpdateRange(updatedProducts);
|
|
int changes = gremlinDb.SaveChanges();
|
|
Console.WriteLine($"Es wurden {changes} Änderungen an der Datenbank durchgeführt.\n Davon waren {updatedProducts.Count} UpdatedProducts, {obsoleteProducts.Count} ObsoleteProducts und {newProducts.Count} NewProducts");
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private static Dictionary<string, int> ColumnMapping(string[] fields)
|
|
{
|
|
Dictionary<string, int> result = new();
|
|
for (int i = 0; i < fields.Length; i++)
|
|
{
|
|
switch (fields[i].ToLower(CultureInfo.CurrentCulture).Trim().Replace(" ", "").Replace("-", "").Replace("_", "").Replace(".", "").Replace(":", ""))
|
|
{
|
|
case "accountid" or "fcustomercd" or "sapaccountnumber":
|
|
result.Add("SAPAccountNumber", i);
|
|
break;
|
|
case "accountname" or "fcustomername":
|
|
result.Add("AccountName", i);
|
|
break;
|
|
case "postalcode" or "fpostcode" or "zip":
|
|
result.Add("ZIP", i);
|
|
break;
|
|
case "city" or "ftown":
|
|
result.Add("City", i);
|
|
break;
|
|
case "street" or "faddress":
|
|
result.Add("Street", i);
|
|
break;
|
|
case "title" or "ftitletext1":
|
|
result.Add("AcademicTitle", i);
|
|
break;
|
|
case "gender" or "fgender1":
|
|
result.Add("Gender", i);
|
|
break;
|
|
case "firstname" or "ffirstname":
|
|
result.Add("FirstName", i);
|
|
break;
|
|
case "lastname" or "flastname":
|
|
result.Add("LastName", i);
|
|
break;
|
|
case "optin" or "femailopt":
|
|
result.Add("OptInStatus", i);
|
|
break;
|
|
case "workemail" or "fworkemail1" or "accountemail":
|
|
result.Add("EMail", i);
|
|
break;
|
|
case "bouncedbackemail" or "fbouncedback":
|
|
result.Add("EmailBounced", i);
|
|
break;
|
|
case "department" or "fdepartment1":
|
|
result.Add("Department", i);
|
|
break;
|
|
case "roomnumber" or "froomnumber":
|
|
result.Add("Room", i);
|
|
break;
|
|
case "workphone" or "fworkphone1" or "phonenumber":
|
|
result.Add("PhoneNumber", i);
|
|
break;
|
|
case "faxnumber":
|
|
result.Add("FaxNumber", i);
|
|
break;
|
|
case "function" or "ffunction":
|
|
result.Add("Function", i);
|
|
break;
|
|
case "contactid" or "fcontactcd":
|
|
result.Add("SAPContactNumber", i);
|
|
break;
|
|
case "contactcreationdate" or "fcreationdate":
|
|
result.Add("SAPContactCreationDate", i);
|
|
break;
|
|
case "mobilephone" or "fmobilephone":
|
|
result.Add("MobileNumber", i);
|
|
break;
|
|
case "jobfunction" or "fjobfunction":
|
|
result.Add("MA_JobFunctions", i);
|
|
break;
|
|
case "productinterest" or "fproductinterest":
|
|
result.Add("MA_ProductInterests", i);
|
|
break;
|
|
case "applicationinterest" or "fapplicationinterest":
|
|
result.Add("MA_ApplicationInterests", i);
|
|
break;
|
|
case "joblevel" or "fjoblevel":
|
|
result.Add("MA_JobLevel", i);
|
|
break;
|
|
case "contactindustry" or "fcontactindustry":
|
|
result.Add("MA_ContactIndustry", i);
|
|
break;
|
|
case "competitiveibase" or "fcompetativeibase":
|
|
result.Add("MA_CompetitiveIBase", i);
|
|
break;
|
|
case "submarketcode" or "fsubmarketcd":
|
|
result.Add("SubMarketCode", i);
|
|
break;
|
|
case "customertypecode" or "fcustomertypecd" or "accounttype" or "accounttypecode":
|
|
result.Add("AccountTypeCode", i);
|
|
break;
|
|
case "phone" or "fphone":
|
|
result.Add("AccountPhoneNumber", i);
|
|
break;
|
|
case "accountcreatedon" or "fcreatedon":
|
|
result.Add("AccountCreatedInSAPOn", i);
|
|
break;
|
|
case "contactchangedon" or "fcontactchangedon":
|
|
result.Add("SAPContactModifiedDate", i);
|
|
break;
|
|
case "notelephonecalls" or "fnotelephonecalls":
|
|
result.Add("NoPhoneCalls", i);
|
|
break;
|
|
case "nohardcopymailing" or "fnohardcopymailing":
|
|
result.Add("NoHardcopyMailing", i);
|
|
break;
|
|
case "accounttypedescription":
|
|
result.Add("AccountTypeDescription", i);
|
|
break;
|
|
case "submarketdescription":
|
|
result.Add("SubMarketDescription", i);
|
|
break;
|
|
case "productlineabbreviation":
|
|
result.Add("ProductLineAbbreviation", i);
|
|
break;
|
|
case "productlinedescription":
|
|
result.Add("ProductLineDescription", i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static List<Product> ParseProductFile(string filepath, string separator, bool dataHasHeading)
|
|
{
|
|
List<Product> results = new(100000);
|
|
//ENCODING CHANGED TO ISO-8859-1 AS EQUIVALENT (?) TO "LATIN1" (unavailable). TO BE TESTED!
|
|
using TextFieldParser csvParser = new(filepath, FileService.GetEncoding(filepath));
|
|
//Parser configuration:
|
|
csvParser.Delimiters = new[] { separator };
|
|
csvParser.CommentTokens = new[] { "#" };
|
|
csvParser.HasFieldsEnclosedInQuotes = true;
|
|
|
|
// Skip the row with the column names:
|
|
if (dataHasHeading)
|
|
{
|
|
_ = csvParser.ReadLine();
|
|
}
|
|
|
|
//decimal oldListPrice;
|
|
//bool listpriceHasChanged;
|
|
while (!csvParser.EndOfData)
|
|
{
|
|
// Read current line fields, pointer moves to the next line.
|
|
Product importedProduct = new()
|
|
{
|
|
ProductLine = new()
|
|
};
|
|
string[] fields = csvParser.ReadFields() ?? new string[1];
|
|
|
|
//Kontrolle, ob Trennzeichen in Daten vorhanden ist:
|
|
if (fields.Length > 27) //27 ist der Normalfall
|
|
{
|
|
//Sonderfall "EnVisionTM G|2":
|
|
//suche fields[x], das auf " G" endet und auf das field[x+1] mit "2 " beginnt, kombiniere die beiden und schiebe alle darauffolgenden Felder in diesem Datensatz eins nach links.
|
|
for (int i = 0; i < fields.Length - 1; i++) //fields.Length - 1, um durch i+1 nicht aus dem Index zu laufen
|
|
{
|
|
if (fields[i].EndsWith(" G"))
|
|
{
|
|
if (fields[i + 1].StartsWith("2 "))
|
|
{
|
|
fields[i] = fields[i] + fields[i + 1];
|
|
for (int j = i + 2; j < fields.Length; j++)
|
|
{
|
|
fields[j - 1] = fields[j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//NICHT ausgewertete Felder:
|
|
//fields[0] = Position [in CPL]
|
|
//fields[8] = Warranty
|
|
//fields[10] = PH Code
|
|
//fields[11] = PH Description
|
|
//fields[15] = Country of Manufacturing
|
|
//fields[16] = ECCL
|
|
//fields[17] = M41
|
|
//fields[18] = First Supplier Code
|
|
//fields[19] = Harmonized Tarif Schedule
|
|
//fields[20] = Hazardous Good Flag
|
|
//fields[21] = Order instructions
|
|
//fields[23] = End of Production Date
|
|
//fields[24] = End of Support Date
|
|
|
|
importedProduct.ProductNumber = fields[1];
|
|
|
|
importedProduct.OptionNumber = fields[2].Length switch
|
|
{
|
|
//Optionsnummer mit führendem Apostroph
|
|
4 => fields[2][1..],
|
|
//3-stellige Optionsnummer übernehmen; keine Aktion bei leerem Feld (keine Optionsnummer)
|
|
3 => fields[2],
|
|
_ => importedProduct.OptionNumber
|
|
};
|
|
|
|
importedProduct.SapShortDescription = fields[3];
|
|
|
|
importedProduct.ListPrice = decimal.Parse(fields[4], new CultureInfo("de-de")); //parsing! compare with old value (either from CSV or from DB) -> price change?
|
|
|
|
//if (fields[5] != "")
|
|
// if (decimal.Parse(fields[5], new CultureInfo("de-de")) != ImportedProduct.ListPrice)
|
|
// listpriceHasChanged = true;
|
|
|
|
importedProduct.BreakRangeFrom = fields[6] == "" ? 0 : Convert.ToInt32(fields[6]);
|
|
importedProduct.HasBreakPrices = importedProduct.BreakRangeFrom > 0;
|
|
importedProduct.BreakRangeTo = fields[7] is "" or "+" ? 0 : Convert.ToInt32(fields[7]); //erfasst sowohl Produkte ohne Break-Preise ("") als auch "+" bei Mengenangaben a la "100+" (= von 100 bis unendlich)
|
|
|
|
importedProduct.ProductLine.ProductLineCode = fields[9];
|
|
|
|
switch (fields[12])
|
|
{
|
|
case "Active":
|
|
importedProduct.DataStatus = Status.Active.ToString();
|
|
importedProduct.ProductStatus = Status.Active.ToString();
|
|
break;
|
|
case "New Product" or "New":
|
|
importedProduct.DataStatus = Status.Active.ToString();
|
|
importedProduct.ProductStatus = Status.New.ToString();
|
|
break;
|
|
case "Price Changed":
|
|
importedProduct.DataStatus = Status.Active.ToString();
|
|
importedProduct.ProductStatus = Status.PriceUpdated.ToString();
|
|
break;
|
|
default:
|
|
importedProduct.DataStatus = Status.StatusUpdated.ToString();
|
|
break;
|
|
}
|
|
|
|
importedProduct.Weight = ParseWeight(fields[14]);
|
|
|
|
if (fields[13] == "G")
|
|
{
|
|
importedProduct.Weight /= 1000; //Umrechnung g in kg
|
|
}
|
|
|
|
if (fields[22] != "")
|
|
{
|
|
importedProduct.IntroductionDate = DateTime.Parse(fields[22]);
|
|
}
|
|
|
|
importedProduct.SapLongDescription = fields[25];
|
|
|
|
results.Add(importedProduct);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
private static float ParseWeight(string input)
|
|
{
|
|
StringBuilder sb = new();
|
|
if (input.StartsWith("."))
|
|
{
|
|
input = sb.Append(0).Append(input).ToString();
|
|
}
|
|
|
|
try
|
|
{
|
|
return float.Parse(input, new CultureInfo("en-us"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine(ex, "Unhandled Error in Function 'ParseWeight'");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private static bool InsertProducts(List<Product> products)
|
|
{
|
|
using (GremlinDb gremlinDb = new())
|
|
{
|
|
|
|
List<ProductLine> productLines = gremlinDb.ProductLines.ToList();
|
|
|
|
foreach (Product product in products)
|
|
{
|
|
|
|
product.ProductLine = productLines.Find(x => x.ProductLineCode == product.ProductLine.ProductLineCode) ?? new ProductLine();
|
|
|
|
_ = MetaDataSetter.ForImport(product, "CSVImporter", "Initial import by CSV Importer (Function DbHelper.ImportProductsFromCSV)");
|
|
}
|
|
|
|
|
|
gremlinDb.Products.AddRange(products);
|
|
|
|
_ = gremlinDb.SaveChanges();
|
|
//Bestätigung senden
|
|
// Console.WriteLine($"Es wurden {products.Count} Produkte erfolgreich der Datenbank hinzugefügt.");
|
|
Console.WriteLine($"Es wurden {products.Count} Produkte erfolgreich der Datenbank hinzugefügt.");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public static void DisplayErrorDetails(Exception ex, string errorRaiser)
|
|
{
|
|
Console.WriteLine($"Source: {ex.Source}{Environment.NewLine}" + $"Message: {ex.Message}{Environment.NewLine}{Environment.NewLine}" + $"Contact: {errorRaiser}");
|
|
}
|
|
|
|
private static string ExtractFileName(string filepath, bool withExtension = false)
|
|
{
|
|
string[] fields = filepath.Split(@"\");
|
|
string[] filename = fields[^1].Split(".");
|
|
return withExtension ? fields[^1] : filename[0];
|
|
}
|
|
|
|
private static string Normalize(string input)
|
|
{
|
|
return input.ToLower().Trim().Replace(" ", "").Replace("-", "").Replace("_", "").Replace(".", "");
|
|
}
|
|
|
|
private static List<Product> FilterNewProducts(List<Product> products)
|
|
{
|
|
DateTime now = DateTime.Now;
|
|
|
|
List<Product> results = new(5000);
|
|
foreach (Product product in products)
|
|
{
|
|
if (product.ProductStatus == Status.New.ToString())
|
|
{
|
|
product.DataCreationDate = now;
|
|
product.DataModificationDate = now;
|
|
product.DataValidFrom = now;
|
|
product.DataValidUntil = farInTheFuture;
|
|
product.DataModificationByUser = "CPL Updater";
|
|
product.DataVersionNumber = 1;
|
|
product.DataVersionComment = "Initial Import by CSV Importer/Updater";
|
|
results.Add(product);
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
//private static List<Product> FilterProductsWithPriceChange(List<Product> products)
|
|
//{
|
|
// List<Product> results = new();
|
|
// foreach (var product in products)
|
|
// {
|
|
// if (product.ProductStatus == Status.PriceUpdated.ToString())
|
|
// {
|
|
// results.Add(product);
|
|
// }
|
|
// }
|
|
// return results;
|
|
//}
|
|
|
|
public static async Task<bool> ImportLsagContactListToolDataAsync()
|
|
{
|
|
return await Task.Run(() => ImportLsagContactListToolData());
|
|
}
|
|
|
|
public static async Task<bool> ImportAccountsFromCsvAsync()
|
|
{
|
|
return await Task.Run(() => ImportAccountsFromCsv());
|
|
}
|
|
|
|
public static async Task<bool> ImportContactsFromCsvAsync()
|
|
{
|
|
return await Task.Run(() => ImportContactsFromCsv());
|
|
}
|
|
|
|
public static async Task<bool> ImportProductsFromCsvAsync()
|
|
{
|
|
return await Task.Run(() => ImportProductsFromCsv());
|
|
}
|
|
|
|
//public static async Task<bool> ImportCustomDescriptionsFromDocxAsync() => await Task.Run(() => ImportCustomDescriptionsFromDocx());
|
|
|
|
public static async Task<bool> ImportCustomDescriptionsFromCsvAsync()
|
|
{
|
|
return await Task.Run(() => ImportCustomDescriptionsFromCsv());
|
|
}
|
|
|
|
public static async Task<bool> UpdateProductsFromCsvAsync()
|
|
{
|
|
return await Task.Run(() => UpdateProductsFromCsv());
|
|
}
|
|
|
|
public static Account ResolveAccountByName(GremlinDb db, string accountName)
|
|
{
|
|
try
|
|
{
|
|
|
|
return db.Accounts.Include(account => account.AccountType).Include(account => account.SubMarket).First(account => account.AccountName == accountName);
|
|
|
|
}
|
|
catch
|
|
{
|
|
return new();
|
|
}
|
|
}
|
|
|
|
public static Account ResolveAccountById(GremlinDb db, uint accountId)
|
|
{
|
|
try
|
|
{
|
|
|
|
return db.Accounts.First(account => account.SapAccountNumber == accountId);
|
|
|
|
}
|
|
catch
|
|
{
|
|
return new();
|
|
}
|
|
}
|
|
|
|
public static AccountType? ResolveAccountType(GremlinDb db, string accountTypeCode)
|
|
{
|
|
try
|
|
{
|
|
|
|
return db.AccountTypes.First(account => account.AccountTypeCode == accountTypeCode);
|
|
|
|
}
|
|
catch
|
|
{
|
|
return new();
|
|
}
|
|
}
|
|
|
|
public static SubMarket ResolveSubmarket(GremlinDb db, string subMarketCode)
|
|
{
|
|
try
|
|
{
|
|
|
|
return db.SubMarkets.First(submarket => submarket.SubMarketCode == subMarketCode);
|
|
|
|
}
|
|
catch
|
|
{
|
|
return new();
|
|
}
|
|
}
|
|
|
|
public static ProductLine ResolveProductLine(GremlinDb db, string productLineCode)
|
|
{
|
|
try
|
|
{
|
|
|
|
return db.ProductLines.First(productline => productline.ProductLineCode == productLineCode);
|
|
|
|
}
|
|
catch
|
|
{
|
|
return new();
|
|
}
|
|
}
|
|
|
|
private static string RandomString(int length)
|
|
{
|
|
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
return new(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());
|
|
}
|
|
} |