diff --git a/Gremlin_BlazorServer/Data/DBClasses/EntityConfiguration.cs b/Gremlin_BlazorServer/Data/DBClasses/EntityConfiguration.cs index c547e87..7039643 100644 --- a/Gremlin_BlazorServer/Data/DBClasses/EntityConfiguration.cs +++ b/Gremlin_BlazorServer/Data/DBClasses/EntityConfiguration.cs @@ -183,15 +183,15 @@ public class ProductConfiguration : IEntityTypeConfiguration { productEntity.Property(p => p.OptionNumber).HasDefaultValue(""); productEntity.Property(p => p.SapShortDescription).HasDefaultValue(""); productEntity.Property(p => p.SapLongDescription).HasDefaultValue(""); - productEntity.Property(p => p.Weight).HasDefaultValue(0); + productEntity.Property(p => p.Weight); productEntity.Property(p => p.ProductStatus).HasDefaultValue("Active"); productEntity.Property(p => p.IntroductionDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd(); - productEntity.Property(p => p.ListPrice).IsRequired(); + productEntity.Property(p => p.ListPrice); productEntity.Property(p => p.DataCreationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd(); productEntity.Property(p => p.DataValidFrom).HasColumnType("DATETIME").HasDefaultValueSql("CURRENT_TIMESTAMP").ValueGeneratedOnAdd(); productEntity.Property(p => p.DataValidUntil).HasColumnType("DATETIME").HasDefaultValueSql("'9999-12-31 23:59:59.000000'").ValueGeneratedOnAdd(); productEntity.Property(p => p.DataVersionNumber).HasDefaultValue(1).IsRequired(); - productEntity.Property(p => p.DataVersionComment).HasDefaultValue(""); + productEntity.Property(p => p.DataVersionComment).HasDefaultValue("Gremlin_BlazorServer"); productEntity.Property(p => p.DataStatus).IsRequired().HasDefaultValue("Active"); productEntity.Property(p => p.DataModificationDate).HasColumnType("TIMESTAMP").HasDefaultValueSql("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP").ValueGeneratedOnAddOrUpdate().IsConcurrencyToken(); productEntity.Property(p => p.DataModificationByUser).HasColumnType("TINYTEXT").IsRequired().HasDefaultValueSql("ON INSERT CURRENT_USER() ON UPDATE CURRENT_USER()"); diff --git a/Gremlin_BlazorServer/Data/EntityClasses/Product.cs b/Gremlin_BlazorServer/Data/EntityClasses/Product.cs index 9b3812a..6b73b7d 100644 --- a/Gremlin_BlazorServer/Data/EntityClasses/Product.cs +++ b/Gremlin_BlazorServer/Data/EntityClasses/Product.cs @@ -19,13 +19,13 @@ public class Product : IMetadata public string? OptionNumber { get; set; } public string? SapShortDescription { get; set; } public string? SapLongDescription { get; set; } - public float Weight { 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; } + 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; diff --git a/Gremlin_BlazorServer/Data/EntityClasses/Quote.cs b/Gremlin_BlazorServer/Data/EntityClasses/Quote.cs index 8cc6385..fa72d68 100644 --- a/Gremlin_BlazorServer/Data/EntityClasses/Quote.cs +++ b/Gremlin_BlazorServer/Data/EntityClasses/Quote.cs @@ -53,5 +53,5 @@ public class Quote : IMetadata public DateTime DataValidFrom { get; set; } = DateTime.Now; public DateTime DataValidUntil { get; set; } = DateTime.MaxValue; public string? DataVersionComment { get; set; } - public uint DataVersionNumber { get; set; } + public uint DataVersionNumber { get; set; } // this is the concurrency token } diff --git a/Gremlin_BlazorServer/Pages/Quotes/QuoteAdd.razor.cs b/Gremlin_BlazorServer/Pages/Quotes/QuoteAdd.razor.cs index 974aeb1..ae264a2 100644 --- a/Gremlin_BlazorServer/Pages/Quotes/QuoteAdd.razor.cs +++ b/Gremlin_BlazorServer/Pages/Quotes/QuoteAdd.razor.cs @@ -71,15 +71,10 @@ public partial class QuoteAdd { newQuote.QuoteId = lastQuote is not null ? lastQuote.QuoteId + 1 : 1; newQuote.QuotationNumber = $"DE-{newQuote.SalesRep?.TerritoryId}-{DateTime.Now:My}-{newQuote.QuoteId}"; newQuote.Description = "Gerät"; - await TryToSaveQuote(newQuote); return newQuote; } - private async Task TryToSaveQuote(Quote newQuote) { - Debug.WriteLine(await GenericController.UpdateAsync(newQuote) > 0 ? "Speichern der Quote erfolgreich." : "Fehler beim Speichern der Quote!"); - } - private async Task SelectQuoteOnChanged(FileChangedEventArgs e) { try { foreach (IFileEntry? file in e.Files) { @@ -112,13 +107,12 @@ public partial class QuoteAdd { _ = await GenericController.InsertAsync(newCustomDescription); } - lineItem.Product = new() { - ProductNumber = lineItem.ProductNumber, - OptionNumber = lineItem.OptionNumber, - CustomDescription = await GenericController.GetAsync(cD => cD.ProductNumber.Equals(lineItem.ProductNumber) && cD.OptionNumber.Equals(lineItem.OptionNumber)) - }; - // lineItem.Product = await GenericController.GetAsync(p => p.ProductNumber.Equals(lineItem.ProductNumber) && p.OptionNumber.Equals(lineItem.OptionNumber), "CustomDescription"); - // quote.LineItems[i].Product.CustomDescription = await genericController.GetAsync(cD => cD.CustomDescriptionId.Equals(newCustomDescription.CustomDescriptionId)); + lineItem.Product = await GenericController.GetAsync(p => p.ProductNumber.Equals(lineItem.ProductNumber) && p.OptionNumber.Equals(lineItem.OptionNumber)); + if (lineItem.Product is null) return; + lineItem.ProductId = lineItem.Product.ProductId; + lineItem.Product.CustomDescription = await GenericController.GetAsync(cD => cD.ProductNumber.Equals(lineItem.ProductNumber) && cD.OptionNumber.Equals(lineItem.OptionNumber)); + lineItem.Quote = quote; + lineItem.QuoteId = lineItem.Quote.QuoteId; } } } @@ -177,7 +171,7 @@ public partial class QuoteAdd { isCreatingTex = true; StringBuilder? tex = await QuoteHandling.CreateTexAsync(quote); - if (tex == null) return; + if (tex is null) return; quote.Tex = tex.ToString(); if (quote.Tex == null) return; diff --git a/Gremlin_BlazorServer/Services/GenericController.cs b/Gremlin_BlazorServer/Services/GenericController.cs index 7682dd2..9f24520 100644 --- a/Gremlin_BlazorServer/Services/GenericController.cs +++ b/Gremlin_BlazorServer/Services/GenericController.cs @@ -49,7 +49,8 @@ public class GenericController { return await gremlinDb.Set().ToListAsync(); } } - catch (Exception exception) { + catch (DbUpdateConcurrencyException exception) { + await HandleDbUpdateConcurrencyException(exception); Console.WriteLine(exception.InnerException); return null; } @@ -61,7 +62,8 @@ public class GenericController { return await gremlinDb.Set().Include(include).ToListAsync(); } } - catch (Exception exception) { + catch (DbUpdateConcurrencyException exception) { + await HandleDbUpdateConcurrencyException(exception); Console.WriteLine(exception.InnerException); return null; } @@ -73,7 +75,8 @@ public class GenericController { return await gremlinDb.Set().Include(include1).Include(include2).ToListAsync(); } } - catch (Exception exception) { + catch (DbUpdateConcurrencyException exception) { + await HandleDbUpdateConcurrencyException(exception); Console.WriteLine(exception.InnerException); return null; } @@ -86,7 +89,8 @@ public class GenericController { return await Task.Run(() => gremlinDb.Set().AsEnumerable().Where(t => search(t)).ToList()); } } - catch (Exception exception) { + catch (DbUpdateConcurrencyException exception) { + await HandleDbUpdateConcurrencyException(exception); Console.WriteLine(exception.InnerException); return null; } @@ -99,7 +103,8 @@ public class GenericController { return await Task.Run(() => gremlinDb.Set().Include(include).AsEnumerable().Where(t => search(t)).ToList()); } } - catch (Exception exception) { + catch (DbUpdateConcurrencyException exception) { + await HandleDbUpdateConcurrencyException(exception); Console.WriteLine(exception.InnerException); return null; } @@ -138,7 +143,8 @@ public class GenericController { return await Task.Run(() => gremlinDb.Set().AsEnumerable().FirstOrDefault(t => search(t))); } } - catch (Exception exception) { + catch (DbUpdateConcurrencyException exception) { + await HandleDbUpdateConcurrencyException(exception); Console.WriteLine(exception.InnerException); return null; } @@ -164,23 +170,26 @@ public class GenericController { return await Task.Run(() => gremlinDb.Set().Include(include1).AsEnumerable().FirstOrDefault(t => search(t))); } } - catch (Exception exception) { + catch (DbUpdateConcurrencyException exception) { + await HandleDbUpdateConcurrencyException(exception); Console.WriteLine(exception.InnerException); return null; } } public async Task GetAsync(Predicate search, string include1, string include2) where TResult : class, IMetadata { - ArgumentNullException.ThrowIfNull(search); - try { - await using (GremlinDb gremlinDb = new()) { - return await Task.Run(() => gremlinDb.Set().Include(include1).Include(include2).AsEnumerable().FirstOrDefault(t => search(t))); - } - } - catch (Exception exception) { - Console.WriteLine(exception.InnerException); - return null; + ArgumentNullException.ThrowIfNull(search); + try { + await using (GremlinDb gremlinDb = new()) { + return await Task.Run(() => gremlinDb.Set().Include(include1).Include(include2).AsEnumerable().FirstOrDefault(t => search(t))); } + } + catch (DbUpdateConcurrencyException exception) { + await HandleDbUpdateConcurrencyException(exception); + Console.WriteLine(exception.InnerException); + return null; + } + } public TResult? GetLast() where TResult : class, IMetadata { @@ -225,19 +234,15 @@ public class GenericController { try { await using (GremlinDb gremlinDb = new()) { gremlinDb.Set().Add(entity); - - //DEBUG - List changedEntries = gremlinDb.ChangeTracker.Entries().ToList(); - foreach (EntityEntry changedEntry in changedEntries) - Console.WriteLine(changedEntry); - return await gremlinDb.SaveChangesAsync(); } } - catch (Exception exception) { + catch (DbUpdateConcurrencyException exception) { + await HandleDbUpdateConcurrencyException(exception); Console.WriteLine(exception.InnerException); return 0; } + } public async Task InsertAsync(IEnumerable entities) where T : class, IMetadata { @@ -247,23 +252,25 @@ public class GenericController { return await gremlinDb.SaveChangesAsync(); } } - catch (Exception exception) { + catch (DbUpdateConcurrencyException exception) { + await HandleDbUpdateConcurrencyException(exception); Console.WriteLine(exception.InnerException); return 0; } + } public static bool IsExisting(Predicate search) where T : class, IMetadata { - ArgumentNullException.ThrowIfNull(search); - try { - using (GremlinDb gremlinDb = new()) { - return gremlinDb.Set().AsEnumerable().Any(t => search(t)); - } - } - catch (Exception exception) { - Console.WriteLine(exception.InnerException); - return false; + ArgumentNullException.ThrowIfNull(search); + try { + using (GremlinDb gremlinDb = new()) { + return gremlinDb.Set().AsEnumerable().Any(t => search(t)); } + } + catch (Exception exception) { + Console.WriteLine(exception.InnerException); + return false; + } } public int Update(T entity) where T : class, IMetadata { @@ -280,15 +287,42 @@ public class GenericController { } public async Task UpdateAsync(T entity) where T : class, IMetadata { - try { - await using (GremlinDb gremlinDb = new()) { + await using (GremlinDb gremlinDb = new()) { + try { gremlinDb.Set().Update(entity); return await gremlinDb.SaveChangesAsync(false); } + catch (DbUpdateConcurrencyException exception) { + await HandleDbUpdateConcurrencyException(exception); + Console.WriteLine(exception.InnerException); + return 0; + } } - catch (Exception exception) { - Console.WriteLine(exception.InnerException); - return 0; + } + + private async Task HandleDbUpdateConcurrencyException(DbUpdateConcurrencyException exception) where T : class, IMetadata { + // Loop through the entities that caused the concurrency conflict + foreach (EntityEntry? entry in exception.Entries) { + if (entry.Entity is T) { + T? clientValues = (T)entry.Entity; + PropertyValues? databaseEntry = await entry.GetDatabaseValuesAsync(); + if (databaseEntry is null) + // The record has been deleted from the database + // Notify the user or handle the error in some other way + throw new("The record has been deleted from the database."); + T? databaseValues = (T)databaseEntry.ToObject(); + // Compare the database values with the client values + if (databaseValues.DataVersionNumber != clientValues.DataVersionNumber) + // The name has been changed by another user + // Notify the user or handle the error in some other way + throw new("The record has been modified by another user."); + // The conflict is caused by a property other than the name + // Notify the user or handle the error in some other way + throw new("A concurrency conflict occurred."); + } + + // Handle concurrency conflicts for other entity types, if necessary + throw new NotSupportedException($"Concurrency conflicts for entities of type {entry.Entity.GetType().Name} are not supported."); } } diff --git a/Gremlin_BlazorServer/wwwroot/quotes/Institut_für_Arbeitsschutz_der_Deutschen_Gesetzlic/2023-4-Witzler-Gerät/DE-83PE89-423-223.pdf b/Gremlin_BlazorServer/wwwroot/quotes/Institut_für_Arbeitsschutz_der_Deutschen_Gesetzlic/2023-4-Witzler-Gerät/DE-83PE89-423-223.pdf index ebc227b..5d37333 100644 Binary files a/Gremlin_BlazorServer/wwwroot/quotes/Institut_für_Arbeitsschutz_der_Deutschen_Gesetzlic/2023-4-Witzler-Gerät/DE-83PE89-423-223.pdf and b/Gremlin_BlazorServer/wwwroot/quotes/Institut_für_Arbeitsschutz_der_Deutschen_Gesetzlic/2023-4-Witzler-Gerät/DE-83PE89-423-223.pdf differ diff --git a/Gremlin_BlazorServer/wwwroot/quotes/Institut_für_Arbeitsschutz_der_Deutschen_Gesetzlic/2023-4-Witzler-Gerät/DE-83PE89-423-223.tex b/Gremlin_BlazorServer/wwwroot/quotes/Institut_für_Arbeitsschutz_der_Deutschen_Gesetzlic/2023-4-Witzler-Gerät/DE-83PE89-423-223.tex index d754f3f..30ab5f8 100644 --- a/Gremlin_BlazorServer/wwwroot/quotes/Institut_für_Arbeitsschutz_der_Deutschen_Gesetzlic/2023-4-Witzler-Gerät/DE-83PE89-423-223.tex +++ b/Gremlin_BlazorServer/wwwroot/quotes/Institut_für_Arbeitsschutz_der_Deutschen_Gesetzlic/2023-4-Witzler-Gerät/DE-83PE89-423-223.tex @@ -35,7 +35,7 @@ \par \begin{flushright} -\colorbox{AgilentBlau}{\textcolor{white}{\textsc{\Huge{Preisinformation}}}} +\colorbox{AgilentBlau}{\textcolor{white}{\textsc{\Huge{Angebot}}}} \end{flushright} \begin{tabular}{p{0.4\hsize}p{0.6\hsize}} @@ -46,8 +46,8 @@ \textbf{Angebotsnummer:}&DE-83PE89-423-223\\ Angebotdatum:&\today\\ Angebotsgültigkeit:&60 Tage\\\textbf{Ansprechpartner:}&Sascha Woitschetzki\\ -Telefon: &+49 208 74129134\\ -Mobil:&+49 176 22285334\\ +Telefon: &+49 176 22285334\\ +Mobil:&\\ 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 diff --git a/Gremlin_BlazorServer/wwwroot/quotes/Stadtwerke_Aachen_AG_Strom-Gas-Wasser-Wärme/2023-4-De Jong-Gerät/DE-83PE89-423-223.pdf b/Gremlin_BlazorServer/wwwroot/quotes/Stadtwerke_Aachen_AG_Strom-Gas-Wasser-Wärme/2023-4-De Jong-Gerät/DE-83PE89-423-223.pdf index d76d405..dd41949 100644 Binary files a/Gremlin_BlazorServer/wwwroot/quotes/Stadtwerke_Aachen_AG_Strom-Gas-Wasser-Wärme/2023-4-De Jong-Gerät/DE-83PE89-423-223.pdf and b/Gremlin_BlazorServer/wwwroot/quotes/Stadtwerke_Aachen_AG_Strom-Gas-Wasser-Wärme/2023-4-De Jong-Gerät/DE-83PE89-423-223.pdf differ diff --git a/Gremlin_BlazorServer/wwwroot/quotes/Stadtwerke_Aachen_AG_Strom-Gas-Wasser-Wärme/2023-4-De Jong-Gerät/DE-83PE89-423-223.tex b/Gremlin_BlazorServer/wwwroot/quotes/Stadtwerke_Aachen_AG_Strom-Gas-Wasser-Wärme/2023-4-De Jong-Gerät/DE-83PE89-423-223.tex index a86edf4..8477ee7 100644 --- a/Gremlin_BlazorServer/wwwroot/quotes/Stadtwerke_Aachen_AG_Strom-Gas-Wasser-Wärme/2023-4-De Jong-Gerät/DE-83PE89-423-223.tex +++ b/Gremlin_BlazorServer/wwwroot/quotes/Stadtwerke_Aachen_AG_Strom-Gas-Wasser-Wärme/2023-4-De Jong-Gerät/DE-83PE89-423-223.tex @@ -69,39 +69,39 @@ Sehr geehrter Herr De Jong,\par nachfolgend erhalten Sie Ihr gewünschtes Angebot über ein(e) Gerät.\\ Es umfasst im Einzelnen: \begin{itemize} -\item quaternäre Pumpe mit integriertem Entgaser (\#1) +\item Product missing (\#1) \begin{itemize} -\item Werkzeugsatz (\#2) -\item Aktive Kolbenhinterspülung (\#3) -\item Aktives Einlassventil (\#4) -\item Säule (\#5) +\item Product missing (\#2) +\item Product missing (\#3) +\item Product missing (\#4) +\item Product missing (\#5) \end{itemize} -\item Vialsampler (\#6) +\item Product missing (\#6) \begin{itemize} -\item Probenteller für 6x11 2,0 ml Vials (\#7) -\item Ohne Gerätetreiber (\#8) +\item Product missing (\#7) +\item Product missing (\#8) \end{itemize} -\item Säulenthermostat (\#9) +\item Product missing (\#9) \begin{itemize} -\item Ventilantrieb (\#10) +\item Product missing (\#10) \end{itemize} -\item 4-Säulenauswahlventil (\#11) +\item Product missing (\#11) \begin{itemize} -\item Kapillarkit (\#12) +\item Product missing (\#12) \end{itemize} -\item Diodenarraydetektor High Sensitivity (\#13) -\item Fluoreszenzspektrendetektor (\#14) -\item OpenLab CDS 2 Instrument Connection (\#15) +\item Product missing (\#13) +\item Product missing (\#14) +\item Product missing (\#15) \begin{itemize} -\item OpenLab CDS 2 IC für LC (\#16) -\item OpenLab CDS 2 IC für 3D-UV/DAD (\#17) +\item Product missing (\#16) +\item Product missing (\#17) \end{itemize} -\item 1260 Infinity II HPLC mit Zusatzfunktionen (\#18) +\item Product missing (\#18) \begin{itemize} -\item Einführung (\#19) -\item Zwei Jahre Gewährleistung (\#20) +\item Product missing (\#19) +\item Product missing (\#20) \end{itemize} -\item Überprüfung, Deinstallation und Versand (\#21) +\item Product missing (\#21) \end{itemize} Für Rückfragen und Änderungswünsche stehe ich Ihnen gerne zur Verfügung.\par Mit freundlichen Grüßen\\ @@ -112,27 +112,6 @@ Mit freundlichen Grüßen\\ \begin{longtable} {| cp{0.595\textwidth} crr |} \hline \textbf{\#} & \textbf{Produktbeschreibung} (Produktnummer) & \textbf{Menge} & \textbf{Discount} & \textbf{Preis}\\ \hline \endhead -1 &\textbf{Quaternäre Pumpe} (G7111B)\newline 1260 Infinity II quaternäre Pumpe, Maximaldruck 600 bar. Mit integriertem 4-Kanal-Entgaser, vergünstigter Säule, Verbindungskapillaren, Lösemittelwanne und -flaschen.\newline Listenpreis: \SI{25079}{\sieuro}&1&\SI{45}{\%}&\SI{13793.45}{\sieuro}\\ -2 &\textbf{Werkzeugsatz} (G7111B\#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{Aktive Kolbenhinterspülung} (G7111B\#030)\newline Automatische Reinigung und Pflege der Pumpenköpfe, -dichtungen und -ventile für maximale Lebensdauer. Besonders empfohlen bei salzhaltigen Analyten oder Puffern.\newline Listenpreis: \SI{1463}{\sieuro}&1&\SI{45}{\%}&\SI{804.65}{\sieuro}\\ -4 &\textbf{Aktives Einlassventil} (G7111B\#032)\newline Aktives Einlassventil (AIV) für einen zuverlässigen Pumpenbetrieb bei der Verwendung von Puffern.\newline Listenpreis: \SI{889}{\sieuro}&1&\SI{45}{\%}&\SI{488.95}{\sieuro}\\ -5 &\textbf{Säule} (G7111B\#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}\\ -6 &\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}\\ -7 &\textbf{Probenteller für 6x11 2,0 ml Vials} (G7129A\#010)\newline \newline Listenpreis: \SI{375}{\sieuro}&1&\SI{45}{\%}&\SI{206.25}{\sieuro}\\ -8 &\textbf{Ohne Gerätetreiber} (G7129A\#060)\newline Es wird ein vorhandener Gerätetreiber verwendet oder mit der Software angeboten.\newline Listenpreis: \SI{-1793}{\sieuro}&1&\SI{45}{\%}&\SI{-986.15}{\sieuro}\\ -9 &\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}\\ -10 &\textbf{Ventilantrieb} (G7116A\#058)\newline Ventilantrieb für 1260 Infinity II Thermostat G7116A. Zur Verwendung mit QuickChange-Ventilköpfen.\newline Listenpreis: \SI{1541}{\sieuro}&1&\SI{45}{\%}&\SI{847.55}{\sieuro}\\ -11 &\textbf{4-Säulenauswahlventil} (G4237A)\newline QuickChange-Ventilkopf zur Auswahl von 4 Säulen (4Pos./10 Anschlüsse), max. 800 bar. Zum schnellen Säulenwechsel oder Schaltung eines Bypasses zur Direktaufgabe auf das Massenspektrometer.\newline Listenpreis: \SI{4808}{\sieuro}&1&\SI{45}{\%}&\SI{2644.4}{\sieuro}\\ -12 &\textbf{Kapillarkit} (G4237A\#006)\newline 4-Säulenauswahlventil-Kapillarkit, Inhalt: 0,17 mm ID Kapillaren und vier Quick Connect-Wärmetauscher, zur Verwendung in G7116A.\newline Listenpreis: \SI{3474}{\sieuro}&1&\SI{45}{\%}&\SI{1910.7}{\sieuro}\\ -13 &\textbf{Diodenarraydetektor HS} (G7117C)\newline 1260 Infinity II Diodenarray-Detektor high sensitivity für höchste Empfindlichkeit, 120 Hz Datenrate für schnelle Multiwellenlängen- und Spektralanalysen. Messbereich 190 – 640 nm, RFID-Tags für Zelle und Lampe. Inklusive Standard-Max-Light-Flusszelle (10 mm, V = 1 µl, max. 70 bar).\newline Listenpreis: \SI{24906}{\sieuro}&1&\SI{45}{\%}&\SI{13698.3}{\sieuro}\\ -14 &\textbf{Fluoreszenzspektrendetektor} (G7121B)\newline 1260 Infinity II Fluoreszenzdetektor, spektrenfähig.\newline Für Multiwellenlängen-Detektion, Online-Aufnahme von  Anregungs- und Emissionsspektren (200 – 1200 nm), Datenrate bis 148 Hz. Inkl. Standard-Durchflusszelle (V = 8 µl, max. 20 bar).\newline Listenpreis: \SI{21984}{\sieuro}&1&\SI{45}{\%}&\SI{12091.2}{\sieuro}\\ -15 &\textbf{OpenLab CDS 2 Instrument Connection} (M8431AA)\newline \newline Listenpreis: \SI{1364}{\sieuro}&1&\SI{45}{\%}&\SI{750.2}{\sieuro}\\ -16 &\textbf{OpenLab CDS 2 IC für LC} (M8431AA\#001)\newline Lizenz und Treiber zur Gerätesteuerung unter OpenLab CDS. Gerätetyp: LC (ohne DAD)\newline Listenpreis: \SI{0}{\sieuro}&1&\SI{45}{\%}&\SI{0}{\sieuro}\\ -17 &\textbf{OpenLab CDS 2 IC für 3D-UV/DAD} (M8431AA\#005)\newline Lizenz und Treiber zur Gerätesteuerung unter OpenLab CDS. Gerätetyp: 3D-UV/DAD\newline Listenpreis: \SI{0}{\sieuro}&1&\SI{45}{\%}&\SI{0}{\sieuro}\\ -18 &\textbf{1260 Infinity II HPLC mit Zusatzfunktionen} (SYS-LC-1260IIE)\newline \newline Listenpreis: \SI{0}{\sieuro}&1&\SI{20}{\%}&\SI{0}{\sieuro}\\ -19 &\textbf{Einführung} (SYS-LC-1260IIE\#2A9)\newline Standardeinweisung für neue Anwender im Rahmen der Installation.\newline Listenpreis: \SI{1193}{\sieuro}&1&\SI{20}{\%}&\SI{954.4}{\sieuro}\\ -20 &\textbf{Erweiterte Gewährleistung für akademische Kunden, zwei Jahre komplett} (SYS-LC-1260IIE\#9EC)\newline Verlängerung der Gewährleistung von 12 auf 24 Monate.\newline Listenpreis: \SI{5215}{\sieuro}&1&\SI{40}{\%}&\SI{3129}{\sieuro}\\ -21 &\textbf{Überprüfung, Deinstallation und Versand} (R2005A)\newline Überprüfung, Deinstallation und Versand der in Zahlung gegebenen Geräte.\newline Die erfolgreiche Überprüfung der Geräte durch einen Agilent Techniker ist Voraussetzung für die Annahme der Inzahlungnahme durch Agilent.\newline Listenpreis: \SI{0}{\sieuro}&1&\SI{0}{\%}&\SI{0}{\sieuro}\\ \hline \end{longtable} \end{center}