refactoring of EntityConfig to avoid new generation of items

pull/1/head
Sascha 2023-03-22 12:09:47 +07:00
parent 884a17c428
commit ab95729a4a
26 changed files with 4509 additions and 4114 deletions

File diff suppressed because it is too large Load Diff

@ -9,22 +9,16 @@ public class AccountConfiguration : IEntityTypeConfiguration<Account>
public void Configure(EntityTypeBuilder<Account> accountEntity)
{
accountEntity.HasKey(e => e.AccountId);
accountEntity.HasMany(d => d.Contacts).WithOne(p => p.Account).IsRequired();
accountEntity.HasMany(d => d.CustomDescriptions).WithOne(p => p.Supplier);
accountEntity
.HasOne(d => d.AccountType)
.WithMany(p => p.Accounts)
.IsRequired()
.OnDelete(DeleteBehavior.Restrict);
accountEntity
.HasOne(d => d.SubMarket)
.WithMany(p => p.Accounts)
.IsRequired()
.OnDelete(DeleteBehavior.Restrict);
accountEntity.HasMany(d => d.Contacts).WithOne(p => p.Account);
// accountEntity.HasMany(d => d.CustomDescriptions).WithOne(p => p.Supplier);
accountEntity.HasOne(d => d.AccountType).WithMany(p => p.Accounts).HasForeignKey(fk => fk.AccountTypeCode);
accountEntity.HasOne(d => d.SubMarket).WithMany(p => p.Accounts).HasForeignKey(fk => fk.SubMarketCode);
accountEntity.HasAlternateKey(e => e.SapAccountNumber); // =Unique
accountEntity.Property(e => e.AccountId).ValueGeneratedOnAdd();
accountEntity.Property(e => e.ParentAccountId).HasDefaultValue(0);
// accountEntity.Property(e => e.ParentAccountId).HasDefaultValue(0);
accountEntity.Property(e => e.AccountName).IsRequired().HasMaxLength(250);
accountEntity.Property(e => e.Notes).HasDefaultValue("");
accountEntity.Property(e => e.Street).IsRequired().HasMaxLength(100);
@ -40,37 +34,14 @@ public class AccountConfiguration : IEntityTypeConfiguration<Account>
accountEntity.Property(e => e.SapAccountNumber).IsRequired();
accountEntity.Property(e => e.AccountCreatedInSapOn).IsRequired();
accountEntity
.Property(e => e.DataCreationDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
accountEntity
.Property(e => e.DataValidFrom)
.HasColumnType("DATETIME")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
accountEntity
.Property(e => e.DataValidUntil)
.HasColumnType("DATETIME")
.HasDefaultValueSql("'9999-12-31 23:59:59.000000'")
.ValueGeneratedOnAdd();
accountEntity.Property(e => e.DataCreationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
accountEntity.Property(e => e.DataValidFrom).HasColumnType("DATETIME").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
accountEntity.Property(e => e.DataValidUntil).HasColumnType("DATETIME").HasDefaultValueSql("'9999-12-31 23:59:59.000000'").ValueGeneratedOnAdd();
accountEntity.Property(e => e.DataVersionNumber).HasDefaultValue(1).IsRequired();
accountEntity.Property(e => e.DataVersionComment).HasDefaultValue("");
accountEntity.Property(e => e.DataStatus).IsRequired().HasDefaultValue("Active");
//.HasDefaultValue("Active") //Default-Wert wird nicht gesetzt?!?
accountEntity
.Property(e => e.DataModificationDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
.ValueGeneratedOnAddOrUpdate()
.IsConcurrencyToken();
//.IsRowVersion() impliziert .ValueGeneratedOnAddOrUpdate() und .IsConcurrencyToken(true)
accountEntity
.Property(e => e.DataModificationByUser)
.HasColumnType("TINYTEXT")
.IsRequired()
.HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()");
accountEntity.Property(e => e.DataStatus).IsRequired().HasDefaultValue("Active"); //.HasDefaultValue("Active") //Default-Wert wird nicht gesetzt?!?
accountEntity.Property(e => e.DataModificationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP").ValueGeneratedOnAddOrUpdate().IsConcurrencyToken(); //.IsRowVersion() impliziert .ValueGeneratedOnAddOrUpdate() und .IsConcurrencyToken(true)
accountEntity.Property(e => e.DataModificationByUser).HasColumnType("TINYTEXT").IsRequired().HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()");
}
}
@ -79,11 +50,11 @@ public class ContactConfiguration : IEntityTypeConfiguration<Contact>
public void Configure(EntityTypeBuilder<Contact> contactEntity)
{
contactEntity.HasKey(e => e.ContactId);
contactEntity.HasOne(p => p.Account).WithMany(d => d.Contacts).IsRequired();
//SW
contactEntity.HasMany(q => q.Quotes).WithOne(c => c.Recipient);
//entity.HasAlternateKey(e => e.SAPContactNumber);
contactEntity.HasOne(p => p.Account).WithMany(d => d.Contacts).HasForeignKey(fk => fk.AccountId);
contactEntity.HasMany(q => q.Quotes).WithOne(c => c.Recipient).HasForeignKey(fk => fk.QuoteId);
contactEntity.HasAlternateKey(e => e.SapContactNumber);
contactEntity.Property(e => e.ContactId);
contactEntity.Property(e => e.SapContactNumber).IsRequired();
@ -97,37 +68,16 @@ public class ContactConfiguration : IEntityTypeConfiguration<Contact>
contactEntity.Property(e => e.Notes).HasDefaultValue("");
contactEntity.Property(e => e.ValidatedContact).HasDefaultValue(false);
contactEntity
.Property(e => e.DataCreationDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
contactEntity
.Property(e => e.DataValidFrom)
.HasColumnType("DATETIME")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
contactEntity
.Property(e => e.DataValidUntil)
.HasColumnType("DATETIME")
.HasDefaultValueSql("'9999-12-31 23:59:59.000000'")
.ValueGeneratedOnAdd();
contactEntity.Property(e => e.DataCreationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
contactEntity.Property(e => e.DataValidFrom).HasColumnType("DATETIME").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
contactEntity.Property(e => e.DataValidUntil).HasColumnType("DATETIME").HasDefaultValueSql("'9999-12-31 23:59:59.000000'").ValueGeneratedOnAdd();
contactEntity.Property(e => e.DataVersionNumber).HasDefaultValue(1).IsRequired();
contactEntity.Property(e => e.DataVersionComment).HasDefaultValue("");
contactEntity.Property(e => e.DataStatus).IsRequired();
//.HasDefaultValue("Active") //Default-Wert wird nicht gesetzt?!?
contactEntity
.Property(e => e.DataModificationDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
.ValueGeneratedOnAddOrUpdate()
.IsConcurrencyToken();
contactEntity.Property(e => e.DataModificationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP").ValueGeneratedOnAddOrUpdate().IsConcurrencyToken();
//.IsRowVersion() impliziert .ValueGeneratedOnAddOrUpdate() und .IsConcurrencyToken(true)
contactEntity
.Property(e => e.DataModificationByUser)
.HasColumnType("TINYTEXT")
.IsRequired()
.HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()");
contactEntity.Property(e => e.DataModificationByUser).HasColumnType("TINYTEXT").IsRequired().HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()");
}
}
@ -136,26 +86,16 @@ public class QuoteConfiguration : IEntityTypeConfiguration<Quote>
public void Configure(EntityTypeBuilder<Quote> quoteEntity)
{
quoteEntity.HasKey(e => e.QuoteId);
quoteEntity
.HasMany(d => d.LineItems)
.WithOne(p => p.Quote)
.IsRequired(false)
.OnDelete(DeleteBehavior.Cascade);
quoteEntity
.Property(e => e.QuotationNumber)
.HasColumnType("VARCHAR(255)")
.IsRequired()
.ValueGeneratedOnAdd();
quoteEntity.Property(e => e.QuotationDate).IsRequired().ValueGeneratedOnAdd();
quoteEntity.Property(e => e.ValidUntil);
quoteEntity.Property(e => e.ValidFor).IsRequired();
//SW
quoteEntity.HasOne(e => e.Recipient).WithMany(c => c.Quotes).IsRequired();
quoteEntity.HasOne(e => e.Recipient).WithMany(c => c.Quotes).HasForeignKey(fk => fk.RecipientId);
quoteEntity.HasOne(e => e.SalesRep).WithMany(c => c.SalesRepQuotes).HasForeignKey(fk => fk.SalesRepId);
quoteEntity.Ignore("SalesRep");
quoteEntity.HasMany(d => d.LineItems).WithOne(p => p.Quote).HasForeignKey(fk => fk.QuoteId);
quoteEntity.Property(e => e.QuotationNumber).HasColumnType("VARCHAR(255)").ValueGeneratedOnAdd();
quoteEntity.Property(e => e.QuotationDate).ValueGeneratedOnAdd();
quoteEntity.Property(e => e.ValidUntil);
quoteEntity.Property(e => e.ValidFor);
quoteEntity.Property(e => e.TotalListprice);
quoteEntity.Property(e => e.TotalDiscount);
quoteEntity.Property(e => e.TotalNet);
@ -165,35 +105,14 @@ public class QuoteConfiguration : IEntityTypeConfiguration<Quote>
quoteEntity.Property(e => e.QuoteContainsRb).HasDefaultValue(false);
quoteEntity.Property(e => e.QuoteTemplate).HasDefaultValue("");
quoteEntity
.Property(e => e.DataCreationDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
quoteEntity
.Property(e => e.DataValidFrom)
.HasColumnType("DATETIME")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
quoteEntity
.Property(e => e.DataValidUntil)
.HasColumnType("DATETIME")
.HasDefaultValueSql("'9999-12-31 23:59:59.000000'")
.ValueGeneratedOnAdd();
quoteEntity.Property(e => e.DataCreationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
quoteEntity.Property(e => e.DataValidFrom).HasColumnType("DATETIME").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
quoteEntity.Property(e => e.DataValidUntil).HasColumnType("DATETIME").HasDefaultValueSql("'9999-12-31 23:59:59.000000'").ValueGeneratedOnAdd();
quoteEntity.Property(e => e.DataVersionNumber).HasDefaultValue(1).IsRequired();
quoteEntity.Property(e => e.DataVersionComment).HasDefaultValue("");
quoteEntity.Property(e => e.DataStatus).IsRequired().HasDefaultValue("Active");
quoteEntity
.Property(e => e.DataModificationDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
.ValueGeneratedOnAddOrUpdate()
.IsConcurrencyToken();
quoteEntity
.Property(e => e.DataModificationByUser)
.HasColumnType("TINYTEXT")
.IsRequired()
.HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()");
quoteEntity.Property(e => e.DataModificationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP").ValueGeneratedOnAddOrUpdate().IsConcurrencyToken();
quoteEntity.Property(e => e.DataModificationByUser).HasColumnType("TINYTEXT").IsRequired().HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()");
}
}
@ -202,16 +121,9 @@ public class LineItemConfiguration : IEntityTypeConfiguration<LineItem>
public void Configure(EntityTypeBuilder<LineItem> lineItemEntity)
{
lineItemEntity.HasKey(e => e.LineItemId);
lineItemEntity
.HasOne(p => p.Quote)
.WithMany(d => d.LineItems)
.HasForeignKey(fk => fk.QuoteId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
lineItemEntity
.HasOne(p => p.CustomDescription)
.WithMany(d => d.LineItems)
.HasForeignKey(fk => fk.CustomDescriptionId);
lineItemEntity.HasOne(p => p.Quote).WithMany(d => d.LineItems).HasForeignKey(fk => fk.QuoteId);
lineItemEntity.HasOne(p => p.CustomDescription).WithMany(d => d.LineItems).HasForeignKey(fk => fk.CustomDescriptionId);
lineItemEntity.Property(e => e.Position).IsRequired();
lineItemEntity.Property(e => e.Amount).IsRequired();
@ -230,35 +142,14 @@ public class LineItemConfiguration : IEntityTypeConfiguration<LineItem>
lineItemEntity.Property(e => e.NetPrice).IsRequired();
lineItemEntity.Property(e => e.Total).IsRequired();
lineItemEntity
.Property(e => e.DataCreationDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
lineItemEntity
.Property(e => e.DataValidFrom)
.HasColumnType("DATETIME")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
lineItemEntity
.Property(e => e.DataValidUntil)
.HasColumnType("DATETIME")
.HasDefaultValueSql("'9999-12-31 23:59:59.000000'")
.ValueGeneratedOnAdd();
lineItemEntity.Property(e => e.DataCreationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
lineItemEntity.Property(e => e.DataValidFrom).HasColumnType("DATETIME").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
lineItemEntity.Property(e => e.DataValidUntil).HasColumnType("DATETIME").HasDefaultValueSql("'9999-12-31 23:59:59.000000'").ValueGeneratedOnAdd();
lineItemEntity.Property(e => e.DataVersionNumber).HasDefaultValue(1).IsRequired();
lineItemEntity.Property(e => e.DataVersionComment).HasDefaultValue("");
lineItemEntity.Property(e => e.DataStatus).IsRequired().HasDefaultValue("Active");
lineItemEntity
.Property(e => e.DataModificationDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
.ValueGeneratedOnAddOrUpdate()
.IsConcurrencyToken();
lineItemEntity
.Property(e => e.DataModificationByUser)
.HasColumnType("TINYTEXT")
.IsRequired()
.HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()");
lineItemEntity.Property(e => e.DataModificationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP").ValueGeneratedOnAddOrUpdate().IsConcurrencyToken();
lineItemEntity.Property(e => e.DataModificationByUser).HasColumnType("TINYTEXT").IsRequired().HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()");
}
}
@ -267,20 +158,8 @@ public class ProductConfiguration : IEntityTypeConfiguration<Product>
public void Configure(EntityTypeBuilder<Product> productEntity)
{
productEntity.HasKey(e => e.ProductId);
productEntity
.HasOne(d => d.CustomDescription)
.WithMany(p => p.Products)
.HasForeignKey("CustomDescriptionId")
.IsRequired()
.OnDelete(DeleteBehavior.SetNull);
productEntity
.HasOne(p => p.ProductLine)
.WithMany(d => d.Products)
.HasForeignKey("ProductLineCode")
.IsRequired()
.OnDelete(DeleteBehavior.Restrict);
productEntity.Property(e => e.CustomDescriptionId).IsRequired();
productEntity.HasOne(p => p.ProductLine).WithMany(d => d.Products).HasForeignKey(fk => fk.ProductLineCode).OnDelete(DeleteBehavior.Restrict);
productEntity.Property(e => e.ProductNumber).IsRequired();
productEntity.Property(e => e.OptionNumber).HasDefaultValue("");
@ -288,42 +167,16 @@ public class ProductConfiguration : IEntityTypeConfiguration<Product>
productEntity.Property(e => e.SapLongDescription).HasDefaultValue("");
productEntity.Property(e => e.Weight).HasDefaultValue(0);
productEntity.Property(e => e.ProductStatus).HasDefaultValue("Active");
productEntity
.Property(e => e.IntroductionDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
productEntity.Property(e => e.IntroductionDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
productEntity.Property(e => e.ListPrice).IsRequired();
productEntity
.Property(e => e.DataCreationDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
productEntity
.Property(e => e.DataValidFrom)
.HasColumnType("DATETIME")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
productEntity
.Property(e => e.DataValidUntil)
.HasColumnType("DATETIME")
.HasDefaultValueSql("'9999-12-31 23:59:59.000000'")
.ValueGeneratedOnAdd();
productEntity.Property(e => e.DataCreationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
productEntity.Property(e => e.DataValidFrom).HasColumnType("DATETIME").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
productEntity.Property(e => e.DataValidUntil).HasColumnType("DATETIME").HasDefaultValueSql("'9999-12-31 23:59:59.000000'").ValueGeneratedOnAdd();
productEntity.Property(e => e.DataVersionNumber).HasDefaultValue(1).IsRequired();
productEntity.Property(e => e.DataVersionComment).HasDefaultValue("");
productEntity.Property(e => e.DataStatus).IsRequired().HasDefaultValue("Active");
productEntity
.Property(e => e.DataModificationDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
.ValueGeneratedOnAddOrUpdate()
.IsConcurrencyToken();
productEntity
.Property(e => e.DataModificationByUser)
.HasColumnType("TINYTEXT")
.IsRequired()
.HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()");
productEntity.Property(e => e.DataModificationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP").ValueGeneratedOnAddOrUpdate().IsConcurrencyToken();
productEntity.Property(e => e.DataModificationByUser).HasColumnType("TINYTEXT").IsRequired().HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()");
}
}
@ -332,14 +185,8 @@ public class CustomDescriptionConfiguration : IEntityTypeConfiguration<CustomDes
public void Configure(EntityTypeBuilder<CustomDescription> customDescriptionEntity)
{
customDescriptionEntity.HasKey(e => e.CustomDescriptionId);
customDescriptionEntity
.HasMany(p => p.Products)
.WithOne(d => d.CustomDescription)
.IsRequired(false);
customDescriptionEntity
.HasOne(p => p.Supplier)
.WithMany(d => d.CustomDescriptions)
.IsRequired();
customDescriptionEntity.HasOne(p => p.Product).WithOne(d => d.CustomDescription).IsRequired(false);
// customDescriptionEntity.HasOne(p => p.Supplier).WithMany(d => d.CustomDescriptions).IsRequired();
customDescriptionEntity.Property(e => e.ProductNumber).IsRequired();
customDescriptionEntity.Property(e => e.OptionNumber).HasDefaultValue("");
@ -348,35 +195,14 @@ public class CustomDescriptionConfiguration : IEntityTypeConfiguration<CustomDes
customDescriptionEntity.Property(e => e.CoverletterText).HasDefaultValue("");
customDescriptionEntity.Property(e => e.Notes).HasDefaultValue("");
customDescriptionEntity
.Property(e => e.DataCreationDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
customDescriptionEntity
.Property(e => e.DataValidFrom)
.HasColumnType("DATETIME")
.HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
customDescriptionEntity
.Property(e => e.DataValidUntil)
.HasColumnType("DATETIME")
.HasDefaultValueSql("'9999-12-31 23:59:59.000000'")
.ValueGeneratedOnAdd();
customDescriptionEntity.Property(e => e.DataCreationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
customDescriptionEntity.Property(e => e.DataValidFrom).HasColumnType("DATETIME").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd();
customDescriptionEntity.Property(e => e.DataValidUntil).HasColumnType("DATETIME").HasDefaultValueSql("'9999-12-31 23:59:59.000000'").ValueGeneratedOnAdd();
customDescriptionEntity.Property(e => e.DataVersionNumber).HasDefaultValue(1).IsRequired();
customDescriptionEntity.Property(e => e.DataVersionComment).HasDefaultValue("");
customDescriptionEntity.Property(e => e.DataStatus).IsRequired().HasDefaultValue("Active");
customDescriptionEntity
.Property(e => e.DataModificationDate)
.HasColumnType("TIMESTAMP")
.HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
.ValueGeneratedOnAddOrUpdate()
.IsConcurrencyToken();
customDescriptionEntity
.Property(e => e.DataModificationByUser)
.HasColumnType("TINYTEXT")
.IsRequired()
.HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()");
customDescriptionEntity.Property(e => e.DataModificationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP").ValueGeneratedOnAddOrUpdate().IsConcurrencyToken();
customDescriptionEntity.Property(e => e.DataModificationByUser).HasColumnType("TINYTEXT").IsRequired().HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()");
}
}

File diff suppressed because it is too large Load Diff

@ -5,102 +5,101 @@ namespace Gremlin_BlazorServer.Data.EntityClasses;
public class Account : IMetadata
//: IEquatable<Account>
{
//primary key:
[Required] public uint AccountId { get; set; }
//foreign keys:
[Required] public uint ParentAccountId { get; set; }
//public string AccountTypeCode { get; set; } = string.Empty;
//public string SubMarketCode { get; set; } = string.Empty;
public IList<Contact>? Contacts { get; set; }
public IList<CustomDescription>? CustomDescriptions { get; set; }
//navigation properties:
public AccountType? AccountType { get; set; }
public SubMarket? SubMarket { get; set; }
//class properties:
[Required] public string? AccountName { get; set; }
public string Notes { get; set; } = string.Empty;
[Required] public string? Street { get; set; }
[Required] public uint Zip { get; set; }
[Required] public string? City { get; set; }
public string FloorOrBuilding { get; set; } = string.Empty;
public float Longitude { get; set; }
public float Latitude { get; set; }
public string PhoneNumber { get; set; } = string.Empty;
public string FaxNumber { get; set; } = string.Empty;
public string Webpage { get; set; } = string.Empty;
public string EMail { get; set; } = string.Empty;
//Agilent-specific Properties:
public uint SapAccountNumber { get; set; }
public DateTime AccountCreatedInSapOn { get; set; }
//metadata:
public DateTime DataCreationDate { get; set; } = DateTime.Now;
public DateTime DataModificationDate { get; set; } = DateTime.Now;
public DateTime DataValidFrom { get; set; } = DateTime.Now;
public DateTime DataValidUntil { get; set; } = DateTime.MaxValue;
public string DataModificationByUser { get; set; } = "Gremlin_BlazorServer";
public uint DataVersionNumber { get; set; }
public string? DataVersionComment { get; set; } = string.Empty;
public string DataStatus { get; set; } = "Active";
//IBase
//tbd
//public bool Equals(Account other)
//{
// if (other == null) return false;
// if (this == null) return false;
// if (this.SAPAccountNumber == other.SAPAccountNumber) return true;
// else return false;
//}
//public static bool operator ==(Account account1, Account account2)
//{
// if (account1.SAPAccountNumber == 0) return false;
// if (account2.SAPAccountNumber == 0) return false;
// if (account1.SAPAccountNumber == account2.SAPAccountNumber) return true;
// else return false;
//}
//public static bool operator !=(Account account1, Account account2)
//{
// if (account1.SAPAccountNumber == 0) return false;
// if (account2.SAPAccountNumber == 0) return false;
// if (account1.SAPAccountNumber == account2.SAPAccountNumber) return false;
// else return true;
//}
//public override bool Equals(object obj)
//{
// if (obj == null) return false;
// Account accountObj = obj as Account;
// if (accountObj == null) return false;
// else return base.Equals(obj);
//}
//public override int GetHashCode()
/////<summary>
/////Returns the (unique) SAP Account ID.
/////</summary>
//{
// return Convert.ToInt32(this.SAPAccountNumber);
//}
public List<Account> AddIfUniqueTo(List<Account> accounts)
{
if (accounts.Count > 0 && SapAccountNumber == accounts[^1].SapAccountNumber) return accounts;
foreach (Account account in accounts)
if (SapAccountNumber == account.SapAccountNumber)
return accounts;
accounts.Add(this);
return accounts;
}
//primary key:
[Required] public uint AccountId { get; set; }
//foreign keys:
// [Required] public uint ParentAccountId { get; set; }
public string AccountTypeCode { get; set; }
public string SubMarketCode { get; set; }
//navigation properties:
public AccountType? AccountType { get; set; }
public SubMarket? SubMarket { get; set; }
public IList<Contact>? Contacts { get; set; }
// public IList<CustomDescription>? CustomDescriptions { get; set; }
//class properties:
[Required] public string? AccountName { get; set; }
public string Notes { get; set; } = string.Empty;
[Required] public string? Street { get; set; }
[Required] public uint Zip { get; set; }
[Required] public string? City { get; set; }
public string FloorOrBuilding { get; set; } = string.Empty;
public float Longitude { get; set; }
public float Latitude { get; set; }
public string PhoneNumber { get; set; } = string.Empty;
public string FaxNumber { get; set; } = string.Empty;
public string Webpage { get; set; } = string.Empty;
public string EMail { get; set; } = string.Empty;
//Agilent-specific Properties:
public uint SapAccountNumber { get; set; }
public DateTime AccountCreatedInSapOn { get; set; }
//metadata:
public DateTime DataCreationDate { get; set; } = DateTime.Now;
public DateTime DataModificationDate { get; set; } = DateTime.Now;
public DateTime DataValidFrom { get; set; } = DateTime.Now;
public DateTime DataValidUntil { get; set; } = DateTime.MaxValue;
public string DataModificationByUser { get; set; } = "Gremlin_BlazorServer";
public uint DataVersionNumber { get; set; }
public string? DataVersionComment { get; set; } = string.Empty;
public string DataStatus { get; set; } = "Active";
//IBase
//tbd
//public bool Equals(Account other)
//{
// if (other == null) return false;
// if (this == null) return false;
// if (this.SAPAccountNumber == other.SAPAccountNumber) return true;
// else return false;
//}
//public static bool operator ==(Account account1, Account account2)
//{
// if (account1.SAPAccountNumber == 0) return false;
// if (account2.SAPAccountNumber == 0) return false;
// if (account1.SAPAccountNumber == account2.SAPAccountNumber) return true;
// else return false;
//}
//public static bool operator !=(Account account1, Account account2)
//{
// if (account1.SAPAccountNumber == 0) return false;
// if (account2.SAPAccountNumber == 0) return false;
// if (account1.SAPAccountNumber == account2.SAPAccountNumber) return false;
// else return true;
//}
//public override bool Equals(object obj)
//{
// if (obj == null) return false;
// Account accountObj = obj as Account;
// if (accountObj == null) return false;
// else return base.Equals(obj);
//}
//public override int GetHashCode()
/////<summary>
/////Returns the (unique) SAP Account ID.
/////</summary>
//{
// return Convert.ToInt32(this.SAPAccountNumber);
//}
public List<Account> AddIfUniqueTo(List<Account> accounts)
{
if (accounts.Count > 0 && SapAccountNumber == accounts[^1].SapAccountNumber) return accounts;
foreach (Account account in accounts)
if (SapAccountNumber == account.SapAccountNumber)
return accounts;
accounts.Add(this);
return accounts;
}
}

@ -2,53 +2,54 @@
public class Contact : IMetadata
{
//primary key:
public uint ContactId { get; set; }
//primary key:
public uint ContactId { get; set; }
//foreign keys:
public uint AccountId { get; set; }
//foreign keys:
public uint AccountId { get; set; }
//navigation properties:
public Account? Account { get; set; }
public IList<Quote>? Quotes { get; set; }
//navigation properties:
public Account? Account { get; set; }
public IList<Quote>? Quotes { get; set; }
public IList<Quote>? SalesRepQuotes { get; set; }
//class properties:
public string? AcademicTitle { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public byte Gender { get; set; }
public bool OptInStatus { get; set; }
public string? Department { get; set; }
public string? Function { get; set; }
public string? Room { get; set; }
public bool IsReference { get; set; }
public string? Notes { get; set; }
public string? PhoneNumber { get; set; }
public string? MobileNumber { get; set; }
public string? EMail { get; set; }
public string? PreferredContactMethod { get; set; }
public bool NoPhoneCalls { get; set; }
public bool EmailBounced { get; set; }
public bool NoHardcopyMailing { get; set; }
public bool ValidatedContact { get; set; }
//class properties:
public string? AcademicTitle { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public byte Gender { get; set; }
public bool OptInStatus { get; set; }
public string? Department { get; set; }
public string? Function { get; set; }
public string? Room { get; set; }
public bool IsReference { get; set; }
public string? Notes { get; set; }
public string? PhoneNumber { get; set; }
public string? MobileNumber { get; set; }
public string? EMail { get; set; }
public string? PreferredContactMethod { get; set; }
public bool NoPhoneCalls { get; set; }
public bool EmailBounced { get; set; }
public bool NoHardcopyMailing { get; set; }
public bool ValidatedContact { get; set; }
//Agilent-specific Properties:
public int SapContactNumber { get; set; }
public DateTime SapContactCreationDate { get; set; } = DateTime.Now;
public DateTime SapContactModifiedDate { get; set; } = DateTime.Now;
public string? SapJobFunction { get; set; }
public string? SapProductInterest { get; set; }
public string? SapApplicationInterest { get; set; }
public string? SapJobLevel { get; set; }
public string? SapCompetitiveIBase { get; set; }
//Agilent-specific Properties:
public uint SapContactNumber { get; set; }
public DateTime SapContactCreationDate { get; set; } = DateTime.Now;
public DateTime SapContactModifiedDate { get; set; } = DateTime.Now;
public string? SapJobFunction { get; set; }
public string? SapProductInterest { get; set; }
public string? SapApplicationInterest { get; set; }
public string? SapJobLevel { get; set; }
public string? SapCompetitiveIBase { get; set; }
//metadata:
public DateTime DataCreationDate { get; set; } = DateTime.Now;
public DateTime DataModificationDate { get; set; } = DateTime.Now;
public DateTime DataValidFrom { get; set; } = DateTime.Now;
public DateTime DataValidUntil { get; set; } = DateTime.MaxValue;
public string DataModificationByUser { get; set; } = "Gremlin_BlazorServer";
public uint DataVersionNumber { get; set; } = 1;
public string? DataVersionComment { get; set; }
public string DataStatus { get; set; } = "Active";
//metadata:
public DateTime DataCreationDate { get; set; } = DateTime.Now;
public DateTime DataModificationDate { get; set; } = DateTime.Now;
public DateTime DataValidFrom { get; set; } = DateTime.Now;
public DateTime DataValidUntil { get; set; } = DateTime.MaxValue;
public string DataModificationByUser { get; set; } = "Gremlin_BlazorServer";
public uint DataVersionNumber { get; set; } = 1;
public string? DataVersionComment { get; set; }
public string DataStatus { get; set; } = "Active";
}

@ -8,11 +8,12 @@ public class CustomDescription : IMetadata
public uint CustomDescriptionId { get; set; }
//foreign keys:
//public uint ProductId { get; set; }
public uint ProductId { get; set; }
public uint AccountId { get; set; }
public uint SupplierId { get; set; }
//navigation properties:
public IList<Product>? Products { get; set; }
public Product? Product { get; set; }
public Account? Supplier { get; set; }
public IList<LineItem>? LineItems { get; set; }

@ -2,42 +2,42 @@
public class LineItem : IMetadata
{
//primary key:
public uint LineItemId { get; set; }
//primary key:
public uint LineItemId { get; set; }
//foreign keys:
public uint QuoteId { get; set; }
public uint CustomDescriptionId { get; set; }
//foreign keys:
public uint QuoteId { get; set; }
public uint CustomDescriptionId { get; set; }
//navigation properties:
public Quote? Quote { get; set; }
public CustomDescription? CustomDescription { get; set; }
//navigation properties:
public Quote? Quote { get; set; }
public CustomDescription? CustomDescription { get; set; }
//class properties:
public ushort Position { get; set; }
public ushort Amount { get; set; }
public string? ProductNumber { get; set; }
public string? OptionNumber { get; set; }
public string? SapShortDescription { get; set; }
public string? SapLongDescription { get; set; }
public string? ProductLine { get; set; }
public decimal TotalDiscount { get; set; }
public decimal SalesDiscount { get; set; }
public decimal PromotionalDiscount { get; set; }
public decimal ContractualDiscount { get; set; }
public decimal DemoDiscount { get; set; }
public decimal ListPrice { get; set; }
public decimal ExtendedListPrice { get; set; }
public decimal NetPrice { get; set; }
public decimal Total { get; set; }
//class properties:
public ushort Position { get; set; }
public ushort Amount { get; set; }
public string? ProductNumber { get; set; }
public string? OptionNumber { get; set; }
public string? SapShortDescription { get; set; }
public string? SapLongDescription { get; set; }
public string? ProductLine { get; set; }
public decimal TotalDiscount { get; set; }
public decimal SalesDiscount { get; set; }
public decimal PromotionalDiscount { get; set; }
public decimal ContractualDiscount { get; set; }
public decimal DemoDiscount { get; set; }
public decimal ListPrice { get; set; }
public decimal ExtendedListPrice { get; set; }
public decimal NetPrice { get; set; }
public decimal Total { get; set; }
//metadata:
public DateTime DataCreationDate { get; set; } = DateTime.Now;
public string DataModificationByUser { get; set; } = "Gremlin_BlazorServer";
public DateTime DataModificationDate { get; set; } = DateTime.Now;
public string DataStatus { get; set; } = "Active";
public DateTime DataValidFrom { get; set; } = DateTime.Now;
public DateTime DataValidUntil { get; set; } = DateTime.MaxValue;
public string? DataVersionComment { get; set; }
public uint DataVersionNumber { get; set; }
//metadata:
public DateTime DataCreationDate { get; set; } = DateTime.Now;
public string DataModificationByUser { get; set; } = "Gremlin_BlazorServer";
public DateTime DataModificationDate { get; set; } = DateTime.Now;
public string DataStatus { get; set; } = "Active";
public DateTime DataValidFrom { get; set; } = DateTime.Now;
public DateTime DataValidUntil { get; set; } = DateTime.MaxValue;
public string? DataVersionComment { get; set; }
public uint DataVersionNumber { get; set; }
}

@ -2,37 +2,36 @@
public class Product : IMetadata
{
//primary key:
public uint ProductId { get; set; }
//primary key:
public uint ProductId { get; set; }
//navigation properties:
public CustomDescription? CustomDescription { get; set; }
public ProductLine? ProductLine { get; set; }
//navigation properties:
public ProductLine? ProductLine { get; set; }
public CustomDescription CustomDescription { get; set; }
//foreign keys
public uint CustomDescriptionId { get; set; }
public string? ProductLineCode { get; set; }
//foreign keys
public string? ProductLineCode { get; set; }
//Agilent-specific properties:
public string? ProductNumber { get; set; }
public string? OptionNumber { get; set; }
public string? SapShortDescription { get; set; }
public string? SapLongDescription { get; set; }
public float Weight { get; set; }
public string? ProductStatus { get; set; }
public DateTime IntroductionDate { get; set; } = DateTime.Now;
public decimal ListPrice { get; set; }
public bool HasBreakPrices { get; set; }
public int BreakRangeFrom { get; set; }
public int BreakRangeTo { get; set; }
//Agilent-specific properties:
public string? ProductNumber { get; set; }
public string? OptionNumber { get; set; }
public string? SapShortDescription { get; set; }
public string? SapLongDescription { get; set; }
public float Weight { get; set; }
public string? ProductStatus { get; set; }
public DateTime IntroductionDate { get; set; } = DateTime.Now;
public decimal ListPrice { get; set; }
public bool HasBreakPrices { get; set; }
public int BreakRangeFrom { get; set; }
public int BreakRangeTo { get; set; }
//metadata:
public DateTime DataCreationDate { get; set; } = DateTime.Now;
public DateTime DataModificationDate { get; set; } = DateTime.Now;
public DateTime DataValidFrom { get; set; } = DateTime.Now;
public DateTime DataValidUntil { get; set; } = DateTime.MaxValue;
public string DataModificationByUser { get; set; } = "Gremlin_BlazorServer";
public uint DataVersionNumber { get; set; }
public string? DataVersionComment { get; set; }
public string DataStatus { get; set; } = "Active";
//metadata:
public DateTime DataCreationDate { get; set; } = DateTime.Now;
public DateTime DataModificationDate { get; set; } = DateTime.Now;
public DateTime DataValidFrom { get; set; } = DateTime.Now;
public DateTime DataValidUntil { get; set; } = DateTime.MaxValue;
public string DataModificationByUser { get; set; } = "Gremlin_BlazorServer";
public uint DataVersionNumber { get; set; }
public string? DataVersionComment { get; set; }
public string DataStatus { get; set; } = "Active";
}

@ -2,53 +2,55 @@
public class Quote : IMetadata
{
//primary key:
public uint QuoteId { get; set; }
//primary key:
public uint QuoteId { get; set; }
//foreign keys:
public uint ContactId { get; set; }
//foreign keys:
public uint RecipientId { get; set; }
public uint SalesRepId { get; set; }
//navigation properties:
public Contact? Recipient { get; set; }
public IList<LineItem>? LineItems { get; set; }
//navigation properties:
public Contact Recipient { get; set; } = new() { Account = new() };
public Contact SalesRep { get; set; } = new() { Account = new() };
public IList<LineItem>? LineItems { get; set; }
//class properties:
public Contact? SalesRep { get; set; }
public string? QuotationNumber { get; set; }
public DateTime QuotationDate { get; set; } = DateTime.Now;
public DateTime ValidUntil { get; set; } = DateTime.Now.AddDays(60);
public byte ValidFor { get; set; } = 60;
public decimal TotalListprice { get; set; }
public decimal TotalDiscount { get; set; }
public decimal TotalNet { get; set; }
public float Vat { get; set; } = 19f;
public decimal TotalGross { get; set; }
public bool QuoteContains3Pp { get; set; }
public bool QuoteContainsRb { get; set; }
public string? QuoteTemplate { get; set; }
public int Warranty { get; set; } = 12;
public decimal TotalFreightOnly { get; set; }
public decimal TotalFreight { get; set; }
public decimal TotalVat { get; set; }
public decimal Freight { get; set; } = 3;
public bool IsPriceInformation { get; set; }
public bool ShowSinglePrices { get; set; } = true;
public bool ShowDiscounts { get; set; } = true;
public bool ShowBrutto { get; set; } = true;
public string? QuoteDescription { get; set; }
public string? Tex { get; set; }
public string? Description { get; set; }
public string? Path { get; set; }
//new properties
//class properties:
public string? QuotationNumber { get; set; }
public DateTime QuotationDate { get; set; } = DateTime.Now;
public DateTime ValidUntil { get; set; } = DateTime.Now.AddDays(60);
public byte ValidFor { get; set; } = 60;
public decimal TotalListprice { get; set; }
public decimal TotalDiscount { get; set; }
public decimal TotalNet { get; set; }
public float Vat { get; set; } = 19f;
public decimal TotalGross { get; set; }
public bool QuoteContains3Pp { get; set; }
public bool QuoteContainsRb { get; set; }
public string? QuoteTemplate { get; set; }
public int Warranty { get; set; } = 12;
public decimal TotalFreightOnly { get; set; }
public decimal TotalFreight { get; set; }
public decimal TotalVat { get; set; }
public decimal Freight { get; set; } = 3;
public bool IsPriceInformation { get; set; }
public bool ShowSinglePrices { get; set; } = true;
public bool ShowDiscounts { get; set; } = true;
public bool ShowBrutto { get; set; } = true;
public string? QuoteDescription { get; set; }
public string? Tex { get; set; }
public string? Description { get; set; }
public string? Path { get; set; }
//metadata:
public DateTime DataCreationDate { get; set; } = DateTime.Now;
public string DataModificationByUser { get; set; } = "Gremlin_BlazorServer";
public DateTime DataModificationDate { get; set; } = DateTime.Now;
public string DataStatus { get; set; } = "Active";
public DateTime DataValidFrom { get; set; } = DateTime.Now;
public DateTime DataValidUntil { get; set; } = DateTime.MaxValue;
public string? DataVersionComment { get; set; }
public uint DataVersionNumber { get; set; }
//new properties
//metadata:
public DateTime DataCreationDate { get; set; } = DateTime.Now;
public string DataModificationByUser { get; set; } = "Gremlin_BlazorServer";
public DateTime DataModificationDate { get; set; } = DateTime.Now;
public string DataStatus { get; set; } = "Active";
public DateTime DataValidFrom { get; set; } = DateTime.Now;
public DateTime DataValidUntil { get; set; } = DateTime.MaxValue;
public string? DataVersionComment { get; set; }
public uint DataVersionNumber { get; set; }
}

@ -1,106 +1,124 @@
using System.Globalization;
using System.Security.Claims;
using Blazorise;
using Blazorise.DataGrid;
using Gremlin_BlazorServer.Data.EntityClasses;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using System.Globalization;
using System.Security.Claims;
namespace Gremlin_BlazorServer.Pages;
public partial class Contacts {
[CascadingParameter]
private Task<AuthenticationState>? authenticationStateTask { get; set; }
public partial class Contacts
{
[CascadingParameter]
private Task<AuthenticationState>? authenticationStateTask { get; set; }
private IList<Contact>? contacts;
private Contact? selectedContact;
private readonly List<Contact>? selectedContacts;
private Quote? selectedQuote;
private readonly CultureInfo cultureInfo = new("de-DE");
private readonly int totalContacts;
protected override async Task OnInitializedAsync()
{
if (authenticationStateTask != null)
{
ClaimsPrincipal user = (await authenticationStateTask).User;
if (user.Identity is { IsAuthenticated: true })
{
contacts = await genericController.GetAllAsync<Contact>();
}
}
private IList<Contact>? contacts;
private Contact? selectedContact;
private readonly List<Contact>? selectedContacts;
private Quote? selectedQuote;
private readonly CultureInfo cultureInfo = new("de-DE");
private readonly int totalContacts;
protected override async Task OnInitializedAsync() {
if (authenticationStateTask != null) {
ClaimsPrincipal user = (await authenticationStateTask).User;
if (user.Identity is { IsAuthenticated: true }) {
contacts = await genericController.GetAllAsync<Contact>();
}
await base.OnInitializedAsync();
}
await base.OnInitializedAsync();
}
private async Task OnSelectedContactChanged(Contact _selectedContact)
{
if (_selectedContact != null)
{
selectedContact = _selectedContact;
selectedContact.Quotes = await genericController.GetAllAsync<Quote>(q => q.RecipientId.Equals(selectedContact.ContactId));
}
private async Task OnSelectedContactChanged(Contact _selectedContact) {
if (_selectedContact != null) {
selectedContact = _selectedContact;
selectedContact.Quotes = await genericController.GetAllAsync<Quote>(q => q.ContactId.Equals(selectedContact.ContactId));
return;
}
return;
}
private async Task OnSelectedQuoteChanged(Quote _selectedQuote)
{
if (_selectedQuote != null)
{
selectedQuote = _selectedQuote;
selectedQuote.LineItems = await genericController.GetAllAsync<LineItem>(lI => lI.QuoteId.Equals(selectedQuote.QuoteId));
}
private async Task OnSelectedQuoteChanged(Quote _selectedQuote) {
if (_selectedQuote != null) {
selectedQuote = _selectedQuote;
selectedQuote.LineItems = await genericController.GetAllAsync<LineItem>(lI => lI.QuoteId.Equals(selectedQuote.QuoteId));
return;
}
return;
}
private async Task OnRowInsertedAsync(SavedRowItem<Contact, Dictionary<string, object>> contact)
{
Contact newContact = await ResolveContactAsync(contact.Item);
if (newContact.Account == null)
return;
int count = await genericController.InsertAsync(newContact);
Console.WriteLine($"Inserted {count} properties for new contact {newContact.ContactId}: {newContact.FirstName} {newContact.LastName}.");
}
private async Task OnRowInsertedAsync(SavedRowItem<Contact, Dictionary<string, object>> contact) {
Contact newContact = await ResolveContactAsync(contact.Item);
if (newContact.Account == null)
return;
int count = await genericController.InsertAsync(newContact);
Console.WriteLine($"Inserted {count} properties for new contact {newContact.ContactId}: {newContact.FirstName} {newContact.LastName}.");
}
private async Task OnRowUpdatedAsync(SavedRowItem<Contact, Dictionary<string, object>> contact)
{
Contact newContact = await ResolveContactAsync(contact.Item);
if (newContact.Account == null)
return;
int count = await genericController.UpdateAsync(contact.Item);
Console.WriteLine($"Updated {count} properties in contact {newContact.ContactId}: {newContact.FirstName} {newContact.LastName}.");
}
private async Task OnRowUpdatedAsync(SavedRowItem<Contact, Dictionary<string, object>> contact) {
Contact newContact = await ResolveContactAsync(contact.Item);
if (newContact.Account == null)
return;
int count = await genericController.UpdateAsync(contact.Item);
Console.WriteLine($"Updated {count} properties in contact {newContact.ContactId}: {newContact.FirstName} {newContact.LastName}.");
}
private async Task OnRowRemovedAsync(Contact contact)
{
int count = await genericController.RemoveAsync(contact);
Console.WriteLine($"Removed {count} properties and contact {contact.ContactId}: {contact.FirstName} {contact.LastName}.");
}
private async Task OnRowRemovedAsync(Contact contact) {
int count = await genericController.RemoveAsync(contact);
Console.WriteLine($"Removed {count} properties and contact {contact.ContactId}: {contact.FirstName} {contact.LastName}.");
}
private async Task<Contact> ResolveContactAsync(Contact newContact)
{
newContact.Account = await genericController.GetAsync<Account>(a => a.AccountId.Equals(newContact.AccountId));
if (newContact.Account != null)
{
newContact.NoPhoneCalls = false;
newContact.EmailBounced = false;
newContact.NoHardcopyMailing = false;
newContact.ValidatedContact = true;
newContact.DataModificationByUser = "Gremlin Blazor Server GUI";
newContact.DataVersionNumber++;
}
else
{
Console.WriteLine($"No account with AccountId {newContact.AccountId} found!");
}
private async Task<Contact> ResolveContactAsync(Contact newContact) {
newContact.Account = await genericController.GetAsync<Account>(a => a.AccountId.Equals(newContact.AccountId));
if (newContact.Account != null) {
newContact.NoPhoneCalls = false;
newContact.EmailBounced = false;
newContact.NoHardcopyMailing = false;
newContact.ValidatedContact = true;
newContact.DataModificationByUser = "Gremlin Blazor Server GUI";
newContact.DataVersionNumber++;
}
else {
Console.WriteLine($"No account with AccountId {newContact.AccountId} found!");
return newContact;
}
return newContact;
}
private async Task OnImportContacts(FileChangedEventArgs fileChangedEventArgs)
{
try
{
foreach (IFileEntry? file in fileChangedEventArgs.Files)
{
using MemoryStream stream = new();
await file.WriteToStreamAsync(stream);
_ = stream.Seek(0, SeekOrigin.Begin);
using StreamReader reader = new(stream);
string fileContent = await reader.ReadToEndAsync();
_ = await genericImporter.ImportCsvAsync<Account>(fileContent);
}
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
private async Task OnImportContacts(FileChangedEventArgs fileChangedEventArgs) {
try {
foreach (IFileEntry? file in fileChangedEventArgs.Files) {
using MemoryStream stream = new();
await file.WriteToStreamAsync(stream);
_ = stream.Seek(0, SeekOrigin.Begin);
using StreamReader reader = new(stream);
string fileContent = await reader.ReadToEndAsync();
_ = await genericImporter.ImportCsvAsync<Account>(fileContent);
}
StateHasChanged();
return;
}
catch (Exception exception) {
Console.WriteLine(exception.Message);
}
StateHasChanged();
return;
}
}

@ -13,7 +13,11 @@ namespace Gremlin_BlazorServer.Pages
[Parameter] public List<CustomDescription> SuggestedCustomDescriptions { get; set; }
private CustomDescription? selectedSuggestedCustomDescription;
private async Task OnSave() => await ModalService.Hide();
private async Task OnSave()
{
//TODO EventCallback to save new CD to DB
await ModalService.Hide();
}
private void OnSelectedSuggestedCustomDescription(CustomDescription _selectedSuggestedCustomDescriptions)
{

@ -54,7 +54,7 @@
</Paragraph>
</Div>
@if (selectedProduct?.CustomDescription != null) {
@* @if (selectedProduct?.CustomDescription != null) {
<Div Margin="Margin.Is3"
Border="Border.Dark.OnAll"
Padding="Padding.Is3"
@ -101,7 +101,7 @@
</Field>
</Paragraph>
</Div>
}
} *@
</Authorized>
<NotAuthorized>
<Div Margin="Margin.Is3"

@ -22,7 +22,7 @@
<Paragraph>
<DataGrid TItem="Contact"
Data="@contacts"
SelectedRow="@selectedContact"
SelectedRow="@selectedContact"
SelectedRowChanged="@OnSelectedContactChanged"
Bordered Hoverable Filterable Striped ShowPager Responsive Sortable>
@ -39,139 +39,142 @@
</Paragraph>
</Div>
<Div Margin="Margin.Is3"
Border="Border.Dark.OnAll"
Padding="Padding.Is3"
style="box-shadow: 10px 10px #343A40">
<Heading Size="HeadingSize.Is5">Quote Details</Heading>
<Paragraph>
<Row>
<Column ColumnSize="ColumnSize.Is4">
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Angebotsname</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit Text="@quote.Description" TextChanged="@OnDescriptionChanged"/>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Angebotsnummer</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit Text="@quote.QuotationNumber" TextChanged="@OnQuotationNumberChanged"/>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Angebotspfad</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.Path"/>"
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Gewährleistung (Monate)</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit Text="@quote.Warranty.ToString()" TextChanged="@OnWarrantyChanged"/>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Angebotsgültigkeit (Tage)</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit Text="@quote.ValidFor.ToString()" TextChanged="@OnValidForChanged"/>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Mehrwertsteuer (%)</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit Text="@quote.Vat.ToString(CultureInfo.CurrentCulture)" TextChanged="@OnVATChanged"/>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Versandkosten (%)</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit Text="@quote.Freight.ToString(CultureInfo.CurrentCulture)"/>
</FieldBody>
</Field>
</Column>
@if (quote != null)
{
<Div Margin="Margin.Is3"
Border="Border.Dark.OnAll"
Padding="Padding.Is3"
style="box-shadow: 10px 10px #343A40">
@if (quote.Recipient != null && quote.Recipient.Account != null)
{
<Column ColumnSize="ColumnSize.Is3">
<Heading Size="HeadingSize.Is5">Quote Details</Heading>
<Paragraph>
<Row>
<Column ColumnSize="ColumnSize.Is4">
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">FirstName</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">@quote.Recipient.FirstName</FieldBody>
<FieldLabel ColumnSize="ColumnSize.Is4">Angebotsname</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit Text="@quote.Description" TextChanged="@OnDescriptionChanged"/>
</FieldBody>
</Field>
<Field >
<FieldLabel ColumnSize="ColumnSize.Is4">LastName</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">@quote.Recipient.LastName</FieldBody>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Angebotsnummer</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit Text="@quote.QuotationNumber" TextChanged="@OnQuotationNumberChanged"/>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Angebotspfad</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.Path"/>"
</FieldBody>
</Field>
<Field >
<FieldLabel ColumnSize="ColumnSize.Is4">AccountName</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">@quote.Recipient.Account.AccountName</FieldBody>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Gewährleistung (Monate)</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit Text="@quote.Warranty.ToString()" TextChanged="@OnWarrantyChanged"/>
</FieldBody>
</Field>
<Field >
<FieldLabel ColumnSize="ColumnSize.Is4">Street</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">@quote.Recipient.Account.Street</FieldBody>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Angebotsgültigkeit (Tage)</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit Text="@quote.ValidFor.ToString()" TextChanged="@OnValidForChanged"/>
</FieldBody>
</Field>
<Field >
<FieldLabel ColumnSize="ColumnSize.Is4">Zip</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">@quote.Recipient.Account.Zip.ToString()</FieldBody>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Mehrwertsteuer (%)</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit Text="@quote.Vat.ToString(CultureInfo.CurrentCulture)" TextChanged="@OnVATChanged"/>
</FieldBody>
</Field>
<Field >
<FieldLabel ColumnSize="ColumnSize.Is4">City</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">@quote.Recipient.Account.City</FieldBody>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Versandkosten (%)</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit Text="@quote.Freight.ToString(CultureInfo.CurrentCulture)"/>
</FieldBody>
</Field>
</Column>
}
<Column ColumnSize="ColumnSize.Is2">
<Check TValue="bool" Checked="@quote.IsPriceInformation" CheckedChanged="@OnIsPriceInformationChanged">Preisinformation</Check>
<Check TValue="bool" Checked="@quote.ShowBrutto" CheckedChanged="@OnShowBruttoChanged">Bruttopreise anzeigen</Check>
<Check TValue="bool" Checked="@quote.ShowSinglePrices" CheckedChanged="@OnShowSinglePricesChanged">Einzelpreise ausweisen</Check>
<Check TValue="bool" Checked="@quote.ShowDiscounts" CheckedChanged="@OnShowDiscountsChanged">Discounts ausweisen</Check>
</Column>
@if (quote != null && quote.Recipient != null && quote.Recipient.Account != null)
{
<Column ColumnSize="ColumnSize.Is3">
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">FirstName</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">@quote.Recipient.FirstName</FieldBody>
</Field>
<Field >
<FieldLabel ColumnSize="ColumnSize.Is4">LastName</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">@quote.Recipient.LastName</FieldBody>
</Field>
<Field >
<FieldLabel ColumnSize="ColumnSize.Is4">AccountName</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">@quote.Recipient.Account.AccountName</FieldBody>
</Field>
<Field >
<FieldLabel ColumnSize="ColumnSize.Is4">Street</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">@quote.Recipient.Account.Street</FieldBody>
</Field>
<Field >
<FieldLabel ColumnSize="ColumnSize.Is4">Zip</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">@quote.Recipient.Account.Zip.ToString()</FieldBody>
</Field>
<Field >
<FieldLabel ColumnSize="ColumnSize.Is4">City</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">@quote.Recipient.Account.City</FieldBody>
</Field>
</Column>
}
<Column ColumnSize="ColumnSize.Is3">
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Listenpreis netto</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.TotalListprice.ToString("C", CultureInfo.CurrentCulture)"></TextEdit>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Summe netto</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.TotalNet.ToString("C", CultureInfo.CurrentCulture)"></TextEdit>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Versandkosten</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.TotalFreightOnly.ToString("C", CultureInfo.CurrentCulture)"></TextEdit>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Gesamtsumme netto</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.TotalFreight.ToString("C", CultureInfo.CurrentCulture)"></TextEdit>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Mehrwertsteuer</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.TotalVat.ToString("C", CultureInfo.CurrentCulture)"></TextEdit>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Gesamtsumme brutto</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.TotalGross.ToString("C", CultureInfo.CurrentCulture)"></TextEdit>
</FieldBody>
</Field>
</Column>
</Row>
</Paragraph>
</Div>
<Column ColumnSize="ColumnSize.Is2">
<Check TValue="bool" Checked="@quote.IsPriceInformation" CheckedChanged="@OnIsPriceInformationChanged">Preisinformation</Check>
<Check TValue="bool" Checked="@quote.ShowBrutto" CheckedChanged="@OnShowBruttoChanged">Bruttopreise anzeigen</Check>
<Check TValue="bool" Checked="@quote.ShowSinglePrices" CheckedChanged="@OnShowSinglePricesChanged">Einzelpreise ausweisen</Check>
<Check TValue="bool" Checked="@quote.ShowDiscounts" CheckedChanged="@OnShowDiscountsChanged">Discounts ausweisen</Check>
</Column>
<Column ColumnSize="ColumnSize.Is3">
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Listenpreis netto</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.TotalListprice.ToString("C", CultureInfo.CurrentCulture)"></TextEdit>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Summe netto</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.TotalNet.ToString("C", CultureInfo.CurrentCulture)"></TextEdit>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Versandkosten</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.TotalFreightOnly.ToString("C", CultureInfo.CurrentCulture)"></TextEdit>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Gesamtsumme netto</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.TotalFreight.ToString("C", CultureInfo.CurrentCulture)"></TextEdit>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Mehrwertsteuer</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.TotalVat.ToString("C", CultureInfo.CurrentCulture)"></TextEdit>
</FieldBody>
</Field>
<Field>
<FieldLabel ColumnSize="ColumnSize.Is4">Gesamtsumme brutto</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<TextEdit ReadOnly Text="@quote.TotalGross.ToString("C", CultureInfo.CurrentCulture)"></TextEdit>
</FieldBody>
</Field>
</Column>
</Row>
</Paragraph>
</Div>
}
@if (quote.LineItems != null) {
@if (quote != null && quote.LineItems != null) {
<Div Margin="Margin.Is3"
Border="Border.Dark.OnAll"
Padding="Padding.Is3"
@ -230,7 +233,7 @@
}
}
@if (quote.LineItems == null) {
@if (quote != null && quote.LineItems == null) {
<Div Margin="Margin.Is3"
Border="Border.Dark.OnAll"
Padding="Padding.Is3"
@ -275,7 +278,7 @@
</Div>
}
@if (quote.Tex != null && debug) {
@if (quote != null && quote.Tex != null && debug) {
<Div Margin="Margin.Is3"
Border="Border.Dark.OnAll"
Padding="Padding.Is3"

@ -1,243 +1,262 @@
using System.Diagnostics;
using System.Globalization;
using System.Security.Claims;
using System.Text;
using Blazorise;
using Gremlin_BlazorServer.Data.EntityClasses;
using Gremlin_BlazorServer.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.JSInterop;
using System.Globalization;
using System.Security.Claims;
using System.Text;
namespace Gremlin_BlazorServer.Pages.Quotes;
public partial class QuoteAdd {
[CascadingParameter] private Task<AuthenticationState>? AuthenticationStateTask { get; set; }
[Inject] public IModalService? ModalService { get; set; }
private IList<Contact>? contacts;
private Quote quote = new();
private Contact? selectedContact;
private readonly CultureInfo cultureInfo = new("de-DE");
private bool pdfNotReady = true;
private bool isCreatingPdf;
private bool texNotReady = true;
private bool isCreatingTex;
private bool lineItemsNotReady = true;
private string? url;
private readonly bool debug;
private List<CustomDescription>? suggestedCustomDescriptions;
private CustomDescription? newCustomDescription;
private LineItem? selectedLineItem;
public Task ShowCustomDescriptionModal() =>
ModalService.Show<CustomDescriptionModal>(builder => {
builder.Add(parameter => parameter.CustomDescription, newCustomDescription);
builder.Add(parameter => parameter.SuggestedCustomDescriptions, suggestedCustomDescriptions);
});
protected override async Task OnParametersSetAsync() {
if (AuthenticationStateTask != null) {
ClaimsPrincipal user = (await AuthenticationStateTask).User;
if (user.Identity is { IsAuthenticated: true }) {
await ApplicationLoadingIndicatorService.Show();
contacts = await genericController.GetAllAsync<Contact>();
await ApplicationLoadingIndicatorService.Hide();
quote = await GenerateNewQuote(quote, "Woitschetzki");
}
public partial class QuoteAdd
{
[CascadingParameter] private Task<AuthenticationState>? AuthenticationStateTask { get; set; }
[Inject] public IModalService? ModalService { get; set; }
private IList<Contact>? contacts;
private Quote? quote;
private Contact? selectedContact;
private readonly CultureInfo cultureInfo = new("de-DE");
private bool pdfNotReady = true;
private bool isCreatingPdf;
private bool texNotReady = true;
private bool isCreatingTex;
private bool lineItemsNotReady = true;
private string? url;
private readonly bool debug;
private List<CustomDescription>? suggestedCustomDescriptions;
private CustomDescription? newCustomDescription;
private LineItem? selectedLineItem;
public Task ShowCustomDescriptionModal() =>
ModalService.Show<CustomDescriptionModal>(builder =>
{
builder.Add(parameter => parameter.CustomDescription, newCustomDescription);
builder.Add(parameter => parameter.SuggestedCustomDescriptions, suggestedCustomDescriptions);
});
protected override async Task OnParametersSetAsync()
{
if (AuthenticationStateTask != null)
{
ClaimsPrincipal user = (await AuthenticationStateTask).User;
if (user.Identity is { IsAuthenticated: true })
{
await ApplicationLoadingIndicatorService.Show();
contacts = await genericController.GetAllAsync<Contact>();
await ApplicationLoadingIndicatorService.Hide();
quote = await GenerateNewQuote(quote, "Woitschetzki");
}
}
await base.OnInitializedAsync();
}
private async Task<Quote> GenerateNewQuote(Quote? _quote, string salesRepLastName)
{
if (_quote == null)
{
_quote = new();
await genericController.InsertAsync(_quote);
}
_quote.SalesRep = await genericController.GetAsync<Contact>(c => c.LastName == salesRepLastName);
if (_quote.SalesRep != null)
//Read Account seperatly to avoid new creation of account
_quote.SalesRep.Account = await genericController.GetAsync<Account>(a => a.AccountId == _quote.SalesRep.AccountId);
Quote? lastQuote = genericController.GetLast<Quote>();
_quote.QuoteId = lastQuote != null ? lastQuote.QuoteId + 1 : 1;
_quote.QuotationNumber = _quote.SalesRep != null ? _quote.SalesRep.LastName switch
{
"Woitschetzki" => $"DE-83PE89-{DateTime.Now:My}-{_quote.QuoteId}",
"Welsch" => $"DE-83RE32-{DateTime.Now:My}-{_quote.QuoteId}",
_ => $"DE-XXYYXX-{DateTime.Now:My}-{_quote.QuoteId}"
}
: $"DE-XXYYXX-{DateTime.Now:My}-{_quote.QuoteId}";
_quote.Description = "Gerät";
TryToSaveQuote(_quote);
return _quote;
}
private async Task TryToSaveQuote(Quote _quote)
{
if (await genericController.UpdateAsync(_quote) > 0)
Debug.WriteLine("Speichern der Quote erfolgreich.");
else
Debug.WriteLine("Fehler beim Speichern der Quote!");
return;
}
await base.OnInitializedAsync();
}
private async Task<Quote> GenerateNewQuote(Quote _quote, string salesRepLastName) {
if (_quote == null)
return new();
_quote.SalesRep = await genericController.GetAsync<Contact>(
c => c.LastName.Equals(salesRepLastName),
"Account"
);
Quote? lastQuote = genericController.GetLast<Quote>();
_quote.QuoteId = lastQuote != null ? lastQuote.QuoteId + 1 : 1;
_quote.QuotationNumber =
_quote.SalesRep != null
? _quote.SalesRep.LastName switch {
"Woitschetzki" => $"DE-83PE89-{DateTime.Now:My}-{_quote.QuoteId}",
"Welsch" => $"DE-83RE32-{DateTime.Now:My}-{_quote.QuoteId}",
_ => $"DE-XXYYXX-{DateTime.Now:My}-{_quote.QuoteId}"
private async Task SelectQuoteOnChanged(FileChangedEventArgs e)
{
try
{
foreach (IFileEntry? file in e.Files)
{
using MemoryStream stream = new();
await file.WriteToStreamAsync(stream);
_ = stream.Seek(0, SeekOrigin.Begin);
using StreamReader reader = new(stream);
string fileContent = await reader.ReadToEndAsync();
quote = QuoteHandling.ReadLineItems(quote, fileContent);
if (quote.Recipient?.Account?.AccountName != null) quote = hostingService.SetPath(quote);
if (quote.LineItems == null) return;
FileService.WriteQuoteToTsv(fileContent, quote);
//TODO Load all relevant CustomDescriptions upfront
for (int i = 0; i < quote.LineItems.Count; i++)
{
newCustomDescription = await genericController.GetAsync<CustomDescription>(
newCustomDescription => newCustomDescription.ProductNumber.Equals(quote.LineItems[i].ProductNumber, StringComparison.Ordinal)
&& newCustomDescription.OptionNumber.Equals(quote.LineItems[i].OptionNumber, StringComparison.Ordinal)
);
if (newCustomDescription == null)
{
Console.WriteLine($"Keine CustomDescription für {quote.LineItems[i].ProductNumber}#{quote.LineItems[i].OptionNumber} verfügbar!");
suggestedCustomDescriptions = await SuggestCustomDescriptions(quote.LineItems[i]);
newCustomDescription = new()
{
ProductNumber = quote.LineItems[i].ProductNumber,
OptionNumber = quote.LineItems[i].OptionNumber,
Heading = quote.LineItems[i].SapShortDescription,
DescriptionText = quote.LineItems[i].SapLongDescription
};
//Show windows to edit new cD
await ShowCustomDescriptionModal();
//TODO need to wait for modal!
//Insert new CustomDescription to db
newCustomDescription.AccountId = 1;
_ = await genericController.InsertAsync(newCustomDescription);
}
//read cD form db to cleanup ChangeTracker
quote.LineItems[i].CustomDescription = await genericController.GetAsync<CustomDescription>(cD => cD.CustomDescriptionId.Equals(newCustomDescription.CustomDescriptionId));
}
}
: $"DE-XXYYXX-{DateTime.Now:My}-{_quote.QuoteId}";
_quote.Description = "Gerät";
return _quote;
}
private async Task SelectQuoteOnChanged(FileChangedEventArgs e) {
try {
foreach (IFileEntry? file in e.Files) {
using MemoryStream stream = new();
await file.WriteToStreamAsync(stream);
_ = stream.Seek(0, SeekOrigin.Begin);
using StreamReader reader = new(stream);
string fileContent = await reader.ReadToEndAsync();
quote = QuoteHandling.ReadLineItems(quote, fileContent);
if (quote.Recipient?.Account?.AccountName != null) quote = hostingService.SetPath(quote);
if (quote.LineItems == null) return;
FileService.WriteQuoteToTsv(fileContent, quote);
//TODO Load all relevant CustomDescriptions upfront
for (int i = 0; i < quote.LineItems.Count; i++) {
newCustomDescription = await genericController.GetAsync<CustomDescription>(
newCustomDescription =>
newCustomDescription.ProductNumber.Equals(
quote.LineItems[i].ProductNumber,
StringComparison.Ordinal
)
&& newCustomDescription.OptionNumber.Equals(
quote.LineItems[i].OptionNumber,
StringComparison.Ordinal
)
);
if (newCustomDescription == null) {
Console.WriteLine(
$"Keine CustomDescription für {quote.LineItems[i].ProductNumber}#{quote.LineItems[i].OptionNumber} verfügbar!"
);
suggestedCustomDescriptions = await SuggestCustomDescriptions(
quote.LineItems[i]
);
newCustomDescription = new() {
ProductNumber = quote.LineItems[i].ProductNumber,
OptionNumber = quote.LineItems[i].OptionNumber,
Heading = quote.LineItems[i].SapShortDescription,
DescriptionText = quote.LineItems[i].SapLongDescription
};
//Show windows to edit new cD
await ShowCustomDescriptionModal();
//TODO need to wait for modal!
//Insert new CustomDescription to db
newCustomDescription.AccountId = 1;
_ = await genericController.InsertAsync(newCustomDescription);
}
//read cD form db to cleanup ChangeTracker
quote.LineItems[i].CustomDescription =
await genericController.GetAsync<CustomDescription>(cD => cD.CustomDescriptionId == newCustomDescription.CustomDescriptionId);
}
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
finally
{
if (quote.Recipient != null) lineItemsNotReady = false;
StateHasChanged();
}
}
catch (Exception exc) {
Console.WriteLine(exc.Message);
private async Task<List<CustomDescription>?> SuggestCustomDescriptions(LineItem lineItem)
{
//IList<CustomDescription>? fromProductNumber = await genericController.GetAllAsync<CustomDescription>(cD => cD.ProductNumber.Equals(lineItem.ProductNumber, StringComparison.Ordinal));
IList<CustomDescription>? fromOptionNumber = new List<CustomDescription>();
if (lineItem.OptionNumber != "")
fromOptionNumber = await genericController.GetAllAsync<CustomDescription>(cD => cD.OptionNumber.Equals(lineItem.OptionNumber, StringComparison.Ordinal));
//if (fromOptionNumber == null && fromProductNumber == null) return null;
//if (fromOptionNumber == null) return fromProductNumber.ToList();
//if (fromProductNumber == null) return fromOptionNumber.ToList();
//return fromProductNumber.Union(fromOptionNumber).ToList();
return fromOptionNumber.ToList();
}
finally {
if (quote.Recipient != null)
lineItemsNotReady = false;
StateHasChanged();
private static void SelectQuoteOnWritten(FileWrittenEventArgs e) =>
Console.WriteLine($"File: {e.File.Name} Position: {e.Position} Data: {Convert.ToBase64String(e.Data)}");
private static void SelectQuoteOnProgressed(FileProgressedEventArgs e) =>
Console.WriteLine($"File: {e.File.Name} Progress: {e.Percentage}");
private async Task OnSelectedContactChanged(Contact _selectedContact)
{
if (quote == null) return;
quote.Recipient = await genericController.GetAsync<Contact>(c => c.ContactId.Equals(_selectedContact.ContactId));
if (quote.Recipient != null)
//Read account seperatly to avoid new generation
quote.Recipient.Account = await genericController.GetAsync<Account>(a => a.AccountId.Equals(quote.Recipient.AccountId));
if (quote.LineItems != null && quote.Recipient != null && quote.Recipient.Account != null) lineItemsNotReady = false;
selectedContact = _selectedContact;
}
}
private async Task<List<CustomDescription>?> SuggestCustomDescriptions(LineItem lineItem) {
//IList<CustomDescription>? fromProductNumber = await genericController.GetAllAsync<CustomDescription>(cD => cD.ProductNumber.Equals(lineItem.ProductNumber, StringComparison.Ordinal));
IList<CustomDescription>? fromOptionNumber = new List<CustomDescription>();
if (lineItem.OptionNumber != "") {
fromOptionNumber = await genericController.GetAllAsync<CustomDescription>(
cD => cD.OptionNumber.Equals(lineItem.OptionNumber, StringComparison.Ordinal)
);
private async Task OnSave()
{
//HACK Try to avoid new generation of FKs
// quote.Recipient = new() { Account = new() };
// quote.SalesRep = new() { Account = new() };
// quote.LineItems = null;
if (await genericController.UpdateAsync(quote) > 0)
navigationManager.NavigateTo("Quotes/QuoteIndex");
}
//if (fromOptionNumber == null && fromProductNumber == null) return null;
//if (fromOptionNumber == null) return fromProductNumber.ToList();
//if (fromProductNumber == null) return fromOptionNumber.ToList();
//return fromProductNumber.Union(fromOptionNumber).ToList();
return fromOptionNumber.ToList();
}
private static void SelectQuoteOnWritten(FileWrittenEventArgs e) =>
Console.WriteLine(
$"File: {e.File.Name} Position: {e.Position} Data: {Convert.ToBase64String(e.Data)}"
);
private static void SelectQuoteOnProgressed(FileProgressedEventArgs e) =>
Console.WriteLine($"File: {e.File.Name} Progress: {e.Percentage}");
private async Task OnSelectedContactChanged(Contact _selectedContact) {
selectedContact = _selectedContact;
quote.Recipient = await genericController.GetAsync<Contact>(c => c.ContactId == _selectedContact.ContactId);
if (quote.Recipient != null)
quote.Recipient.Account = await genericController.GetAsync<Account>(a => a.AccountId.Equals(quote.Recipient.AccountId));
if (quote.LineItems != null && quote.Recipient != null)
lineItemsNotReady = false;
}
private async Task OnSave() {
//HACK remove something from quote to make save possible
// foreach (LineItem lineItem in quote.LineItems)
// {
// lineItem.CustomDescription = null;
// lineItem.CustomDescriptionId = 0;
// }
// quote.Recipient = null;
// quote.ContactId = 0;
if (await genericController.InsertAsync(quote) > 0)
navigationManager.NavigateTo("Quotes/QuoteIndex");
}
private async Task OnCreateTex() {
isCreatingTex = true;
StringBuilder? tex = await QuoteHandling.CreateTexAsync(quote);
if (tex == null)
return;
quote.Tex = tex.ToString();
if (quote.Tex == null)
return;
await FileService.WriteTexFile(quote);
isCreatingTex = false;
Console.WriteLine("Tex file succesfull created.");
texNotReady = false;
}
private async Task OnCreatePdf() {
isCreatingPdf = true;
if (await PdfService.CreatePdf(quote)) {
pdfNotReady = false;
isCreatingPdf = false;
Console.WriteLine("PDF successfull written.");
url = HostingService.GetPdfUrl(quote);
Console.WriteLine($"URL to PDF is {url}");
private async Task OnCreateTex()
{
isCreatingTex = true;
StringBuilder? tex = await QuoteHandling.CreateTexAsync(quote);
if (tex == null) return;
quote.Tex = tex.ToString();
if (quote.Tex == null) return;
await FileService.WriteTexFile(quote);
isCreatingTex = false;
Console.WriteLine("Tex file succesfull created.");
texNotReady = false;
}
private async Task OnCreatePdf()
{
isCreatingPdf = true;
if (await PdfService.CreatePdf(quote))
{
pdfNotReady = false;
isCreatingPdf = false;
Console.WriteLine("PDF successfull written.");
url = HostingService.GetPdfUrl(quote);
Console.WriteLine($"URL to PDF is {url}");
}
}
}
private void OnOpenPdfApp() => PdfService.OpenPdfWithOkular(quote);
private void OnOpenPdfApp() => PdfService.OpenPdfWithOkular(quote);
private async Task OnOpenPdfNewTab() =>
await jSRuntime.InvokeVoidAsync("OpenNewTab", $"quotes/{url}");
private async Task OnOpenPdfNewTab() =>
await jSRuntime.InvokeVoidAsync("OpenNewTab", $"quotes/{url}");
private void OnDescriptionChanged(string description) => quote.Description = description;
private void OnDescriptionChanged(string description) => quote.Description = description;
private void OnQuotationNumberChanged(string quotationNumber) =>
quote.QuotationNumber = quotationNumber;
private void OnQuotationNumberChanged(string quotationNumber) =>
quote.QuotationNumber = quotationNumber;
private void OnValidForChanged(string validFor) => quote.ValidFor = byte.Parse(validFor);
private void OnValidForChanged(string validFor) => quote.ValidFor = byte.Parse(validFor);
private void OnVATChanged(string vat) => quote.Vat = float.Parse(vat);
private void OnVATChanged(string vat) => quote.Vat = float.Parse(vat);
private void OnIsPriceInformationChanged(bool isPriceInformation) =>
quote.IsPriceInformation = isPriceInformation;
private void OnIsPriceInformationChanged(bool isPriceInformation) =>
quote.IsPriceInformation = isPriceInformation;
private void OnShowBruttoChanged(bool onShowBrutto) => quote.ShowBrutto = onShowBrutto;
private void OnShowBruttoChanged(bool onShowBrutto) => quote.ShowBrutto = onShowBrutto;
private void OnShowDiscountsChanged(bool showDiscount) => quote.ShowDiscounts = showDiscount;
private void OnShowDiscountsChanged(bool showDiscount) => quote.ShowDiscounts = showDiscount;
private void OnShowSinglePricesChanged(bool showSinglePrices) =>
quote.ShowSinglePrices = showSinglePrices;
private void OnShowSinglePricesChanged(bool showSinglePrices) =>
quote.ShowSinglePrices = showSinglePrices;
private void OnSelectedLineItemChanged(LineItem _selectedLineItem) =>
selectedLineItem = _selectedLineItem;
private void OnSelectedLineItemChanged(LineItem _selectedLineItem) =>
selectedLineItem = _selectedLineItem;
private void OnWarrantyChanged(string warranty) => quote.Warranty = int.Parse(warranty);
private void OnWarrantyChanged(string warranty) => quote.Warranty = int.Parse(warranty);
private void OnCancel() => navigationManager.NavigateTo("Quotes/QuoteIndex");
private void OnCancel() => navigationManager.NavigateTo("Quotes/QuoteIndex");
}

@ -1,48 +1,57 @@
using System.Globalization;
using System.Security.Claims;
using Gremlin_BlazorServer.Data.EntityClasses;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using System.Globalization;
using System.Security.Claims;
namespace Gremlin_BlazorServer.Pages.Quotes {
public partial class QuoteIndex {
[CascadingParameter]
private Task<AuthenticationState>? authenticationStateTask { get; set; }
namespace Gremlin_BlazorServer.Pages.Quotes
{
public partial class QuoteIndex
{
[CascadingParameter]
private Task<AuthenticationState>? authenticationStateTask { get; set; }
private IList<Quote>? quotes;
private Quote? selectedQuote;
private readonly CultureInfo cultureInfo = new("de-DE");
private string selectedTab = "details";
protected override async Task OnInitializedAsync() {
if (authenticationStateTask != null) {
ClaimsPrincipal user = (await authenticationStateTask).User;
if (user.Identity is { IsAuthenticated: true }) {
quotes = await genericController.GetAllAsync<Quote>();
}
}
private IList<Quote>? quotes;
private Quote? selectedQuote;
private readonly CultureInfo cultureInfo = new("de-DE");
private string selectedTab = "details";
protected override async Task OnInitializedAsync()
{
if (authenticationStateTask != null)
{
ClaimsPrincipal user = (await authenticationStateTask).User;
if (user.Identity is { IsAuthenticated: true })
{
quotes = await genericController.GetAllAsync<Quote>();
}
}
await base.OnInitializedAsync();
}
await base.OnInitializedAsync();
}
private async Task OnSelectedQuoteChanged(Quote _selectedQuote) {
selectedQuote = _selectedQuote;
selectedQuote.Recipient = await genericController.GetAsync<Contact>(c => c.ContactId.Equals(selectedQuote.ContactId));
if (selectedQuote.Recipient != null && selectedQuote != null) {
selectedQuote = await genericController.GetAsync<Quote>(c => c.QuoteId.Equals(_selectedQuote.QuoteId), "Recipient", "LineItems");
selectedQuote.Recipient.Account = await genericController.GetAsync<Account>(a => a.AccountId.Equals(selectedQuote.Recipient.AccountId));
}
private async Task OnSelectedQuoteChanged(Quote _selectedQuote)
{
selectedQuote = _selectedQuote;
selectedQuote.Recipient = await genericController.GetAsync<Contact>(c => c.ContactId.Equals(selectedQuote.RecipientId));
if (selectedQuote.Recipient != null && selectedQuote != null)
{
selectedQuote = await genericController.GetAsync<Quote>(c => c.QuoteId.Equals(_selectedQuote.QuoteId), "Recipient", "LineItems");
selectedQuote.Recipient.Account = await genericController.GetAsync<Account>(a => a.AccountId.Equals(selectedQuote.Recipient.AccountId));
}
//selectedQuote.LineItems = await genericController.GetAllAsync<LineItem>(lI => lI.Quote.Equals(selectedQuote));
return;
}
//selectedQuote.LineItems = await genericController.GetAllAsync<LineItem>(lI => lI.Quote.Equals(selectedQuote));
return;
}
private void OnCreateNewQuote() {
navigationManager.NavigateTo("Quotes/QuoteAdd");
}
private void OnCreateNewQuote()
{
navigationManager.NavigateTo("Quotes/QuoteAdd");
}
private Task OnSelectedTabChanged(string _selectedTab) {
selectedTab = _selectedTab;
return Task.CompletedTask;
private Task OnSelectedTabChanged(string _selectedTab)
{
selectedTab = _selectedTab;
return Task.CompletedTask;
}
}
}
}

@ -198,16 +198,13 @@ public class GenericController
}
}
public async Task<TResult?> GetAsync<TResult>(Predicate<TResult> search)
where TResult : class, IMetadata
public async Task<TResult?> GetAsync<TResult>(Predicate<TResult> search) where TResult : class, IMetadata
{
try
{
using (GremlinDb gremlinDb = new())
{
return await Task.Run(
() => gremlinDb.Set<TResult>().AsNoTracking().AsEnumerable().FirstOrDefault(t => search(t))
);
return await Task.Run(() => gremlinDb.Set<TResult>().AsEnumerable().FirstOrDefault(t => search(t)));
}
}
catch (Exception exception)
@ -217,19 +214,13 @@ public class GenericController
}
}
public TResult? Get<TResult>(Predicate<TResult> search, string include)
where TResult : class, IMetadata
public TResult? Get<TResult>(Predicate<TResult> search, string include) where TResult : class, IMetadata
{
try
{
using (GremlinDb gremlinDb = new())
{
return gremlinDb
.Set<TResult>()
.AsNoTracking()
.Include(include)
.AsEnumerable()
.FirstOrDefault(t => search(t));
return gremlinDb.Set<TResult>().AsNoTracking().Include(include).AsEnumerable().FirstOrDefault(t => search(t));
}
}
catch (Exception exception)
@ -246,15 +237,7 @@ public class GenericController
{
using (GremlinDb gremlinDb = new())
{
return await Task.Run(
() =>
gremlinDb
.Set<TResult>()
.AsNoTracking()
.Include(include1)
.AsEnumerable()
.FirstOrDefault(t => search(t))
);
return await Task.Run(() => gremlinDb.Set<TResult>().Include(include1).AsEnumerable().FirstOrDefault(t => search(t)));
}
}
catch (Exception exception)
@ -346,8 +329,7 @@ public class GenericController
}
}
public async Task<int> InsertAsync<T>(T entity)
where T : class, IMetadata
public async Task<int> InsertAsync<T>(T entity) where T : class, IMetadata
{
try
{
@ -423,14 +405,19 @@ public class GenericController
}
}
public async Task<int> UpdateAsync<T>(T entity)
where T : class, IMetadata
public async Task<int> UpdateAsync<T>(T entity) where T : class, IMetadata
{
try
{
using (GremlinDb gremlinDb = new())
{
gremlinDb.Set<T>().Update(entity);
//DEBUG
var changedEntries = gremlinDb.ChangeTracker.Entries().ToList();
foreach (var changedEntry in changedEntries)
Console.WriteLine(changedEntry);
return await gremlinDb.SaveChangesAsync();
}
}

@ -60,7 +60,7 @@ public class GenericImporter
SubMarket = new(),
PhoneNumber = line[8],
EMail = line[9],
ParentAccountId = 0,
// ParentAccountId = 0,
DataModificationByUser = "Gremlin Generic Importer"
};

@ -0,0 +1,161 @@
\documentclass[a4paper,ngerman,parskip,10pt]{scrlttr2}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage[hidelinks]{hyperref}
\usepackage[left=2cm, right=2cm, top=2cm, bottom=2cm]{geometry}
\usepackage[table]{xcolor}
\usepackage[right]{{eurosym}}
\usepackage[locale=DE]{{siunitx}}
\usepackage{{scrlayer-scrpage}}
\usepackage{{lastpage}}
\usepackage{{graphicx}}
\usepackage{{multirow}}
\usepackage{{longtable}}
\usepackage{{enumitem}}
\usepackage{{fp, xstring, spreadtab, numprint}}
\DeclareSIUnit{{\sieuro}}{{\mbox{{\euro}}}}
\rohead{DE-83PE89-323-1}
\cfoot{Seite \thepage/\pageref{LastPage}}
\sisetup{round-integer-to-decimal,round-precision=2,round-mode=places}
\newcommand{\produkttitel}[1]{\textsc{#1}}
\renewcommand{\arraystretch}{1.2}
\definecolor{AgilentBlau}{HTML}{0085d5}
\setlist{noitemsep}
\begin{document}
\begin{tabular}{p{0.4\hsize}p{0.5\hsize}}
\multirow{4}{*}{\includegraphics[width=0.9\hsize]{agilentLogo.png}}
&\normalsize{Agilent Technologies Deutschland GmbH}\\
&\normalsize{Life Sciences \& Chemical Analysis}\\
&\normalsize{Hewlett-Packard-Str. 8}\\
&\normalsize{D-76337 Waldbronn}
\end{tabular}
\par
\begin{flushright}
\colorbox{AgilentBlau}{\textcolor{white}{\textsc{\Huge{Angebot}}}}
\end{flushright}
\begin{tabular}{p{0.4\hsize}p{0.6\hsize}}
&
\multirow{4}{*}{
\begin{tabular}{|ll|}
\hline
\textbf{Angebotsnummer:}&DE-83PE89-323-1\\
Angebotdatum:&\today\\
Angebotsgültigkeit:&60 Tage\\\textbf{Ansprechpartner:}&Sascha Woitschetzki\\
Telefon: &+49 208 74129134\\
Mobil:&+49 176 22285334\\
E-Mail:&\href{mailto:sascha.woitschetzki@non.agilent.com}{sascha.woitschetzki@non.agilent.com}\\
\textbf{Auftragsannahme:}&\href{mailto:salesservices\_germany@agilent.com}{salesservices\_germany@agilent.com}\\
\hline
\end{tabular}
}\\
Herr Dieter Franke
\\
Siegwerk Druckfarben AG \& Co KGaA
\\
Alfred-Keller-Str. 55
\\
53721 Siegburg
\\
&\\
&\\
\end{tabular}
\vspace{1cm}\par
Sehr geehrter Herr Franke,\par
nachfolgend erhalten Sie Ihr gewünschtes Angebot über ein(e) GPC.\\
Es umfasst im Einzelnen:
\begin{itemize}
\item Isokratische Pumpe (\#1)
\begin{itemize}
\item Werkzeugsatz (\#2)
\item Säule (\#3)
\end{itemize}
\item Säulenthermostat (\#4)
\item Vialsampler (\#5)
\begin{itemize}
\item Probenteller für 6x11 2,0 ml Vials (\#6)
\end{itemize}
\item RI-Detektor (\#7)
\item UV/VIS-Detektor (\#8)
\begin{itemize}
\item Standardflusszelle (\#9)
\end{itemize}
\item Agilent GPC/SEC-Software (\#10)
\item PLgel 10um 500A 300 x 7.5 mm (\#11)
\item PLgel 10um 100A 300 x 7.5 mm (\#12)
\item 1260 Infinity II HPLC-System (\#13)
\begin{itemize}
\item Einweisung und First Run Assist (\#14)
\item Silber-Vertrag (Laufzeit: 1 Jahr) (\#15)
\end{itemize}
\end{itemize}
Für Rückfragen und Änderungswünsche stehe ich Ihnen gerne zur Verfügung.\par
Mit freundlichen Grüßen\\
\includegraphics[width = 5cm]{signWoitschetzki.png}
\vspace{1cm} \\
\begin{center}
\begin{longtable}
{| cp{0.595\textwidth} crr |} \hline
\textbf{\#} & \textbf{Produktbeschreibung} (Produktnummer) & \textbf{Menge} & \textbf{Discount} & \textbf{Preis}\\ \hline \endhead
1 &\textbf{Isokratische Pumpe} (G7110B)\newline 1260 Infinity II isokratische Pumpe, Maximaldruck 600 bar.Inkl. vergünstigter Säule, Verbindungskapillaren, Lösemittelwanne und CAN-Kabel.\newline Listenpreis: \SI{8908}{\sieuro}&1&\SI{45}{\%}&\SI{4899,4}{\sieuro}\\
2 &\textbf{Werkzeugsatz} (G7110B\#001)\newline HPLC System Tool Kit, für Agilent 1260/1290 Infinity II LC.\newline Listenpreis: \SI{400}{\sieuro}&1&\SI{45}{\%}&\SI{220}{\sieuro}\\
3 &\textbf{Säule} (G7110B\#094)\newline InfinityLab Poroshell 120 EC-C18 3.0 x 150 mm, 2.7 µm.\newline Listenpreis: \SI{1}{\sieuro}&1&\SI{45}{\%}&\SI{0,55}{\sieuro}\\
4 &\textbf{Säulenthermostat} (G7116A)\newline 1260 Infinity II Thermostat für bis zu vier 30 cm Säulen, Temperaturbereich: 10° unter Raumtemperatur (min. 4 °C) bis max. 85 °C, inkl. Säulenidentifikations-Kit. Ventilantrieb optional.\newline Listenpreis: \SI{6494}{\sieuro}&1&\SI{45}{\%}&\SI{3571,7}{\sieuro}\\
5 &\textbf{Vialsampler} (G7129A)\newline 1260 Infinity II automatischer Flüssigprobengeber zur Verwendung bei bis zu 600 bar. Mit integriertem Nadelspülanschluss zur Minimierung der Verschleppung, 100 µl Dosiereinheit und 100 µl Probenschleife. Inklusive Gerätetreiber für ein LC-System (2D-UV).\newline Listenpreis: \SI{19905}{\sieuro}&1&\SI{45}{\%}&\SI{10947,75}{\sieuro}\\
6 &\textbf{Probenteller für 6x11 2,0 ml Vials} (G7129A\#010)\newline \newline Listenpreis: \SI{375}{\sieuro}&1&\SI{45}{\%}&\SI{206,25}{\sieuro}\\
7 &\textbf{RI-Detektor} (G7162A)\newline Agilent 1260 Infinity II Brechungsindexdetektor. \newline Datenrate bis zu 72 Hz, mit integrierter 8 µl Flusszelle.\newline Listenpreis: \SI{13989}{\sieuro}&1&\SI{45}{\%}&\SI{7693,95}{\sieuro}\\
8 &\textbf{UV/VIS-Detektor} (G7114A)\newline 1260 Infinity II variabler Wellenlängendetektor (190 600 nm). Für schnelle programmierbare Einzel- (bis zu 120 Hz) und Doppelwellenlängen-Detektion. RFID-Tags für Durchflusszellen und UV-Lampe.\newline Listenpreis: \SI{9307}{\sieuro}&1&\SI{45}{\%}&\SI{5118,85}{\sieuro}\\
9 &\textbf{Standardflusszelle} (G7114A\#018)\newline Standarddurchflusszelle VWD aus Edelstahl mit RFID-Tag zur Identifizierung, 10 mm, 14 µl.\newline Listenpreis: \SI{1612}{\sieuro}&1&\SI{45}{\%}&\SI{886,6}{\sieuro}\\
10 &\textbf{Agilent GPC/SEC-Software} (G7850AA)\newline Agilent GPC/SEC-Software für GPC-Berechnungen. Nur Datenanalyse. Kann mit Gerätesteuerung (G7854AA) und Multi-Detektor-GPC (G7852AA) aufgerüstet werden.\newline Listenpreis: \SI{14789}{\sieuro}&1&\SI{45}{\%}&\SI{8133,95}{\sieuro}\\
11 &\textbf{PLgel 10um 500A 300 x 7.5 mm} (PL1110-6125)\newline \newline Listenpreis: \SI{1806}{\sieuro}&2&\SI{45}{\%}&\SI{1986,6}{\sieuro}\\
12 &\textbf{PLgel 10um 100A 300 x 7.5 mm} (PL1110-6120)\newline \newline Listenpreis: \SI{1806}{\sieuro}&2&\SI{45}{\%}&\SI{1986,6}{\sieuro}\\
13 &\textbf{1260 Infinity II HPLC-System} (SYS-LC-1260II)\newline \newline Listenpreis: \SI{0}{\sieuro}&1&\SI{20}{\%}&\SI{0}{\sieuro}\\
14 &\textbf{Einweisung und First Run Assist} (SYS-LC-1260II\#2C9)\newline Einweisung für neue Anwender und zusätzlich Unterstützung bei der Einrichtung der ersten Methode (erfordert Prüfung der Methode vorab durch Agilent).\newline Listenpreis: \SI{1034}{\sieuro}&1&\SI{20}{\%}&\SI{827,2}{\sieuro}\\
15 &\textbf{Silber-Wartungsvertrag} (SYS-LC-1260II\#8R1)\newline Laufzeit: 1 Jahr.\newline Listenpreis: \SI{2688}{\sieuro}&1&\SI{20}{\%}&\SI{2150,4}{\sieuro}\\
\hline
\end{longtable}
\end{center}
\vspace{-2cm}
\begin{flushright}
\begin{tabular}{|rr|}
\hline
\textbf{Summe netto} & \SI{48629,80}{\sieuro}\\
\textbf{Versand und Bereitstellungskosten (3\%)} & \SI{1458,894}{\sieuro}\\
\textbf{Gesamtsumme netto} & \SI{50088,694}{\sieuro}\\
\textbf{Umsatzsteuer (19\%)} & \SI{9516,85186}{\sieuro}\\
\textbf{Gesamtsumme brutto} & \SI{59605,54586}{\sieuro}\\
\hline
\end{tabular}
\end{flushright}
Der Betrag versteht sich zzgl. der gesetzlichen Steuern.\\
Diese werden im Rechnungszeitraum auf der Rechnung gesondert ausgewiesen.\\
Zahlungsbedingungen: 30 Tage netto ab Rechnungsdatum.\\
Incoterm (2010) für Lieferungen innerhalb Deutschlands: DDP.
\begin{small}
\textbf{Gewährleistung:}\\
Die Gewährleistung für Zubehör und Ersatzteilprodukte und für Analytik-Hardwareprodukte beträgt 12 Monate.
\textbf{Hinweis:}\\
Für den Verkauf der in diesem Angebot aufgeführten Standard-Produkte und -Services gelten die aktuellen \emph{Agilent Geschäftsbedingungen} und alle sonstigen anwendbaren Zusatzbedingungen sowie zusätzliche Bedingungen, soweit darauf hier Bezug genommen wird. Soweit Produkte oder Services nach speziellen Kundenanforderungen hergestellt, konfiguriert oder angepasst werden, gelten für den Verkauf aller in diesem Angebot aufgeführten Produkte und Services die aktuellen \emph{Agilent Geschäftsbedingungen für kundenspezifische Produkte} und alle sonstigen anwendbaren Zusatzbedingungen sowie zusätzliche Bedingungen, soweit darauf hier Bezug genommen wird. Eine Kopie der maßgeblichen Bedingungen ist entweder beigefügt oder wurde Ihnen bereits zur Verfügung gestellt. Sollten Sie keine Kopie erhalten haben oder eine weitere Kopie benötigen, setzen Sie sich bitte mit uns in Verbindung. Soweit Sie mit Agilent eine gesonderte Vereinbarung getroffen haben, die den Verkauf der in diesem Angebot aufgeführten Produkte und Services umfasst, sind die Bestimmungen dieser Vereinbarung anwendbar. Abweichende oder ergänzende Vereinbarungen, insbesondere widersprechende Geschäftsbedingungen, sind nur gültig, wenn sie ausdrücklich schriftlich vereinbart worden sind. Die angegebenen Daten zur Verfügbarkeit von Produkten und Services sind vorläufig. Die tatsächlichen Lieferzeiten bzw. Lieferperioden werden Ihnen bei Auftragsbestätigung mitgeteilt. Waren, Technologien oder Software, die aus den Vereinigten Staaten von Amerika (\emph{USA}) oder anderen exportierenden Ländern ausgeführt werden, unterliegen den Ausfuhrbestimmungen der USA sowie anderer Rechtsordnungen. Bei Ausfuhr ist der Kunde dafür verantwortlich, dass die anwendbaren Ausfuhrbestimmungen eingehalten werden.
\end{small}
\begin{scriptsize}
Agilent Technologies Deutschland GmbH, Hewlett-Packard-Str. 8, D-76337 Waldbronn\\
Telefon +49 (0)7243-602-0\\
USt.-IdNr.: DE812729296, WEEE-Reg.-Nr. DE 86631749\\
Sitz der Gesellschaft: Waldbronn Amtsgericht Mannheim, HRB 723782\\
Geschäftsführer: Dr. Andreas Kistner (Vorsitzender der Geschäftsführung), Armin Jehle, Norbert Sabatzki, Dr. Knut Wintergerst\\
\href{www.agilent.com}{www.agilent.com}
\end{scriptsize}
\end{document}

@ -0,0 +1,16 @@
# Part Number Opt PL Description Qty Price EUR Breaks EUR Uplift % Total Discount % Net EUR Total EUR Sales Discount YA9% Contractual Discount Y99% Promotion Discount Y07% Demo Discount Y04% PH Code PH Description YMax
1 G7110B 29 1260 Infinity II isokratische Pumpe 1 8908 0 0 45 4899.4 4899.4 45 0 0 0 ISL100P1 Pumps
2 G7110B 001 29 HPLC System Tool Kit 1260 Infinity II 1 400 0 0 45 220 220 45 0 0 0
3 G7110B 094 29 Poroshell 120 EC-C18 3,0x150mm, 2,7um 1 1 0 0 45 0.55 0.55 45 0 0 0
4 G7116A 29 1260 Infinity II Therm. f. mehr. Saeulen 1 6494 0 0 45 3571.7 3571.7 45 0 0 0 ISL100LC1 LC Hardware
5 G7129A 29 1260 Inf. II Fluessigprobengeber 1 19905 0 0 45 10947.75 10947.75 45 0 0 0 ISL100A1 Autosamplers
6 G7129A 010 29 Standard-Schublade (6x11 Probenflaschen) 1 375 0 0 45 206.25 206.25 45 0 0 0
7 G7162A 29 1260 Infinity II Brechungsindexdetektor 1 13989 0 0 45 7693.95 7693.95 45 0 0 0 ISL100D1 Detectors
8 G7114A 29 1260 Infinity II VW-Detektor 1 9307 0 0 45 5118.85 5118.85 45 0 0 0 ISL100D1 Detectors
9 G7114A 018 29 Standarddurchflusszelle VWD 1 1612 0 0 45 886.6 886.6 45 0 0 0
10 G7850AA 29 Agilent GPC/SEC-Software 1 14789 0 0 45 8133.95 8133.95 45 0 0 0 ISL230L230 Special LC
11 PL1110-6125 BC PLgel 10um 500A 300 x 7.5 mm 2 1806 0 0 45 993.3 1986.6 45 0 0 0 CSCV27C04L GPC/SEC - PLgel
12 PL1110-6120 BC PLgel 10um 100A 300 x 7.5 mm 2 1806 0 0 45 993.3 1986.6 45 0 0 0 CSCV27C04L GPC/SEC - PLgel
13 SYS-LC-1260II 74 LC 1260 Infinity II System 1 0 0 0 20 0 0 20 0 0 0 TSSYS0SYLC Service Systems - Liquid Chromatography
14 SYS-LC-1260II 2C9 74 Einweisung zum ersten Methodenlauf 1 1034 0 0 20 827.2 827.2 20 0 0 0 TSSTRN Training Services
15 SYS-LC-1260II 8R1 74 CrossLab Silver - 1J, kompl. 1 2688 0 0 20 2150.4 2150.4 20 0 0 0 TSSYS1 Serviced As Systems - 1 YR
1 # Part Number Opt PL Description Qty Price EUR Breaks EUR Uplift % Total Discount % Net EUR Total EUR Sales Discount YA9% Contractual Discount Y99% Promotion Discount Y07% Demo Discount Y04% PH Code PH Description YMax
2 1 G7110B 29 1260 Infinity II isokratische Pumpe 1 8908 0 0 45 4899.4 4899.4 45 0 0 0 ISL100P1 Pumps
3 2 G7110B 001 29 HPLC System Tool Kit 1260 Infinity II 1 400 0 0 45 220 220 45 0 0 0
4 3 G7110B 094 29 Poroshell 120 EC-C18 3,0x150mm, 2,7um 1 1 0 0 45 0.55 0.55 45 0 0 0
5 4 G7116A 29 1260 Infinity II Therm. f. mehr. Saeulen 1 6494 0 0 45 3571.7 3571.7 45 0 0 0 ISL100LC1 LC Hardware
6 5 G7129A 29 1260 Inf. II Fluessigprobengeber 1 19905 0 0 45 10947.75 10947.75 45 0 0 0 ISL100A1 Autosamplers
7 6 G7129A 010 29 Standard-Schublade (6x11 Probenflaschen) 1 375 0 0 45 206.25 206.25 45 0 0 0
8 7 G7162A 29 1260 Infinity II Brechungsindexdetektor 1 13989 0 0 45 7693.95 7693.95 45 0 0 0 ISL100D1 Detectors
9 8 G7114A 29 1260 Infinity II VW-Detektor 1 9307 0 0 45 5118.85 5118.85 45 0 0 0 ISL100D1 Detectors
10 9 G7114A 018 29 Standarddurchflusszelle VWD 1 1612 0 0 45 886.6 886.6 45 0 0 0
11 10 G7850AA 29 Agilent GPC/SEC-Software 1 14789 0 0 45 8133.95 8133.95 45 0 0 0 ISL230L230 Special LC
12 11 PL1110-6125 BC PLgel 10um 500A 300 x 7.5 mm 2 1806 0 0 45 993.3 1986.6 45 0 0 0 CSCV27C04L GPC/SEC - PLgel
13 12 PL1110-6120 BC PLgel 10um 100A 300 x 7.5 mm 2 1806 0 0 45 993.3 1986.6 45 0 0 0 CSCV27C04L GPC/SEC - PLgel
14 13 SYS-LC-1260II 74 LC 1260 Infinity II System 1 0 0 0 20 0 0 20 0 0 0 TSSYS0SYLC Service Systems - Liquid Chromatography
15 14 SYS-LC-1260II 2C9 74 Einweisung zum ersten Methodenlauf 1 1034 0 0 20 827.2 827.2 20 0 0 0 TSSTRN Training Services
16 15 SYS-LC-1260II 8R1 74 CrossLab Silver - 1J, kompl. 1 2688 0 0 20 2150.4 2150.4 20 0 0 0 TSSYS1 Serviced As Systems - 1 YR

@ -0,0 +1,161 @@
\documentclass[a4paper,ngerman,parskip,10pt]{scrlttr2}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage[hidelinks]{hyperref}
\usepackage[left=2cm, right=2cm, top=2cm, bottom=2cm]{geometry}
\usepackage[table]{xcolor}
\usepackage[right]{{eurosym}}
\usepackage[locale=DE]{{siunitx}}
\usepackage{{scrlayer-scrpage}}
\usepackage{{lastpage}}
\usepackage{{graphicx}}
\usepackage{{multirow}}
\usepackage{{longtable}}
\usepackage{{enumitem}}
\usepackage{{fp, xstring, spreadtab, numprint}}
\DeclareSIUnit{{\sieuro}}{{\mbox{{\euro}}}}
\rohead{DE-83PE89-323-223}
\cfoot{Seite \thepage/\pageref{LastPage}}
\sisetup{round-integer-to-decimal,round-precision=2,round-mode=places}
\newcommand{\produkttitel}[1]{\textsc{#1}}
\renewcommand{\arraystretch}{1.2}
\definecolor{AgilentBlau}{HTML}{0085d5}
\setlist{noitemsep}
\begin{document}
\begin{tabular}{p{0.4\hsize}p{0.5\hsize}}
\multirow{4}{*}{\includegraphics[width=0.9\hsize]{agilentLogo.png}}
&\normalsize{Agilent Technologies Deutschland GmbH}\\
&\normalsize{Life Sciences \& Chemical Analysis}\\
&\normalsize{Hewlett-Packard-Str. 8}\\
&\normalsize{D-76337 Waldbronn}
\end{tabular}
\par
\begin{flushright}
\colorbox{AgilentBlau}{\textcolor{white}{\textsc{\Huge{Angebot}}}}
\end{flushright}
\begin{tabular}{p{0.4\hsize}p{0.6\hsize}}
&
\multirow{4}{*}{
\begin{tabular}{|ll|}
\hline
\textbf{Angebotsnummer:}&DE-83PE89-323-223\\
Angebotdatum:&\today\\
Angebotsgültigkeit:&60 Tage\\\textbf{Ansprechpartner:}&Sascha Woitschetzki\\
Telefon: &+49 208 74129134\\
Mobil:&+49 176 22285334\\
E-Mail:&\href{mailto:sascha.woitschetzki@non.agilent.com}{sascha.woitschetzki@non.agilent.com}\\
\textbf{Auftragsannahme:}&\href{mailto:salesservices\_germany@agilent.com}{salesservices\_germany@agilent.com}\\
\hline
\end{tabular}
}\\
Herr Dieter Franke
\\
Siegwerk Druckfarben AG \& Co KGaA
\\
Alfred-Keller-Str. 55
\\
53721 Siegburg
\\
&\\
&\\
\end{tabular}
\vspace{1cm}\par
Sehr geehrter Herr Franke,\par
nachfolgend erhalten Sie Ihr gewünschtes Angebot über ein(e) GPC.\\
Es umfasst im Einzelnen:
\begin{itemize}
\item Isokratische Pumpe (\#1)
\begin{itemize}
\item Werkzeugsatz (\#2)
\item Säule (\#3)
\end{itemize}
\item Säulenthermostat (\#4)
\item Vialsampler (\#5)
\begin{itemize}
\item Probenteller für 6x11 2,0 ml Vials (\#6)
\end{itemize}
\item RI-Detektor (\#7)
\item UV/VIS-Detektor (\#8)
\begin{itemize}
\item Standardflusszelle (\#9)
\end{itemize}
\item Agilent GPC/SEC-Software (\#10)
\item PLgel 10um 500A 300 x 7.5 mm (\#11)
\item PLgel 10um 100A 300 x 7.5 mm (\#12)
\item 1260 Infinity II HPLC-System (\#13)
\begin{itemize}
\item Einweisung und First Run Assist (\#14)
\item Silber-Vertrag (Laufzeit: 1 Jahr) (\#15)
\end{itemize}
\end{itemize}
Für Rückfragen und Änderungswünsche stehe ich Ihnen gerne zur Verfügung.\par
Mit freundlichen Grüßen\\
\includegraphics[width = 5cm]{signWoitschetzki.png}
\vspace{1cm} \\
\begin{center}
\begin{longtable}
{| cp{0.595\textwidth} crr |} \hline
\textbf{\#} & \textbf{Produktbeschreibung} (Produktnummer) & \textbf{Menge} & \textbf{Discount} & \textbf{Preis}\\ \hline \endhead
1 &\textbf{Isokratische Pumpe} (G7110B)\newline 1260 Infinity II isokratische Pumpe, Maximaldruck 600 bar.Inkl. vergünstigter Säule, Verbindungskapillaren, Lösemittelwanne und CAN-Kabel.\newline Listenpreis: \SI{8908}{\sieuro}&1&\SI{45}{\%}&\SI{4899,4}{\sieuro}\\
2 &\textbf{Werkzeugsatz} (G7110B\#001)\newline HPLC System Tool Kit, für Agilent 1260/1290 Infinity II LC.\newline Listenpreis: \SI{400}{\sieuro}&1&\SI{45}{\%}&\SI{220}{\sieuro}\\
3 &\textbf{Säule} (G7110B\#094)\newline InfinityLab Poroshell 120 EC-C18 3.0 x 150 mm, 2.7 µm.\newline Listenpreis: \SI{1}{\sieuro}&1&\SI{45}{\%}&\SI{0,55}{\sieuro}\\
4 &\textbf{Säulenthermostat} (G7116A)\newline 1260 Infinity II Thermostat für bis zu vier 30 cm Säulen, Temperaturbereich: 10° unter Raumtemperatur (min. 4 °C) bis max. 85 °C, inkl. Säulenidentifikations-Kit. Ventilantrieb optional.\newline Listenpreis: \SI{6494}{\sieuro}&1&\SI{45}{\%}&\SI{3571,7}{\sieuro}\\
5 &\textbf{Vialsampler} (G7129A)\newline 1260 Infinity II automatischer Flüssigprobengeber zur Verwendung bei bis zu 600 bar. Mit integriertem Nadelspülanschluss zur Minimierung der Verschleppung, 100 µl Dosiereinheit und 100 µl Probenschleife. Inklusive Gerätetreiber für ein LC-System (2D-UV).\newline Listenpreis: \SI{19905}{\sieuro}&1&\SI{45}{\%}&\SI{10947,75}{\sieuro}\\
6 &\textbf{Probenteller für 6x11 2,0 ml Vials} (G7129A\#010)\newline \newline Listenpreis: \SI{375}{\sieuro}&1&\SI{45}{\%}&\SI{206,25}{\sieuro}\\
7 &\textbf{RI-Detektor} (G7162A)\newline Agilent 1260 Infinity II Brechungsindexdetektor. \newline Datenrate bis zu 72 Hz, mit integrierter 8 µl Flusszelle.\newline Listenpreis: \SI{13989}{\sieuro}&1&\SI{45}{\%}&\SI{7693,95}{\sieuro}\\
8 &\textbf{UV/VIS-Detektor} (G7114A)\newline 1260 Infinity II variabler Wellenlängendetektor (190 600 nm). Für schnelle programmierbare Einzel- (bis zu 120 Hz) und Doppelwellenlängen-Detektion. RFID-Tags für Durchflusszellen und UV-Lampe.\newline Listenpreis: \SI{9307}{\sieuro}&1&\SI{45}{\%}&\SI{5118,85}{\sieuro}\\
9 &\textbf{Standardflusszelle} (G7114A\#018)\newline Standarddurchflusszelle VWD aus Edelstahl mit RFID-Tag zur Identifizierung, 10 mm, 14 µl.\newline Listenpreis: \SI{1612}{\sieuro}&1&\SI{45}{\%}&\SI{886,6}{\sieuro}\\
10 &\textbf{Agilent GPC/SEC-Software} (G7850AA)\newline Agilent GPC/SEC-Software für GPC-Berechnungen. Nur Datenanalyse. Kann mit Gerätesteuerung (G7854AA) und Multi-Detektor-GPC (G7852AA) aufgerüstet werden.\newline Listenpreis: \SI{14789}{\sieuro}&1&\SI{45}{\%}&\SI{8133,95}{\sieuro}\\
11 &\textbf{PLgel 10um 500A 300 x 7.5 mm} (PL1110-6125)\newline \newline Listenpreis: \SI{1806}{\sieuro}&2&\SI{45}{\%}&\SI{1986,6}{\sieuro}\\
12 &\textbf{PLgel 10um 100A 300 x 7.5 mm} (PL1110-6120)\newline \newline Listenpreis: \SI{1806}{\sieuro}&2&\SI{45}{\%}&\SI{1986,6}{\sieuro}\\
13 &\textbf{1260 Infinity II HPLC-System} (SYS-LC-1260II)\newline \newline Listenpreis: \SI{0}{\sieuro}&1&\SI{20}{\%}&\SI{0}{\sieuro}\\
14 &\textbf{Einweisung und First Run Assist} (SYS-LC-1260II\#2C9)\newline Einweisung für neue Anwender und zusätzlich Unterstützung bei der Einrichtung der ersten Methode (erfordert Prüfung der Methode vorab durch Agilent).\newline Listenpreis: \SI{1034}{\sieuro}&1&\SI{20}{\%}&\SI{827,2}{\sieuro}\\
15 &\textbf{Silber-Wartungsvertrag} (SYS-LC-1260II\#8R1)\newline Laufzeit: 1 Jahr.\newline Listenpreis: \SI{2688}{\sieuro}&1&\SI{20}{\%}&\SI{2150,4}{\sieuro}\\
\hline
\end{longtable}
\end{center}
\vspace{-2cm}
\begin{flushright}
\begin{tabular}{|rr|}
\hline
\textbf{Summe netto} & \SI{48629,80}{\sieuro}\\
\textbf{Versand und Bereitstellungskosten (3\%)} & \SI{1458,894}{\sieuro}\\
\textbf{Gesamtsumme netto} & \SI{50088,694}{\sieuro}\\
\textbf{Umsatzsteuer (19\%)} & \SI{9516,85186}{\sieuro}\\
\textbf{Gesamtsumme brutto} & \SI{59605,54586}{\sieuro}\\
\hline
\end{tabular}
\end{flushright}
Der Betrag versteht sich zzgl. der gesetzlichen Steuern.\\
Diese werden im Rechnungszeitraum auf der Rechnung gesondert ausgewiesen.\\
Zahlungsbedingungen: 30 Tage netto ab Rechnungsdatum.\\
Incoterm (2010) für Lieferungen innerhalb Deutschlands: DDP.
\begin{small}
\textbf{Gewährleistung:}\\
Die Gewährleistung für Zubehör und Ersatzteilprodukte und für Analytik-Hardwareprodukte beträgt 12 Monate.
\textbf{Hinweis:}\\
Für den Verkauf der in diesem Angebot aufgeführten Standard-Produkte und -Services gelten die aktuellen \emph{Agilent Geschäftsbedingungen} und alle sonstigen anwendbaren Zusatzbedingungen sowie zusätzliche Bedingungen, soweit darauf hier Bezug genommen wird. Soweit Produkte oder Services nach speziellen Kundenanforderungen hergestellt, konfiguriert oder angepasst werden, gelten für den Verkauf aller in diesem Angebot aufgeführten Produkte und Services die aktuellen \emph{Agilent Geschäftsbedingungen für kundenspezifische Produkte} und alle sonstigen anwendbaren Zusatzbedingungen sowie zusätzliche Bedingungen, soweit darauf hier Bezug genommen wird. Eine Kopie der maßgeblichen Bedingungen ist entweder beigefügt oder wurde Ihnen bereits zur Verfügung gestellt. Sollten Sie keine Kopie erhalten haben oder eine weitere Kopie benötigen, setzen Sie sich bitte mit uns in Verbindung. Soweit Sie mit Agilent eine gesonderte Vereinbarung getroffen haben, die den Verkauf der in diesem Angebot aufgeführten Produkte und Services umfasst, sind die Bestimmungen dieser Vereinbarung anwendbar. Abweichende oder ergänzende Vereinbarungen, insbesondere widersprechende Geschäftsbedingungen, sind nur gültig, wenn sie ausdrücklich schriftlich vereinbart worden sind. Die angegebenen Daten zur Verfügbarkeit von Produkten und Services sind vorläufig. Die tatsächlichen Lieferzeiten bzw. Lieferperioden werden Ihnen bei Auftragsbestätigung mitgeteilt. Waren, Technologien oder Software, die aus den Vereinigten Staaten von Amerika (\emph{USA}) oder anderen exportierenden Ländern ausgeführt werden, unterliegen den Ausfuhrbestimmungen der USA sowie anderer Rechtsordnungen. Bei Ausfuhr ist der Kunde dafür verantwortlich, dass die anwendbaren Ausfuhrbestimmungen eingehalten werden.
\end{small}
\begin{scriptsize}
Agilent Technologies Deutschland GmbH, Hewlett-Packard-Str. 8, D-76337 Waldbronn\\
Telefon +49 (0)7243-602-0\\
USt.-IdNr.: DE812729296, WEEE-Reg.-Nr. DE 86631749\\
Sitz der Gesellschaft: Waldbronn Amtsgericht Mannheim, HRB 723782\\
Geschäftsführer: Dr. Andreas Kistner (Vorsitzender der Geschäftsführung), Armin Jehle, Norbert Sabatzki, Dr. Knut Wintergerst\\
\href{www.agilent.com}{www.agilent.com}
\end{scriptsize}
\end{document}

@ -0,0 +1,16 @@
# Part Number Opt PL Description Qty Price EUR Breaks EUR Uplift % Total Discount % Net EUR Total EUR Sales Discount YA9% Contractual Discount Y99% Promotion Discount Y07% Demo Discount Y04% PH Code PH Description YMax
1 G7110B 29 1260 Infinity II isokratische Pumpe 1 8908 0 0 45 4899.4 4899.4 45 0 0 0 ISL100P1 Pumps
2 G7110B 001 29 HPLC System Tool Kit 1260 Infinity II 1 400 0 0 45 220 220 45 0 0 0
3 G7110B 094 29 Poroshell 120 EC-C18 3,0x150mm, 2,7um 1 1 0 0 45 0.55 0.55 45 0 0 0
4 G7116A 29 1260 Infinity II Therm. f. mehr. Saeulen 1 6494 0 0 45 3571.7 3571.7 45 0 0 0 ISL100LC1 LC Hardware
5 G7129A 29 1260 Inf. II Fluessigprobengeber 1 19905 0 0 45 10947.75 10947.75 45 0 0 0 ISL100A1 Autosamplers
6 G7129A 010 29 Standard-Schublade (6x11 Probenflaschen) 1 375 0 0 45 206.25 206.25 45 0 0 0
7 G7162A 29 1260 Infinity II Brechungsindexdetektor 1 13989 0 0 45 7693.95 7693.95 45 0 0 0 ISL100D1 Detectors
8 G7114A 29 1260 Infinity II VW-Detektor 1 9307 0 0 45 5118.85 5118.85 45 0 0 0 ISL100D1 Detectors
9 G7114A 018 29 Standarddurchflusszelle VWD 1 1612 0 0 45 886.6 886.6 45 0 0 0
10 G7850AA 29 Agilent GPC/SEC-Software 1 14789 0 0 45 8133.95 8133.95 45 0 0 0 ISL230L230 Special LC
11 PL1110-6125 BC PLgel 10um 500A 300 x 7.5 mm 2 1806 0 0 45 993.3 1986.6 45 0 0 0 CSCV27C04L GPC/SEC - PLgel
12 PL1110-6120 BC PLgel 10um 100A 300 x 7.5 mm 2 1806 0 0 45 993.3 1986.6 45 0 0 0 CSCV27C04L GPC/SEC - PLgel
13 SYS-LC-1260II 74 LC 1260 Infinity II System 1 0 0 0 20 0 0 20 0 0 0 TSSYS0SYLC Service Systems - Liquid Chromatography
14 SYS-LC-1260II 2C9 74 Einweisung zum ersten Methodenlauf 1 1034 0 0 20 827.2 827.2 20 0 0 0 TSSTRN Training Services
15 SYS-LC-1260II 8R1 74 CrossLab Silver - 1J, kompl. 1 2688 0 0 20 2150.4 2150.4 20 0 0 0 TSSYS1 Serviced As Systems - 1 YR
1 # Part Number Opt PL Description Qty Price EUR Breaks EUR Uplift % Total Discount % Net EUR Total EUR Sales Discount YA9% Contractual Discount Y99% Promotion Discount Y07% Demo Discount Y04% PH Code PH Description YMax
2 1 G7110B 29 1260 Infinity II isokratische Pumpe 1 8908 0 0 45 4899.4 4899.4 45 0 0 0 ISL100P1 Pumps
3 2 G7110B 001 29 HPLC System Tool Kit 1260 Infinity II 1 400 0 0 45 220 220 45 0 0 0
4 3 G7110B 094 29 Poroshell 120 EC-C18 3,0x150mm, 2,7um 1 1 0 0 45 0.55 0.55 45 0 0 0
5 4 G7116A 29 1260 Infinity II Therm. f. mehr. Saeulen 1 6494 0 0 45 3571.7 3571.7 45 0 0 0 ISL100LC1 LC Hardware
6 5 G7129A 29 1260 Inf. II Fluessigprobengeber 1 19905 0 0 45 10947.75 10947.75 45 0 0 0 ISL100A1 Autosamplers
7 6 G7129A 010 29 Standard-Schublade (6x11 Probenflaschen) 1 375 0 0 45 206.25 206.25 45 0 0 0
8 7 G7162A 29 1260 Infinity II Brechungsindexdetektor 1 13989 0 0 45 7693.95 7693.95 45 0 0 0 ISL100D1 Detectors
9 8 G7114A 29 1260 Infinity II VW-Detektor 1 9307 0 0 45 5118.85 5118.85 45 0 0 0 ISL100D1 Detectors
10 9 G7114A 018 29 Standarddurchflusszelle VWD 1 1612 0 0 45 886.6 886.6 45 0 0 0
11 10 G7850AA 29 Agilent GPC/SEC-Software 1 14789 0 0 45 8133.95 8133.95 45 0 0 0 ISL230L230 Special LC
12 11 PL1110-6125 BC PLgel 10um 500A 300 x 7.5 mm 2 1806 0 0 45 993.3 1986.6 45 0 0 0 CSCV27C04L GPC/SEC - PLgel
13 12 PL1110-6120 BC PLgel 10um 100A 300 x 7.5 mm 2 1806 0 0 45 993.3 1986.6 45 0 0 0 CSCV27C04L GPC/SEC - PLgel
14 13 SYS-LC-1260II 74 LC 1260 Infinity II System 1 0 0 0 20 0 0 20 0 0 0 TSSYS0SYLC Service Systems - Liquid Chromatography
15 14 SYS-LC-1260II 2C9 74 Einweisung zum ersten Methodenlauf 1 1034 0 0 20 827.2 827.2 20 0 0 0 TSSTRN Training Services
16 15 SYS-LC-1260II 8R1 74 CrossLab Silver - 1J, kompl. 1 2688 0 0 20 2150.4 2150.4 20 0 0 0 TSSYS1 Serviced As Systems - 1 YR

@ -0,0 +1,161 @@
\documentclass[a4paper,ngerman,parskip,10pt]{scrlttr2}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage[hidelinks]{hyperref}
\usepackage[left=2cm, right=2cm, top=2cm, bottom=2cm]{geometry}
\usepackage[table]{xcolor}
\usepackage[right]{{eurosym}}
\usepackage[locale=DE]{{siunitx}}
\usepackage{{scrlayer-scrpage}}
\usepackage{{lastpage}}
\usepackage{{graphicx}}
\usepackage{{multirow}}
\usepackage{{longtable}}
\usepackage{{enumitem}}
\usepackage{{fp, xstring, spreadtab, numprint}}
\DeclareSIUnit{{\sieuro}}{{\mbox{{\euro}}}}
\rohead{DE-83PE89-323-223}
\cfoot{Seite \thepage/\pageref{LastPage}}
\sisetup{round-integer-to-decimal,round-precision=2,round-mode=places}
\newcommand{\produkttitel}[1]{\textsc{#1}}
\renewcommand{\arraystretch}{1.2}
\definecolor{AgilentBlau}{HTML}{0085d5}
\setlist{noitemsep}
\begin{document}
\begin{tabular}{p{0.4\hsize}p{0.5\hsize}}
\multirow{4}{*}{\includegraphics[width=0.9\hsize]{agilentLogo.png}}
&\normalsize{Agilent Technologies Deutschland GmbH}\\
&\normalsize{Life Sciences \& Chemical Analysis}\\
&\normalsize{Hewlett-Packard-Str. 8}\\
&\normalsize{D-76337 Waldbronn}
\end{tabular}
\par
\begin{flushright}
\colorbox{AgilentBlau}{\textcolor{white}{\textsc{\Huge{Angebot}}}}
\end{flushright}
\begin{tabular}{p{0.4\hsize}p{0.6\hsize}}
&
\multirow{4}{*}{
\begin{tabular}{|ll|}
\hline
\textbf{Angebotsnummer:}&DE-83PE89-323-223\\
Angebotdatum:&\today\\
Angebotsgültigkeit:&60 Tage\\\textbf{Ansprechpartner:}&Sascha Woitschetzki\\
Telefon: &+49 208 74129134\\
Mobil:&+49 176 22285334\\
E-Mail:&\href{mailto:sascha.woitschetzki@non.agilent.com}{sascha.woitschetzki@non.agilent.com}\\
\textbf{Auftragsannahme:}&\href{mailto:salesservices\_germany@agilent.com}{salesservices\_germany@agilent.com}\\
\hline
\end{tabular}
}\\
Herr Dieter Franke
\\
Siegwerk Druckfarben AG \& Co KGaA
\\
Alfred-Keller-Str. 55
\\
53721 Siegburg
\\
&\\
&\\
\end{tabular}
\vspace{1cm}\par
Sehr geehrter Herr Franke,\par
nachfolgend erhalten Sie Ihr gewünschtes Angebot über ein(e) Gerät.\\
Es umfasst im Einzelnen:
\begin{itemize}
\item Isokratische Pumpe (\#1)
\begin{itemize}
\item Werkzeugsatz (\#2)
\item Säule (\#3)
\end{itemize}
\item Säulenthermostat (\#4)
\item Vialsampler (\#5)
\begin{itemize}
\item Probenteller für 6x11 2,0 ml Vials (\#6)
\end{itemize}
\item RI-Detektor (\#7)
\item UV/VIS-Detektor (\#8)
\begin{itemize}
\item Standardflusszelle (\#9)
\end{itemize}
\item Agilent GPC/SEC-Software (\#10)
\item PLgel 10um 500A 300 x 7.5 mm (\#11)
\item PLgel 10um 100A 300 x 7.5 mm (\#12)
\item 1260 Infinity II HPLC-System (\#13)
\begin{itemize}
\item Einweisung und First Run Assist (\#14)
\item Silber-Vertrag (Laufzeit: 1 Jahr) (\#15)
\end{itemize}
\end{itemize}
Für Rückfragen und Änderungswünsche stehe ich Ihnen gerne zur Verfügung.\par
Mit freundlichen Grüßen\\
\includegraphics[width = 5cm]{signWoitschetzki.png}
\vspace{1cm} \\
\begin{center}
\begin{longtable}
{| cp{0.595\textwidth} crr |} \hline
\textbf{\#} & \textbf{Produktbeschreibung} (Produktnummer) & \textbf{Menge} & \textbf{Discount} & \textbf{Preis}\\ \hline \endhead
1 &\textbf{Isokratische Pumpe} (G7110B)\newline 1260 Infinity II isokratische Pumpe, Maximaldruck 600 bar.Inkl. vergünstigter Säule, Verbindungskapillaren, Lösemittelwanne und CAN-Kabel.\newline Listenpreis: \SI{8908}{\sieuro}&1&\SI{45}{\%}&\SI{4899,4}{\sieuro}\\
2 &\textbf{Werkzeugsatz} (G7110B\#001)\newline HPLC System Tool Kit, für Agilent 1260/1290 Infinity II LC.\newline Listenpreis: \SI{400}{\sieuro}&1&\SI{45}{\%}&\SI{220}{\sieuro}\\
3 &\textbf{Säule} (G7110B\#094)\newline InfinityLab Poroshell 120 EC-C18 3.0 x 150 mm, 2.7 µm.\newline Listenpreis: \SI{1}{\sieuro}&1&\SI{45}{\%}&\SI{0,55}{\sieuro}\\
4 &\textbf{Säulenthermostat} (G7116A)\newline 1260 Infinity II Thermostat für bis zu vier 30 cm Säulen, Temperaturbereich: 10° unter Raumtemperatur (min. 4 °C) bis max. 85 °C, inkl. Säulenidentifikations-Kit. Ventilantrieb optional.\newline Listenpreis: \SI{6494}{\sieuro}&1&\SI{45}{\%}&\SI{3571,7}{\sieuro}\\
5 &\textbf{Vialsampler} (G7129A)\newline 1260 Infinity II automatischer Flüssigprobengeber zur Verwendung bei bis zu 600 bar. Mit integriertem Nadelspülanschluss zur Minimierung der Verschleppung, 100 µl Dosiereinheit und 100 µl Probenschleife. Inklusive Gerätetreiber für ein LC-System (2D-UV).\newline Listenpreis: \SI{19905}{\sieuro}&1&\SI{45}{\%}&\SI{10947,75}{\sieuro}\\
6 &\textbf{Probenteller für 6x11 2,0 ml Vials} (G7129A\#010)\newline \newline Listenpreis: \SI{375}{\sieuro}&1&\SI{45}{\%}&\SI{206,25}{\sieuro}\\
7 &\textbf{RI-Detektor} (G7162A)\newline Agilent 1260 Infinity II Brechungsindexdetektor. \newline Datenrate bis zu 72 Hz, mit integrierter 8 µl Flusszelle.\newline Listenpreis: \SI{13989}{\sieuro}&1&\SI{45}{\%}&\SI{7693,95}{\sieuro}\\
8 &\textbf{UV/VIS-Detektor} (G7114A)\newline 1260 Infinity II variabler Wellenlängendetektor (190 600 nm). Für schnelle programmierbare Einzel- (bis zu 120 Hz) und Doppelwellenlängen-Detektion. RFID-Tags für Durchflusszellen und UV-Lampe.\newline Listenpreis: \SI{9307}{\sieuro}&1&\SI{45}{\%}&\SI{5118,85}{\sieuro}\\
9 &\textbf{Standardflusszelle} (G7114A\#018)\newline Standarddurchflusszelle VWD aus Edelstahl mit RFID-Tag zur Identifizierung, 10 mm, 14 µl.\newline Listenpreis: \SI{1612}{\sieuro}&1&\SI{45}{\%}&\SI{886,6}{\sieuro}\\
10 &\textbf{Agilent GPC/SEC-Software} (G7850AA)\newline Agilent GPC/SEC-Software für GPC-Berechnungen. Nur Datenanalyse. Kann mit Gerätesteuerung (G7854AA) und Multi-Detektor-GPC (G7852AA) aufgerüstet werden.\newline Listenpreis: \SI{14789}{\sieuro}&1&\SI{45}{\%}&\SI{8133,95}{\sieuro}\\
11 &\textbf{PLgel 10um 500A 300 x 7.5 mm} (PL1110-6125)\newline \newline Listenpreis: \SI{1806}{\sieuro}&2&\SI{45}{\%}&\SI{1986,6}{\sieuro}\\
12 &\textbf{PLgel 10um 100A 300 x 7.5 mm} (PL1110-6120)\newline \newline Listenpreis: \SI{1806}{\sieuro}&2&\SI{45}{\%}&\SI{1986,6}{\sieuro}\\
13 &\textbf{1260 Infinity II HPLC-System} (SYS-LC-1260II)\newline \newline Listenpreis: \SI{0}{\sieuro}&1&\SI{20}{\%}&\SI{0}{\sieuro}\\
14 &\textbf{Einweisung und First Run Assist} (SYS-LC-1260II\#2C9)\newline Einweisung für neue Anwender und zusätzlich Unterstützung bei der Einrichtung der ersten Methode (erfordert Prüfung der Methode vorab durch Agilent).\newline Listenpreis: \SI{1034}{\sieuro}&1&\SI{20}{\%}&\SI{827,2}{\sieuro}\\
15 &\textbf{Silber-Wartungsvertrag} (SYS-LC-1260II\#8R1)\newline Laufzeit: 1 Jahr.\newline Listenpreis: \SI{2688}{\sieuro}&1&\SI{20}{\%}&\SI{2150,4}{\sieuro}\\
\hline
\end{longtable}
\end{center}
\vspace{-2cm}
\begin{flushright}
\begin{tabular}{|rr|}
\hline
\textbf{Summe netto} & \SI{48629,80}{\sieuro}\\
\textbf{Versand und Bereitstellungskosten (3\%)} & \SI{1458,894}{\sieuro}\\
\textbf{Gesamtsumme netto} & \SI{50088,694}{\sieuro}\\
\textbf{Umsatzsteuer (19\%)} & \SI{9516,85186}{\sieuro}\\
\textbf{Gesamtsumme brutto} & \SI{59605,54586}{\sieuro}\\
\hline
\end{tabular}
\end{flushright}
Der Betrag versteht sich zzgl. der gesetzlichen Steuern.\\
Diese werden im Rechnungszeitraum auf der Rechnung gesondert ausgewiesen.\\
Zahlungsbedingungen: 30 Tage netto ab Rechnungsdatum.\\
Incoterm (2010) für Lieferungen innerhalb Deutschlands: DDP.
\begin{small}
\textbf{Gewährleistung:}\\
Die Gewährleistung für Zubehör und Ersatzteilprodukte und für Analytik-Hardwareprodukte beträgt 12 Monate.
\textbf{Hinweis:}\\
Für den Verkauf der in diesem Angebot aufgeführten Standard-Produkte und -Services gelten die aktuellen \emph{Agilent Geschäftsbedingungen} und alle sonstigen anwendbaren Zusatzbedingungen sowie zusätzliche Bedingungen, soweit darauf hier Bezug genommen wird. Soweit Produkte oder Services nach speziellen Kundenanforderungen hergestellt, konfiguriert oder angepasst werden, gelten für den Verkauf aller in diesem Angebot aufgeführten Produkte und Services die aktuellen \emph{Agilent Geschäftsbedingungen für kundenspezifische Produkte} und alle sonstigen anwendbaren Zusatzbedingungen sowie zusätzliche Bedingungen, soweit darauf hier Bezug genommen wird. Eine Kopie der maßgeblichen Bedingungen ist entweder beigefügt oder wurde Ihnen bereits zur Verfügung gestellt. Sollten Sie keine Kopie erhalten haben oder eine weitere Kopie benötigen, setzen Sie sich bitte mit uns in Verbindung. Soweit Sie mit Agilent eine gesonderte Vereinbarung getroffen haben, die den Verkauf der in diesem Angebot aufgeführten Produkte und Services umfasst, sind die Bestimmungen dieser Vereinbarung anwendbar. Abweichende oder ergänzende Vereinbarungen, insbesondere widersprechende Geschäftsbedingungen, sind nur gültig, wenn sie ausdrücklich schriftlich vereinbart worden sind. Die angegebenen Daten zur Verfügbarkeit von Produkten und Services sind vorläufig. Die tatsächlichen Lieferzeiten bzw. Lieferperioden werden Ihnen bei Auftragsbestätigung mitgeteilt. Waren, Technologien oder Software, die aus den Vereinigten Staaten von Amerika (\emph{USA}) oder anderen exportierenden Ländern ausgeführt werden, unterliegen den Ausfuhrbestimmungen der USA sowie anderer Rechtsordnungen. Bei Ausfuhr ist der Kunde dafür verantwortlich, dass die anwendbaren Ausfuhrbestimmungen eingehalten werden.
\end{small}
\begin{scriptsize}
Agilent Technologies Deutschland GmbH, Hewlett-Packard-Str. 8, D-76337 Waldbronn\\
Telefon +49 (0)7243-602-0\\
USt.-IdNr.: DE812729296, WEEE-Reg.-Nr. DE 86631749\\
Sitz der Gesellschaft: Waldbronn Amtsgericht Mannheim, HRB 723782\\
Geschäftsführer: Dr. Andreas Kistner (Vorsitzender der Geschäftsführung), Armin Jehle, Norbert Sabatzki, Dr. Knut Wintergerst\\
\href{www.agilent.com}{www.agilent.com}
\end{scriptsize}
\end{document}

@ -0,0 +1,16 @@
# Part Number Opt PL Description Qty Price EUR Breaks EUR Uplift % Total Discount % Net EUR Total EUR Sales Discount YA9% Contractual Discount Y99% Promotion Discount Y07% Demo Discount Y04% PH Code PH Description YMax
1 G7110B 29 1260 Infinity II isokratische Pumpe 1 8908 0 0 45 4899.4 4899.4 45 0 0 0 ISL100P1 Pumps
2 G7110B 001 29 HPLC System Tool Kit 1260 Infinity II 1 400 0 0 45 220 220 45 0 0 0
3 G7110B 094 29 Poroshell 120 EC-C18 3,0x150mm, 2,7um 1 1 0 0 45 0.55 0.55 45 0 0 0
4 G7116A 29 1260 Infinity II Therm. f. mehr. Saeulen 1 6494 0 0 45 3571.7 3571.7 45 0 0 0 ISL100LC1 LC Hardware
5 G7129A 29 1260 Inf. II Fluessigprobengeber 1 19905 0 0 45 10947.75 10947.75 45 0 0 0 ISL100A1 Autosamplers
6 G7129A 010 29 Standard-Schublade (6x11 Probenflaschen) 1 375 0 0 45 206.25 206.25 45 0 0 0
7 G7162A 29 1260 Infinity II Brechungsindexdetektor 1 13989 0 0 45 7693.95 7693.95 45 0 0 0 ISL100D1 Detectors
8 G7114A 29 1260 Infinity II VW-Detektor 1 9307 0 0 45 5118.85 5118.85 45 0 0 0 ISL100D1 Detectors
9 G7114A 018 29 Standarddurchflusszelle VWD 1 1612 0 0 45 886.6 886.6 45 0 0 0
10 G7850AA 29 Agilent GPC/SEC-Software 1 14789 0 0 45 8133.95 8133.95 45 0 0 0 ISL230L230 Special LC
11 PL1110-6125 BC PLgel 10um 500A 300 x 7.5 mm 2 1806 0 0 45 993.3 1986.6 45 0 0 0 CSCV27C04L GPC/SEC - PLgel
12 PL1110-6120 BC PLgel 10um 100A 300 x 7.5 mm 2 1806 0 0 45 993.3 1986.6 45 0 0 0 CSCV27C04L GPC/SEC - PLgel
13 SYS-LC-1260II 74 LC 1260 Infinity II System 1 0 0 0 20 0 0 20 0 0 0 TSSYS0SYLC Service Systems - Liquid Chromatography
14 SYS-LC-1260II 2C9 74 Einweisung zum ersten Methodenlauf 1 1034 0 0 20 827.2 827.2 20 0 0 0 TSSTRN Training Services
15 SYS-LC-1260II 8R1 74 CrossLab Silver - 1J, kompl. 1 2688 0 0 20 2150.4 2150.4 20 0 0 0 TSSYS1 Serviced As Systems - 1 YR
1 # Part Number Opt PL Description Qty Price EUR Breaks EUR Uplift % Total Discount % Net EUR Total EUR Sales Discount YA9% Contractual Discount Y99% Promotion Discount Y07% Demo Discount Y04% PH Code PH Description YMax
2 1 G7110B 29 1260 Infinity II isokratische Pumpe 1 8908 0 0 45 4899.4 4899.4 45 0 0 0 ISL100P1 Pumps
3 2 G7110B 001 29 HPLC System Tool Kit 1260 Infinity II 1 400 0 0 45 220 220 45 0 0 0
4 3 G7110B 094 29 Poroshell 120 EC-C18 3,0x150mm, 2,7um 1 1 0 0 45 0.55 0.55 45 0 0 0
5 4 G7116A 29 1260 Infinity II Therm. f. mehr. Saeulen 1 6494 0 0 45 3571.7 3571.7 45 0 0 0 ISL100LC1 LC Hardware
6 5 G7129A 29 1260 Inf. II Fluessigprobengeber 1 19905 0 0 45 10947.75 10947.75 45 0 0 0 ISL100A1 Autosamplers
7 6 G7129A 010 29 Standard-Schublade (6x11 Probenflaschen) 1 375 0 0 45 206.25 206.25 45 0 0 0
8 7 G7162A 29 1260 Infinity II Brechungsindexdetektor 1 13989 0 0 45 7693.95 7693.95 45 0 0 0 ISL100D1 Detectors
9 8 G7114A 29 1260 Infinity II VW-Detektor 1 9307 0 0 45 5118.85 5118.85 45 0 0 0 ISL100D1 Detectors
10 9 G7114A 018 29 Standarddurchflusszelle VWD 1 1612 0 0 45 886.6 886.6 45 0 0 0
11 10 G7850AA 29 Agilent GPC/SEC-Software 1 14789 0 0 45 8133.95 8133.95 45 0 0 0 ISL230L230 Special LC
12 11 PL1110-6125 BC PLgel 10um 500A 300 x 7.5 mm 2 1806 0 0 45 993.3 1986.6 45 0 0 0 CSCV27C04L GPC/SEC - PLgel
13 12 PL1110-6120 BC PLgel 10um 100A 300 x 7.5 mm 2 1806 0 0 45 993.3 1986.6 45 0 0 0 CSCV27C04L GPC/SEC - PLgel
14 13 SYS-LC-1260II 74 LC 1260 Infinity II System 1 0 0 0 20 0 0 20 0 0 0 TSSYS0SYLC Service Systems - Liquid Chromatography
15 14 SYS-LC-1260II 2C9 74 Einweisung zum ersten Methodenlauf 1 1034 0 0 20 827.2 827.2 20 0 0 0 TSSTRN Training Services
16 15 SYS-LC-1260II 8R1 74 CrossLab Silver - 1J, kompl. 1 2688 0 0 20 2150.4 2150.4 20 0 0 0 TSSYS1 Serviced As Systems - 1 YR