using System.Globalization; using System.Text; using Gremlin_BlazorServer.Data.EntityClasses; using Gremlin_BlazorServer.Pages.Quotes; using NuGet.Packaging; namespace Gremlin_BlazorServer.Services; public class QuoteHandling { // private static readonly GenericController genericController = new(); 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 static Quote ReadLineItems(Quote quote, Contact recipient, string clipboard) { try { quote = ResetTotals(quote); quote.LineItems = ReadLineItemsFromClipboard(quote, 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 (recipient.Account.AccountName is not null) quote.ValidFor = CheckForAcademic(recipient.Account); foreach (LineItem lineItem in quote.LineItems) { if (lineItem.OptionNumber is null or "") 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 static List ReadLineItemsFromClipboard(Quote quote, 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(quote, clipboardList).Result; return lineItems; } private static Task> ParseClipboardList(Quote quote, 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), QuoteId = quote.QuoteId }; lineItems.Add(lineItem); } else { Console.WriteLine("Angebot konnte nicht eingelesen werden!"); } return Task.FromResult(lineItems); } private static byte CheckForAcademic(Account account) { return account.AccountType?.AccountTypeCode == null ? (byte)60 : (byte)(account.AccountType.AccountTypeCode.StartsWith("N") ? 90 : 60); } private static decimal GetFreight(decimal net, decimal freight) { decimal freightNet = net * freight / 100; return freightNet < 3000 ? freightNet : 3000; } private static 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 static 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 static decimal GetTotal(Quote quote, string type) { decimal total = 0; if (quote.LineItems.Count == 0) 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 static 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 static async Task GenerateQuoteFromString(Quote quote, Contact recipient, string fileContent) { quote = ReadLineItems(quote, recipient, fileContent); if (recipient.Account.AccountName is not null) quote.Path = HostingService.GetPath(quote, recipient) ?? "Path not found!"; if (quote.LineItems is null || quote.LineItems.Count == 0) return quote; FileService.WriteQuoteToTsv(fileContent, quote); //TODO Load all relevant CustomDescriptions upfront foreach (LineItem lineItem in quote.LineItems) { CustomDescription? newCustomDescription = GenericController.Get(newCustomDescription => newCustomDescription.ProductNumber.Equals(lineItem.ProductNumber, StringComparison.Ordinal) && newCustomDescription.OptionNumber!.Equals(lineItem.OptionNumber, StringComparison.Ordinal)); if (newCustomDescription is null) continue; if (lineItem.ProductNumber is null) continue; if (newCustomDescription.DescriptionText 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); } // Product product = await GenericController.GetAsync(p => p.ProductNumber.Equals(lineItem.ProductNumber) && p.OptionNumber.Equals(lineItem.OptionNumber)); // lineItem.ProductId = product.ProductId; CustomDescription? customDescription = GenericController.Get(cD => cD.ProductNumber.Equals(lineItem.ProductNumber) && cD.OptionNumber.Equals(lineItem.OptionNumber)); if (customDescription is not null) lineItem.CustomDescriptionId = customDescription.CustomDescriptionId; // lineItem.QuoteId = quote.QuoteId; } return quote; } private static async Task> SuggestCustomDescriptions(LineItem lineItem) { IList suggestions = new List(); if (lineItem.ProductNumber is not null) suggestions.AddRange(await GenericController.GetAllAsync(cD => cD.ProductNumber!.Equals(lineItem.ProductNumber, StringComparison.Ordinal))); if (lineItem.OptionNumber is not null) suggestions.AddRange(await GenericController.GetAllAsync(cD => cD.OptionNumber!.Equals(lineItem.OptionNumber, StringComparison.Ordinal))); return suggestions.ToList(); } }