Merge pull request #94 from Basimodo/GenericImporter

Generic importer
pull/1/head
Sascha 2021-06-23 17:07:54 +07:00 committed by GitHub
commit 4b98a4ccef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 2427 additions and 834 deletions

@ -1,7 +1,7 @@
<Application x:Class="Gremlin.GremlinData.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="GremlinUI/QuoteUI.xaml">
StartupUri="GremlinUI/MainWindow.xaml">
<Application.Resources>
</Application.Resources>

@ -14,10 +14,13 @@
</PropertyGroup>
<ItemGroup>
<None Remove="GremlinUtilities\GUData\DataIdentifier.txt" />
<None Remove="GremlinUtilities\GUData\MappingDictionary.txt" />
<None Remove="Resources\Images\gremlin.jpg" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="GremlinUtilities\GUData\DataIdentifier.txt" />
<EmbeddedResource Include="GremlinUtilities\GUData\MappingDictionary.txt">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
@ -32,6 +35,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.818.41" />
<PackageReference Include="morelinq" Version="3.3.2" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.0" />
</ItemGroup>
@ -52,7 +56,12 @@
<ItemGroup>
<Folder Include="GremlinServices\" />
<Folder Include="GremlinUtilities\GUClasses\" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\Images\gremlin.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Resource>
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

