From 69afdd7755a0ed54e552040810a9c2f9b3cc9d92 Mon Sep 17 00:00:00 2001 From: Alexander Kastler Date: Sun, 25 Feb 2024 21:15:50 +0100 Subject: [PATCH] Extend integration tests #255 --- src/BraunauMobil.VeloBasar/appsettings.json | 2 +- .../Program.cs | 91 +----- .../AngleSharpExtensions.cs | 20 +- .../{AcceptSellers.cs => Acccept.cs} | 2 +- .../FirstBasar/{Creation.cs => Create.cs} | 2 +- .../FirstBasar/{SellProducts.cs => Sell.cs} | 2 +- .../{SettleSellers.cs => Settle.cs} | 5 +- .../SecondBasar/{Creation.cs => Create.cs} | 2 +- .../Steps/SecondBasar/Sell/SellProducts.cs | 74 +++++ .../Steps/SecondBasar/Settle.cs | 282 ++++++++++++++++++ .../TestContext.cs | 150 +++++++--- .../VeloBasarTest.cs | 11 +- 12 files changed, 497 insertions(+), 146 deletions(-) rename test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/{AcceptSellers.cs => Acccept.cs} (99%) rename test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/{Creation.cs => Create.cs} (97%) rename test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/{SellProducts.cs => Sell.cs} (98%) rename test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/{SettleSellers.cs => Settle.cs} (97%) rename test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/{Creation.cs => Create.cs} (97%) create mode 100644 test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Settle.cs diff --git a/src/BraunauMobil.VeloBasar/appsettings.json b/src/BraunauMobil.VeloBasar/appsettings.json index 549da4ef..128f6d91 100644 --- a/src/BraunauMobil.VeloBasar/appsettings.json +++ b/src/BraunauMobil.VeloBasar/appsettings.json @@ -2,7 +2,7 @@ "AllowedHosts": "*", "ApplicationSettings": { "Culture": "de-AT", - "ConnectionString": "User ID=postgres;Password=postgres;Host=localhost;Port=5432;Database=velobasar-integration-test;Pooling=true;" + "ConnectionString": "User ID=postgres;Password=postgres;Host=localhost;Port=5432;Database=velobasar;Pooling=true;" }, "Logging": { "LogLevel": { diff --git a/test/BraunauMobil.VeloBasar.DataGenerator/Program.cs b/test/BraunauMobil.VeloBasar.DataGenerator/Program.cs index 9b362294..3a3adb20 100644 --- a/test/BraunauMobil.VeloBasar.DataGenerator/Program.cs +++ b/test/BraunauMobil.VeloBasar.DataGenerator/Program.cs @@ -10,9 +10,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; -using System.Diagnostics; using System.Globalization; -using System.Text; using Xan.Extensions; namespace BraunauMobil.VeloBasar.DataGenerator; @@ -24,94 +22,7 @@ public static async Task Main() CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US"); CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US"); - Random rand = new(); - - StringBuilder sb = new(); - - string[] countries = ["Austria", "Germany"]; - - string firstName = rand.GetRandomElement(Names.FirstNames); - string lastName = rand.GetRandomElement(Names.FirstNames); - sb.AppendLine($"{{ \"BankAccountHolder\", \"{firstName} {firstName[0]}.{lastName[0]}. {lastName}\" }},"); - sb.AppendLine($"{{ \"City\", \"{rand.GetRandomElement(Names.Cities)}\" }},"); - sb.AppendLine($"{{ \"CountryId\", ID.Countries.{rand.GetRandomElement(countries)} }},"); - sb.AppendLine($"{{ \"EMail\", \"{firstName.ToLower().Replace(" ", "")}@{lastName.ToLower().Replace(" ", "")}.me\" }},"); - sb.AppendLine($"{{ \"FirstName\", \"{firstName}\" }},"); - sb.AppendLine($"{{ \"HasNewsletterPermission\", {(rand.Next(0, 2) == 0).ToString().ToLower()} }},"); - sb.AppendLine("{ \"IBAN\", \"\" },"); - sb.AppendLine($"{{ \"LastName\", \"{lastName}\" }},"); - sb.AppendLine($"{{ \"Street\", \"{rand.GetRandomElement(Names.Streets)} {rand.Next(1, 50)}\" }},"); - sb.Append("{ \"PhoneNumber\", \""); - for (int counter = 0; counter < rand.Next(8, 11); counter++) - { - sb.Append(rand.Next(0, 10)); - } - sb.AppendLine("\" },"); - sb.AppendLine($"{{ \"ZIP\", \"{rand.Next(1, 10)}{rand.Next(1, 10)}{rand.Next(1, 10)}{rand.Next(1, 10)}\" }},"); - - sb.AppendLine(); - - sb.AppendLine("--------------------------------------------------------------------------"); - sb.AppendLine("Products"); - sb.AppendLine(); - - - string[] typeNames = [ - "Unicycle", - "RoadBike", - "MansCityBike", - "WomansCityBike", - "ChildrensBike", - "Scooter", - "EBike", - "SteelSteed", - ]; - string[] colors = [ - "red", - "blue", - "green", - "yellow", - "orange", - "purple", - "pink", - "brown", - "gray", - "turquoise", - "lavender", - "maroon", - "indigo", - "cyan", - "olive", - "peach", - "teal", - "magenta", - "beige", - "slate", - ]; - - foreach (int _ in Enumerable.Range(0, 4)) - { - string brand = rand.GetRandomElement(Names.BrandNames); - sb.AppendLine($"{{ \"TypeId\", ID.ProductTypes.{rand.GetRandomElement(typeNames)} }},"); - sb.AppendLine($"{{ \"Brand\", \"{brand}\" }},"); - sb.AppendLine($"{{ \"Color\", \"{rand.GetRandomElement(colors)}\" }},"); - if (rand.Next(0, 2) == 0) - { - sb.AppendLine($"{{ \"FrameNumber\", \"{Guid.NewGuid().ToString()[..rand.Next(7, 10)]}\" }},"); - } - sb.AppendLine($"{{ \"Description\", \"{brand[..].ToUpper()}_{rand.Next(10000, 999999)}\" }},"); - sb.AppendLine($"{{ \"TireSize\", \"{rand.GetRandomElement(Names.TireSizes)}\" }},"); - sb.AppendLine($"{{ \"Price\", {Math.Round((decimal)rand.GetGaussian(100, 50), 2)}M }},"); - sb.AppendLine(); - } - - string fileName = @"c:\temp\testData.txt"; - File.WriteAllText(fileName, sb.ToString()); - ProcessStartInfo info = new(fileName) - { - UseShellExecute = true - }; - Process.Start(info); + await GeneratePostgresAsync("User ID=postgres;Password=postgres;Host=localhost;Port=5432;Database=velobasar;Pooling=true;"); } private static async Task GeneratePostgresAsync(string connectionString) diff --git a/test/BraunauMobil.VeloBasar.IntegrationTests/AngleSharpExtensions.cs b/test/BraunauMobil.VeloBasar.IntegrationTests/AngleSharpExtensions.cs index 9908a018..85e46a5f 100644 --- a/test/BraunauMobil.VeloBasar.IntegrationTests/AngleSharpExtensions.cs +++ b/test/BraunauMobil.VeloBasar.IntegrationTests/AngleSharpExtensions.cs @@ -25,28 +25,28 @@ public static IHtmlAnchorElement QueryTableApplyLink(this IParentNode node, int { ArgumentNullException.ThrowIfNull(node); - IHtmlTableElement? table = node.QuerySelector("table"); - table.Should().NotBeNull(); - IHtmlTableRowElement headerRow = table!.Rows[0]; - INode idHeaderCell = headerRow.Cells.Should().ContainSingle(cell => cell.TextContent == "Id").Subject; - int idColumnIndex = headerRow.Cells.Index(idHeaderCell); - - IHtmlTableRowElement row = table.Rows.Should().ContainSingle(row => row.Cells[idColumnIndex].TextContent == rowId.ToString()).Subject; - return row.QueryAnchorByText("Apply"); + return node.QueryTableLinkByIdAndText(rowId, "Apply"); } public static IHtmlAnchorElement QueryTableDetailsLink(this IParentNode node, int rowId) { ArgumentNullException.ThrowIfNull(node); + return node.QueryTableLinkByIdAndText(rowId, "Details"); + } + + public static IHtmlAnchorElement QueryTableLinkByIdAndText(this IParentNode node, int rowId, string linkText) + { + ArgumentNullException.ThrowIfNull(node); + IHtmlTableElement? table = node.QuerySelector("table"); - table.Should().NotBeNull(); + table!.Should().NotBeNull(); IHtmlTableRowElement headerRow = table!.Rows[0]; INode idHeaderCell = headerRow.Cells.Should().ContainSingle(cell => cell.TextContent == "Id").Subject; int idColumnIndex = headerRow.Cells.Index(idHeaderCell); IHtmlTableRowElement row = table.Rows.Should().ContainSingle(row => row.Cells[idColumnIndex].TextContent == rowId.ToString()).Subject; - return row.QueryAnchorByText("Details"); + return row.QueryAnchorByText(linkText); } public static IHtmlFormElement QueryForm(this IParentNode node, string selector = "form") diff --git a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/AcceptSellers.cs b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Acccept.cs similarity index 99% rename from test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/AcceptSellers.cs rename to test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Acccept.cs index c9a0b78f..ab095288 100644 --- a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/AcceptSellers.cs +++ b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Acccept.cs @@ -1,6 +1,6 @@ namespace BraunauMobil.VeloBasar.IntegrationTests.Steps.FirstBasar; -public class AcceptSellers(TestContext context) +public class Acccept(TestContext context) { public async Task Run() { diff --git a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Creation.cs b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Create.cs similarity index 97% rename from test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Creation.cs rename to test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Create.cs index c23b75b0..93d923f1 100644 --- a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Creation.cs +++ b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Create.cs @@ -1,6 +1,6 @@ namespace BraunauMobil.VeloBasar.IntegrationTests.Steps.FirstBasar; -public class Creation(TestContext context) +public class Create(TestContext context) { public async Task Run() { diff --git a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/SellProducts.cs b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Sell.cs similarity index 98% rename from test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/SellProducts.cs rename to test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Sell.cs index 92e7d51e..6db2800c 100644 --- a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/SellProducts.cs +++ b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Sell.cs @@ -2,7 +2,7 @@ namespace BraunauMobil.VeloBasar.IntegrationTests.Steps.FirstBasar; -public class SellProducts(TestContext context) +public class Sell(TestContext context) { public async Task Run() { diff --git a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/SettleSellers.cs b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Settle.cs similarity index 97% rename from test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/SettleSellers.cs rename to test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Settle.cs index eabe8071..98d86fdf 100644 --- a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/SettleSellers.cs +++ b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/FirstBasar/Settle.cs @@ -1,6 +1,6 @@ namespace BraunauMobil.VeloBasar.IntegrationTests.Steps.FirstBasar; -public class SettleSellers(TestContext context) +public class Settle(TestContext context) { public async Task Run() { @@ -17,7 +17,8 @@ public async Task Run() IHtmlAnchorElement voucherAnchor = successDocument.QueryAnchorByText("Voucher"); SettlementDocumentModel document = await context.HttpClient.GetSettlementDocumentAsync(voucherAnchor.Href); - document.Should().BeEquivalentTo(context.SettlementDocument("XYZ - First Bazaar : Settlement #1", + document.Should().BeEquivalentTo(context.SettlementDocument( + "XYZ - First Bazaar : Settlement #1", "Edoras, 5/4/2063", "Schattenfell Magsame".Line("Heidenschuss 41").Line("6295 Hobbingen").Line(), "Seller.-ID: 1", diff --git a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Creation.cs b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Create.cs similarity index 97% rename from test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Creation.cs rename to test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Create.cs index 29ee23a2..f23547bd 100644 --- a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Creation.cs +++ b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Create.cs @@ -1,6 +1,6 @@ namespace BraunauMobil.VeloBasar.IntegrationTests.Steps.SecondBasar; -public class Creation(TestContext context) +public class Create(TestContext context) { public async Task Run() { diff --git a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Sell/SellProducts.cs b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Sell/SellProducts.cs index 926ae1fd..f0af6a00 100644 --- a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Sell/SellProducts.cs +++ b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Sell/SellProducts.cs @@ -8,5 +8,79 @@ public async Task Run() await new LockProductUnlockAndSellIt(context).Run(); await new LooseProductUnlockAndSellIt(context).Run(); await new SellTwoProductsCancelOneSellItAgainCancelItAndFinallySellIt(context).Run(); + + await AssertBasarDetails(); + } + + private async Task AssertBasarDetails() + { + BasarSettlementStatus basarSettlementStatus = new(false, + new SellerGroupSettlementStatus(7, 0), + new SellerGroupSettlementStatus(6, 0), + new SellerGroupSettlementStatus(1, 0) + ); + BasarDetailsModel expectedDetails = new(new BasarEntity(), basarSettlementStatus) + { + AcceptanceCount = 9, + AcceptedProductsAmount = 1369.43M, + AcceptedProductsCount = 14, + AcceptedProductTypesByAmount = [ + new ChartDataPoint(172.10M, "Scooter", X.AnyColor), + new ChartDataPoint(69.54M, "E-bike", X.AnyColor), + new ChartDataPoint(125.97M, "Road bike", X.AnyColor), + new ChartDataPoint(151.34M, "Steel steed", X.AnyColor), + new ChartDataPoint(333.40M, "Men's city bike", X.AnyColor), + new ChartDataPoint(183.90M, "Woman's city bike", X.AnyColor), + new ChartDataPoint(189.54M, "Unicycle", X.AnyColor), + new ChartDataPoint(143.64M, "Children's bike", X.AnyColor), + ], + AcceptedProductTypesByCount = [ + new ChartDataPoint(3, "Scooter", X.AnyColor), + new ChartDataPoint(1, "E-bike", X.AnyColor), + new ChartDataPoint(2, "Road bike", X.AnyColor), + new ChartDataPoint(1, "Steel steed", X.AnyColor), + new ChartDataPoint(2, "Men's city bike", X.AnyColor), + new ChartDataPoint(2, "Woman's city bike", X.AnyColor), + new ChartDataPoint(2, "Unicycle", X.AnyColor), + new ChartDataPoint(1, "Children's bike", X.AnyColor), + ], + LockedProductsCount = 0, + LostProductsCount = 0, + PriceDistribution = [ + new ChartDataPoint(1, "$10.00", X.AnyColor), + new ChartDataPoint(1, "$50.00", X.AnyColor), + new ChartDataPoint(1, "$60.00", X.AnyColor), + new ChartDataPoint(2, "$70.00", X.AnyColor), + new ChartDataPoint(1, "$80.00", X.AnyColor), + new ChartDataPoint(1, "$90.00", X.AnyColor), + new ChartDataPoint(1, "$110.00", X.AnyColor), + new ChartDataPoint(2, "$120.00", X.AnyColor), + new ChartDataPoint(2, "$150.00", X.AnyColor), + new ChartDataPoint(1, "$160.00", X.AnyColor), + new ChartDataPoint(1, "$190.00", X.AnyColor), + ], + SaleCount = 6, + SaleDistribution = [ + new ChartDataPoint(554.89M, "12:23 PM", X.AnyColor), + ], + SoldProductsAmount = 554.89M, + SoldProductsCount = 6, + SoldProductTypesByAmount = [ + new ChartDataPoint(51.06M, "Scooter", X.AnyColor), + new ChartDataPoint(69.54M, "E-bike", X.AnyColor), + new ChartDataPoint(183.90M, "Woman's city bike", X.AnyColor), + new ChartDataPoint(106.75M, "Unicycle", X.AnyColor), + new ChartDataPoint(143.64M, "Children's bike", X.AnyColor), + ], + SoldProductTypesByCount = [ + new ChartDataPoint(1, "Scooter", X.AnyColor), + new ChartDataPoint(1, "E-bike", X.AnyColor), + new ChartDataPoint(2, "Woman's city bike", X.AnyColor), + new ChartDataPoint(1, "Unicycle", X.AnyColor), + new ChartDataPoint(1, "Children's bike", X.AnyColor), + ], + }; + + await context.AssertBasarDetails(ID.SecondBasar, expectedDetails); } } diff --git a/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Settle.cs b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Settle.cs new file mode 100644 index 00000000..eddf6cd6 --- /dev/null +++ b/test/BraunauMobil.VeloBasar.IntegrationTests/Steps/SecondBasar/Settle.cs @@ -0,0 +1,282 @@ +namespace BraunauMobil.VeloBasar.IntegrationTests.Steps.SecondBasar; + +public class Settle(TestContext context) +{ + public async Task Run() + { + await SettleSeller(ID.Sellers.MeneldorBorondir, "Seller #2 Meneldor Borondir - Velo Basar", "Settlement #1 - Velo Basar", context.SettlementDocument( + "XYZ - Second Bazaar : Settlement #1", + "Thal, 6/4/2064", + "Meneldor Borondir".Line("Heßgasse 10").Line("2828 Bree").Line(), + "Seller.-ID: 2", + "Sales commission (10.00% of $120.60):", + "$120.60", + "$12.06", + "$108.54", + "2 Product", + "$120.60", + [ + new ProductTableRowDocumentModel("3", "Additive - Scooter".Line("X45").Line(" blue X290jbgn"), "16", "$51.06", null), + new ProductTableRowDocumentModel("5", "Draisin - E-bike".Line("DR-F5").Line(" white"), "23", "$69.54", null) + ], + "2 Product", + "$163.23", + [ + new ProductTableRowDocumentModel("4", "Toxy - Scooter".Line("TY 66-17").Line(" white"), "17", "$45.75", null), + new ProductTableRowDocumentModel("6", "Cyclecraft - Road bike".Line("No lights, brakes are fine").Line(" yellow"), "28", "$117.48", null) + ], + false, + "Meneldor Borondir", + "", + context.BankingQrCode("Meneldor Borondir", "EUR108.54", "XYZ - Revenue Second Bazaar"), + "Thal on Tuesday, May 6, 2064 at 12:23 PM" + ) + ); + + await SettleSeller(ID.Sellers.AnsenGróin, "Seller #8 Ansen Gróin - Velo Basar", "Settlement #2 - Velo Basar", context.SettlementDocument( + "XYZ - Second Bazaar : Settlement #2", + "Thal, 6/4/2064", + "Ansen Gróin".Line("Liebiggasse 3").Line("4579 Tuckbergen").Line(), + "Seller.-ID: 8", + "1 Product", + "$75.29", + [ + new ProductTableRowDocumentModel("15", "Nishiki - Scooter".Line("NISHIKI_266634").Line(" peach"), "14", "$75.29", null), + ], + false, + "Ansen A.G. Gróin", + "AT06 2011 1979 1882 1983", + context.BankingQrCode("Ansen A.G. Gróin", "AT062011197918821983", "EUR", "XYZ - Revenue Second Bazaar"), + "Thal on Tuesday, May 6, 2064 at 12:23 PM" + ) + ); + + await SettleSeller(ID.Sellers.AmrothGerstenmann, "Seller #3 Amroth Gerstenmann - Velo Basar", "Settlement #3 - Velo Basar", context.SettlementDocument( + "XYZ - Second Bazaar : Settlement #3", + "Thal, 6/4/2064", + "Amroth Gerstenmann".Line("Concordiaplatz 48").Line("7872 Dwollingen").Line(), + "Seller.-ID: 3", + false, + "Amroth Gerstenmann", + "", + context.BankingQrCode("Amroth Gerstenmann", "EUR", "XYZ - Revenue Second Bazaar"), + "Thal on Tuesday, May 6, 2064 at 12:23 PM" + ) + ); + + await SettleSeller(ID.Sellers.LanghöhlenSiriondil, "Seller #4 Langhöhlen Siriondil - Velo Basar", "Settlement #4 - Velo Basar", context.SettlementDocument( + "XYZ - Second Bazaar : Settlement #4", + "Thal, 6/4/2064", + "Langhöhlen Siriondil".Line("Börseplatz 11").Line("2178 Nargothrond").Line(), + "Seller.-ID: 4", + "Sales commission (10.00% of $69.54):", + "$69.54", + "$6.95", + "$62.59", + "1 Product", + "$69.54", + [ + new ProductTableRowDocumentModel("7", "Epple - Woman's city bike".Line("No tires").Line(" white G#%$BIBM#$)"), "22", "$69.54", null), + ], + "1 Product", + "$82.79", + [ + new ProductTableRowDocumentModel("13", "Subtil Bikes - Unicycle".Line("SUBTIL BIKES_963431").Line(" brown d3b90198"), "24", "$82.79", null), + ], + false, + "Langhöhlen Siriondil", + "", + context.BankingQrCode("Langhöhlen Siriondil", "EUR62.59", "XYZ - Revenue Second Bazaar"), + "Thal on Tuesday, May 6, 2064 at 12:23 PM" + ) + ); + + await SettleSeller(ID.Sellers.FrórBilbo, "Seller #5 Frór Bilbo - Velo Basar", "Settlement #5 - Velo Basar", context.SettlementDocument( + "XYZ - Second Bazaar : Settlement #5", + "Thal, 6/4/2064", + "Frór Bilbo".Line("Helmut-Zilk-Platz 27").Line("8475 Andúnië").Line(), + "Seller.-ID: 5", + "Sales commission (10.00% of $221.11):", + "$221.11", + "$22.11", + "$199.00", + "2 Product", + "$221.11", + [ + new ProductTableRowDocumentModel("10", "Seidel & Naumann - Unicycle".Line("SALIKO_52513").Line(" lavender"), "14", "$106.75", null), + new ProductTableRowDocumentModel("11", "Leiba - Woman's city bike".Line("MIELE_398047").Line(" maroon 1b26-4d44-94fe-027810ef43e7"), "17", "$114.36", null) + ], + "2 Product", + "$334.87", + [ + new ProductTableRowDocumentModel("8", "Pedalpower - Steel steed".Line("VOSS SPEZIALRAD_465693").Line(" gray 95f7-4ba0-94b6-6c45a1cd0913"), "16", "$151.34", null), + new ProductTableRowDocumentModel("9", "Egon Rahe - Men's city bike".Line("VELOMOBILES_92370").Line(" maroon"), "20", "$183.53", null) + ], + false, + "Frór F.B. Bilbo", + "", + context.BankingQrCode("Frór F.B. Bilbo", "EUR199", "XYZ - Revenue Second Bazaar"), + "Thal on Tuesday, May 6, 2064 at 12:23 PM" + ) + ); + + await SettleSeller(ID.Sellers.MallorFimbrethil, "Seller #9 Mallor Fimbrethil - Velo Basar", "Settlement #6 - Velo Basar", context.SettlementDocument( + "XYZ - Second Bazaar : Settlement #6", + "Thal, 6/4/2064", + "Mallor Fimbrethil".Line("Schönlaterngasse 16").Line("2758 Edhellond").Line(), + "Seller.-ID: 9", + "1 Product", + "$8.49", + [ + new ProductTableRowDocumentModel("16", "Idworx - Road bike".Line("IDWORX_768016").Line(" orange 12a2dc85-"), "24", "$8.49", null), + ], + false, + "Mallor M.F. Fimbrethil", + "", + context.BankingQrCode("Mallor M.F. Fimbrethil", "EUR", "XYZ - Revenue Second Bazaar"), + "Thal on Tuesday, May 6, 2064 at 12:23 PM" + ) + ); + + await SettleSeller(ID.Sellers.ChicaCiryatur, "Seller #6 Chica Ciryatur - Velo Basar", "Settlement #7 - Velo Basar", context.SettlementDocument( + "XYZ - Second Bazaar : Settlement #7", + "Thal, 6/4/2064", + "Chica Ciryatur".Line("Tiefer Graben 6").Line("7332 Avallóne").Line(), + "Seller.-ID: 6", + "Sales commission (10.00% of $143.64):", + "$143.64", + "$14.36", + "$129.28", + "1 Product", + "$143.64", + [ + new ProductTableRowDocumentModel("12", "Indienrad - Children's bike".Line("INDIENRAD_246011").Line(" brown"), "26", "$143.64", null), + ], + true, + "Chica C.C. Ciryatur", + "AT38 1400 0163 1454 4716", + context.BankingQrCode("Chica C.C. Ciryatur", "AT381400016314544716", "EUR129.28", "XYZ - Revenue Second Bazaar"), + "Thal on Tuesday, May 6, 2064 at 12:23 PM" + ) + ); + + await SettleSeller(ID.Sellers.FolcwineGollum, "Seller #7 Folcwine Gollum - Velo Basar", "Settlement #8 - Velo Basar", context.SettlementDocument( + "XYZ - Second Bazaar : Settlement #8", + "Thal, 6/4/2064", + "Folcwine Gollum".Line("Domgasse 25").Line("7356 Unterharg").Line(), + "Seller.-ID: 7", + "1 Product", + "$149.87", + [ + new ProductTableRowDocumentModel("14", "Univega - Men's city bike".Line("UNIVEGA_749336").Line(" slate 3eb2377a-"), "26", "$149.87", null) + ], + false, + "Folcwine F.G. Gollum", + "", + context.BankingQrCode("Folcwine F.G. Gollum", "EUR", "XYZ - Revenue Second Bazaar"), + "Thal on Tuesday, May 6, 2064 at 12:23 PM" + ) + ); + + await AssertBasarDetails(); + } + + private async Task AssertBasarDetails() + { + BasarSettlementStatus basarSettlementStatus = new(true, + new SellerGroupSettlementStatus(7, 7), + new SellerGroupSettlementStatus(6, 6), + new SellerGroupSettlementStatus(1, 1) + ); + BasarDetailsModel expectedDetails = new(new BasarEntity(), basarSettlementStatus) + { + AcceptanceCount = 9, + AcceptedProductsAmount = 1369.43M, + AcceptedProductsCount = 14, + AcceptedProductTypesByAmount = [ + new ChartDataPoint(172.10M, "Scooter", X.AnyColor), + new ChartDataPoint(69.54M, "E-bike", X.AnyColor), + new ChartDataPoint(125.97M, "Road bike", X.AnyColor), + new ChartDataPoint(151.34M, "Steel steed", X.AnyColor), + new ChartDataPoint(333.40M, "Men's city bike", X.AnyColor), + new ChartDataPoint(183.90M, "Woman's city bike", X.AnyColor), + new ChartDataPoint(189.54M, "Unicycle", X.AnyColor), + new ChartDataPoint(143.64M, "Children's bike", X.AnyColor), + ], + AcceptedProductTypesByCount = [ + new ChartDataPoint(3, "Scooter", X.AnyColor), + new ChartDataPoint(1, "E-bike", X.AnyColor), + new ChartDataPoint(2, "Road bike", X.AnyColor), + new ChartDataPoint(1, "Steel steed", X.AnyColor), + new ChartDataPoint(2, "Men's city bike", X.AnyColor), + new ChartDataPoint(2, "Woman's city bike", X.AnyColor), + new ChartDataPoint(2, "Unicycle", X.AnyColor), + new ChartDataPoint(1, "Children's bike", X.AnyColor), + ], + LockedProductsCount = 0, + LostProductsCount = 0, + PriceDistribution = [ + new ChartDataPoint(1, "$10.00", X.AnyColor), + new ChartDataPoint(1, "$50.00", X.AnyColor), + new ChartDataPoint(1, "$60.00", X.AnyColor), + new ChartDataPoint(2, "$70.00", X.AnyColor), + new ChartDataPoint(1, "$80.00", X.AnyColor), + new ChartDataPoint(1, "$90.00", X.AnyColor), + new ChartDataPoint(1, "$110.00", X.AnyColor), + new ChartDataPoint(2, "$120.00", X.AnyColor), + new ChartDataPoint(2, "$150.00", X.AnyColor), + new ChartDataPoint(1, "$160.00", X.AnyColor), + new ChartDataPoint(1, "$190.00", X.AnyColor), + ], + SaleCount = 6, + SaleDistribution = [ + new ChartDataPoint(554.89M, "12:23 PM", X.AnyColor), + ], + SoldProductsAmount = 554.89M, + SoldProductsCount = 6, + SoldProductTypesByAmount = [ + new ChartDataPoint(51.06M, "Scooter", X.AnyColor), + new ChartDataPoint(69.54M, "E-bike", X.AnyColor), + new ChartDataPoint(183.90M, "Woman's city bike", X.AnyColor), + new ChartDataPoint(106.75M, "Unicycle", X.AnyColor), + new ChartDataPoint(143.64M, "Children's bike", X.AnyColor), + ], + SoldProductTypesByCount = [ + new ChartDataPoint(1, "Scooter", X.AnyColor), + new ChartDataPoint(1, "E-bike", X.AnyColor), + new ChartDataPoint(2, "Woman's city bike", X.AnyColor), + new ChartDataPoint(1, "Unicycle", X.AnyColor), + new ChartDataPoint(1, "Children's bike", X.AnyColor), + ], + }; + + await context.AssertBasarDetails(ID.SecondBasar, expectedDetails); + } + + private async Task SettleSeller(int sellerId, string expectedDetailsTitle, string expectedSuccessTitle, SettlementDocumentModel expectedDocument) + { + IHtmlDocument sellerDetailsDocument = await GetSellerDetails(sellerId); + sellerDetailsDocument.Title.Should().Be(expectedDetailsTitle); + + IHtmlAnchorElement settleAnchor = sellerDetailsDocument.QueryAnchorByText("Settle"); + + IHtmlDocument successDocument = await context.HttpClient.GetDocumentAsync(settleAnchor.Href); + successDocument.Title.Should().Be(expectedSuccessTitle); + + IHtmlAnchorElement voucherAnchor = successDocument.QueryAnchorByText("Voucher"); + SettlementDocumentModel document = await context.HttpClient.GetSettlementDocumentAsync(voucherAnchor.Href); + document.Should().BeEquivalentTo(expectedDocument); + } + + private async Task GetSellerDetails(int sellerId) + { + IHtmlDocument sellerListDocument = await context.HttpClient.NavigateMenuAsync("Seller"); + IHtmlFormElement form = sellerListDocument.QueryForm(); + IHtmlButtonElement searchButton = sellerListDocument.QueryButtonByText("Search"); + + return await context.HttpClient.SendFormAsync(form, searchButton, new Dictionary + { + { "SearchString", sellerId } + }); + } +} diff --git a/test/BraunauMobil.VeloBasar.IntegrationTests/TestContext.cs b/test/BraunauMobil.VeloBasar.IntegrationTests/TestContext.cs index b93b7520..2192be94 100644 --- a/test/BraunauMobil.VeloBasar.IntegrationTests/TestContext.cs +++ b/test/BraunauMobil.VeloBasar.IntegrationTests/TestContext.cs @@ -91,8 +91,12 @@ public async Task AssertSellerDetails(int basarId, int sellerId, SellerDetailsMo } public string BankingQrCode(string seller, string amount, string decscription) + => BankingQrCode(seller, "", amount, decscription); + + public string BankingQrCode(string seller, string iban, string amount, string decscription) { ArgumentNullException.ThrowIfNull(seller); + ArgumentNullException.ThrowIfNull(iban); ArgumentNullException.ThrowIfNull(amount); ArgumentNullException.ThrowIfNull(decscription); @@ -102,7 +106,7 @@ public string BankingQrCode(string seller, string amount, string decscription) .Line("SCT") .Line() .Line(seller) - .Line() + .Line(iban) .Line(amount) .Line() .Line() @@ -151,8 +155,112 @@ public SaleDocumentModel SaleDocument(string title, string locationAndDateText, ) ); - public SettlementDocumentModel SettlementDocument(string title, string locationAndDateText, string addressText, string sellerIdText, string commissionPartText, string payoutAmountInclComissionText, string payoutCommissionAmountText, string payoutAmountText, string payoutTableCountText, string payoutTablePriceText, IReadOnlyCollection payoutTableRows, string pickupTableCountText, string pickupTablePriceText, IReadOnlyCollection pickupTableRows, bool addBankingQrCode, string bankAccountHolder, string iban, string bankingQrCodeContent, string signatureText) - => new(title, + public SettlementDocumentModel SettlementDocument(string title, string locationAndDateText, string addressText, string sellerIdText, bool addBankingQrCode, string bankAccountHolder, string iban, string bankingQrCodeContent, string signatureText) + => SettlementDocument(title, + locationAndDateText, + addressText, + sellerIdText, + null, null, null, null, null, null, null, null, null, null, + addBankingQrCode, + bankAccountHolder, + iban, + bankingQrCodeContent, + signatureText + ); + + public SettlementDocumentModel SettlementDocument(string title, string locationAndDateText, string addressText, string sellerIdText, string pickupTableCountText, string pickupTablePriceText, IReadOnlyCollection pickupTableRows, bool addBankingQrCode, string bankAccountHolder, string iban, string bankingQrCodeContent, string signatureText) + => SettlementDocument(title, + locationAndDateText, + addressText, + sellerIdText, + null, null, null, null, null, null, null, + pickupTableCountText, + pickupTablePriceText, + pickupTableRows, + addBankingQrCode, + bankAccountHolder, + iban, + bankingQrCodeContent, + signatureText + ); + + public SettlementDocumentModel SettlementDocument(string title, string locationAndDateText, string addressText, string sellerIdText, string commissionPartText, string payoutAmountInclComissionText, string payoutCommissionAmountText, string payoutAmountText, string payoutTableCountText, string payoutTablePriceText, IReadOnlyCollection payoutTableRows, bool addBankingQrCode, string bankAccountHolder, string iban, string bankingQrCodeContent, string signatureText) + => SettlementDocument(title, + locationAndDateText, + addressText, + sellerIdText, + commissionPartText, + payoutAmountInclComissionText, + payoutCommissionAmountText, + payoutAmountText, + payoutTableCountText, + payoutTablePriceText, + payoutTableRows, + null, null, null, + addBankingQrCode, + bankAccountHolder, + iban, + bankingQrCodeContent, + signatureText + ); + + public SettlementDocumentModel SettlementDocument(string title, string locationAndDateText, string addressText, string sellerIdText, string? commissionPartText, string? payoutAmountInclComissionText, string? payoutCommissionAmountText, string? payoutAmountText, string? payoutTableCountText, string? payoutTablePriceText, IReadOnlyCollection? payoutTableRows, string? pickupTableCountText, string? pickupTablePriceText, IReadOnlyCollection? pickupTableRows, bool addBankingQrCode, string bankAccountHolder, string iban, string bankingQrCodeContent, string signatureText) + { + ProductsTableDocumentModel? payoutTable = null; + + if (payoutTableCountText is not null + && payoutTablePriceText is not null + && payoutTableRows is not null) + { + payoutTable = new ProductsTableDocumentModel( + "Id", + "Procuct description", + "Size", + "Selling price", + "Sum:", + payoutTableCountText, + payoutTablePriceText, + null, + payoutTableRows + ); + } + + ProductsTableDocumentModel? pickupTable = null; + if (pickupTableCountText is not null + && pickupTablePriceText is not null + && pickupTableRows is not null) + { + pickupTable = new ProductsTableDocumentModel( + "Id", + "Procuct description", + "Size", + "Price", + "Sum:", + pickupTableCountText, + pickupTablePriceText, + null, + pickupTableRows + ); + } + + SettlementCommisionSummaryModel? settlementCommisionSummary = null; + if (commissionPartText is not null + && payoutAmountInclComissionText is not null + && payoutCommissionAmountText is not null + && payoutAmountText is not null) + { + settlementCommisionSummary = new SettlementCommisionSummaryModel( + "Revenue from items sold:", + "Costs:", + "Total amount:", + commissionPartText, + payoutAmountInclComissionText, + payoutCommissionAmountText, + payoutAmountText + ); + } + + return new(title, locationAndDateText, "Page {0} of {1}", " - powered by https://github.com/braunau-mobil/velo-basar", @@ -163,38 +271,10 @@ public SettlementDocumentModel SettlementDocument(string title, string locationA PrintSettings.Website, addressText, sellerIdText, - new SettlementCommisionSummaryModel( - "Revenue from items sold:", - "Costs:", - "Total amount:", - commissionPartText, - payoutAmountInclComissionText, - payoutCommissionAmountText, - payoutAmountText - ), - new ProductsTableDocumentModel( - "Id", - "Procuct description", - "Size", - "Selling price", - "Sum:", - payoutTableCountText, - payoutTablePriceText, - null, - payoutTableRows - ), + settlementCommisionSummary, + payoutTable, PrintSettings.Settlement.SoldTitle, - new ProductsTableDocumentModel( - "Id", - "Procuct description", - "Size", - "Price", - "Sum:", - pickupTableCountText, - pickupTablePriceText, - null, - pickupTableRows - ), + pickupTable, PrintSettings.Settlement.NotSoldTitle, PrintSettings.Settlement.ConfirmationText, addBankingQrCode, @@ -205,4 +285,6 @@ public SettlementDocumentModel SettlementDocument(string title, string locationA "Signature ______________________________", signatureText ); + } + } diff --git a/test/BraunauMobil.VeloBasar.IntegrationTests/VeloBasarTest.cs b/test/BraunauMobil.VeloBasar.IntegrationTests/VeloBasarTest.cs index d6315115..d9841d34 100644 --- a/test/BraunauMobil.VeloBasar.IntegrationTests/VeloBasarTest.cs +++ b/test/BraunauMobil.VeloBasar.IntegrationTests/VeloBasarTest.cs @@ -23,16 +23,17 @@ public async Task Run() await new Steps.InitialSetup(_context).Run(); await Login(); - await new Steps.FirstBasar.Creation(_context).Run(); - await new Steps.FirstBasar.AcceptSellers(_context).Run(); - await new Steps.FirstBasar.SellProducts(_context).Run(); - await new Steps.FirstBasar.SettleSellers(_context).Run(); + await new Steps.FirstBasar.Create(_context).Run(); + await new Steps.FirstBasar.Acccept(_context).Run(); + await new Steps.FirstBasar.Sell(_context).Run(); + await new Steps.FirstBasar.Settle(_context).Run(); X.Clock.Now = X.FirstContactDay.AddYears(1).AddMonths(1).AddDays(1).AddHours(1).AddMinutes(1).AddSeconds(1); - await new Steps.SecondBasar.Creation(_context).Run(); + await new Steps.SecondBasar.Create(_context).Run(); await new Steps.SecondBasar.Accept.AcceptSellers(_context).Run(); await new Steps.SecondBasar.Sell.SellProducts(_context).Run(); + await new Steps.SecondBasar.Settle(_context).Run(); } private async Task Login()