using System.Globalization; using System.Text; using Gremlin_BlazorServer.Data.EntityClasses; using Gremlin_BlazorServer.Pages.Quotes; namespace Gremlin_BlazorServer.Services; public class QuoteHandling { private static readonly GenericController genericController = new(); private readonly IWebHostEnvironment hostingEnvironment; public static async Task CreateTexAsync(Quote quote) { StringBuilder? texString = await TexService.CreateTex(quote); if (texString is null) return null; Console.WriteLine(texString.Length > 0 ? "Creating TexFile succesfully." : "Error during TexFile creation!"); return texString; } //FromWindowsGremlin private Quote ReadLineItems(Quote quote, string clipboard) { try { quote = ResetTotals(quote); quote.LineItems = ReadLineItemsFromClipboard(clipboard); quote.QuoteContains3Pp = DoesContains(quote, "3PP"); quote.QuoteContainsRb = DoesContains(quote, "RB"); quote.TotalListprice = GetTotal(quote, "TotalListprice"); quote.TotalDiscount = GetTotal(quote, "AverageDiscount"); quote.TotalNet = GetTotal(quote, "TotalNet"); if (quote.Recipient?.Account != null) quote.ValidFor = CheckForAcademic(quote.Recipient.Account); foreach (LineItem lineItem in quote.LineItems) { if (lineItem.OptionNumber == null) break; if (lineItem.OptionNumber.StartsWith("8D")) quote.Warranty = int.Parse(lineItem.OptionNumber.Last().ToString()) * 12; quote.Warranty = lineItem.OptionNumber switch { "9EC" => 24, "9CC" => 36, _ => quote.Warranty }; } quote = CalculateTotals(quote); return quote; } catch (Exception e) { Console.WriteLine(e); return new(); } } private List ReadLineItemsFromClipboard(string clipboard) { //Zeilen aufteilen IEnumerable clipboardLines = clipboard.Split(Environment.NewLine.ToCharArray()); List clipboardList = (from clipboardLine in clipboardLines where clipboardLine != "" select clipboardLine.Split('\t')).ToList(); List lineItems = ParseClipboardList(clipboardList).Result; return lineItems; } private async Task> ParseClipboardList(List lineItemStrings) { List lineItems = new(); CultureInfo cultureInfoUs = new("en-US"); foreach (string[] lineItemString in lineItemStrings) //Anzahl an Spalten entspricht Clipboard if (lineItemString.Length == 19) { //Header ignorieren if (lineItemString[0] == "#") continue; //Dateiinhalt in Klasse schreiben LineItem lineItem = new() { Position = ushort.Parse(lineItemString[0]), ProductNumber = lineItemString[1], OptionNumber = lineItemString[2], ProductLine = lineItemString[3], SapShortDescription = lineItemString[4], Amount = ushort.Parse(lineItemString[5]), ListPrice = decimal.Parse(lineItemString[6], cultureInfoUs), TotalDiscount = decimal.Parse(lineItemString[9], cultureInfoUs), NetPrice = decimal.Parse(lineItemString[10], cultureInfoUs), Total = decimal.Parse(lineItemString[11], cultureInfoUs), SalesDiscount = decimal.Parse(lineItemString[12], cultureInfoUs), ContractualDiscount = decimal.Parse(lineItemString[13], cultureInfoUs), PromotionalDiscount = decimal.Parse(lineItemString[14], cultureInfoUs), DemoDiscount = decimal.Parse(lineItemString[15], cultureInfoUs) }; lineItems.Add(lineItem); } else { Console.WriteLine("Angebot konnte nicht eingelesen werden!"); } return lineItems; } private byte CheckForAcademic(Account account) { return account.AccountType?.AccountTypeCode == null ? (byte)60 : (byte)(account.AccountType.AccountTypeCode.StartsWith("N") ? 90 : 60); } private decimal GetFreight(decimal net, decimal freight) { decimal freightNet = net * freight / 100; return freightNet < 3000 ? freightNet : 3000; } private Quote CalculateTotals(Quote quote) { quote.TotalFreightOnly = GetFreight(quote.TotalNet, quote.Freight); quote.TotalFreight = quote.TotalNet + quote.TotalFreightOnly; quote.TotalVat = quote.TotalFreight * Convert.ToDecimal(quote.Vat) / 100; quote.TotalGross = quote.TotalFreight * (100 + Convert.ToDecimal(quote.Vat)) / 100; return quote; } private Quote ResetTotals(Quote quote) { quote.TotalListprice = 0; quote.TotalNet = 0; quote.TotalFreightOnly = 0; quote.TotalFreight = 0; quote.TotalVat = 0; quote.TotalGross = 0; return quote; } private decimal GetTotal(Quote quote, string type) { decimal total = 0; if (quote.LineItems == null) return total; foreach (LineItem lineItem in quote.LineItems) switch (type) { case "TotalListprice": total += lineItem.ListPrice; break; case "TotalNet": total += lineItem.Total; break; case "AverageDiscount": total += lineItem.TotalDiscount; break; } if ((type == "AverageDiscount") & (quote.LineItems.Count != 0)) total /= quote.LineItems.Count; return total; } private bool DoesContains(Quote quote, string type) { if (quote.LineItems is null) return false; foreach (LineItem lineItem in quote.LineItems) switch (type) { case "3PP": if (lineItem.ProductLine == "3PP") { Console.WriteLine($"Quote contains 3PP with ProductNumber {lineItem.ProductNumber}"); return true; } break; case "RB": if ((lineItem.ProductLine == "RB") & (lineItem.ProductNumber != "R2005A")) { Console.WriteLine($"Quote contains RB with ProductNumber {lineItem.ProductNumber}"); return true; } break; } return false; } public async Task GenerateQuoteFromString(Quote quote, string fileContent) { HostingService hostingService = new(hostingEnvironment); quote = ReadLineItems(quote, fileContent); if (quote.Recipient?.Account?.AccountName is not null) quote = hostingService.SetPath(quote); if (quote.LineItems is null) return quote; FileService.WriteQuoteToTsv(fileContent, quote); //TODO Load all relevant CustomDescriptions upfront foreach (LineItem lineItem in quote.LineItems) { CustomDescription newCustomDescription = await genericController.GetAsync(newCustomDescription => newCustomDescription.ProductNumber.Equals(lineItem.ProductNumber, StringComparison.Ordinal) && newCustomDescription.OptionNumber.Equals(lineItem.OptionNumber, StringComparison.Ordinal)); if (newCustomDescription is null) { Console.WriteLine($"Keine CustomDescription für {lineItem.ProductNumber}#{lineItem.OptionNumber} verfügbar!"); List? suggestedCustomDescriptions = await SuggestCustomDescriptions(lineItem); newCustomDescription = new() { ProductNumber = lineItem.ProductNumber, OptionNumber = lineItem.OptionNumber, Heading = lineItem.SapShortDescription, DescriptionText = lineItem.SapLongDescription }; //Show windows to edit new cD await QuoteAdd.ShowCustomDescriptionModal(suggestedCustomDescriptions); //TODO need to wait for modal! //Insert new CustomDescription to db newCustomDescription.AccountId = 1; _ = await genericController.InsertAsync(newCustomDescription); } lineItem.Product = await genericController.GetAsync(p => p.ProductNumber.Equals(lineItem.ProductNumber) && p.OptionNumber.Equals(lineItem.OptionNumber)); if (lineItem.Product is null) return quote; 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; } return quote; } private static async Task?> SuggestCustomDescriptions(LineItem lineItem) { //IList? fromProductNumber = await genericController.GetAllAsync(cD => cD.ProductNumber.Equals(lineItem.ProductNumber, StringComparison.Ordinal)); IList? fromOptionNumber = new List(); if (lineItem.OptionNumber != "") fromOptionNumber = await genericController.GetAllAsync(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(); } }