From d025f880b31e55aa3a14289fafea45afbe1e86d5 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Tue, 17 Mar 2026 15:46:13 +0000 Subject: [PATCH 1/2] Initial plan From 1928902eecb76b7e20811aba61ebb509100bdce7 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Tue, 17 Mar 2026 15:54:37 +0000 Subject: [PATCH 2/2] Implement ERP/Inventory hierarchical grid sample - Add hierarchical data models (Order, OrderDetails, DeliveryDetails, OrderStatus, DataPoint) - Update InventoryData model to support nested Orders collection - Update InventoryService to calculate derived fields (UnitsSold, TotalNetProfit) - Convert ERPInventoryComponent to use IgbHierarchicalGrid with IgbRowIsland - Add parent grid columns: SKU, Product Name, Category, Rating, Units Sold, Gross Price, Net Price, Net Profit - Add child grid (IgbRowIsland) showing Order details with collapsible column groups - Implement Delivery column group (Date Ordered, Date Shipped, Date Delivered) - Implement Order Information column group (Country, City, Zip Code, Street) - Add grid toolbar with Hiding and Pinning actions for both grids - Enable filtering, sorting, and multiple row selection on both grid levels - Maintain live data updates every 3 seconds Co-authored-by: dkamburov <1182001+dkamburov@users.noreply.github.com> --- .../ERPInventoryComponent.razor | 67 ++++++++++++++----- .../ERPInventory.Library/Models/DataPoint.cs | 9 +++ .../Models/DeliveryDetails.cs | 15 +++++ .../Models/InventoryData.cs | 56 ++++++++-------- .../ERPInventory.Library/Models/Order.cs | 18 +++++ .../Models/OrderDetails.cs | 21 ++++++ .../Models/OrderStatus.cs | 9 +++ .../Services/InventoryService.cs | 24 ++++--- 8 files changed, 165 insertions(+), 54 deletions(-) create mode 100644 src/samples/ERPInventory.Library/Models/DataPoint.cs create mode 100644 src/samples/ERPInventory.Library/Models/DeliveryDetails.cs create mode 100644 src/samples/ERPInventory.Library/Models/Order.cs create mode 100644 src/samples/ERPInventory.Library/Models/OrderDetails.cs create mode 100644 src/samples/ERPInventory.Library/Models/OrderStatus.cs diff --git a/src/samples/ERPInventory.Library/ERPInventoryComponent.razor b/src/samples/ERPInventory.Library/ERPInventoryComponent.razor index 81f9afd..7446325 100644 --- a/src/samples/ERPInventory.Library/ERPInventoryComponent.razor +++ b/src/samples/ERPInventory.Library/ERPInventoryComponent.razor @@ -22,22 +22,55 @@ } else { - - - - - - - - - - - - + + + + Inventory + + + + + + + + + + + + + + + + + + Sales data for the last month + + + + + + + + + + + + + + + + + + + + +
Data updates every 3 seconds to simulate live inventory data @@ -49,7 +82,7 @@ @code { private bool isLoading = true; private System.Timers.Timer? updateTimer; - private IgbGrid? grid; + private IgbHierarchicalGrid? grid; protected override async Task OnInitializedAsync() { diff --git a/src/samples/ERPInventory.Library/Models/DataPoint.cs b/src/samples/ERPInventory.Library/Models/DataPoint.cs new file mode 100644 index 0000000..82dbd0a --- /dev/null +++ b/src/samples/ERPInventory.Library/Models/DataPoint.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace ERPInventory.Library.Models; + +public class DataPoint +{ + [JsonPropertyName("unitsSold")] + public int UnitsSold { get; set; } +} diff --git a/src/samples/ERPInventory.Library/Models/DeliveryDetails.cs b/src/samples/ERPInventory.Library/Models/DeliveryDetails.cs new file mode 100644 index 0000000..ab716bf --- /dev/null +++ b/src/samples/ERPInventory.Library/Models/DeliveryDetails.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace ERPInventory.Library.Models; + +public class DeliveryDetails +{ + [JsonPropertyName("dateOrdered")] + public string? DateOrdered { get; set; } + + [JsonPropertyName("dateShipped")] + public string? DateShipped { get; set; } + + [JsonPropertyName("dateDelivered")] + public string? DateDelivered { get; set; } +} diff --git a/src/samples/ERPInventory.Library/Models/InventoryData.cs b/src/samples/ERPInventory.Library/Models/InventoryData.cs index 00805dc..4d385b9 100644 --- a/src/samples/ERPInventory.Library/Models/InventoryData.cs +++ b/src/samples/ERPInventory.Library/Models/InventoryData.cs @@ -4,36 +4,36 @@ namespace ERPInventory.Library.Models; public class InventoryData { - [JsonPropertyName("id")] - public string? Id { get; set; } - + [JsonPropertyName("sku")] + public string? Sku { get; set; } + + [JsonPropertyName("imageUrl")] + public string? ImageUrl { get; set; } + [JsonPropertyName("productName")] public string? ProductName { get; set; } - + [JsonPropertyName("category")] public string? Category { get; set; } - - [JsonPropertyName("sku")] - public string? Sku { get; set; } - - [JsonPropertyName("quantity")] - public int Quantity { get; set; } - - [JsonPropertyName("unitPrice")] - public double UnitPrice { get; set; } - - [JsonPropertyName("totalValue")] - public double TotalValue { get; set; } - - [JsonPropertyName("supplier")] - public string? Supplier { get; set; } - - [JsonPropertyName("warehouse")] - public string? Warehouse { get; set; } - - [JsonPropertyName("status")] - public string? Status { get; set; } - - [JsonPropertyName("lastUpdated")] - public DateTime LastUpdated { get; set; } + + [JsonPropertyName("rating")] + public double Rating { get; set; } + + [JsonPropertyName("unitsSold")] + public int UnitsSold { get; set; } + + [JsonPropertyName("grossPrice")] + public double GrossPrice { get; set; } + + [JsonPropertyName("netPrice")] + public double NetPrice { get; set; } + + [JsonPropertyName("totalNetProfit")] + public double TotalNetProfit { get; set; } + + [JsonPropertyName("salesTrendData")] + public List SalesTrendData { get; set; } = new(); + + [JsonPropertyName("orders")] + public List Orders { get; set; } = new(); } diff --git a/src/samples/ERPInventory.Library/Models/Order.cs b/src/samples/ERPInventory.Library/Models/Order.cs new file mode 100644 index 0000000..23da2e6 --- /dev/null +++ b/src/samples/ERPInventory.Library/Models/Order.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace ERPInventory.Library.Models; + +public class Order +{ + [JsonPropertyName("orderId")] + public int OrderId { get; set; } + + [JsonPropertyName("status")] + public string? Status { get; set; } + + [JsonPropertyName("delivery")] + public DeliveryDetails Delivery { get; set; } = new(); + + [JsonPropertyName("orderInformation")] + public OrderDetails OrderInformation { get; set; } = new(); +} diff --git a/src/samples/ERPInventory.Library/Models/OrderDetails.cs b/src/samples/ERPInventory.Library/Models/OrderDetails.cs new file mode 100644 index 0000000..e560245 --- /dev/null +++ b/src/samples/ERPInventory.Library/Models/OrderDetails.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; + +namespace ERPInventory.Library.Models; + +public class OrderDetails +{ + [JsonPropertyName("country")] + public string? Country { get; set; } + + [JsonPropertyName("city")] + public string? City { get; set; } + + [JsonPropertyName("zipCode")] + public int ZipCode { get; set; } + + [JsonPropertyName("streetName")] + public string? StreetName { get; set; } + + [JsonPropertyName("streetNumber")] + public string? StreetNumber { get; set; } +} diff --git a/src/samples/ERPInventory.Library/Models/OrderStatus.cs b/src/samples/ERPInventory.Library/Models/OrderStatus.cs new file mode 100644 index 0000000..acddd39 --- /dev/null +++ b/src/samples/ERPInventory.Library/Models/OrderStatus.cs @@ -0,0 +1,9 @@ +namespace ERPInventory.Library.Models; + +public static class OrderStatus +{ + public const string Packed = "Packed"; + public const string InTransit = "In Transit"; + public const string Customs = "Customs"; + public const string Delivered = "Delivered"; +} diff --git a/src/samples/ERPInventory.Library/Services/InventoryService.cs b/src/samples/ERPInventory.Library/Services/InventoryService.cs index f58d43b..5d1c9fc 100644 --- a/src/samples/ERPInventory.Library/Services/InventoryService.cs +++ b/src/samples/ERPInventory.Library/Services/InventoryService.cs @@ -27,11 +27,18 @@ public async Task LoadDataAsync() { var jsonText = await _httpClient.GetStringAsync(DataUrl); Data = JsonSerializer.Deserialize>(jsonText, options) ?? new(); - + // Calculate derived fields foreach (var record in Data) { - record.TotalValue = Math.Round(record.Quantity * record.UnitPrice, 2); + // Set unitsSold from last month's sales data + if (record.SalesTrendData.Count > 0) + { + record.UnitsSold = record.SalesTrendData[^1].UnitsSold; + } + + // Calculate totalNetProfit + record.TotalNetProfit = Math.Round(record.UnitsSold * record.NetPrice, 2); } OnDataChanged?.Invoke(); @@ -46,7 +53,7 @@ public void UpdateAllData() { foreach (var dataRow in Data) { - // Simulate live data updates - randomly adjust quantity + // Simulate live data updates - randomly adjust units sold var volatility = 0.05; var rnd = Math.Round(Random.Shared.NextDouble(), 2); var changePercent = 2 * volatility * rnd; @@ -55,12 +62,11 @@ public void UpdateAllData() changePercent -= 2 * volatility; } - var changeAmount = dataRow.Quantity * changePercent; - var newQuantity = dataRow.Quantity + (int)Math.Round(changeAmount); - dataRow.Quantity = Math.Max(0, newQuantity); - - dataRow.TotalValue = Math.Round(dataRow.Quantity * dataRow.UnitPrice, 2); - dataRow.LastUpdated = DateTime.Now; + var changeAmount = dataRow.UnitsSold * changePercent; + var newUnitsSold = dataRow.UnitsSold + (int)Math.Round(changeAmount); + dataRow.UnitsSold = Math.Max(0, newUnitsSold); + + dataRow.TotalNetProfit = Math.Round(dataRow.UnitsSold * dataRow.NetPrice, 2); } OnDataChanged?.Invoke();