@ -119,7 +119,7 @@ namespace Gremlin.GremlinData.DBClasses
entity.Property(e => e.SAPAccountNumber)
.IsRequired(true)
;
entity.Property(e => e.AccountCreatedinSAPOn)
entity.Property(e => e.AccountCreatedInSAPOn)
.IsRequired(true)
;
@ -470,7 +470,7 @@ namespace Gremlin.GremlinData.DBClasses
.IsRequired(true);
entity.Property(e => e.DescriptionText);
entity.Property(e => e.CoverletterText);
entity.Property(e => e.Note);
entity.Property(e => e.Notes);
}
}
@ -478,7 +478,7 @@ namespace Gremlin.GremlinData.DBClasses
{
public void Configure(EntityTypeBuilder<ProductLine> entity)
{
entity.HasKey(e => e.ProductLineId);
//entity.HasKey(e => e.ProductLineId); //Property removed. PK is AccountTypeCode (defined via data annotation in class).
entity.HasMany(p => p.Products).WithOne(d => d.ProductLine);
entity.Property(e => e.DataCreationDate)
.HasColumnType("TIMESTAMP")

File diff suppressed because it is too large Load Diff

@ -0,0 +1,13 @@
namespace Gremlin.GremlinData.DBClasses
{
internal class GremlinTypeConverter
{
internal static object Convert(string stringToConvert)
{
//noch nicht implementiert.
//für vollkommen generischen Importer
//
return default;
}
}
}

@ -0,0 +1,65 @@
using Gremlin.GremlinData.EntityClasses;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
using static Gremlin.GremlinData.EntityClasses.Enums;
namespace Gremlin.GremlinData.DBClasses
{
public static class MetaDataSetter
{
private static readonly DateTime FarInTheFuture = DateTime.Parse("2050-12-31t00:00:00.000000z", CultureInfo.CurrentCulture);
public static IMetadata ForImport(
IMetadata entity,
string datamodifiedby = "",
string dataversioncomment = "",
[CallerMemberName] string callername = "")
{
SetMetaData(entity, datamodifiedby, dataversioncomment, callername);
return entity;
}
public static List<IMetadata> ForImport(
List<IMetadata> entities,
string datamodifiedby = "",
string dataversioncomment = "",
[CallerMemberName] string callername = "")
{
//check if entities implements IMetaData:
//Ist das überhaupt nötig?
if ((entities is IMetadata) == false)
{
//no action / return list unchanged
return entities;
}
//set metadata
foreach (var entity in entities)
{
SetMetaData(entity, datamodifiedby, dataversioncomment, callername);
}
return entities;
}
private static IMetadata SetMetaData(
IMetadata entity,
string datamodifiedby = "",
string dataversioncomment = "",
[CallerMemberName] string callername = "")
{
entity.DataCreationDate = DateTime.Now;
entity.DataModificationDate = DateTime.Now;
entity.DataModificationByUser = datamodifiedby == "" ? callername : datamodifiedby;
entity.DataStatus = Status.Active.ToString();
entity.DataValidFrom = DateTime.Now;
entity.DataValidUntil = FarInTheFuture;
entity.DataVersionNumber++;
entity.DataVersionComment = dataversioncomment;
return entity;
}
}
}

@ -46,7 +46,7 @@ namespace Gremlin.GremlinData.EntityClasses
//public string AccountTypeCode { get; set; } //enum
//public string AccountSubMarketCode { get; set; } //enum
public uint SAPAccountNumber { get; set; }
public DateTime AccountCreatedinSAPOn { get; set; }
public DateTime AccountCreatedInSAPOn { get; set; }
//IBase
@ -100,7 +100,7 @@ namespace Gremlin.GremlinData.EntityClasses
// return Convert.ToInt32(this.SAPAccountNumber);
//}
public List<Account> AddIfUnique(List<Account> accounts)
public List<Account> AddIfUniqueTo(List<Account> accounts)
{
if (accounts.Count > 0 && SAPAccountNumber == accounts[accounts.Count - 1].SAPAccountNumber)
return accounts;

@ -32,8 +32,8 @@ namespace Gremlin.GremlinData.EntityClasses
public string Heading { get; set; }
public string DescriptionText { get; set; }
public string CoverletterText { get; set; }
public string Note { get; set; } //Hinweise, Tipps, Caveats, etc. für Konfiguration, Verwendung, Best Practice usw.
public string Notes { get; set; } //Hinweise, Tipps, Caveats, etc. für Konfiguration, Verwendung, Best Practice usw.
//Agilent-Specific properties:
//NONE

@ -1,12 +1,15 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Gremlin.GremlinData.EntityClasses
{
public class ProductLine : IMetadata
{
//primary key:
public uint ProductLineId { get; set; }
//public uint ProductLineId { get; set; }
[Key]
public string ProductLineCode { get; set; }
//navigation properties:
public List<Product> Products { get; set; }
@ -23,7 +26,6 @@ namespace Gremlin.GremlinData.EntityClasses
public string DataStatus { get; set; }
//class properties:
public string ProductLineAbbreviation { get; set; }
public string ProductLineDescription { get; set; }
}
}

@ -1,4 +1,4 @@
Produktnummer|Option|Non Agilent Produkt|Überschrift|Produktbeschreibung|Anschreiben|Hinweise
Produktnummer|Option|Non Agilent Produkt|Ueberschrift|Produktbeschreibung|Anschreiben|Hinweise
0100-0089|||T-Stück, Edelstahl|T-Stück aus Edelstahl, 1/4 Zoll.||
0100-1847|||Adapter für Überbrückungskapillare|Adapter zur Überbrückung des Gradientenventils von quaternären Pumpen (max. 1000 psi).||
0100-3150|||Überdruckventil|Überdruckventil zum Schutz von Detektorflusszellen, Auslöseschwelle: 7 bar.||

@ -0,0 +1,50 @@
<Window x:Class="Gremlin.GremlinUI.DataImport"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Gremlin.GremlinUI"
mc:Ignorable="d"
Title="DataImport" Height="220" Width="500" MinHeight="220" MaxHeight="300" MinWidth="350">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
<RowDefinition Height="30"/>
<RowDefinition Height="15"/>
</Grid.RowDefinitions>
<Label x:Name="lblSource" Grid.Row="0"
Content="Bitte Datenquelle auswählen"
Padding="20 0 0 0"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
FontSize="14"
VerticalAlignment="Top" FontWeight="Bold" />
<Grid Grid.Row="1" Height="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="3*" MinWidth="150"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<StackPanel x:Name="Fields" Grid.Column="0" Orientation="Vertical" MinHeight="120" HorizontalAlignment="Center">
<TextBlock x:Name="lblDataSource" Text="Datenquelle" TextAlignment="Left" Padding="10 4 10 4" Margin="0 4 0 5"/>
<TextBlock x:Name="lblDataEncoding" Text="Encoding" TextAlignment="Left" Padding="10 4 10 4" Margin="0 3 0 5"/>
<TextBlock x:Name="lblDataSeparator" Text="Trennzeichen" TextAlignment="Left" Padding="10 4 10 4" Margin="0 3 0 3"/>
</StackPanel>
<StackPanel x:Name="Data" Grid.Column="1" Orientation="Vertical">
<TextBox x:Name="tbDataSource" Text="" MouseDoubleClick="tbDataSource_MouseDoubleClick" Padding="10 4 10 4" TextWrapping="Wrap" Margin="0 3 0 3"/>
<TextBox x:Name="tbEncoding" Text="" Padding="10 4 10 4" Margin="0 3 0 3"/>
<TextBox x:Name="tbSeparator" Text="" Padding="10 4 10 4" Margin="0 3 0 3"/>
</StackPanel>
<StackPanel x:Name="ButtonsRight" Grid.Column="2" Orientation="Vertical" HorizontalAlignment="Stretch">
<Button x:Name="btnOpenFile" Content="..." Click="btnOpenFile_Click" Grid.Column="2" Height="22" Margin="3 5 5 5"></Button>
<Button x:Name="btnGetEncoding" Content="Auto" Click="btnGetEncoding_Click" Grid.Column="2" Height="22" Margin="3 6 5 5"></Button>
<Button x:Name="btnGetSeparator" Content="Auto" Click="btnGetSeparator_Click" Grid.Column="2" Height="22" Margin="3 4 5 0"></Button>
</StackPanel>
</Grid>
<StackPanel x:Name="Buttons" Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Name="btnOK" Content="Import starten" Click="btnOK_Click" Margin="15 0 15 0" Padding="20 0 20 0" Height="30" Width="120"/>
<Button x:Name="btnCancel" Content="Abbrechen" IsCancel="True" Click="btnCancel_Click" Margin="15 0 15 0" Padding="20 0 20 0" Height="30" Width="120"/>
</StackPanel>
</Grid>
</Window>

@ -0,0 +1,71 @@
using Gremlin.GremlinData.DBClasses;
using Gremlin.GremlinUtilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Gremlin.GremlinUI
{
/// <summary>
/// Interaktionslogik für DataImport.xaml
/// </summary>
public partial class DataImport : Window
{
private string _filepath;
private string _encodingName;
public DataImport()
{
InitializeComponent();
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
Close();
}
private async void btnOK_Click(object sender, RoutedEventArgs e)
{
//GenericImporter.Run(tbDataSource.Text, tbSeparator.Text, tbEncoding.Text);
bool success = await GenericImporter.RunAsync(_filepath, tbSeparator.Text, tbEncoding.Text);
if (success) Close();
}
private void btnOpenFile_Click(object sender, RoutedEventArgs e)
{
_filepath = FileHelper.GetFilepathFromUser();
if (_filepath != "")
{
tbDataSource.Text = DbHelper.ExtractFileName(_filepath, true);
tbEncoding.Text = "";
tbSeparator.Text = "";
}
}
private void tbDataSource_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
btnOpenFile_Click(sender, e);
}
private void btnGetEncoding_Click(object sender, RoutedEventArgs e)
{
_encodingName = FileHelper.GetEncoding(_filepath)?.HeaderName;
tbEncoding.Text = FileHelper.GetEncoding(_filepath)?.EncodingName;
}
private void btnGetSeparator_Click(object sender, RoutedEventArgs e)
{
tbSeparator.Text = GenericImporter.GuessSeparator(_filepath, _encodingName);
}
}
}

@ -31,8 +31,9 @@
<Button Content="Import Custom Descriptions from CSV..." Margin="10,5,10,5" Name="btnImportCDFromCSV" Click="BtnImportCDFromCSV_Click" />
</StackPanel>
<StackPanel x:Name="Work" Grid.Row="1" Grid.Column="1" Orientation="Vertical" >
<Button Content="Select a quote..." VerticalAlignment="top" Margin="10,5,10,5" Name="btnOpenQuote" Click="BtnOpenQuote_Click" />
<Button Content="Refresh Account List" VerticalAlignment="top" Margin="10,5,10,5" Name ="btnRefreshAccountList" Click="BtnRefreshAccountList_Click"/>
<Button Content="Select a quote..." VerticalAlignment="top" Margin="10,5,10,3" Name="btnOpenQuote" Click="BtnOpenQuote_Click" />
<Button Content="Refresh Account List" VerticalAlignment="top" Margin="10,5,10,3" Name ="btnRefreshAccountList" Click="BtnRefreshAccountList_Click"/>
<Button Content="Test" VerticalAlignment="Top" Margin="10,50,10,3" Name="btnTest" Click="BtnTest_Click" Height="60" />
<Button Content="Open QuoteUI" VerticalAlignment="top" Margin="10,5,10,5" Name="btnQuoteUI" Click="BtnQuoteUI_Click" />
</StackPanel>
<StackPanel x:Name="DB" Grid.Row="2" Grid.Column="2" Orientation="Vertical">

@ -1,4 +1,5 @@
using Gremlin.GremlinData.DBClasses;
using Gremlin.GremlinUtilities;
using Gremlin.GremlinData.EntityClasses;
using Gremlin.GremlinUI.ViewModels;
using Gremlin.Models;
@ -7,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using static Gremlin.GremlinData.DBClasses.GremlinContext;
@ -58,19 +60,19 @@ namespace Gremlin.GremlinUI
private async void BtnImportAccounts_Click(object sender, RoutedEventArgs e)
{
//DbHelper.ImportAccountsFromCSV();
_ = await DbHelper.ImportAccountsFromCSVAsync();
_ = await DbHelper.ImportAccountsFromCsvAsync();
}
private async void BtnImportContacts_Click(object sender, RoutedEventArgs e)
{
//DbHelper.ImportContactsFromCSV();
_ = await DbHelper.ImportContactsFromCSVAsync();
_ = await DbHelper.ImportContactsFromCsvAsync();
}
private async void BtnImportProducts_Click(object sender, RoutedEventArgs e)
{
//DbHelper.ImportProductsFromCSV();
_ = await DbHelper.ImportProductsFromCSVAsync();
_ = await DbHelper.ImportProductsFromCsvAsync();
}
private async void BtnImportCDs_Click(object sender, RoutedEventArgs e)
@ -124,6 +126,12 @@ namespace Gremlin.GremlinUI
_ = await DbHelper.ImportCustomDescriptionsFromCsvAsync();
}
private void BtnTest_Click(object sender, RoutedEventArgs e)
{
DataImport dataImport = new();
dataImport.ShowDialog();
}
private void BtnQuoteUI_Click(object sender, RoutedEventArgs e)
{
QuoteUI quoteUI = new();

@ -32,7 +32,7 @@ namespace Gremlin.GremlinUI.ViewModels
customDescriptionVM.Heading = customDescription.Heading;
customDescriptionVM.DescriptionText = customDescription.DescriptionText;
customDescriptionVM.CoverletterText = customDescription.CoverletterText;
customDescriptionVM.Note = customDescription.Note;
customDescriptionVM.Note = customDescription.Notes;
return customDescriptionVM;
}

@ -27,6 +27,8 @@ namespace Gremlin.GremlinUtilities
public static Encoding GetEncoding(string fileName)
{
if (fileName == "" || fileName == null) return null;
Stream fileStream = File.OpenRead(fileName);
using (var reader = new StreamReader(fileStream, defaultEncodingIfNoBom, true))
{

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq;
using System.IO;
using System.Reflection;
@ -8,20 +6,6 @@ namespace Gremlin.GremlinUtilities
{
public static class FileIO
{
public static Dictionary<string, string> ReadMappingTableFromFile()
{
Dictionary<string, string> result = new();
string fileInput = ReadResource("MappingDictionary.txt");
string[] lines = fileInput.Split(Environment.NewLine);
foreach (string line in lines)
{
string[] fields;
fields = line.Split("|");
result.Add(fields[0], fields[1]);
}
return result;
}
public static string ReadResource(string name)
//Source and credit to: https://stackoverflow.com/questions/3314140/how-to-read-embedded-resource-text-file
{

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Gremlin.GremlinUtilities.GUClasses
{
class DataIdType
{
private readonly string _dataType;
private readonly List<string> _qualifiers;
private List<string> _matchedQualifiers;
private readonly int _numberOfQualifiers;
private int _score = 0;
private bool _allQualifierMatched = false;
public string DataType
{
get => _dataType;
}
public List<string> Qualifiers
{
get => _qualifiers;
}
public int Score
{
get => _score;
}
public bool AllQualifierMatched
{
get => _allQualifierMatched;
}
public DataIdType(string DataType, IEnumerable<string> Qualifiers)
{
_dataType = DataType;
_qualifiers = Qualifiers.ToList();
_numberOfQualifiers = _qualifiers.Count;
_matchedQualifiers = new();
}
public void AddFoundQualfier(string QualifierFound)
{
_matchedQualifiers.Add(QualifierFound);
_score++;
_allQualifierMatched = (_matchedQualifiers.Count == _numberOfQualifiers);
}
public bool CheckForQualifier(string qualifier)
{
return _qualifiers.Contains(qualifier);
}
public void IncreaseScore(int value = 1)
{
_score += value;
}
public void ResetScore()
{
_score = 0;
}
public override bool Equals(object obj)
{
return obj is DataIdType type
&& _dataType == type._dataType;
}
public override int GetHashCode()
{
return HashCode.Combine(_dataType);
}
}
}

@ -0,0 +1,146 @@
using MoreLinq;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Gremlin.GremlinUtilities.GUClasses
{
class DataIdentificator
{
private readonly string _source; //Qualifier-Liste
private readonly Dictionary<string, int> _mappingTable; //Mapping Spaltenzahl <-> Property/(übersetzte) Spaltenüberschrift
public List<DataIdType> DataTypes { get; set; }
public DataIdentificator(Dictionary<string, int> MappingTable)
{
_mappingTable = MappingTable;
//DataTypes populieren. Dazu: einlesen, nach DT qualifier in temp. Liste speichern, damit neuen DIDT erzeugen und zur Liste hinzufügen
this.Initialize();
}
private void Initialize()
{
string _currentDataType;
DataTypes = new();
List<DataIdentifier> dataIdentifier = ReadDataIdentifierFromFile();
_currentDataType = dataIdentifier[0].DataType;
List<string> _identifierOfCurrentType = new();
foreach (DataIdentifier qualifier in dataIdentifier)
{
if (qualifier.DataType == _currentDataType)
{
_identifierOfCurrentType.Add(qualifier.Identifier);
if (qualifier == dataIdentifier[^1]) //letztes Element der Liste
{
DataIdType typeToBeAdded = new(_currentDataType, _identifierOfCurrentType);
DataTypes.Add(typeToBeAdded);
//_currentDataType = qualifier.DataType;
}
continue;
}
else
{
DataIdType typeToBeAdded = new(_currentDataType, _identifierOfCurrentType);
DataTypes.Add(typeToBeAdded);
_currentDataType = qualifier.DataType;
_identifierOfCurrentType.Clear();
_identifierOfCurrentType.Add(qualifier.Identifier);
}
}
}
public List<string> Identify(bool MustMatchAllQualifer = true)
{
List<string> winners = new();
foreach (DataIdType datatype in DataTypes)
{
foreach (string qualifier in datatype.Qualifiers)
{
if (_mappingTable.ContainsKey(qualifier))
{
datatype.AddFoundQualfier(qualifier);
}
}
}
if (MustMatchAllQualifer)
{
foreach (DataIdType dataType in DataTypes) //may return multiple winners
{
if (dataType.AllQualifierMatched)
{
winners.Add(dataType.DataType);
}
}
}
else //return the winner by highest score:
{
winners.Add(DataTypes.Aggregate((x, y) => x.Score > y.Score ? x : y).DataType.ToString());
}
//Plausibilty checkpoint:
//1. Remove "PL", "AccountType", "Submarket" from Winner-List, if detected datatype is "LSAG" or "Account".
//2. LSAG = Account + Contact --> when LSAG is a winner, remove "LSAG" and add "Account" and "Contact" to use their dedicated import methods.
//3. Remove any other winner, when winner is one of "PL", "AccountType", "Submarket" AND fields[].count = 2.
if (MustMatchAllQualifer == true && winners.Contains("LSAG"))
{
if (winners.Contains("ProductLine")) winners.Remove("ProductLine");
if (winners.Contains("AccountType")) winners.Remove("AccountType");
if (winners.Contains("SubMarket")) winners.Remove("SubMarket");
if (winners.Contains("Account")) winners.Remove("Account");
if (winners.Contains("Contact")) winners.Remove("Contact");
}
if (MustMatchAllQualifer == true && winners.Contains("Account"))
{
if (winners.Contains("ProductLine")) winners.Remove("ProductLine");
if (winners.Contains("AccountType")) winners.Remove("AccountType");
if (winners.Contains("SubMarket")) winners.Remove("SubMarket");
}
if (MustMatchAllQualifer == false && _mappingTable.Count == 2)
{
if (winners.Contains("ProductLine"))
{
winners.Clear();
winners.Add("ProductLine");
}
if (winners.Contains("AccountType"))
{
winners.Clear();
winners.Add("AccountType");
}
if (winners.Contains("SubMarket"))
{
winners.Clear();
winners.Add("SubMarket");
}
}
return winners;
}
public List<DataIdentifier> ReadDataIdentifierFromFile()
{
List<DataIdentifier> result = new(50);
string fileInput = FileIO.ReadResource("DataIdentifier.txt");
string[] lines = fileInput.Split(Environment.NewLine);
foreach (string line in lines)
{
string[] fields;
DataIdentifier identifier = new();
fields = line.Split("|");
identifier.DataType = fields[0];
identifier.Identifier = fields[1];
result.Add(identifier);
}
return result;
}
}
}

@ -0,0 +1,8 @@
namespace Gremlin.GremlinUtilities.GUClasses
{
public class DataIdentifier
{
public string DataType { get; set; }
public string Identifier { get; set; }
}
}

@ -0,0 +1,38 @@
AccountType|AccountTypeCode
AccountType|AccountTypeDescription
SubMarket|SubMarketCode
SubMarket|SubMarketDescription
ProductLine|ProductLineCode
ProductLine|ProductLineDescription
Product|ProductNumber
Product|ListPrice
Product|Weight
Product|BreakRangeFrom
LSAG|AccountName
LSAG|Street
LSAG|ZIP
LSAG|City
LSAG|PhoneNumber
LSAG|SAPAccountNumber
LSAG|AccountTypeCode
LSAG|SubMarketCode
LSAG|SAPContactNumber
LSAG|LastName
LSAG|MA_ProductInterests
Account|AccountName
Account|Street
Account|ZIP
Account|City
Account|PhoneNumber
Account|SAPAccountNumber
Account|AccountTypeCode
Account|SubMarketCode
Contact|LastName
Contact|SAPContactNumber
Contact|FirstName
Contact|Gender
CustomDescription|Heading
CustomDescription|ProductNumber
CustomDescription|OptionNumber
CustomDescription|DescriptionText
CustomDescription|CoverletterText

@ -68,11 +68,14 @@ macompetitiveibase|MA_CompetitiveIBase
competitiveibase|MA_CompetitiveIBase
fcompetativeibase|MA_CompetitiveIBase
submarketcode|SubMarketCode
submarketcodes|SubMarketCode
fsubmarketcd|SubMarketCode
accountsubmarketcode|SubMarketCode
accounttypecode|AccountTypeCode
customertypecode|AccountTypeCode
fcustomertypecd|AccountTypeCode
accounttype|AccountTypeCode
accounttypes|AccountTypeCode
accountphonenumber|AccountPhoneNumber
phone|AccountPhoneNumber
fphone|AccountPhoneNumber
@ -89,5 +92,51 @@ nohardcopymailing|NoHardcopyMailing
fnohardcopymailing|NoHardcopyMailing
accounttypedescription|AccountTypeDescription
submarketdescription|SubMarketDescription
productlineabbreviation|ProductLineAbbreviation
productlinedescription|ProductLineDescription
submarketdescriptions|SubMarketDescription
productlineabbreviation|ProductLineCode
productlineabbreviations|ProductLineCode
productlinedescription|ProductLineDescription
productlinedescriptions|ProductLineDescription
productNumber|ProductNumber
partnumber|ProductNumber
produktnummer|ProductNumber
optionnumber|OptionNumber
option|OptionNumber
sapshortdescription|SapShortDescription
description|SapShortDescription
listprice|ListPrice
currentmonthprice(eur)|ListPrice
breakrangefrom|BreakRangeFrom
breaksrangefrom|BreakRangeFrom
breakrangeto|BreakRangeTo
breaksrangeto|BreakRangeTo
productline|ProductLineCode
weight|Weight
airpackagedweight|Weight
introductiondate|IntroductionDate
saplongdescription|SapLongDescription
longdescription|SapLongDescription
status|ProductStatus
datastatus|Datastatus
weightunit|WeightUnit
airpackagedunit|WeightUnit
previousmonthprice(eur)|PreviousMonthPrice
warranty|Warranty
phcode|PHCode
phdescription|PHDescription
countryofmanufacturing|CountryOfManufacturing
eccl|ECCL
m41|M41
firstsuppliercode|FirstSupplierCode
harmonizedtarifschedule|HarmonizedTarifSchedule
hazardousgoodsflag|HazardousGoodsFlag
orderinstructions|OrderInstructions
endofproductiondate|EndOfProductionDate
endofsupportdate|EndOfSupportDate
nonagilentprodukt|Supplier
überschrift|Heading
ueberschrift|Heading
heading|Heading
produktbeschreibung|DescriptionText
anschreiben|CoverletterText
hinweise|Notes