From 717a42f63b0f3838c1a72a2f22958e35c2a139a1 Mon Sep 17 00:00:00 2001 From: DJh2o2 Date: Thu, 13 Apr 2023 11:32:37 +0200 Subject: [PATCH] Clipboard paste --- .../Gremlin_BlazorServer.csproj | 29 +- .../Pages/Quotes/QuoteAdd.razor | 536 +++++++++--------- .../Pages/Quotes/QuoteAdd.razor.cs | 112 +--- Gremlin_BlazorServer/Program.cs | 1 + .../Services/HostingService.cs | 11 +- .../Services/QuoteHandling.cs | 78 ++- 6 files changed, 376 insertions(+), 391 deletions(-) diff --git a/Gremlin_BlazorServer/Gremlin_BlazorServer.csproj b/Gremlin_BlazorServer/Gremlin_BlazorServer.csproj index c92ac2d..9f676f5 100644 --- a/Gremlin_BlazorServer/Gremlin_BlazorServer.csproj +++ b/Gremlin_BlazorServer/Gremlin_BlazorServer.csproj @@ -20,27 +20,28 @@ - - - - - - - + + + + + + + + - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/Gremlin_BlazorServer/Pages/Quotes/QuoteAdd.razor b/Gremlin_BlazorServer/Pages/Quotes/QuoteAdd.razor index 279f585..fab5c07 100644 --- a/Gremlin_BlazorServer/Pages/Quotes/QuoteAdd.razor +++ b/Gremlin_BlazorServer/Pages/Quotes/QuoteAdd.razor @@ -2,306 +2,304 @@ @using Gremlin_BlazorServer.Services @using Gremlin_BlazorServer.Data.EntityClasses @using System.Globalization -@using System.Security.Claims; -@using System.Text; @inject GenericController GenericController @inject NavigationManager NavigationManager +@inject QuoteHandling QuoteHandling @inject HostingService HostingService @inject IJSRuntime JsRuntime -@inject ILoadingIndicatorService ApplicationLoadingIndicatorService +@* @inject ILoadingIndicatorService ApplicationLoadingIndicatorService *@ - -
- - Recipient - - - - - - - - - - - - - - -
- - @if (quote is not null) - { -
+ +
- Quote Details - - - - - Angebotsname - - - - - - Angebotsnummer - - - - - - Angebotspfad - - " - - - - Gewährleistung (Monate) - - - - - - Angebotsgültigkeit (Tage) - - - - - - Mehrwertsteuer (%) - - - - - - Versandkosten (%) - - - - - + Recipient + + - @if (quote?.Recipient?.Account is not null) - { - - - FirstName - @quote.Recipient.FirstName - - - LastName - @quote.Recipient.LastName - - - AccountName - @quote.Recipient.Account.AccountName - - - Street - @quote.Recipient.Account.Street - - - Zip - @quote.Recipient.Account.Zip.ToString() - - - City - @quote.Recipient.Account.City - - - } + + + + + + + + + + + +
- - Preisinformation - Bruttopreise anzeigen - Einzelpreise ausweisen - Discounts ausweisen - +
- - - Listenpreis netto - - - - - - Summe netto - - - - - - Versandkosten - - - - - - Gesamtsumme netto - - - - - - Mehrwertsteuer - - - - - - Gesamtsumme brutto - - - - - - - -
- } + Quote Details + + + + + Angebotsname + + + + + + Angebotsnummer + + + + + + Angebotspfad + + " + + + + Gewährleistung (Monate) + + + + + + Angebotsgültigkeit (Tage) + + + + + + Mehrwertsteuer (%) + + + + + + Versandkosten (%) + + + + + - @if (quote?.LineItems is not null) { -
- - LineItems - - - - - - - - - - - - - -
- - @if (selectedLineItem?.Product?.CustomDescription is not null) { -
- - CustomDescriptions - + @if (quote?.Recipient?.Account is not null) { + - ProductNumber - @selectedLineItem.Product.CustomDescription.ProductNumber + FirstName + @quote.Recipient.FirstName - - OptionNumber - @selectedLineItem.OptionNumber + + LastName + @quote.Recipient.LastName - - Heading - @selectedLineItem.Product.CustomDescription.Heading + + AccountName + @quote.Recipient.Account.AccountName - - CoverletterText - @selectedLineItem.Product.CustomDescription.CoverletterText + + Street + @quote.Recipient.Account.Street - - DescriptionText - @selectedLineItem.Product.CustomDescription.DescriptionText + + Zip + @quote.Recipient.Account.Zip.ToString() + + + City + @quote.Recipient.Account.City - -
+ } - } - @if (quote is {LineItems: null }) { -
+ + Preisinformation + Bruttopreise anzeigen + Einzelpreise ausweisen + Discounts ausweisen + - Upload PriceSurfer Quote - - - Please select PriceSurfer quote as TSV - - - -
- } + + + Listenpreis netto + + + + + + Summe netto + + + + + + Versandkosten + + + + + + Gesamtsumme netto + + + + + + Mehrwertsteuer + + + + + + Gesamtsumme brutto + + + + + +
+
+
-
- Create Quote +@if (quote?.LineItems is not null) { +
+ + LineItems + + + + + + + + + + + + + +
+ + @if (selectedLineItem?.Product?.CustomDescription is not null) { +
+ + CustomDescriptions - - - - - - + + ProductNumber + @selectedLineItem.Product.CustomDescription.ProductNumber + + + OptionNumber + @selectedLineItem.OptionNumber + + + Heading + @selectedLineItem.Product.CustomDescription.Heading + + + CoverletterText + @selectedLineItem.Product.CustomDescription.CoverletterText + + + DescriptionText + @selectedLineItem.Product.CustomDescription.DescriptionText +
+ } +} - @if (!pdfNotReady && url != null && debug) { -
+@if (quote is {LineItems: null }) { +
- PDF - - - -
- } + Load PriceSurfer quote + + + + + + Please select PriceSurfer quote as TSV + + + +
+} - @if (quote != null && quote.Tex != null && debug) { -
+
- Tex - - - -
- } + Create Quote + + + + + + + + +
- +@if (!pdfNotReady && url != null && debug) { +
- -
+ PDF + + + +
+} - Authentication Failure! - You're not signed in. Please click on the upper right to either register or log in. -
- - +@if (quote != null && quote.Tex != null && debug) { +
+ + Tex + + + +
+} + + + + +
+ Authentication Failure! + You're not signed in. Please click on the upper right to either register or log in. +
+
+ \ No newline at end of file diff --git a/Gremlin_BlazorServer/Pages/Quotes/QuoteAdd.razor.cs b/Gremlin_BlazorServer/Pages/Quotes/QuoteAdd.razor.cs index ae264a2..4e30b57 100644 --- a/Gremlin_BlazorServer/Pages/Quotes/QuoteAdd.razor.cs +++ b/Gremlin_BlazorServer/Pages/Quotes/QuoteAdd.razor.cs @@ -1,4 +1,3 @@ -using System.Diagnostics; using System.Globalization; using System.Security.Claims; using System.Text; @@ -19,18 +18,18 @@ public partial class QuoteAdd { private bool isCreatingPdf; private bool isCreatingTex; private bool lineItemsNotReady = true; - private CustomDescription? newCustomDescription; + private static CustomDescription newCustomDescription; private bool pdfNotReady = true; private Quote quote = new(); private Contact? selectedContact; private LineItem? selectedLineItem; - private List? suggestedCustomDescriptions; + // private List? suggestedCustomDescriptions; private bool texNotReady = true; private string? url; [CascadingParameter] private Task? AuthenticationStateTask { get; set; } - [Inject] public IModalService? ModalService { get; set; } + [Inject] public static IModalService ModalService { get; set; } - public Task ShowCustomDescriptionModal() { + public static Task ShowCustomDescriptionModal(List suggestedCustomDescriptions) { return ModalService.Show(builder => { builder.Add(parameter => parameter.CustomDescription, newCustomDescription); builder.Add(parameter => parameter.SuggestedCustomDescriptions, suggestedCustomDescriptions); @@ -44,7 +43,7 @@ public partial class QuoteAdd { contacts = await GenericController.GetAllAsync(); selectedContact = contacts?.FirstOrDefault(); if (selectedContact is not null) - await OnSelectedContactChanged(selectedContact); + await SelectedContactChanged(selectedContact); SalesRep newSalesRep = new() { LastName = "Woitschetzki", @@ -83,37 +82,8 @@ public partial class QuoteAdd { _ = 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 is not null) quote = HostingService.SetPath(quote); - if (quote.LineItems is null) return; - - FileService.WriteQuoteToTsv(fileContent, quote); - - //TODO Load all relevant CustomDescriptions upfront - foreach (LineItem lineItem in quote.LineItems) { - 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!"); - 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 ShowCustomDescriptionModal(); - //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; - 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; - } + + quote = await QuoteHandling.GenerateQuoteFromString(quote, fileContent); } } catch (Exception exc) { @@ -125,18 +95,6 @@ public partial class QuoteAdd { } } - private 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(); - } - private static void SelectQuoteOnWritten(FileWrittenEventArgs e) { Console.WriteLine($"File: {e.File.Name} Position: {e.Position} Data: {Convert.ToBase64String(e.Data)}"); } @@ -145,7 +103,7 @@ public partial class QuoteAdd { Console.WriteLine($"File: {e.File.Name} Progress: {e.Percentage}"); } - private async Task OnSelectedContactChanged(Contact newSelectedContact) { + private async Task SelectedContactChanged(Contact newSelectedContact) { quote.Recipient = await GenericController.GetAsync(c => c.ContactId.Equals(newSelectedContact.ContactId)); if (quote.Recipient is not null) @@ -193,55 +151,31 @@ public partial class QuoteAdd { } } - 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 newSelectedLineItem) => selectedLineItem = newSelectedLineItem; - 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"); + + private async Task GetClipboardTextAsync() => await JsRuntime.InvokeAsync("navigator.clipboard.readText"); } \ No newline at end of file diff --git a/Gremlin_BlazorServer/Program.cs b/Gremlin_BlazorServer/Program.cs index 197764e..333ec44 100644 --- a/Gremlin_BlazorServer/Program.cs +++ b/Gremlin_BlazorServer/Program.cs @@ -22,6 +22,7 @@ builder.Services.AddServerSideBlazor(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddBlazorise(options => { options.Immediate = true; }) diff --git a/Gremlin_BlazorServer/Services/HostingService.cs b/Gremlin_BlazorServer/Services/HostingService.cs index 5a656bb..e43c0e1 100644 --- a/Gremlin_BlazorServer/Services/HostingService.cs +++ b/Gremlin_BlazorServer/Services/HostingService.cs @@ -2,14 +2,11 @@ using Gremlin_BlazorServer.Data.EntityClasses; namespace Gremlin_BlazorServer.Services; -internal class HostingService +public class HostingService { - private readonly IWebHostEnvironment _hostingEnvironment; + private readonly IWebHostEnvironment hostingEnvironment; - public HostingService(IWebHostEnvironment hostingEnvironment) - { - _hostingEnvironment = hostingEnvironment; - } + public HostingService(IWebHostEnvironment newHostingEnvironment) => hostingEnvironment = newHostingEnvironment; public Quote SetPath(Quote quote) { @@ -23,7 +20,7 @@ internal class HostingService string description = quote.Description.Replace(" ", "_"); quote.Path = Path.Combine( - _hostingEnvironment.WebRootPath, + hostingEnvironment.WebRootPath, "quotes", accountName, $"{DateTime.Today.Year}-{DateTime.Today.Month}-{quote.Recipient?.LastName}-{description}" diff --git a/Gremlin_BlazorServer/Services/QuoteHandling.cs b/Gremlin_BlazorServer/Services/QuoteHandling.cs index f90ef70..3c0858e 100644 --- a/Gremlin_BlazorServer/Services/QuoteHandling.cs +++ b/Gremlin_BlazorServer/Services/QuoteHandling.cs @@ -1,12 +1,14 @@ using System.Globalization; using System.Text; using Gremlin_BlazorServer.Data.EntityClasses; +using Gremlin_BlazorServer.Pages.Quotes; namespace Gremlin_BlazorServer.Services; -public static class QuoteHandling { - private static GenericController genericController = new(); +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; @@ -17,7 +19,7 @@ public static class QuoteHandling { //FromWindowsGremlin - public static Quote ReadLineItems(Quote quote, string clipboard) { + private Quote ReadLineItems(Quote quote, string clipboard) { try { quote = ResetTotals(quote); @@ -53,7 +55,7 @@ public static class QuoteHandling { } } - private static List ReadLineItemsFromClipboard(string clipboard) { + 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(); @@ -61,7 +63,7 @@ public static class QuoteHandling { return lineItems; } - private static async Task> ParseClipboardList(List lineItemStrings) { + private async Task> ParseClipboardList(List lineItemStrings) { List lineItems = new(); CultureInfo cultureInfoUs = new("en-US"); @@ -98,16 +100,16 @@ public static class QuoteHandling { return lineItems; } - private static byte CheckForAcademic(Account account) { + private 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) { + private decimal GetFreight(decimal net, decimal freight) { decimal freightNet = net * freight / 100; return freightNet < 3000 ? freightNet : 3000; } - private static Quote CalculateTotals(Quote quote) { + 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; @@ -115,7 +117,7 @@ public static class QuoteHandling { return quote; } - private static Quote ResetTotals(Quote quote) { + private Quote ResetTotals(Quote quote) { quote.TotalListprice = 0; quote.TotalNet = 0; quote.TotalFreightOnly = 0; @@ -126,7 +128,7 @@ public static class QuoteHandling { return quote; } - private static decimal GetTotal(Quote quote, string type) { + private decimal GetTotal(Quote quote, string type) { decimal total = 0; if (quote.LineItems == null) return total; @@ -148,8 +150,8 @@ public static class QuoteHandling { return total; } - private static bool DoesContains(Quote quote, string type) { - if (quote.LineItems == null) return false; + private bool DoesContains(Quote quote, string type) { + if (quote.LineItems is null) return false; foreach (LineItem lineItem in quote.LineItems) switch (type) { @@ -171,4 +173,56 @@ public static class QuoteHandling { 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(); + } } \ No newline at end of file