From 7093fee7e6534aa0c78e98e96604317a4da10f58 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 30 Apr 2024 08:04:04 -0700 Subject: [PATCH 001/301] Database Changes for Ordering Stuff --- Hippo.Core/Domain/History.cs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Hippo.Core/Domain/History.cs b/Hippo.Core/Domain/History.cs index 3bb71699..aa046301 100644 --- a/Hippo.Core/Domain/History.cs +++ b/Hippo.Core/Domain/History.cs @@ -32,6 +32,8 @@ public History() public int ClusterId { get; set; } //When we have a cluster identifier public Cluster Cluster { get; set; } + //TODO: Link to the order that is nullable + [MaxLength(50)] public string Status { get; set; } @@ -74,5 +76,31 @@ public class Actions QueuedEventUpdated }.ToList(); } + + public class OrderActions + { + public const string Created = "Created"; + public const string Updated = "Updated"; + public const string Submitted = "Submitted"; + public const string Processing = "Processing"; + public const string Cancelled = "Cancelled"; + public const string Active = "Active"; + public const string Rejected = "Rejected"; + public const string Completed = "Completed"; + public const string AdhocPayment = "Adhoc Payment"; + + public static List TypeList = new List + { + Created, + Updated, + Submitted, + Processing, + Cancelled, + Active, + Rejected, + Completed, + AdhocPayment + }.ToList(); + } } } From 025f57166f18070313a639634ed5727041f7ff40 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 30 Apr 2024 08:24:07 -0700 Subject: [PATCH 002/301] Financial Detail table --- Hippo.Core/Data/AppDbContext.cs | 2 ++ Hippo.Core/Domain/Cluster.cs | 10 ++++++++++ Hippo.Core/Domain/FinancialDetail.cs | 25 +++++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 Hippo.Core/Domain/FinancialDetail.cs diff --git a/Hippo.Core/Data/AppDbContext.cs b/Hippo.Core/Data/AppDbContext.cs index 5dbfb32a..255330fa 100644 --- a/Hippo.Core/Data/AppDbContext.cs +++ b/Hippo.Core/Data/AppDbContext.cs @@ -41,6 +41,7 @@ protected AppDbContext(DbContextOptions options) : base(options) public virtual DbSet TempKerberos { get; set; } public virtual DbSet QueuedEvents { get; set; } public virtual DbSet AccessTypes { get; set; } + public virtual DbSet FinancialDetails { get; set; } protected override void OnModelCreating(ModelBuilder builder) { @@ -57,6 +58,7 @@ protected override void OnModelCreating(ModelBuilder builder) Domain.GroupMemberAccount.OnModelCreating(builder); QueuedEvent.OnModelCreating(builder); AccessType.OnModelCreating(builder); + FinancialDetail.OnModelCreating(builder); } } } diff --git a/Hippo.Core/Domain/Cluster.cs b/Hippo.Core/Domain/Cluster.cs index bb0770b1..15a33109 100644 --- a/Hippo.Core/Domain/Cluster.cs +++ b/Hippo.Core/Domain/Cluster.cs @@ -44,6 +44,9 @@ public class Cluster [MinLength(1)] public List AccessTypes { get; set; } = new(); + [JsonIgnore] + public FinancialDetail FinancialDetail { get; set; } + internal static void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity().HasQueryFilter(a => a.IsActive); @@ -67,6 +70,13 @@ internal static void OnModelCreating(ModelBuilder modelBuilder) .WithMany() .HasForeignKey(p => p.ClusterId) .OnDelete(DeleteBehavior.Restrict); + + // Cluster has a one to one relationship with FinancialDetail where the financial detail is nullable + modelBuilder.Entity() + .HasOne(c => c.FinancialDetail) + .WithOne(c => c.Cluster) + .HasForeignKey(fd => fd.ClusterId) + .OnDelete(DeleteBehavior.Restrict); } } } diff --git a/Hippo.Core/Domain/FinancialDetail.cs b/Hippo.Core/Domain/FinancialDetail.cs new file mode 100644 index 00000000..2635f40e --- /dev/null +++ b/Hippo.Core/Domain/FinancialDetail.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations; + +namespace Hippo.Core.Domain +{ + public class FinancialDetail + { + [Key] + int Id { get; set; } + [StringLength(128)] //Probably doesn't need to be this big... + string SlothApiKey { get; set; } + [MaxLength(50)] + string SlothSource { get; set; } + string ChartString { get; set; } + bool AutoApprove { get; set; } + [Required] + public int ClusterId { get; set; } + public Cluster Cluster { get; set; } + + internal static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().Property(a => a.AutoApprove).HasDefaultValue(true); + } + } +} From 983304dfd6e103a221abc1dab9bc2847b6321850 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 30 Apr 2024 10:44:40 -0700 Subject: [PATCH 003/301] WIP Product and order tables --- Hippo.Core/Data/AppDbContext.cs | 3 ++ Hippo.Core/Domain/Cluster.cs | 17 +++++++ Hippo.Core/Domain/History.cs | 4 +- Hippo.Core/Domain/Order.cs | 87 +++++++++++++++++++++++++++++++++ Hippo.Core/Domain/Product.cs | 33 +++++++++++++ Hippo.Core/Domain/User.cs | 8 +++ 6 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 Hippo.Core/Domain/Order.cs create mode 100644 Hippo.Core/Domain/Product.cs diff --git a/Hippo.Core/Data/AppDbContext.cs b/Hippo.Core/Data/AppDbContext.cs index 255330fa..6f004bd2 100644 --- a/Hippo.Core/Data/AppDbContext.cs +++ b/Hippo.Core/Data/AppDbContext.cs @@ -42,6 +42,8 @@ protected AppDbContext(DbContextOptions options) : base(options) public virtual DbSet QueuedEvents { get; set; } public virtual DbSet AccessTypes { get; set; } public virtual DbSet FinancialDetails { get; set; } + public virtual DbSet Products { get; set; } + public virtual DbSet Orders { get; set; } protected override void OnModelCreating(ModelBuilder builder) { @@ -59,6 +61,7 @@ protected override void OnModelCreating(ModelBuilder builder) QueuedEvent.OnModelCreating(builder); AccessType.OnModelCreating(builder); FinancialDetail.OnModelCreating(builder); + Product.OnModelCreating(builder); } } } diff --git a/Hippo.Core/Domain/Cluster.cs b/Hippo.Core/Domain/Cluster.cs index 15a33109..4a2bd858 100644 --- a/Hippo.Core/Domain/Cluster.cs +++ b/Hippo.Core/Domain/Cluster.cs @@ -47,6 +47,12 @@ public class Cluster [JsonIgnore] public FinancialDetail FinancialDetail { get; set; } + [JsonIgnore] + public List Products { get; set; } = new(); + + [JsonIgnore] + public List Orders { get; set; } = new(); + internal static void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity().HasQueryFilter(a => a.IsActive); @@ -77,6 +83,17 @@ internal static void OnModelCreating(ModelBuilder modelBuilder) .WithOne(c => c.Cluster) .HasForeignKey(fd => fd.ClusterId) .OnDelete(DeleteBehavior.Restrict); + + modelBuilder.Entity() + .HasOne(p => p.Cluster) + .WithMany(c => c.Products) + .HasForeignKey(p => p.ClusterId) + .OnDelete(DeleteBehavior.Restrict); + modelBuilder.Entity() + .HasOne(o => o.Cluster) + .WithMany(c => c.Orders) + .HasForeignKey(o => o.ClusterId) + .OnDelete(DeleteBehavior.Restrict); } } } diff --git a/Hippo.Core/Domain/History.cs b/Hippo.Core/Domain/History.cs index aa046301..69ef4192 100644 --- a/Hippo.Core/Domain/History.cs +++ b/Hippo.Core/Domain/History.cs @@ -32,7 +32,8 @@ public History() public int ClusterId { get; set; } //When we have a cluster identifier public Cluster Cluster { get; set; } - //TODO: Link to the order that is nullable + public int? OrderId { get; set; } + public Order Order { get; set; } [MaxLength(50)] public string Status { get; set; } @@ -45,6 +46,7 @@ internal static void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity().HasIndex(h => h.ClusterId); modelBuilder.Entity().HasOne(h => h.ActedBy).WithMany().HasForeignKey(a => a.ActedById).OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity().HasOne(h => h.Cluster).WithMany().HasForeignKey(a => a.ClusterId).OnDelete(DeleteBehavior.Restrict); + modelBuilder.Entity().HasOne(h => h.Order).WithMany().HasForeignKey(a => a.OrderId).OnDelete(DeleteBehavior.Restrict); } public class Actions diff --git a/Hippo.Core/Domain/Order.cs b/Hippo.Core/Domain/Order.cs new file mode 100644 index 00000000..c8d5b8ac --- /dev/null +++ b/Hippo.Core/Domain/Order.cs @@ -0,0 +1,87 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace Hippo.Core.Domain +{ + public class Order + { + [Key] + public int Id { get; set; } + + [Required] + public string Category { get; set; } + [Required] + [MaxLength(50)] + public string Name { get; set; } + [MaxLength(250)] + public string Description { get; set; } + public string ExternalReference { get; set; } + [Required] + [Range(0.01, double.MaxValue)] + public decimal Price { get; set; } + public int Quantity { get; set; } + + public int Installments { get; set; } + + + public decimal Adjustments { get; set; } + public string AdjustmentReason { get; set; } + public decimal Total { get; set; } + public string Notes { get; set; } + public string AdminNotes { get; set; } + public string Status { get; set; } + + + [Required] + public int ClusterId { get; set; } + public Cluster Cluster { get; set; } + + [Required] + public int CreatedById { get; set; } + public User CreatedBy { get; set; } + + [Required] + public int PrincipalInvestigatorId { get; set; } + public User PrincipalInvestigator { get; set; } + + [JsonIgnore] + public List History { get; set; } = new(); + + public class Statuses + { + public const string Created = "Created"; + public const string Submitted = "Submitted"; + public const string Processing = "Processing"; + public const string Cancelled = "Cancelled"; + public const string Active = "Active"; + public const string Rejected = "Rejected"; //Not sure if we need this + public const string Completed = "Completed"; + + public static List StatusTypes = new List + { + Created, + Submitted, + Processing, + Cancelled, + Active, + Rejected, + Completed + }; + } + internal static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasQueryFilter(o => o.Cluster.IsActive); + modelBuilder.Entity().HasIndex(o => o.CreatedById); + modelBuilder.Entity().HasIndex(o => o.PrincipalInvestigatorId); + modelBuilder.Entity().HasOne(o => o.CreatedBy).WithMany().HasForeignKey(o => o.CreatedById).OnDelete(DeleteBehavior.Restrict); + modelBuilder.Entity().HasOne(o => o.Order).WithMany().HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); + //The Principal Investigator reference is declared in the User class + } + } +} diff --git a/Hippo.Core/Domain/Product.cs b/Hippo.Core/Domain/Product.cs new file mode 100644 index 00000000..a82c2741 --- /dev/null +++ b/Hippo.Core/Domain/Product.cs @@ -0,0 +1,33 @@ +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations; + +namespace Hippo.Core.Domain +{ + public class Product + { + [Key] + public int Id { get; set; } + bool IsActive { get; set; } + [Required] + public string Category { get; set; } + [Required] + [MaxLength(50)] + public string Name { get; set; } + [MaxLength(250)] + public string Description { get; set; } + [Required] + [Range(0.01, double.MaxValue)] + public decimal Price { get; set; } + //Not sure if we want to do this, but it lets a default number of payment installments to be specified + public int Installments { get; set; } + + [Required] + public int ClusterId { get; set; } + public Cluster Cluster { get; set; } + internal static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().Property(a => a.IsActive).HasDefaultValue(true); + modelBuilder.Entity().HasQueryFilter(a => a.IsActive); + } + } +} diff --git a/Hippo.Core/Domain/User.cs b/Hippo.Core/Domain/User.cs index e39e52e7..70fdf6a6 100644 --- a/Hippo.Core/Domain/User.cs +++ b/Hippo.Core/Domain/User.cs @@ -45,6 +45,9 @@ public class User [JsonIgnore] public List Permissions { get; set; } = new(); + [JsonIgnore] + public List Orders { get; set; } = new(); + internal static void OnModelCreating(ModelBuilder modelBuilder) { @@ -62,6 +65,11 @@ internal static void OnModelCreating(ModelBuilder modelBuilder) .WithMany(u => u.Permissions) .HasForeignKey(p => p.UserId) .OnDelete(DeleteBehavior.Restrict); + modelBuilder.Entity() + .HasOne(o => o.PrincipalInvestigator) + .WithMany(u => u.Orders) + .HasForeignKey(o => o.PrincipalInvestigatorId) + .OnDelete(DeleteBehavior.Restrict); } } } From e54dfc6bfebe0328fdb5a030bce71123a54137ec Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 30 Apr 2024 13:40:53 -0700 Subject: [PATCH 004/301] Account billing table --- Hippo.Core/Domain/Billing.cs | 17 +++++++++++++++++ Hippo.Core/Domain/History.cs | 4 +++- Hippo.Core/Domain/Order.cs | 5 +++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 Hippo.Core/Domain/Billing.cs diff --git a/Hippo.Core/Domain/Billing.cs b/Hippo.Core/Domain/Billing.cs new file mode 100644 index 00000000..d5dd2cd8 --- /dev/null +++ b/Hippo.Core/Domain/Billing.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace Hippo.Core.Domain +{ + public class Billing + { + [Key] + public int Id { get; set; } + [Required] + public string ChartString { get; set; } + public decimal Percentage { get; set; } = 100; + [Required] + public int OrderId { get; set; } + public Order Order { get; set; } + public DateTime Updated { get; set; } = DateTime.UtcNow; + } +} diff --git a/Hippo.Core/Domain/History.cs b/Hippo.Core/Domain/History.cs index 69ef4192..6525d620 100644 --- a/Hippo.Core/Domain/History.cs +++ b/Hippo.Core/Domain/History.cs @@ -90,6 +90,7 @@ public class OrderActions public const string Rejected = "Rejected"; public const string Completed = "Completed"; public const string AdhocPayment = "Adhoc Payment"; + public const string ChartStringUpdated = "Chart String Updated"; public static List TypeList = new List { @@ -101,7 +102,8 @@ public class OrderActions Active, Rejected, Completed, - AdhocPayment + AdhocPayment, + ChartStringUpdated }.ToList(); } } diff --git a/Hippo.Core/Domain/Order.cs b/Hippo.Core/Domain/Order.cs index c8d5b8ac..a68fd047 100644 --- a/Hippo.Core/Domain/Order.cs +++ b/Hippo.Core/Domain/Order.cs @@ -50,6 +50,10 @@ public class Order public int PrincipalInvestigatorId { get; set; } public User PrincipalInvestigator { get; set; } + public DateTime Created { get; set; } = DateTime.UtcNow; + + public List Billings { get; set; } = new(); + [JsonIgnore] public List History { get; set; } = new(); @@ -81,6 +85,7 @@ internal static void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity().HasIndex(o => o.PrincipalInvestigatorId); modelBuilder.Entity().HasOne(o => o.CreatedBy).WithMany().HasForeignKey(o => o.CreatedById).OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity().HasOne(o => o.Order).WithMany().HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); + modelBuilder.Entity().HasOne(o => o.Order).WithMany(o => o.Billings).HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); //The Principal Investigator reference is declared in the User class } } From 02bb6811be894c07dcb737f59a606b3c91b2ddc0 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 30 Apr 2024 15:14:43 -0700 Subject: [PATCH 005/301] WIP new tables --- Hippo.Core/Data/AppDbContext.cs | 4 ++++ Hippo.Core/Domain/Order.cs | 8 ++++++- Hippo.Core/Domain/OrderMetaData.cs | 34 ++++++++++++++++++++++++++++++ Hippo.Core/Domain/Payment.cs | 32 ++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 Hippo.Core/Domain/OrderMetaData.cs create mode 100644 Hippo.Core/Domain/Payment.cs diff --git a/Hippo.Core/Data/AppDbContext.cs b/Hippo.Core/Data/AppDbContext.cs index 6f004bd2..62ae4a19 100644 --- a/Hippo.Core/Data/AppDbContext.cs +++ b/Hippo.Core/Data/AppDbContext.cs @@ -44,6 +44,9 @@ protected AppDbContext(DbContextOptions options) : base(options) public virtual DbSet FinancialDetails { get; set; } public virtual DbSet Products { get; set; } public virtual DbSet Orders { get; set; } + public virtual DbSet Billings { get; set; } + public virtual DbSet MetaData { get; set; } + public virtual DbSet Payments { get; set; } protected override void OnModelCreating(ModelBuilder builder) { @@ -62,6 +65,7 @@ protected override void OnModelCreating(ModelBuilder builder) AccessType.OnModelCreating(builder); FinancialDetail.OnModelCreating(builder); Product.OnModelCreating(builder); + OrderMetaData.OnModelCreating(builder); } } } diff --git a/Hippo.Core/Domain/Order.cs b/Hippo.Core/Domain/Order.cs index a68fd047..60057d00 100644 --- a/Hippo.Core/Domain/Order.cs +++ b/Hippo.Core/Domain/Order.cs @@ -50,10 +50,14 @@ public class Order public int PrincipalInvestigatorId { get; set; } public User PrincipalInvestigator { get; set; } - public DateTime Created { get; set; } = DateTime.UtcNow; + public DateTime CreatedOn { get; set; } = DateTime.UtcNow; public List Billings { get; set; } = new(); + public List MetaData { get; set; } = new(); + + public List Payments { get; set; } = new(); + [JsonIgnore] public List History { get; set; } = new(); @@ -86,6 +90,8 @@ internal static void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity().HasOne(o => o.CreatedBy).WithMany().HasForeignKey(o => o.CreatedById).OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity().HasOne(o => o.Order).WithMany().HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity().HasOne(o => o.Order).WithMany(o => o.Billings).HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); + modelBuilder.Entity().HasOne(o => o.Order).WithMany(o => o.MetaData).HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); + modelBuilder.Entity().HasOne(o => o.Order).WithMany(o => o.Payments).HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); //The Principal Investigator reference is declared in the User class } } diff --git a/Hippo.Core/Domain/OrderMetaData.cs b/Hippo.Core/Domain/OrderMetaData.cs new file mode 100644 index 00000000..d8197139 --- /dev/null +++ b/Hippo.Core/Domain/OrderMetaData.cs @@ -0,0 +1,34 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace Hippo.Core.Domain +{ + public class OrderMetaData + { + [Key] + [JsonIgnore] + public string Id { get; set; } = Guid.NewGuid().ToString(); + [Required] + public int OrderId { get; set; } + public Order Order { get; set; } + [Required] + [MaxLength(128)] + public string Name { get; set; } + + [Required] + [MaxLength(450)] + public string Value { get; set; } + + internal static void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasIndex(a => a.OrderId); + modelBuilder.Entity().HasIndex(a => new {a.OrderId, a.Name, a.Value }); + } + } +} diff --git a/Hippo.Core/Domain/Payment.cs b/Hippo.Core/Domain/Payment.cs new file mode 100644 index 00000000..bfb416ab --- /dev/null +++ b/Hippo.Core/Domain/Payment.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Hippo.Core.Domain +{ + public class Payment + { + [Key] + public int Id { get; set; } + public string SlothId { get; set; } + public string TrackingNumber { get; set; } // KFS tracking number + public DateTime CreatedOn { get; set; } = DateTime.UtcNow; + public decimal Amount { get; set; } + public string Status { get; set; } + + public string ClusterChartString { get; set; } + public string OrderChartStrings { get; set; } //.Serialize() of the billings chart strings and percentages used + + + [Required] + public int OrderId { get; set; } + public Order Order { get; set; } + + //Optional createdBy. If not set, was crated by a job + public int? CreatedById { get; set; } + public User CreatedBy { get; set; } + } +} From b7e9b6061602f711f160f195e885dee4128de29d Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 08:19:50 -0700 Subject: [PATCH 006/301] WIP table stuff --- Hippo.Core/Domain/Order.cs | 16 +++++++++++----- Hippo.Core/Domain/User.cs | 5 +++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Hippo.Core/Domain/Order.cs b/Hippo.Core/Domain/Order.cs index 60057d00..e946f6d3 100644 --- a/Hippo.Core/Domain/Order.cs +++ b/Hippo.Core/Domain/Order.cs @@ -21,22 +21,29 @@ public class Order public string Name { get; set; } [MaxLength(250)] public string Description { get; set; } + [MaxLength(150)] public string ExternalReference { get; set; } [Required] [Range(0.01, double.MaxValue)] public decimal Price { get; set; } - public int Quantity { get; set; } - + [Required] + [Range(0.0001, double.MaxValue)] + public decimal Quantity { get; set; } + [Required] + [Range(1, int.MaxValue)] public int Installments { get; set; } - public decimal Adjustments { get; set; } + public decimal Adjustment { get; set; } public string AdjustmentReason { get; set; } + public decimal SubTotal { get; set; } public decimal Total { get; set; } + public decimal BalanceRemaining { get; set; } // do here, or just get the total of the billings? public string Notes { get; set; } public string AdminNotes { get; set; } public string Status { get; set; } + public decimal InstalmentAmount => Math.Round(Total / Installments, 2); [Required] public int ClusterId { get; set; } @@ -87,12 +94,11 @@ internal static void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity().HasQueryFilter(o => o.Cluster.IsActive); modelBuilder.Entity().HasIndex(o => o.CreatedById); modelBuilder.Entity().HasIndex(o => o.PrincipalInvestigatorId); - modelBuilder.Entity().HasOne(o => o.CreatedBy).WithMany().HasForeignKey(o => o.CreatedById).OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity().HasOne(o => o.Order).WithMany().HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity().HasOne(o => o.Order).WithMany(o => o.Billings).HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity().HasOne(o => o.Order).WithMany(o => o.MetaData).HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity().HasOne(o => o.Order).WithMany(o => o.Payments).HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); - //The Principal Investigator reference is declared in the User class + } } } diff --git a/Hippo.Core/Domain/User.cs b/Hippo.Core/Domain/User.cs index 70fdf6a6..421ec277 100644 --- a/Hippo.Core/Domain/User.cs +++ b/Hippo.Core/Domain/User.cs @@ -70,6 +70,11 @@ internal static void OnModelCreating(ModelBuilder modelBuilder) .WithMany(u => u.Orders) .HasForeignKey(o => o.PrincipalInvestigatorId) .OnDelete(DeleteBehavior.Restrict); + modelBuilder.Entity() + .HasOne(o => o.CreatedBy) + .WithMany(u => u.Orders) + .HasForeignKey(o => o.CreatedById) + .OnDelete(DeleteBehavior.Restrict); } } } From f73c733a370df64390bc03514b93a4346c5f0467 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 09:25:23 -0700 Subject: [PATCH 007/301] Make more generic --- Hippo.Core/Domain/FinancialDetail.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Hippo.Core/Domain/FinancialDetail.cs b/Hippo.Core/Domain/FinancialDetail.cs index 2635f40e..9ed01442 100644 --- a/Hippo.Core/Domain/FinancialDetail.cs +++ b/Hippo.Core/Domain/FinancialDetail.cs @@ -8,9 +8,9 @@ public class FinancialDetail [Key] int Id { get; set; } [StringLength(128)] //Probably doesn't need to be this big... - string SlothApiKey { get; set; } + string ApiKey { get; set; } [MaxLength(50)] - string SlothSource { get; set; } + string ApiSource { get; set; } string ChartString { get; set; } bool AutoApprove { get; set; } [Required] From cd5686f7ef4030571ad802719e2710a2b8fc0da3 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 10:05:43 -0700 Subject: [PATCH 008/301] Suggestions --- Hippo.Core/Domain/FinancialDetail.cs | 4 ++-- Hippo.Core/Domain/Order.cs | 7 ++++--- Hippo.Core/Domain/OrderMetaData.cs | 3 +-- Hippo.Core/Domain/Payment.cs | 5 ++--- Hippo.Core/Domain/Product.cs | 5 ++++- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Hippo.Core/Domain/FinancialDetail.cs b/Hippo.Core/Domain/FinancialDetail.cs index 9ed01442..9a711d9d 100644 --- a/Hippo.Core/Domain/FinancialDetail.cs +++ b/Hippo.Core/Domain/FinancialDetail.cs @@ -8,9 +8,9 @@ public class FinancialDetail [Key] int Id { get; set; } [StringLength(128)] //Probably doesn't need to be this big... - string ApiKey { get; set; } + string FinancialSystemApiKey { get; set; } [MaxLength(50)] - string ApiSource { get; set; } + string FinancialSystemApiSource { get; set; } string ChartString { get; set; } bool AutoApprove { get; set; } [Required] diff --git a/Hippo.Core/Domain/Order.cs b/Hippo.Core/Domain/Order.cs index e946f6d3..a9e77b64 100644 --- a/Hippo.Core/Domain/Order.cs +++ b/Hippo.Core/Domain/Order.cs @@ -23,9 +23,10 @@ public class Order public string Description { get; set; } [MaxLength(150)] public string ExternalReference { get; set; } + public string Units { get; set; } //Informational like TB, or fairshair points [Required] [Range(0.01, double.MaxValue)] - public decimal Price { get; set; } + public decimal UnitPrice { get; set; } [Required] [Range(0.0001, double.MaxValue)] public decimal Quantity { get; set; } @@ -38,12 +39,12 @@ public class Order public string AdjustmentReason { get; set; } public decimal SubTotal { get; set; } public decimal Total { get; set; } - public decimal BalanceRemaining { get; set; } // do here, or just get the total of the billings? + public decimal BalanceRemaining { get; set; } //We will also calculate this when we do a payment public string Notes { get; set; } public string AdminNotes { get; set; } public string Status { get; set; } - public decimal InstalmentAmount => Math.Round(Total / Installments, 2); + public decimal InstallmentAmount => Math.Round(Total / Installments, 2); [Required] public int ClusterId { get; set; } diff --git a/Hippo.Core/Domain/OrderMetaData.cs b/Hippo.Core/Domain/OrderMetaData.cs index d8197139..5c2e7483 100644 --- a/Hippo.Core/Domain/OrderMetaData.cs +++ b/Hippo.Core/Domain/OrderMetaData.cs @@ -12,8 +12,7 @@ namespace Hippo.Core.Domain public class OrderMetaData { [Key] - [JsonIgnore] - public string Id { get; set; } = Guid.NewGuid().ToString(); + public int Id { get; set; } [Required] public int OrderId { get; set; } public Order Order { get; set; } diff --git a/Hippo.Core/Domain/Payment.cs b/Hippo.Core/Domain/Payment.cs index bfb416ab..b998d67f 100644 --- a/Hippo.Core/Domain/Payment.cs +++ b/Hippo.Core/Domain/Payment.cs @@ -11,14 +11,13 @@ public class Payment { [Key] public int Id { get; set; } - public string SlothId { get; set; } + public string FinancialSystemId { get; set; } public string TrackingNumber { get; set; } // KFS tracking number public DateTime CreatedOn { get; set; } = DateTime.UtcNow; public decimal Amount { get; set; } public string Status { get; set; } - public string ClusterChartString { get; set; } - public string OrderChartStrings { get; set; } //.Serialize() of the billings chart strings and percentages used + public string Details { get; set; } //chart strings, credit/debit, and amounts [Required] diff --git a/Hippo.Core/Domain/Product.cs b/Hippo.Core/Domain/Product.cs index a82c2741..ce961b4d 100644 --- a/Hippo.Core/Domain/Product.cs +++ b/Hippo.Core/Domain/Product.cs @@ -15,12 +15,15 @@ public class Product public string Name { get; set; } [MaxLength(250)] public string Description { get; set; } + public string Units { get; set; } //Informational like TB, or fairshair points [Required] [Range(0.01, double.MaxValue)] - public decimal Price { get; set; } + public decimal UnitPrice { get; set; } //Not sure if we want to do this, but it lets a default number of payment installments to be specified public int Installments { get; set; } + public DateTime LastUpdated { get; set; } = DateTime.UtcNow; + [Required] public int ClusterId { get; set; } public Cluster Cluster { get; set; } From 321148711466e452797c5bfe58c65e310a0cf7a5 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 12:49:10 -0700 Subject: [PATCH 009/301] Remove Created By, if admin does it I can just log in the history --- Hippo.Core/Domain/Order.cs | 3 --- Hippo.Core/Domain/User.cs | 7 ++----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Hippo.Core/Domain/Order.cs b/Hippo.Core/Domain/Order.cs index a9e77b64..dd558d55 100644 --- a/Hippo.Core/Domain/Order.cs +++ b/Hippo.Core/Domain/Order.cs @@ -50,9 +50,6 @@ public class Order public int ClusterId { get; set; } public Cluster Cluster { get; set; } - [Required] - public int CreatedById { get; set; } - public User CreatedBy { get; set; } [Required] public int PrincipalInvestigatorId { get; set; } diff --git a/Hippo.Core/Domain/User.cs b/Hippo.Core/Domain/User.cs index 421ec277..c67d023c 100644 --- a/Hippo.Core/Domain/User.cs +++ b/Hippo.Core/Domain/User.cs @@ -49,6 +49,7 @@ public class User public List Orders { get; set; } = new(); + internal static void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity().HasIndex(a => a.Iam).IsUnique(); @@ -70,11 +71,7 @@ internal static void OnModelCreating(ModelBuilder modelBuilder) .WithMany(u => u.Orders) .HasForeignKey(o => o.PrincipalInvestigatorId) .OnDelete(DeleteBehavior.Restrict); - modelBuilder.Entity() - .HasOne(o => o.CreatedBy) - .WithMany(u => u.Orders) - .HasForeignKey(o => o.CreatedById) - .OnDelete(DeleteBehavior.Restrict); + } } } From dcef56f614af6460fef47a098a63c2b4c126765a Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 12:52:31 -0700 Subject: [PATCH 010/301] remove index --- Hippo.Core/Domain/Order.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Hippo.Core/Domain/Order.cs b/Hippo.Core/Domain/Order.cs index dd558d55..25c7f641 100644 --- a/Hippo.Core/Domain/Order.cs +++ b/Hippo.Core/Domain/Order.cs @@ -90,7 +90,6 @@ public class Statuses internal static void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity().HasQueryFilter(o => o.Cluster.IsActive); - modelBuilder.Entity().HasIndex(o => o.CreatedById); modelBuilder.Entity().HasIndex(o => o.PrincipalInvestigatorId); modelBuilder.Entity().HasOne(o => o.Order).WithMany().HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity().HasOne(o => o.Order).WithMany(o => o.Billings).HasForeignKey(o => o.OrderId).OnDelete(DeleteBehavior.Restrict); From 65146a15a8bf8d654fb070241e96ae9808215d21 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 12:54:22 -0700 Subject: [PATCH 011/301] fix key --- Hippo.Core/Domain/FinancialDetail.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hippo.Core/Domain/FinancialDetail.cs b/Hippo.Core/Domain/FinancialDetail.cs index 9a711d9d..42ec8d9d 100644 --- a/Hippo.Core/Domain/FinancialDetail.cs +++ b/Hippo.Core/Domain/FinancialDetail.cs @@ -6,7 +6,7 @@ namespace Hippo.Core.Domain public class FinancialDetail { [Key] - int Id { get; set; } + public int Id { get; set; } [StringLength(128)] //Probably doesn't need to be this big... string FinancialSystemApiKey { get; set; } [MaxLength(50)] From 95f7ce1fb04321653128570fdeba86ef3f66a43d Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 12:55:48 -0700 Subject: [PATCH 012/301] fix --- Hippo.Core/Domain/Product.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hippo.Core/Domain/Product.cs b/Hippo.Core/Domain/Product.cs index ce961b4d..9d6b961c 100644 --- a/Hippo.Core/Domain/Product.cs +++ b/Hippo.Core/Domain/Product.cs @@ -7,7 +7,7 @@ public class Product { [Key] public int Id { get; set; } - bool IsActive { get; set; } + public bool IsActive { get; set; } [Required] public string Category { get; set; } [Required] From 34caf6c7006d70f226f391ed10c0b0e0ea0cfd57 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 12:56:53 -0700 Subject: [PATCH 013/301] Migration --- .../20240501195621_Orders20240501.Designer.cs | 1083 +++++++++++++++++ .../20240501195621_Orders20240501.cs | 305 +++++ .../AppDbContextSqlServerModelSnapshot.cs | 370 ++++++ .../20240501195617_Orders20240501.Designer.cs | 1045 ++++++++++++++++ .../Sqlite/20240501195617_Orders20240501.cs | 305 +++++ .../Sqlite/AppDbContextSqliteModelSnapshot.cs | 358 ++++++ 6 files changed, 3466 insertions(+) create mode 100644 Hippo.Core/Migrations/SqlServer/20240501195621_Orders20240501.Designer.cs create mode 100644 Hippo.Core/Migrations/SqlServer/20240501195621_Orders20240501.cs create mode 100644 Hippo.Core/Migrations/Sqlite/20240501195617_Orders20240501.Designer.cs create mode 100644 Hippo.Core/Migrations/Sqlite/20240501195617_Orders20240501.cs diff --git a/Hippo.Core/Migrations/SqlServer/20240501195621_Orders20240501.Designer.cs b/Hippo.Core/Migrations/SqlServer/20240501195621_Orders20240501.Designer.cs new file mode 100644 index 00000000..b10e14b4 --- /dev/null +++ b/Hippo.Core/Migrations/SqlServer/20240501195621_Orders20240501.Designer.cs @@ -0,0 +1,1083 @@ +// +using System; +using Hippo.Core.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hippo.Core.Migrations.SqlServer +{ + [DbContext(typeof(AppDbContextSqlServer))] + [Migration("20240501195621_Orders20240501")] + partial class Orders20240501 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.19") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.Property("AccessTypesId") + .HasColumnType("int"); + + b.Property("AccountsId") + .HasColumnType("int"); + + b.HasKey("AccessTypesId", "AccountsId"); + + b.HasIndex("AccountsId"); + + b.ToTable("AccessTypeAccount"); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.Property("AccessTypesId") + .HasColumnType("int"); + + b.Property("ClustersId") + .HasColumnType("int"); + + b.HasKey("AccessTypesId", "ClustersId"); + + b.HasIndex("ClustersId"); + + b.ToTable("AccessTypeCluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.AccessType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AccessTypes"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("SshKey") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("CreatedOn"); + + b.HasIndex("Email"); + + b.HasIndex("Kerberos"); + + b.HasIndex("Name"); + + b.HasIndex("OwnerId"); + + b.HasIndex("UpdatedOn"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Percentage") + .HasColumnType("decimal(18,2)"); + + b.Property("Updated") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Description") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Domain") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("SshKeyId") + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("SshName") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("SshUrl") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Clusters"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId", "Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("int"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupAdminAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("int"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMemberAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ActedById") + .HasColumnType("int"); + + b.Property("ActedDate") + .HasColumnType("datetime2"); + + b.Property("Action") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("AdminAction") + .HasColumnType("bit"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("OrderId1") + .HasColumnType("int"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ActedById"); + + b.HasIndex("ActedDate"); + + b.HasIndex("Action"); + + b.HasIndex("ClusterId"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId1"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Adjustment") + .HasColumnType("decimal(18,2)"); + + b.Property("AdjustmentReason") + .HasColumnType("nvarchar(max)"); + + b.Property("AdminNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("BalanceRemaining") + .HasColumnType("decimal(18,2)"); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("Total") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("FinancialSystemId") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("TrackingNumber") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Action") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)"); + + b.Property("RequestId") + .HasColumnType("int"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("RequestId"); + + b.HasIndex("Status"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ActorId") + .HasColumnType("int"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("Group") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("RequesterId") + .HasColumnType("int"); + + b.Property("SshKey") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("SupervisingPI") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorId"); + + b.HasIndex("ClusterId"); + + b.HasIndex("Group"); + + b.HasIndex("RequesterId"); + + b.HasIndex("Status"); + + b.ToTable("Requests"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempGroup", b => + { + b.Property("Group") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Group"); + + b.ToTable("TempGroups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempKerberos", b => + { + b.Property("Kerberos") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Kerberos"); + + b.ToTable("TempKerberos"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Email") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Iam") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("MothraId") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("Iam") + .IsUnique() + .HasFilter("[Iam] IS NOT NULL"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Account", null) + .WithMany() + .HasForeignKey("AccountsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Cluster", null) + .WithMany() + .HasForeignKey("ClustersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Accounts") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Cluster"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Groups") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.HasOne("Hippo.Core.Domain.User", "ActedBy") + .WithMany() + .HasForeignKey("ActedById") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Order", null) + .WithMany("History") + .HasForeignKey("OrderId1"); + + b.Navigation("ActedBy"); + + b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.HasOne("Hippo.Core.Domain.Request", "Request") + .WithMany("QueuedEvents") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Request"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.HasOne("Hippo.Core.Domain.User", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Requester") + .WithMany() + .HasForeignKey("RequesterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Actor"); + + b.Navigation("Cluster"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Navigation("Accounts"); + + b.Navigation("FinancialDetail"); + + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Navigation("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Orders"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Hippo.Core/Migrations/SqlServer/20240501195621_Orders20240501.cs b/Hippo.Core/Migrations/SqlServer/20240501195621_Orders20240501.cs new file mode 100644 index 00000000..c7d0b784 --- /dev/null +++ b/Hippo.Core/Migrations/SqlServer/20240501195621_Orders20240501.cs @@ -0,0 +1,305 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hippo.Core.Migrations.SqlServer +{ + public partial class Orders20240501 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "OrderId", + table: "Histories", + type: "int", + nullable: true); + + migrationBuilder.AddColumn( + name: "OrderId1", + table: "Histories", + type: "int", + nullable: true); + + migrationBuilder.CreateTable( + name: "FinancialDetails", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + AutoApprove = table.Column(type: "bit", nullable: false, defaultValue: true), + ClusterId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FinancialDetails", x => x.Id); + table.ForeignKey( + name: "FK_FinancialDetails_Clusters_ClusterId", + column: x => x.ClusterId, + principalTable: "Clusters", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Orders", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Category = table.Column(type: "nvarchar(max)", nullable: false), + Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + Description = table.Column(type: "nvarchar(250)", maxLength: 250, nullable: true), + ExternalReference = table.Column(type: "nvarchar(150)", maxLength: 150, nullable: true), + Units = table.Column(type: "nvarchar(max)", nullable: true), + UnitPrice = table.Column(type: "decimal(18,2)", nullable: false), + Quantity = table.Column(type: "decimal(18,2)", nullable: false), + Installments = table.Column(type: "int", nullable: false), + Adjustment = table.Column(type: "decimal(18,2)", nullable: false), + AdjustmentReason = table.Column(type: "nvarchar(max)", nullable: true), + SubTotal = table.Column(type: "decimal(18,2)", nullable: false), + Total = table.Column(type: "decimal(18,2)", nullable: false), + BalanceRemaining = table.Column(type: "decimal(18,2)", nullable: false), + Notes = table.Column(type: "nvarchar(max)", nullable: true), + AdminNotes = table.Column(type: "nvarchar(max)", nullable: true), + Status = table.Column(type: "nvarchar(max)", nullable: true), + ClusterId = table.Column(type: "int", nullable: false), + PrincipalInvestigatorId = table.Column(type: "int", nullable: false), + CreatedOn = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Orders", x => x.Id); + table.ForeignKey( + name: "FK_Orders_Clusters_ClusterId", + column: x => x.ClusterId, + principalTable: "Clusters", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Orders_Users_PrincipalInvestigatorId", + column: x => x.PrincipalInvestigatorId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Products", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + IsActive = table.Column(type: "bit", nullable: false, defaultValue: true), + Category = table.Column(type: "nvarchar(max)", nullable: false), + Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + Description = table.Column(type: "nvarchar(250)", maxLength: 250, nullable: true), + Units = table.Column(type: "nvarchar(max)", nullable: true), + UnitPrice = table.Column(type: "decimal(18,2)", nullable: false), + Installments = table.Column(type: "int", nullable: false), + LastUpdated = table.Column(type: "datetime2", nullable: false), + ClusterId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Products", x => x.Id); + table.ForeignKey( + name: "FK_Products_Clusters_ClusterId", + column: x => x.ClusterId, + principalTable: "Clusters", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Billings", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ChartString = table.Column(type: "nvarchar(max)", nullable: false), + Percentage = table.Column(type: "decimal(18,2)", nullable: false), + OrderId = table.Column(type: "int", nullable: false), + Updated = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Billings", x => x.Id); + table.ForeignKey( + name: "FK_Billings_Orders_OrderId", + column: x => x.OrderId, + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "MetaData", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + OrderId = table.Column(type: "int", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Value = table.Column(type: "nvarchar(450)", maxLength: 450, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MetaData", x => x.Id); + table.ForeignKey( + name: "FK_MetaData_Orders_OrderId", + column: x => x.OrderId, + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Payments", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + FinancialSystemId = table.Column(type: "nvarchar(max)", nullable: true), + TrackingNumber = table.Column(type: "nvarchar(max)", nullable: true), + CreatedOn = table.Column(type: "datetime2", nullable: false), + Amount = table.Column(type: "decimal(18,2)", nullable: false), + Status = table.Column(type: "nvarchar(max)", nullable: true), + Details = table.Column(type: "nvarchar(max)", nullable: true), + OrderId = table.Column(type: "int", nullable: false), + CreatedById = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Payments", x => x.Id); + table.ForeignKey( + name: "FK_Payments_Orders_OrderId", + column: x => x.OrderId, + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Payments_Users_CreatedById", + column: x => x.CreatedById, + principalTable: "Users", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_Histories_OrderId", + table: "Histories", + column: "OrderId"); + + migrationBuilder.CreateIndex( + name: "IX_Histories_OrderId1", + table: "Histories", + column: "OrderId1"); + + migrationBuilder.CreateIndex( + name: "IX_Billings_OrderId", + table: "Billings", + column: "OrderId"); + + migrationBuilder.CreateIndex( + name: "IX_FinancialDetails_ClusterId", + table: "FinancialDetails", + column: "ClusterId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_MetaData_OrderId", + table: "MetaData", + column: "OrderId"); + + migrationBuilder.CreateIndex( + name: "IX_MetaData_OrderId_Name_Value", + table: "MetaData", + columns: new[] { "OrderId", "Name", "Value" }); + + migrationBuilder.CreateIndex( + name: "IX_Orders_ClusterId", + table: "Orders", + column: "ClusterId"); + + migrationBuilder.CreateIndex( + name: "IX_Orders_PrincipalInvestigatorId", + table: "Orders", + column: "PrincipalInvestigatorId"); + + migrationBuilder.CreateIndex( + name: "IX_Payments_CreatedById", + table: "Payments", + column: "CreatedById"); + + migrationBuilder.CreateIndex( + name: "IX_Payments_OrderId", + table: "Payments", + column: "OrderId"); + + migrationBuilder.CreateIndex( + name: "IX_Products_ClusterId", + table: "Products", + column: "ClusterId"); + + migrationBuilder.AddForeignKey( + name: "FK_Histories_Orders_OrderId", + table: "Histories", + column: "OrderId", + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_Histories_Orders_OrderId1", + table: "Histories", + column: "OrderId1", + principalTable: "Orders", + principalColumn: "Id"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Histories_Orders_OrderId", + table: "Histories"); + + migrationBuilder.DropForeignKey( + name: "FK_Histories_Orders_OrderId1", + table: "Histories"); + + migrationBuilder.DropTable( + name: "Billings"); + + migrationBuilder.DropTable( + name: "FinancialDetails"); + + migrationBuilder.DropTable( + name: "MetaData"); + + migrationBuilder.DropTable( + name: "Payments"); + + migrationBuilder.DropTable( + name: "Products"); + + migrationBuilder.DropTable( + name: "Orders"); + + migrationBuilder.DropIndex( + name: "IX_Histories_OrderId", + table: "Histories"); + + migrationBuilder.DropIndex( + name: "IX_Histories_OrderId1", + table: "Histories"); + + migrationBuilder.DropColumn( + name: "OrderId", + table: "Histories"); + + migrationBuilder.DropColumn( + name: "OrderId1", + table: "Histories"); + } + } +} diff --git a/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs b/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs index ed1ab3be..010e7602 100644 --- a/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs +++ b/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs @@ -130,6 +130,34 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Accounts"); }); + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Percentage") + .HasColumnType("decimal(18,2)"); + + b.Property("Updated") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => { b.Property("Id") @@ -180,6 +208,30 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Clusters"); }); + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + modelBuilder.Entity("Hippo.Core.Domain.Group", b => { b.Property("Id") @@ -268,6 +320,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Details") .HasColumnType("nvarchar(max)"); + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("OrderId1") + .HasColumnType("int"); + b.Property("Status") .HasMaxLength(50) .HasColumnType("nvarchar(50)"); @@ -282,9 +340,163 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("ClusterId"); + b.HasIndex("OrderId"); + + b.HasIndex("OrderId1"); + b.ToTable("Histories"); }); + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Adjustment") + .HasColumnType("decimal(18,2)"); + + b.Property("AdjustmentReason") + .HasColumnType("nvarchar(max)"); + + b.Property("AdminNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("BalanceRemaining") + .HasColumnType("decimal(18,2)"); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("Total") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("FinancialSystemId") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("TrackingNumber") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => { b.Property("Id") @@ -313,6 +525,54 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Permissions"); }); + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => { b.Property("Id") @@ -558,6 +818,28 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Owner"); }); + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + modelBuilder.Entity("Hippo.Core.Domain.Group", b => { b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") @@ -620,9 +902,67 @@ protected override void BuildModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Restrict) .IsRequired(); + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Order", null) + .WithMany("History") + .HasForeignKey("OrderId1"); + b.Navigation("ActedBy"); b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); }); modelBuilder.Entity("Hippo.Core.Domain.Permission", b => @@ -651,6 +991,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("User"); }); + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => { b.HasOne("Hippo.Core.Domain.Request", "Request") @@ -691,7 +1042,24 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Navigation("Accounts"); + b.Navigation("FinancialDetail"); + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); }); modelBuilder.Entity("Hippo.Core.Domain.Request", b => @@ -703,6 +1071,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Navigation("Accounts"); + b.Navigation("Orders"); + b.Navigation("Permissions"); }); #pragma warning restore 612, 618 diff --git a/Hippo.Core/Migrations/Sqlite/20240501195617_Orders20240501.Designer.cs b/Hippo.Core/Migrations/Sqlite/20240501195617_Orders20240501.Designer.cs new file mode 100644 index 00000000..6f8edc3d --- /dev/null +++ b/Hippo.Core/Migrations/Sqlite/20240501195617_Orders20240501.Designer.cs @@ -0,0 +1,1045 @@ +// +using System; +using Hippo.Core.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hippo.Core.Migrations.Sqlite +{ + [DbContext(typeof(AppDbContextSqlite))] + [Migration("20240501195617_Orders20240501")] + partial class Orders20240501 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.19"); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.Property("AccessTypesId") + .HasColumnType("INTEGER"); + + b.Property("AccountsId") + .HasColumnType("INTEGER"); + + b.HasKey("AccessTypesId", "AccountsId"); + + b.HasIndex("AccountsId"); + + b.ToTable("AccessTypeAccount"); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.Property("AccessTypesId") + .HasColumnType("INTEGER"); + + b.Property("ClustersId") + .HasColumnType("INTEGER"); + + b.HasKey("AccessTypesId", "ClustersId"); + + b.HasIndex("ClustersId"); + + b.ToTable("AccessTypeCluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.AccessType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AccessTypes"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("INTEGER"); + + b.Property("SshKey") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("CreatedOn"); + + b.HasIndex("Email"); + + b.HasIndex("Kerberos"); + + b.HasIndex("Name"); + + b.HasIndex("OwnerId"); + + b.HasIndex("UpdatedOn"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Percentage") + .HasColumnType("TEXT"); + + b.Property("Updated") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Domain") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("SshKeyId") + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("SshName") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("SshUrl") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Clusters"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DisplayName") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId", "Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.Property("AccountId") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupAdminAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.Property("AccountId") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMemberAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ActedById") + .HasColumnType("INTEGER"); + + b.Property("ActedDate") + .HasColumnType("TEXT"); + + b.Property("Action") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("AdminAction") + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("OrderId1") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ActedById"); + + b.HasIndex("ActedDate"); + + b.HasIndex("Action"); + + b.HasIndex("ClusterId"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId1"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Adjustment") + .HasColumnType("TEXT"); + + b.Property("AdjustmentReason") + .HasColumnType("TEXT"); + + b.Property("AdminNotes") + .HasColumnType("TEXT"); + + b.Property("BalanceRemaining") + .HasColumnType("TEXT"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("SubTotal") + .HasColumnType("TEXT"); + + b.Property("Total") + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("FinancialSystemId") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("TrackingNumber") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("ErrorMessage") + .HasColumnType("TEXT"); + + b.Property("RequestId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("RequestId"); + + b.HasIndex("Status"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ActorId") + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Group") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("RequesterId") + .HasColumnType("INTEGER"); + + b.Property("SshKey") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("SupervisingPI") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorId"); + + b.HasIndex("ClusterId"); + + b.HasIndex("Group"); + + b.HasIndex("RequesterId"); + + b.HasIndex("Status"); + + b.ToTable("Requests"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempGroup", b => + { + b.Property("Group") + .HasColumnType("TEXT"); + + b.HasKey("Group"); + + b.ToTable("TempGroups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempKerberos", b => + { + b.Property("Kerberos") + .HasColumnType("TEXT"); + + b.HasKey("Kerberos"); + + b.ToTable("TempKerberos"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Iam") + .HasMaxLength(10) + .HasColumnType("TEXT"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("MothraId") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("Iam") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Account", null) + .WithMany() + .HasForeignKey("AccountsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Cluster", null) + .WithMany() + .HasForeignKey("ClustersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Accounts") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Cluster"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Groups") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.HasOne("Hippo.Core.Domain.User", "ActedBy") + .WithMany() + .HasForeignKey("ActedById") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Order", null) + .WithMany("History") + .HasForeignKey("OrderId1"); + + b.Navigation("ActedBy"); + + b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.HasOne("Hippo.Core.Domain.Request", "Request") + .WithMany("QueuedEvents") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Request"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.HasOne("Hippo.Core.Domain.User", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Requester") + .WithMany() + .HasForeignKey("RequesterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Actor"); + + b.Navigation("Cluster"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Navigation("Accounts"); + + b.Navigation("FinancialDetail"); + + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Navigation("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Orders"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Hippo.Core/Migrations/Sqlite/20240501195617_Orders20240501.cs b/Hippo.Core/Migrations/Sqlite/20240501195617_Orders20240501.cs new file mode 100644 index 00000000..061dc061 --- /dev/null +++ b/Hippo.Core/Migrations/Sqlite/20240501195617_Orders20240501.cs @@ -0,0 +1,305 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hippo.Core.Migrations.Sqlite +{ + public partial class Orders20240501 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "OrderId", + table: "Histories", + type: "INTEGER", + nullable: true); + + migrationBuilder.AddColumn( + name: "OrderId1", + table: "Histories", + type: "INTEGER", + nullable: true); + + migrationBuilder.CreateTable( + name: "FinancialDetails", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AutoApprove = table.Column(type: "INTEGER", nullable: false, defaultValue: true), + ClusterId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FinancialDetails", x => x.Id); + table.ForeignKey( + name: "FK_FinancialDetails_Clusters_ClusterId", + column: x => x.ClusterId, + principalTable: "Clusters", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Orders", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Category = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 50, nullable: false), + Description = table.Column(type: "TEXT", maxLength: 250, nullable: true), + ExternalReference = table.Column(type: "TEXT", maxLength: 150, nullable: true), + Units = table.Column(type: "TEXT", nullable: true), + UnitPrice = table.Column(type: "TEXT", nullable: false), + Quantity = table.Column(type: "TEXT", nullable: false), + Installments = table.Column(type: "INTEGER", nullable: false), + Adjustment = table.Column(type: "TEXT", nullable: false), + AdjustmentReason = table.Column(type: "TEXT", nullable: true), + SubTotal = table.Column(type: "TEXT", nullable: false), + Total = table.Column(type: "TEXT", nullable: false), + BalanceRemaining = table.Column(type: "TEXT", nullable: false), + Notes = table.Column(type: "TEXT", nullable: true), + AdminNotes = table.Column(type: "TEXT", nullable: true), + Status = table.Column(type: "TEXT", nullable: true), + ClusterId = table.Column(type: "INTEGER", nullable: false), + PrincipalInvestigatorId = table.Column(type: "INTEGER", nullable: false), + CreatedOn = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Orders", x => x.Id); + table.ForeignKey( + name: "FK_Orders_Clusters_ClusterId", + column: x => x.ClusterId, + principalTable: "Clusters", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Orders_Users_PrincipalInvestigatorId", + column: x => x.PrincipalInvestigatorId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Products", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + IsActive = table.Column(type: "INTEGER", nullable: false, defaultValue: true), + Category = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 50, nullable: false), + Description = table.Column(type: "TEXT", maxLength: 250, nullable: true), + Units = table.Column(type: "TEXT", nullable: true), + UnitPrice = table.Column(type: "TEXT", nullable: false), + Installments = table.Column(type: "INTEGER", nullable: false), + LastUpdated = table.Column(type: "TEXT", nullable: false), + ClusterId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Products", x => x.Id); + table.ForeignKey( + name: "FK_Products_Clusters_ClusterId", + column: x => x.ClusterId, + principalTable: "Clusters", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Billings", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + ChartString = table.Column(type: "TEXT", nullable: false), + Percentage = table.Column(type: "TEXT", nullable: false), + OrderId = table.Column(type: "INTEGER", nullable: false), + Updated = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Billings", x => x.Id); + table.ForeignKey( + name: "FK_Billings_Orders_OrderId", + column: x => x.OrderId, + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "MetaData", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + OrderId = table.Column(type: "INTEGER", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 128, nullable: false), + Value = table.Column(type: "TEXT", maxLength: 450, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MetaData", x => x.Id); + table.ForeignKey( + name: "FK_MetaData_Orders_OrderId", + column: x => x.OrderId, + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Payments", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + FinancialSystemId = table.Column(type: "TEXT", nullable: true), + TrackingNumber = table.Column(type: "TEXT", nullable: true), + CreatedOn = table.Column(type: "TEXT", nullable: false), + Amount = table.Column(type: "TEXT", nullable: false), + Status = table.Column(type: "TEXT", nullable: true), + Details = table.Column(type: "TEXT", nullable: true), + OrderId = table.Column(type: "INTEGER", nullable: false), + CreatedById = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Payments", x => x.Id); + table.ForeignKey( + name: "FK_Payments_Orders_OrderId", + column: x => x.OrderId, + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Payments_Users_CreatedById", + column: x => x.CreatedById, + principalTable: "Users", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_Histories_OrderId", + table: "Histories", + column: "OrderId"); + + migrationBuilder.CreateIndex( + name: "IX_Histories_OrderId1", + table: "Histories", + column: "OrderId1"); + + migrationBuilder.CreateIndex( + name: "IX_Billings_OrderId", + table: "Billings", + column: "OrderId"); + + migrationBuilder.CreateIndex( + name: "IX_FinancialDetails_ClusterId", + table: "FinancialDetails", + column: "ClusterId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_MetaData_OrderId", + table: "MetaData", + column: "OrderId"); + + migrationBuilder.CreateIndex( + name: "IX_MetaData_OrderId_Name_Value", + table: "MetaData", + columns: new[] { "OrderId", "Name", "Value" }); + + migrationBuilder.CreateIndex( + name: "IX_Orders_ClusterId", + table: "Orders", + column: "ClusterId"); + + migrationBuilder.CreateIndex( + name: "IX_Orders_PrincipalInvestigatorId", + table: "Orders", + column: "PrincipalInvestigatorId"); + + migrationBuilder.CreateIndex( + name: "IX_Payments_CreatedById", + table: "Payments", + column: "CreatedById"); + + migrationBuilder.CreateIndex( + name: "IX_Payments_OrderId", + table: "Payments", + column: "OrderId"); + + migrationBuilder.CreateIndex( + name: "IX_Products_ClusterId", + table: "Products", + column: "ClusterId"); + + migrationBuilder.AddForeignKey( + name: "FK_Histories_Orders_OrderId", + table: "Histories", + column: "OrderId", + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_Histories_Orders_OrderId1", + table: "Histories", + column: "OrderId1", + principalTable: "Orders", + principalColumn: "Id"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Histories_Orders_OrderId", + table: "Histories"); + + migrationBuilder.DropForeignKey( + name: "FK_Histories_Orders_OrderId1", + table: "Histories"); + + migrationBuilder.DropTable( + name: "Billings"); + + migrationBuilder.DropTable( + name: "FinancialDetails"); + + migrationBuilder.DropTable( + name: "MetaData"); + + migrationBuilder.DropTable( + name: "Payments"); + + migrationBuilder.DropTable( + name: "Products"); + + migrationBuilder.DropTable( + name: "Orders"); + + migrationBuilder.DropIndex( + name: "IX_Histories_OrderId", + table: "Histories"); + + migrationBuilder.DropIndex( + name: "IX_Histories_OrderId1", + table: "Histories"); + + migrationBuilder.DropColumn( + name: "OrderId", + table: "Histories"); + + migrationBuilder.DropColumn( + name: "OrderId1", + table: "Histories"); + } + } +} diff --git a/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs b/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs index 35f3f753..cf665997 100644 --- a/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs +++ b/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs @@ -121,6 +121,32 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Accounts"); }); + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Percentage") + .HasColumnType("TEXT"); + + b.Property("Updated") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => { b.Property("Id") @@ -169,6 +195,28 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Clusters"); }); + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + modelBuilder.Entity("Hippo.Core.Domain.Group", b => { b.Property("Id") @@ -253,6 +301,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Details") .HasColumnType("TEXT"); + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("OrderId1") + .HasColumnType("INTEGER"); + b.Property("Status") .HasMaxLength(50) .HasColumnType("TEXT"); @@ -267,9 +321,157 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("ClusterId"); + b.HasIndex("OrderId"); + + b.HasIndex("OrderId1"); + b.ToTable("Histories"); }); + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Adjustment") + .HasColumnType("TEXT"); + + b.Property("AdjustmentReason") + .HasColumnType("TEXT"); + + b.Property("AdminNotes") + .HasColumnType("TEXT"); + + b.Property("BalanceRemaining") + .HasColumnType("TEXT"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("SubTotal") + .HasColumnType("TEXT"); + + b.Property("Total") + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("FinancialSystemId") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("TrackingNumber") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => { b.Property("Id") @@ -296,6 +498,52 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Permissions"); }); + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => { b.Property("Id") @@ -532,6 +780,28 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Owner"); }); + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + modelBuilder.Entity("Hippo.Core.Domain.Group", b => { b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") @@ -594,9 +864,67 @@ protected override void BuildModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Restrict) .IsRequired(); + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Order", null) + .WithMany("History") + .HasForeignKey("OrderId1"); + b.Navigation("ActedBy"); b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); }); modelBuilder.Entity("Hippo.Core.Domain.Permission", b => @@ -625,6 +953,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("User"); }); + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => { b.HasOne("Hippo.Core.Domain.Request", "Request") @@ -665,7 +1004,24 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Navigation("Accounts"); + b.Navigation("FinancialDetail"); + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); }); modelBuilder.Entity("Hippo.Core.Domain.Request", b => @@ -677,6 +1033,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Navigation("Accounts"); + b.Navigation("Orders"); + b.Navigation("Permissions"); }); #pragma warning restore 612, 618 From 31919e953b31a75d0fe800aa690a1fd881e8e54a Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 13:26:59 -0700 Subject: [PATCH 014/301] Fix migration --- Hippo.Core/Domain/FinancialDetail.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Hippo.Core/Domain/FinancialDetail.cs b/Hippo.Core/Domain/FinancialDetail.cs index 42ec8d9d..98e4143f 100644 --- a/Hippo.Core/Domain/FinancialDetail.cs +++ b/Hippo.Core/Domain/FinancialDetail.cs @@ -8,11 +8,11 @@ public class FinancialDetail [Key] public int Id { get; set; } [StringLength(128)] //Probably doesn't need to be this big... - string FinancialSystemApiKey { get; set; } + public string FinancialSystemApiKey { get; set; } [MaxLength(50)] - string FinancialSystemApiSource { get; set; } - string ChartString { get; set; } - bool AutoApprove { get; set; } + public string FinancialSystemApiSource { get; set; } + public string ChartString { get; set; } + public bool AutoApprove { get; set; } [Required] public int ClusterId { get; set; } public Cluster Cluster { get; set; } From c1d77b7d060a6ef364771c21f8bb4a60b8e5598d Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 13:31:33 -0700 Subject: [PATCH 015/301] Migration to add missing fields --- ...40501203029_FixFinancialDetail.Designer.cs | 1094 +++++++++++++++++ .../20240501203029_FixFinancialDetail.cs | 47 + .../AppDbContextSqlServerModelSnapshot.cs | 11 + ...40501203025_FixFinancialDetail.Designer.cs | 1056 ++++++++++++++++ .../20240501203025_FixFinancialDetail.cs | 47 + .../Sqlite/AppDbContextSqliteModelSnapshot.cs | 11 + 6 files changed, 2266 insertions(+) create mode 100644 Hippo.Core/Migrations/SqlServer/20240501203029_FixFinancialDetail.Designer.cs create mode 100644 Hippo.Core/Migrations/SqlServer/20240501203029_FixFinancialDetail.cs create mode 100644 Hippo.Core/Migrations/Sqlite/20240501203025_FixFinancialDetail.Designer.cs create mode 100644 Hippo.Core/Migrations/Sqlite/20240501203025_FixFinancialDetail.cs diff --git a/Hippo.Core/Migrations/SqlServer/20240501203029_FixFinancialDetail.Designer.cs b/Hippo.Core/Migrations/SqlServer/20240501203029_FixFinancialDetail.Designer.cs new file mode 100644 index 00000000..c080e5cb --- /dev/null +++ b/Hippo.Core/Migrations/SqlServer/20240501203029_FixFinancialDetail.Designer.cs @@ -0,0 +1,1094 @@ +// +using System; +using Hippo.Core.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hippo.Core.Migrations.SqlServer +{ + [DbContext(typeof(AppDbContextSqlServer))] + [Migration("20240501203029_FixFinancialDetail")] + partial class FixFinancialDetail + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.19") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.Property("AccessTypesId") + .HasColumnType("int"); + + b.Property("AccountsId") + .HasColumnType("int"); + + b.HasKey("AccessTypesId", "AccountsId"); + + b.HasIndex("AccountsId"); + + b.ToTable("AccessTypeAccount"); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.Property("AccessTypesId") + .HasColumnType("int"); + + b.Property("ClustersId") + .HasColumnType("int"); + + b.HasKey("AccessTypesId", "ClustersId"); + + b.HasIndex("ClustersId"); + + b.ToTable("AccessTypeCluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.AccessType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AccessTypes"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("SshKey") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("CreatedOn"); + + b.HasIndex("Email"); + + b.HasIndex("Kerberos"); + + b.HasIndex("Name"); + + b.HasIndex("OwnerId"); + + b.HasIndex("UpdatedOn"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Percentage") + .HasColumnType("decimal(18,2)"); + + b.Property("Updated") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Description") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Domain") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("SshKeyId") + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("SshName") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("SshUrl") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Clusters"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("ChartString") + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("FinancialSystemApiKey") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("FinancialSystemApiSource") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId", "Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("int"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupAdminAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("int"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMemberAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ActedById") + .HasColumnType("int"); + + b.Property("ActedDate") + .HasColumnType("datetime2"); + + b.Property("Action") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("AdminAction") + .HasColumnType("bit"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("OrderId1") + .HasColumnType("int"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ActedById"); + + b.HasIndex("ActedDate"); + + b.HasIndex("Action"); + + b.HasIndex("ClusterId"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId1"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Adjustment") + .HasColumnType("decimal(18,2)"); + + b.Property("AdjustmentReason") + .HasColumnType("nvarchar(max)"); + + b.Property("AdminNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("BalanceRemaining") + .HasColumnType("decimal(18,2)"); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("Total") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("FinancialSystemId") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("TrackingNumber") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Action") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)"); + + b.Property("RequestId") + .HasColumnType("int"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("RequestId"); + + b.HasIndex("Status"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ActorId") + .HasColumnType("int"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("Group") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("RequesterId") + .HasColumnType("int"); + + b.Property("SshKey") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("SupervisingPI") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorId"); + + b.HasIndex("ClusterId"); + + b.HasIndex("Group"); + + b.HasIndex("RequesterId"); + + b.HasIndex("Status"); + + b.ToTable("Requests"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempGroup", b => + { + b.Property("Group") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Group"); + + b.ToTable("TempGroups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempKerberos", b => + { + b.Property("Kerberos") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Kerberos"); + + b.ToTable("TempKerberos"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Email") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Iam") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("MothraId") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("Iam") + .IsUnique() + .HasFilter("[Iam] IS NOT NULL"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Account", null) + .WithMany() + .HasForeignKey("AccountsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Cluster", null) + .WithMany() + .HasForeignKey("ClustersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Accounts") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Cluster"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Groups") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.HasOne("Hippo.Core.Domain.User", "ActedBy") + .WithMany() + .HasForeignKey("ActedById") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Order", null) + .WithMany("History") + .HasForeignKey("OrderId1"); + + b.Navigation("ActedBy"); + + b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.HasOne("Hippo.Core.Domain.Request", "Request") + .WithMany("QueuedEvents") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Request"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.HasOne("Hippo.Core.Domain.User", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Requester") + .WithMany() + .HasForeignKey("RequesterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Actor"); + + b.Navigation("Cluster"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Navigation("Accounts"); + + b.Navigation("FinancialDetail"); + + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Navigation("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Orders"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Hippo.Core/Migrations/SqlServer/20240501203029_FixFinancialDetail.cs b/Hippo.Core/Migrations/SqlServer/20240501203029_FixFinancialDetail.cs new file mode 100644 index 00000000..3398a912 --- /dev/null +++ b/Hippo.Core/Migrations/SqlServer/20240501203029_FixFinancialDetail.cs @@ -0,0 +1,47 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hippo.Core.Migrations.SqlServer +{ + public partial class FixFinancialDetail : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ChartString", + table: "FinancialDetails", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "FinancialSystemApiKey", + table: "FinancialDetails", + type: "nvarchar(128)", + maxLength: 128, + nullable: true); + + migrationBuilder.AddColumn( + name: "FinancialSystemApiSource", + table: "FinancialDetails", + type: "nvarchar(50)", + maxLength: 50, + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ChartString", + table: "FinancialDetails"); + + migrationBuilder.DropColumn( + name: "FinancialSystemApiKey", + table: "FinancialDetails"); + + migrationBuilder.DropColumn( + name: "FinancialSystemApiSource", + table: "FinancialDetails"); + } + } +} diff --git a/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs b/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs index 010e7602..0bfd99f5 100644 --- a/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs +++ b/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs @@ -221,9 +221,20 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("bit") .HasDefaultValue(true); + b.Property("ChartString") + .HasColumnType("nvarchar(max)"); + b.Property("ClusterId") .HasColumnType("int"); + b.Property("FinancialSystemApiKey") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("FinancialSystemApiSource") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + b.HasKey("Id"); b.HasIndex("ClusterId") diff --git a/Hippo.Core/Migrations/Sqlite/20240501203025_FixFinancialDetail.Designer.cs b/Hippo.Core/Migrations/Sqlite/20240501203025_FixFinancialDetail.Designer.cs new file mode 100644 index 00000000..2395bbd3 --- /dev/null +++ b/Hippo.Core/Migrations/Sqlite/20240501203025_FixFinancialDetail.Designer.cs @@ -0,0 +1,1056 @@ +// +using System; +using Hippo.Core.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hippo.Core.Migrations.Sqlite +{ + [DbContext(typeof(AppDbContextSqlite))] + [Migration("20240501203025_FixFinancialDetail")] + partial class FixFinancialDetail + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.19"); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.Property("AccessTypesId") + .HasColumnType("INTEGER"); + + b.Property("AccountsId") + .HasColumnType("INTEGER"); + + b.HasKey("AccessTypesId", "AccountsId"); + + b.HasIndex("AccountsId"); + + b.ToTable("AccessTypeAccount"); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.Property("AccessTypesId") + .HasColumnType("INTEGER"); + + b.Property("ClustersId") + .HasColumnType("INTEGER"); + + b.HasKey("AccessTypesId", "ClustersId"); + + b.HasIndex("ClustersId"); + + b.ToTable("AccessTypeCluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.AccessType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AccessTypes"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("INTEGER"); + + b.Property("SshKey") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("CreatedOn"); + + b.HasIndex("Email"); + + b.HasIndex("Kerberos"); + + b.HasIndex("Name"); + + b.HasIndex("OwnerId"); + + b.HasIndex("UpdatedOn"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Percentage") + .HasColumnType("TEXT"); + + b.Property("Updated") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Domain") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("SshKeyId") + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("SshName") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("SshUrl") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Clusters"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("ChartString") + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("FinancialSystemApiKey") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("FinancialSystemApiSource") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DisplayName") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId", "Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.Property("AccountId") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupAdminAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.Property("AccountId") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMemberAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ActedById") + .HasColumnType("INTEGER"); + + b.Property("ActedDate") + .HasColumnType("TEXT"); + + b.Property("Action") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("AdminAction") + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("OrderId1") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ActedById"); + + b.HasIndex("ActedDate"); + + b.HasIndex("Action"); + + b.HasIndex("ClusterId"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId1"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Adjustment") + .HasColumnType("TEXT"); + + b.Property("AdjustmentReason") + .HasColumnType("TEXT"); + + b.Property("AdminNotes") + .HasColumnType("TEXT"); + + b.Property("BalanceRemaining") + .HasColumnType("TEXT"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("SubTotal") + .HasColumnType("TEXT"); + + b.Property("Total") + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("FinancialSystemId") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("TrackingNumber") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("ErrorMessage") + .HasColumnType("TEXT"); + + b.Property("RequestId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("RequestId"); + + b.HasIndex("Status"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ActorId") + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Group") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("RequesterId") + .HasColumnType("INTEGER"); + + b.Property("SshKey") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("SupervisingPI") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorId"); + + b.HasIndex("ClusterId"); + + b.HasIndex("Group"); + + b.HasIndex("RequesterId"); + + b.HasIndex("Status"); + + b.ToTable("Requests"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempGroup", b => + { + b.Property("Group") + .HasColumnType("TEXT"); + + b.HasKey("Group"); + + b.ToTable("TempGroups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempKerberos", b => + { + b.Property("Kerberos") + .HasColumnType("TEXT"); + + b.HasKey("Kerberos"); + + b.ToTable("TempKerberos"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Iam") + .HasMaxLength(10) + .HasColumnType("TEXT"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("MothraId") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("Iam") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Account", null) + .WithMany() + .HasForeignKey("AccountsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Cluster", null) + .WithMany() + .HasForeignKey("ClustersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Accounts") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Cluster"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Groups") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.HasOne("Hippo.Core.Domain.User", "ActedBy") + .WithMany() + .HasForeignKey("ActedById") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Order", null) + .WithMany("History") + .HasForeignKey("OrderId1"); + + b.Navigation("ActedBy"); + + b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.HasOne("Hippo.Core.Domain.Request", "Request") + .WithMany("QueuedEvents") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Request"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.HasOne("Hippo.Core.Domain.User", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Requester") + .WithMany() + .HasForeignKey("RequesterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Actor"); + + b.Navigation("Cluster"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Navigation("Accounts"); + + b.Navigation("FinancialDetail"); + + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Navigation("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Orders"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Hippo.Core/Migrations/Sqlite/20240501203025_FixFinancialDetail.cs b/Hippo.Core/Migrations/Sqlite/20240501203025_FixFinancialDetail.cs new file mode 100644 index 00000000..42133b26 --- /dev/null +++ b/Hippo.Core/Migrations/Sqlite/20240501203025_FixFinancialDetail.cs @@ -0,0 +1,47 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hippo.Core.Migrations.Sqlite +{ + public partial class FixFinancialDetail : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ChartString", + table: "FinancialDetails", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "FinancialSystemApiKey", + table: "FinancialDetails", + type: "TEXT", + maxLength: 128, + nullable: true); + + migrationBuilder.AddColumn( + name: "FinancialSystemApiSource", + table: "FinancialDetails", + type: "TEXT", + maxLength: 50, + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ChartString", + table: "FinancialDetails"); + + migrationBuilder.DropColumn( + name: "FinancialSystemApiKey", + table: "FinancialDetails"); + + migrationBuilder.DropColumn( + name: "FinancialSystemApiSource", + table: "FinancialDetails"); + } + } +} diff --git a/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs b/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs index cf665997..02ece8ff 100644 --- a/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs +++ b/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs @@ -206,9 +206,20 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("INTEGER") .HasDefaultValue(true); + b.Property("ChartString") + .HasColumnType("TEXT"); + b.Property("ClusterId") .HasColumnType("INTEGER"); + b.Property("FinancialSystemApiKey") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("FinancialSystemApiSource") + .HasMaxLength(50) + .HasColumnType("TEXT"); + b.HasKey("Id"); b.HasIndex("ClusterId") From 5ef2402e531eaa20770f492839a88f59bd01fcff Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 13:59:35 -0700 Subject: [PATCH 016/301] Create FinancialDetails --- .../Controllers/ClusterAdminController.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Hippo.Web/Controllers/ClusterAdminController.cs b/Hippo.Web/Controllers/ClusterAdminController.cs index 2a98059c..d0d30fce 100644 --- a/Hippo.Web/Controllers/ClusterAdminController.cs +++ b/Hippo.Web/Controllers/ClusterAdminController.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Hippo.Core.Domain; namespace Hippo.Web.Controllers { @@ -149,5 +150,38 @@ public async Task Update([FromBody] ClusterModel clusterModel) return Ok(clusterModel); } + public async Task UpdateFinancialDetails(int id, [FromBody] FinancialDetail model) + { + //Possibly use the secret service to set the FinancialSystemApiKey + var cluster = await _dbContext.Clusters.SingleAsync(c => c.Id == id); + var existingFinancialDetail = await _dbContext.FinancialDetails.SingleOrDefaultAsync(fd => fd.ClusterId == id); + if (existingFinancialDetail == null) + { + existingFinancialDetail = new FinancialDetail + { + ClusterId = id + }; + } + await _secretsService.SetSecret($"FinancialApiKeyCluster{cluster.Id}", model.FinancialSystemApiKey); + //var xxx = await _secretsService.GetSecret($"FinancialApiKeyCluster{cluster.Id}"); + //existingFinancialDetail.FinancialSystemApiKey = model.FinancialSystemApiKey; + existingFinancialDetail.FinancialSystemApiSource = model.FinancialSystemApiSource; + existingFinancialDetail.ChartString = model.ChartString; + existingFinancialDetail.AutoApprove = model.AutoApprove; + + if (existingFinancialDetail.Id == 0) + { + await _dbContext.FinancialDetails.AddAsync(existingFinancialDetail); + } + else + { + _dbContext.FinancialDetails.Update(existingFinancialDetail); + } + + await _dbContext.SaveChangesAsync(); + return Ok(existingFinancialDetail); + + } + } } From e8dd803b853a68544ffe950c5101c335c21b7dae Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 15:37:20 -0700 Subject: [PATCH 017/301] use super secret --- Hippo.Core/Domain/FinancialDetail.cs | 4 ++-- .../OrderModels/FinancialDetailPostModel.cs | 19 +++++++++++++++++++ .../Controllers/ClusterAdminController.cs | 15 ++++++++++----- 3 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 Hippo.Core/Models/OrderModels/FinancialDetailPostModel.cs diff --git a/Hippo.Core/Domain/FinancialDetail.cs b/Hippo.Core/Domain/FinancialDetail.cs index 98e4143f..cd631756 100644 --- a/Hippo.Core/Domain/FinancialDetail.cs +++ b/Hippo.Core/Domain/FinancialDetail.cs @@ -7,8 +7,8 @@ public class FinancialDetail { [Key] public int Id { get; set; } - [StringLength(128)] //Probably doesn't need to be this big... - public string FinancialSystemApiKey { get; set; } + public Guid SecretAccessKey { get; set; } //Used to get the FinancialSystemApiKey from the secret service + [Required] [MaxLength(50)] public string FinancialSystemApiSource { get; set; } public string ChartString { get; set; } diff --git a/Hippo.Core/Models/OrderModels/FinancialDetailPostModel.cs b/Hippo.Core/Models/OrderModels/FinancialDetailPostModel.cs new file mode 100644 index 00000000..759f0abf --- /dev/null +++ b/Hippo.Core/Models/OrderModels/FinancialDetailPostModel.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Hippo.Core.Models.OrderModels +{ + public class FinancialDetailPostModel + { + public string FinancialSystemApiKey { get; set; } + [Required] + [MaxLength(50)] + public string FinancialSystemApiSource { get; set; } + public string ChartString { get; set; } + public bool AutoApprove { get; set; } + } +} diff --git a/Hippo.Web/Controllers/ClusterAdminController.cs b/Hippo.Web/Controllers/ClusterAdminController.cs index d0d30fce..aaf2da5c 100644 --- a/Hippo.Web/Controllers/ClusterAdminController.cs +++ b/Hippo.Web/Controllers/ClusterAdminController.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Hippo.Core.Domain; +using Hippo.Core.Models.OrderModels; namespace Hippo.Web.Controllers { @@ -150,7 +151,7 @@ public async Task Update([FromBody] ClusterModel clusterModel) return Ok(clusterModel); } - public async Task UpdateFinancialDetails(int id, [FromBody] FinancialDetail model) + public async Task UpdateFinancialDetails(int id, [FromBody] FinancialDetailPostModel model) { //Possibly use the secret service to set the FinancialSystemApiKey var cluster = await _dbContext.Clusters.SingleAsync(c => c.Id == id); @@ -159,12 +160,16 @@ public async Task UpdateFinancialDetails(int id, [FromBody] Finan { existingFinancialDetail = new FinancialDetail { - ClusterId = id + ClusterId = id, + SecretAccessKey = Guid.NewGuid(), + }; } - await _secretsService.SetSecret($"FinancialApiKeyCluster{cluster.Id}", model.FinancialSystemApiKey); - //var xxx = await _secretsService.GetSecret($"FinancialApiKeyCluster{cluster.Id}"); - //existingFinancialDetail.FinancialSystemApiKey = model.FinancialSystemApiKey; + if (!string.IsNullOrWhiteSpace(model.FinancialSystemApiKey)) + { + await _secretsService.SetSecret(existingFinancialDetail.SecretAccessKey.ToString(), model.FinancialSystemApiKey); + } + //var xxx = await _secretsService.GetSecret(existingFinancialDetail.SecretAccessKey.ToString()); existingFinancialDetail.FinancialSystemApiSource = model.FinancialSystemApiSource; existingFinancialDetail.ChartString = model.ChartString; existingFinancialDetail.AutoApprove = model.AutoApprove; From 2e83e231e4720dcd2232d5d2604b98ba953525c6 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 1 May 2024 15:39:51 -0700 Subject: [PATCH 018/301] migration --- ...223936_useSecretFinancilDetail.Designer.cs | 1094 +++++++++++++++++ .../20240501223936_useSecretFinancilDetail.cs | 60 + .../AppDbContextSqlServerModelSnapshot.cs | 8 +- ...223931_useSecretFinancilDetail.Designer.cs | 1056 ++++++++++++++++ .../20240501223931_useSecretFinancilDetail.cs | 60 + .../Sqlite/AppDbContextSqliteModelSnapshot.cs | 8 +- 6 files changed, 2278 insertions(+), 8 deletions(-) create mode 100644 Hippo.Core/Migrations/SqlServer/20240501223936_useSecretFinancilDetail.Designer.cs create mode 100644 Hippo.Core/Migrations/SqlServer/20240501223936_useSecretFinancilDetail.cs create mode 100644 Hippo.Core/Migrations/Sqlite/20240501223931_useSecretFinancilDetail.Designer.cs create mode 100644 Hippo.Core/Migrations/Sqlite/20240501223931_useSecretFinancilDetail.cs diff --git a/Hippo.Core/Migrations/SqlServer/20240501223936_useSecretFinancilDetail.Designer.cs b/Hippo.Core/Migrations/SqlServer/20240501223936_useSecretFinancilDetail.Designer.cs new file mode 100644 index 00000000..d632ffb3 --- /dev/null +++ b/Hippo.Core/Migrations/SqlServer/20240501223936_useSecretFinancilDetail.Designer.cs @@ -0,0 +1,1094 @@ +// +using System; +using Hippo.Core.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hippo.Core.Migrations.SqlServer +{ + [DbContext(typeof(AppDbContextSqlServer))] + [Migration("20240501223936_useSecretFinancilDetail")] + partial class useSecretFinancilDetail + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.19") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.Property("AccessTypesId") + .HasColumnType("int"); + + b.Property("AccountsId") + .HasColumnType("int"); + + b.HasKey("AccessTypesId", "AccountsId"); + + b.HasIndex("AccountsId"); + + b.ToTable("AccessTypeAccount"); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.Property("AccessTypesId") + .HasColumnType("int"); + + b.Property("ClustersId") + .HasColumnType("int"); + + b.HasKey("AccessTypesId", "ClustersId"); + + b.HasIndex("ClustersId"); + + b.ToTable("AccessTypeCluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.AccessType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AccessTypes"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("SshKey") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("CreatedOn"); + + b.HasIndex("Email"); + + b.HasIndex("Kerberos"); + + b.HasIndex("Name"); + + b.HasIndex("OwnerId"); + + b.HasIndex("UpdatedOn"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Percentage") + .HasColumnType("decimal(18,2)"); + + b.Property("Updated") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Description") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Domain") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("SshKeyId") + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("SshName") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("SshUrl") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Clusters"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("ChartString") + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("FinancialSystemApiSource") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("SecretAccessKey") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId", "Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("int"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupAdminAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("int"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMemberAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ActedById") + .HasColumnType("int"); + + b.Property("ActedDate") + .HasColumnType("datetime2"); + + b.Property("Action") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("AdminAction") + .HasColumnType("bit"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("OrderId1") + .HasColumnType("int"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ActedById"); + + b.HasIndex("ActedDate"); + + b.HasIndex("Action"); + + b.HasIndex("ClusterId"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId1"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Adjustment") + .HasColumnType("decimal(18,2)"); + + b.Property("AdjustmentReason") + .HasColumnType("nvarchar(max)"); + + b.Property("AdminNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("BalanceRemaining") + .HasColumnType("decimal(18,2)"); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("Total") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("FinancialSystemId") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("TrackingNumber") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Action") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)"); + + b.Property("RequestId") + .HasColumnType("int"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("RequestId"); + + b.HasIndex("Status"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ActorId") + .HasColumnType("int"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("Group") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("RequesterId") + .HasColumnType("int"); + + b.Property("SshKey") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("SupervisingPI") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorId"); + + b.HasIndex("ClusterId"); + + b.HasIndex("Group"); + + b.HasIndex("RequesterId"); + + b.HasIndex("Status"); + + b.ToTable("Requests"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempGroup", b => + { + b.Property("Group") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Group"); + + b.ToTable("TempGroups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempKerberos", b => + { + b.Property("Kerberos") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Kerberos"); + + b.ToTable("TempKerberos"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Email") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Iam") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("MothraId") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("Iam") + .IsUnique() + .HasFilter("[Iam] IS NOT NULL"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Account", null) + .WithMany() + .HasForeignKey("AccountsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Cluster", null) + .WithMany() + .HasForeignKey("ClustersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Accounts") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Cluster"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Groups") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.HasOne("Hippo.Core.Domain.User", "ActedBy") + .WithMany() + .HasForeignKey("ActedById") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Order", null) + .WithMany("History") + .HasForeignKey("OrderId1"); + + b.Navigation("ActedBy"); + + b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.HasOne("Hippo.Core.Domain.Request", "Request") + .WithMany("QueuedEvents") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Request"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.HasOne("Hippo.Core.Domain.User", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Requester") + .WithMany() + .HasForeignKey("RequesterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Actor"); + + b.Navigation("Cluster"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Navigation("Accounts"); + + b.Navigation("FinancialDetail"); + + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Navigation("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Orders"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Hippo.Core/Migrations/SqlServer/20240501223936_useSecretFinancilDetail.cs b/Hippo.Core/Migrations/SqlServer/20240501223936_useSecretFinancilDetail.cs new file mode 100644 index 00000000..a708b50b --- /dev/null +++ b/Hippo.Core/Migrations/SqlServer/20240501223936_useSecretFinancilDetail.cs @@ -0,0 +1,60 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hippo.Core.Migrations.SqlServer +{ + public partial class useSecretFinancilDetail : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "FinancialSystemApiKey", + table: "FinancialDetails"); + + migrationBuilder.AlterColumn( + name: "FinancialSystemApiSource", + table: "FinancialDetails", + type: "nvarchar(50)", + maxLength: 50, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "nvarchar(50)", + oldMaxLength: 50, + oldNullable: true); + + migrationBuilder.AddColumn( + name: "SecretAccessKey", + table: "FinancialDetails", + type: "uniqueidentifier", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "SecretAccessKey", + table: "FinancialDetails"); + + migrationBuilder.AlterColumn( + name: "FinancialSystemApiSource", + table: "FinancialDetails", + type: "nvarchar(50)", + maxLength: 50, + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(50)", + oldMaxLength: 50); + + migrationBuilder.AddColumn( + name: "FinancialSystemApiKey", + table: "FinancialDetails", + type: "nvarchar(128)", + maxLength: 128, + nullable: true); + } + } +} diff --git a/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs b/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs index 0bfd99f5..d7214868 100644 --- a/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs +++ b/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs @@ -227,14 +227,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ClusterId") .HasColumnType("int"); - b.Property("FinancialSystemApiKey") - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - b.Property("FinancialSystemApiSource") + .IsRequired() .HasMaxLength(50) .HasColumnType("nvarchar(50)"); + b.Property("SecretAccessKey") + .HasColumnType("uniqueidentifier"); + b.HasKey("Id"); b.HasIndex("ClusterId") diff --git a/Hippo.Core/Migrations/Sqlite/20240501223931_useSecretFinancilDetail.Designer.cs b/Hippo.Core/Migrations/Sqlite/20240501223931_useSecretFinancilDetail.Designer.cs new file mode 100644 index 00000000..cb9e99d9 --- /dev/null +++ b/Hippo.Core/Migrations/Sqlite/20240501223931_useSecretFinancilDetail.Designer.cs @@ -0,0 +1,1056 @@ +// +using System; +using Hippo.Core.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hippo.Core.Migrations.Sqlite +{ + [DbContext(typeof(AppDbContextSqlite))] + [Migration("20240501223931_useSecretFinancilDetail")] + partial class useSecretFinancilDetail + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.19"); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.Property("AccessTypesId") + .HasColumnType("INTEGER"); + + b.Property("AccountsId") + .HasColumnType("INTEGER"); + + b.HasKey("AccessTypesId", "AccountsId"); + + b.HasIndex("AccountsId"); + + b.ToTable("AccessTypeAccount"); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.Property("AccessTypesId") + .HasColumnType("INTEGER"); + + b.Property("ClustersId") + .HasColumnType("INTEGER"); + + b.HasKey("AccessTypesId", "ClustersId"); + + b.HasIndex("ClustersId"); + + b.ToTable("AccessTypeCluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.AccessType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AccessTypes"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("INTEGER"); + + b.Property("SshKey") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("CreatedOn"); + + b.HasIndex("Email"); + + b.HasIndex("Kerberos"); + + b.HasIndex("Name"); + + b.HasIndex("OwnerId"); + + b.HasIndex("UpdatedOn"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Percentage") + .HasColumnType("TEXT"); + + b.Property("Updated") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Domain") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("SshKeyId") + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("SshName") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("SshUrl") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Clusters"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("ChartString") + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("FinancialSystemApiSource") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("SecretAccessKey") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DisplayName") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId", "Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.Property("AccountId") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupAdminAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.Property("AccountId") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMemberAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ActedById") + .HasColumnType("INTEGER"); + + b.Property("ActedDate") + .HasColumnType("TEXT"); + + b.Property("Action") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("AdminAction") + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("OrderId1") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ActedById"); + + b.HasIndex("ActedDate"); + + b.HasIndex("Action"); + + b.HasIndex("ClusterId"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId1"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Adjustment") + .HasColumnType("TEXT"); + + b.Property("AdjustmentReason") + .HasColumnType("TEXT"); + + b.Property("AdminNotes") + .HasColumnType("TEXT"); + + b.Property("BalanceRemaining") + .HasColumnType("TEXT"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("SubTotal") + .HasColumnType("TEXT"); + + b.Property("Total") + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("FinancialSystemId") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("TrackingNumber") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("ErrorMessage") + .HasColumnType("TEXT"); + + b.Property("RequestId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("RequestId"); + + b.HasIndex("Status"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ActorId") + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Group") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("RequesterId") + .HasColumnType("INTEGER"); + + b.Property("SshKey") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("SupervisingPI") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorId"); + + b.HasIndex("ClusterId"); + + b.HasIndex("Group"); + + b.HasIndex("RequesterId"); + + b.HasIndex("Status"); + + b.ToTable("Requests"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempGroup", b => + { + b.Property("Group") + .HasColumnType("TEXT"); + + b.HasKey("Group"); + + b.ToTable("TempGroups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempKerberos", b => + { + b.Property("Kerberos") + .HasColumnType("TEXT"); + + b.HasKey("Kerberos"); + + b.ToTable("TempKerberos"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Iam") + .HasMaxLength(10) + .HasColumnType("TEXT"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("MothraId") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("Iam") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Account", null) + .WithMany() + .HasForeignKey("AccountsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Cluster", null) + .WithMany() + .HasForeignKey("ClustersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Accounts") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Cluster"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Groups") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.HasOne("Hippo.Core.Domain.User", "ActedBy") + .WithMany() + .HasForeignKey("ActedById") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Order", null) + .WithMany("History") + .HasForeignKey("OrderId1"); + + b.Navigation("ActedBy"); + + b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.HasOne("Hippo.Core.Domain.Request", "Request") + .WithMany("QueuedEvents") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Request"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.HasOne("Hippo.Core.Domain.User", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Requester") + .WithMany() + .HasForeignKey("RequesterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Actor"); + + b.Navigation("Cluster"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Navigation("Accounts"); + + b.Navigation("FinancialDetail"); + + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Navigation("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Orders"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Hippo.Core/Migrations/Sqlite/20240501223931_useSecretFinancilDetail.cs b/Hippo.Core/Migrations/Sqlite/20240501223931_useSecretFinancilDetail.cs new file mode 100644 index 00000000..5fc498d9 --- /dev/null +++ b/Hippo.Core/Migrations/Sqlite/20240501223931_useSecretFinancilDetail.cs @@ -0,0 +1,60 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hippo.Core.Migrations.Sqlite +{ + public partial class useSecretFinancilDetail : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "FinancialSystemApiKey", + table: "FinancialDetails"); + + migrationBuilder.AlterColumn( + name: "FinancialSystemApiSource", + table: "FinancialDetails", + type: "TEXT", + maxLength: 50, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "TEXT", + oldMaxLength: 50, + oldNullable: true); + + migrationBuilder.AddColumn( + name: "SecretAccessKey", + table: "FinancialDetails", + type: "TEXT", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "SecretAccessKey", + table: "FinancialDetails"); + + migrationBuilder.AlterColumn( + name: "FinancialSystemApiSource", + table: "FinancialDetails", + type: "TEXT", + maxLength: 50, + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT", + oldMaxLength: 50); + + migrationBuilder.AddColumn( + name: "FinancialSystemApiKey", + table: "FinancialDetails", + type: "TEXT", + maxLength: 128, + nullable: true); + } + } +} diff --git a/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs b/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs index 02ece8ff..5202235a 100644 --- a/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs +++ b/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs @@ -212,14 +212,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ClusterId") .HasColumnType("INTEGER"); - b.Property("FinancialSystemApiKey") - .HasMaxLength(128) - .HasColumnType("TEXT"); - b.Property("FinancialSystemApiSource") + .IsRequired() .HasMaxLength(50) .HasColumnType("TEXT"); + b.Property("SecretAccessKey") + .HasColumnType("TEXT"); + b.HasKey("Id"); b.HasIndex("ClusterId") From 9dd84a45afa0d494a4476f55a4215d1d7d746ce3 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Thu, 2 May 2024 07:57:38 -0700 Subject: [PATCH 019/301] WIP a page to test this. --- ...ilPostModel.cs => FinancialDetailModel.cs} | 6 +- Hippo.Web/ClientApp/src/AppNav.tsx | 13 ++- Hippo.Web/ClientApp/src/types.ts | 8 ++ Hippo.Web/Controllers/AdminController.cs | 83 ++++++++++++++++++- .../Controllers/ClusterAdminController.cs | 43 +--------- 5 files changed, 108 insertions(+), 45 deletions(-) rename Hippo.Core/Models/OrderModels/{FinancialDetailPostModel.cs => FinancialDetailModel.cs} (84%) diff --git a/Hippo.Core/Models/OrderModels/FinancialDetailPostModel.cs b/Hippo.Core/Models/OrderModels/FinancialDetailModel.cs similarity index 84% rename from Hippo.Core/Models/OrderModels/FinancialDetailPostModel.cs rename to Hippo.Core/Models/OrderModels/FinancialDetailModel.cs index 759f0abf..06dd053f 100644 --- a/Hippo.Core/Models/OrderModels/FinancialDetailPostModel.cs +++ b/Hippo.Core/Models/OrderModels/FinancialDetailModel.cs @@ -7,7 +7,7 @@ namespace Hippo.Core.Models.OrderModels { - public class FinancialDetailPostModel + public class FinancialDetailModel { public string FinancialSystemApiKey { get; set; } [Required] @@ -15,5 +15,9 @@ public class FinancialDetailPostModel public string FinancialSystemApiSource { get; set; } public string ChartString { get; set; } public bool AutoApprove { get; set; } + + public string MaskedApiKey { get; set; } + + } } diff --git a/Hippo.Web/ClientApp/src/AppNav.tsx b/Hippo.Web/ClientApp/src/AppNav.tsx index 7158664d..52e1fed5 100644 --- a/Hippo.Web/ClientApp/src/AppNav.tsx +++ b/Hippo.Web/ClientApp/src/AppNav.tsx @@ -94,7 +94,6 @@ export const AppNav = () => { > Groups - { Cluster Admins + + + isActive ? { fontWeight: "bold" } : {} + } + > + Financial + + diff --git a/Hippo.Web/ClientApp/src/types.ts b/Hippo.Web/ClientApp/src/types.ts index 917ab6d1..a58d5381 100644 --- a/Hippo.Web/ClientApp/src/types.ts +++ b/Hippo.Web/ClientApp/src/types.ts @@ -212,3 +212,11 @@ export interface PuppetGroupRecord { storage?: PuppetGroupStorage[]; slurm?: SlurmRecord; } + +export interface FinancialDetailModel { + financialSystemApiKey: string; + financialSystemApiSource: string; + chartString: string; + autoApprove: boolean; + maskedApiKey: string; +} diff --git a/Hippo.Web/Controllers/AdminController.cs b/Hippo.Web/Controllers/AdminController.cs index a14dfd2d..af2167e4 100644 --- a/Hippo.Web/Controllers/AdminController.cs +++ b/Hippo.Web/Controllers/AdminController.cs @@ -1,6 +1,7 @@ using Hippo.Core.Data; using Hippo.Core.Domain; using Hippo.Core.Models; +using Hippo.Core.Models.OrderModels; using Hippo.Core.Services; using Hippo.Web.Extensions; using Hippo.Web.Models; @@ -8,6 +9,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Serilog; +using System.Text; using static Hippo.Core.Domain.Account; namespace Hippo.Web.Controllers; @@ -21,8 +23,9 @@ public class AdminController : SuperController private IHistoryService _historyService; private ISshService _sshService; private INotificationService _notificationService; + private ISecretsService _secretsService; - public AdminController(AppDbContext dbContext, IUserService userService, IIdentityService identityService, ISshService sshService, INotificationService notificationService, IHistoryService historyService) + public AdminController(AppDbContext dbContext, IUserService userService, IIdentityService identityService, ISshService sshService, INotificationService notificationService, IHistoryService historyService, ISecretsService secretsService) { _dbContext = dbContext; _userService = userService; @@ -30,6 +33,7 @@ public AdminController(AppDbContext dbContext, IUserService userService, IIdenti _historyService = historyService; _sshService = sshService; _notificationService = notificationService; + _secretsService = secretsService; } [HttpGet] @@ -128,4 +132,81 @@ public async Task Groups() .Select(g => g.Name) .ToArrayAsync()); } + + [HttpGet] + public async Task FinancialDetails() + { + var cluster = await _dbContext.Clusters.AsNoTracking().SingleAsync(c => c.Name == Cluster); + var existingFinancialDetail = await _dbContext.FinancialDetails.SingleOrDefaultAsync(fd => fd.ClusterId == cluster.Id); + var clusterModel = new FinancialDetailModel + { + FinancialSystemApiKey = string.Empty, + FinancialSystemApiSource = existingFinancialDetail?.FinancialSystemApiSource, + ChartString = existingFinancialDetail?.ChartString, + AutoApprove = existingFinancialDetail?.AutoApprove ?? false, + MaskedApiKey = "NOT SET" + }; + + if (existingFinancialDetail != null) + { + var apiKey = await _secretsService.GetSecret(existingFinancialDetail.SecretAccessKey.ToString()); + if (!string.IsNullOrWhiteSpace(apiKey)) + { + var sb = new StringBuilder(); + for (var i = 0; i < apiKey.Length; i++) + { + if (i < 4 || i >= apiKey.Length - 4) + { + sb.Append(apiKey[i]); + } + else + { + sb.Append('*'); + } + } + + clusterModel.MaskedApiKey = sb.ToString(); + } + } + + return Ok(clusterModel); + } + + [HttpPost] + public async Task UpdateFinancialDetails([FromBody] FinancialDetailModel model) + { + //Possibly use the secret service to set the FinancialSystemApiKey + var cluster = await _dbContext.Clusters.SingleAsync(c => c.Name == Cluster); + var existingFinancialDetail = await _dbContext.FinancialDetails.SingleOrDefaultAsync(fd => fd.ClusterId == cluster.Id); + if (existingFinancialDetail == null) + { + existingFinancialDetail = new FinancialDetail + { + ClusterId = cluster.Id, + SecretAccessKey = Guid.NewGuid(), + + }; + } + if (!string.IsNullOrWhiteSpace(model.FinancialSystemApiKey)) + { + await _secretsService.SetSecret(existingFinancialDetail.SecretAccessKey.ToString(), model.FinancialSystemApiKey); + } + //var xxx = await _secretsService.GetSecret(existingFinancialDetail.SecretAccessKey.ToString()); + existingFinancialDetail.FinancialSystemApiSource = model.FinancialSystemApiSource; + existingFinancialDetail.ChartString = model.ChartString; + existingFinancialDetail.AutoApprove = model.AutoApprove; + + if (existingFinancialDetail.Id == 0) + { + await _dbContext.FinancialDetails.AddAsync(existingFinancialDetail); + } + else + { + _dbContext.FinancialDetails.Update(existingFinancialDetail); + } + + await _dbContext.SaveChangesAsync(); + return Ok(existingFinancialDetail); + + } } diff --git a/Hippo.Web/Controllers/ClusterAdminController.cs b/Hippo.Web/Controllers/ClusterAdminController.cs index aaf2da5c..15d47b5e 100644 --- a/Hippo.Web/Controllers/ClusterAdminController.cs +++ b/Hippo.Web/Controllers/ClusterAdminController.cs @@ -1,15 +1,10 @@ -using System; -using System.Linq; using Hippo.Core.Data; +using Hippo.Core.Extensions; using Hippo.Core.Models; using Hippo.Core.Services; -using Hippo.Core.Extensions; -using Hippo.Web.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Hippo.Core.Domain; -using Hippo.Core.Models.OrderModels; namespace Hippo.Web.Controllers { @@ -151,42 +146,6 @@ public async Task Update([FromBody] ClusterModel clusterModel) return Ok(clusterModel); } - public async Task UpdateFinancialDetails(int id, [FromBody] FinancialDetailPostModel model) - { - //Possibly use the secret service to set the FinancialSystemApiKey - var cluster = await _dbContext.Clusters.SingleAsync(c => c.Id == id); - var existingFinancialDetail = await _dbContext.FinancialDetails.SingleOrDefaultAsync(fd => fd.ClusterId == id); - if (existingFinancialDetail == null) - { - existingFinancialDetail = new FinancialDetail - { - ClusterId = id, - SecretAccessKey = Guid.NewGuid(), - - }; - } - if (!string.IsNullOrWhiteSpace(model.FinancialSystemApiKey)) - { - await _secretsService.SetSecret(existingFinancialDetail.SecretAccessKey.ToString(), model.FinancialSystemApiKey); - } - //var xxx = await _secretsService.GetSecret(existingFinancialDetail.SecretAccessKey.ToString()); - existingFinancialDetail.FinancialSystemApiSource = model.FinancialSystemApiSource; - existingFinancialDetail.ChartString = model.ChartString; - existingFinancialDetail.AutoApprove = model.AutoApprove; - - if (existingFinancialDetail.Id == 0) - { - await _dbContext.FinancialDetails.AddAsync(existingFinancialDetail); - } - else - { - _dbContext.FinancialDetails.Update(existingFinancialDetail); - } - - await _dbContext.SaveChangesAsync(); - return Ok(existingFinancialDetail); - - } } } From 827eba6a009913d131b40217af19dbf1b878f982 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Thu, 2 May 2024 08:59:00 -0700 Subject: [PATCH 020/301] WIP --- Hippo.Web/ClientApp/src/App.tsx | 9 +++ Hippo.Web/ClientApp/src/AppNav.tsx | 2 +- .../components/Financial/FinancialDetail.tsx | 79 +++++++++++++++++++ Hippo.Web/Controllers/AdminController.cs | 2 + 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx diff --git a/Hippo.Web/ClientApp/src/App.tsx b/Hippo.Web/ClientApp/src/App.tsx index 209feffd..815d257d 100644 --- a/Hippo.Web/ClientApp/src/App.tsx +++ b/Hippo.Web/ClientApp/src/App.tsx @@ -19,6 +19,7 @@ import { Clusters } from "./components/Account/Clusters"; import { Clusters as AdminClusters } from "./components/ClusterAdmin/Clusters"; import { Groups } from "./components/Admin/Groups"; import { ShowFor } from "./Shared/ShowFor"; +import FinancialDetail from "./components/Financial/FinancialDetail"; declare var Hippo: AppContextShape; @@ -92,6 +93,14 @@ const App = () => { } /> + }> + + + } + /> diff --git a/Hippo.Web/ClientApp/src/AppNav.tsx b/Hippo.Web/ClientApp/src/AppNav.tsx index 52e1fed5..dff2b8e4 100644 --- a/Hippo.Web/ClientApp/src/AppNav.tsx +++ b/Hippo.Web/ClientApp/src/AppNav.tsx @@ -109,7 +109,7 @@ export const AppNav = () => { isActive ? { fontWeight: "bold" } : {} } diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx new file mode 100644 index 00000000..fd1ca531 --- /dev/null +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -0,0 +1,79 @@ +import React, { useState, useEffect } from "react"; +import { FinancialDetailModel } from "../../types"; + +const FinancialDetail: React.FC = () => { + const [financialDetail, setFinancialDetail] = + useState(null); + + useEffect(() => { + // Fetch financial detail data from API or any other data source + // and set it to the state + const fetchFinancialDetail = async () => { + try { + const response = await fetch("/api/caesfarm/admin/FinancialDetails"); // Replace with your API endpoint + const data = await response.json(); + setFinancialDetail(data); + } catch (error) { + console.error("Error fetching financial detail:", error); + } + }; + + fetchFinancialDetail(); + }, []); + + const handleInputChange = (event: React.ChangeEvent) => { + const { name, value } = event.target; + setFinancialDetail((prevFinancialDetail) => ({ + ...prevFinancialDetail, + [name]: value, + })); + }; + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + // Send updated financial detail data to API or any other data source + // for saving changes + console.log("Updated financial detail:", financialDetail); + }; + + if (!financialDetail) { + return
Loading...
; + } + + return ( +
+

Financial Detail

+
+
+
Financial API Key: {financialDetail.maskedApiKey}
+
+
+ + +
+ +
+ + +
+ + {/* Add more input fields for other properties */} + +
+
+ ); +}; + +export default FinancialDetail; diff --git a/Hippo.Web/Controllers/AdminController.cs b/Hippo.Web/Controllers/AdminController.cs index af2167e4..7e066e81 100644 --- a/Hippo.Web/Controllers/AdminController.cs +++ b/Hippo.Web/Controllers/AdminController.cs @@ -134,6 +134,7 @@ public async Task Groups() } [HttpGet] + [Authorize(Policy = AccessCodes.SystemAccess)] public async Task FinancialDetails() { var cluster = await _dbContext.Clusters.AsNoTracking().SingleAsync(c => c.Name == Cluster); @@ -173,6 +174,7 @@ public async Task FinancialDetails() } [HttpPost] + [Authorize(Policy = AccessCodes.SystemAccess)] public async Task UpdateFinancialDetails([FromBody] FinancialDetailModel model) { //Possibly use the secret service to set the FinancialSystemApiKey From ab64b162258737161b92ea23b817a59e906aee4e Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Thu, 2 May 2024 09:12:38 -0700 Subject: [PATCH 021/301] will post. has hard coded values --- .../components/Financial/FinancialDetail.tsx | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx index fd1ca531..d2badab8 100644 --- a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from "react"; import { FinancialDetailModel } from "../../types"; +import { authenticatedFetch } from "../../util/api"; const FinancialDetail: React.FC = () => { const [financialDetail, setFinancialDetail] = @@ -31,8 +32,10 @@ const FinancialDetail: React.FC = () => { const handleSubmit = (event: React.FormEvent) => { event.preventDefault(); - // Send updated financial detail data to API or any other data source - // for saving changes + authenticatedFetch(`/api/caesfarm/admin/UpdateFinancialDetails`, { + method: "POST", + body: JSON.stringify(financialDetail), + }); console.log("Updated financial detail:", financialDetail); }; @@ -48,11 +51,11 @@ const FinancialDetail: React.FC = () => {
Financial API Key: {financialDetail.maskedApiKey}
- + @@ -69,6 +72,16 @@ const FinancialDetail: React.FC = () => { />
+
+ + +
{/* Add more input fields for other properties */} From 8b49d90b06e5d60e6140374b14b10a26330b4b1b Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Thu, 2 May 2024 09:23:44 -0700 Subject: [PATCH 022/301] use cluster --- .../src/components/Financial/FinancialDetail.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx index d2badab8..ecc27aae 100644 --- a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -1,17 +1,21 @@ import React, { useState, useEffect } from "react"; import { FinancialDetailModel } from "../../types"; import { authenticatedFetch } from "../../util/api"; +import { useParams } from "react-router-dom"; const FinancialDetail: React.FC = () => { const [financialDetail, setFinancialDetail] = useState(null); + const { cluster: clusterName } = useParams(); useEffect(() => { // Fetch financial detail data from API or any other data source // and set it to the state const fetchFinancialDetail = async () => { try { - const response = await fetch("/api/caesfarm/admin/FinancialDetails"); // Replace with your API endpoint + const response = await fetch( + `/api/${clusterName}/admin/FinancialDetails`, + ); // Replace with your API endpoint const data = await response.json(); setFinancialDetail(data); } catch (error) { @@ -32,7 +36,7 @@ const FinancialDetail: React.FC = () => { const handleSubmit = (event: React.FormEvent) => { event.preventDefault(); - authenticatedFetch(`/api/caesfarm/admin/UpdateFinancialDetails`, { + authenticatedFetch(`/api/${clusterName}/admin/UpdateFinancialDetails`, { method: "POST", body: JSON.stringify(financialDetail), }); @@ -46,6 +50,7 @@ const FinancialDetail: React.FC = () => { return (

Financial Detail

+

{clusterName}

Financial API Key: {financialDetail.maskedApiKey}
From 697f0c47bb8a2a4786ee32e661b08d7abc3f68d4 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Thu, 2 May 2024 12:49:25 -0700 Subject: [PATCH 023/301] ugly but working --- .../components/Financial/FinancialDetail.tsx | 71 ++++++++++++++----- 1 file changed, 55 insertions(+), 16 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx index ecc27aae..2a4e5412 100644 --- a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -1,12 +1,14 @@ import React, { useState, useEffect } from "react"; import { FinancialDetailModel } from "../../types"; -import { authenticatedFetch } from "../../util/api"; +import { authenticatedFetch, parseBadRequest } from "../../util/api"; import { useParams } from "react-router-dom"; +import { usePromiseNotification } from "../../util/Notifications"; const FinancialDetail: React.FC = () => { const [financialDetail, setFinancialDetail] = useState(null); const { cluster: clusterName } = useParams(); + const [notification, setNotification] = usePromiseNotification(); useEffect(() => { // Fetch financial detail data from API or any other data source @@ -24,7 +26,7 @@ const FinancialDetail: React.FC = () => { }; fetchFinancialDetail(); - }, []); + }, [clusterName]); const handleInputChange = (event: React.ChangeEvent) => { const { name, value } = event.target; @@ -34,13 +36,32 @@ const FinancialDetail: React.FC = () => { })); }; - const handleSubmit = (event: React.FormEvent) => { + const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); - authenticatedFetch(`/api/${clusterName}/admin/UpdateFinancialDetails`, { - method: "POST", - body: JSON.stringify(financialDetail), - }); - console.log("Updated financial detail:", financialDetail); + const request = authenticatedFetch( + `/api/${clusterName}/admin/UpdateFinancialDetails`, + { + method: "POST", + body: JSON.stringify(financialDetail), + }, + ); + setNotification( + request, + "Updating Financial Details", + "Financial Details Updated", + async (r) => { + if (r.status === 400) { + const errors = await parseBadRequest(await request); + return errors; + } else { + return "An error happened, please try again."; + } + }, + ); + if ((await request).ok) { + // refresh the page + window.location.reload(); + } }; if (!financialDetail) { @@ -50,13 +71,12 @@ const FinancialDetail: React.FC = () => { return (

Financial Detail

-

{clusterName}

Financial API Key: {financialDetail.maskedApiKey}
- + {
- +
- +
- {/* Add more input fields for other properties */} - + +
+ + + setFinancialDetail((prevFinancialDetail) => ({ + ...prevFinancialDetail, + autoApprove: e.target.checked, + })) + } + /> +
+
); From a731e9ce718621db2616be790781c7f8fe3b6b0d Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Fri, 3 May 2024 08:34:44 -0700 Subject: [PATCH 024/301] A little style --- .../components/Financial/FinancialDetail.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx index 2a4e5412..7131619b 100644 --- a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -75,10 +75,11 @@ const FinancialDetail: React.FC = () => {
Financial API Key: {financialDetail.maskedApiKey}
-
+
{ />
-
+
{ />
-
+
{ />
-
+
{ } />
-
From 642f4e5706d142aa353ccac141659502cb016935 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Fri, 3 May 2024 08:46:43 -0700 Subject: [PATCH 025/301] Validate chart string --- Hippo.Web/Controllers/AdminController.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Hippo.Web/Controllers/AdminController.cs b/Hippo.Web/Controllers/AdminController.cs index 7e066e81..774ffd76 100644 --- a/Hippo.Web/Controllers/AdminController.cs +++ b/Hippo.Web/Controllers/AdminController.cs @@ -24,8 +24,9 @@ public class AdminController : SuperController private ISshService _sshService; private INotificationService _notificationService; private ISecretsService _secretsService; + private IAggieEnterpriseService _aggieEnterpriseService; - public AdminController(AppDbContext dbContext, IUserService userService, IIdentityService identityService, ISshService sshService, INotificationService notificationService, IHistoryService historyService, ISecretsService secretsService) + public AdminController(AppDbContext dbContext, IUserService userService, IIdentityService identityService, ISshService sshService, INotificationService notificationService, IHistoryService historyService, ISecretsService secretsService, IAggieEnterpriseService aggieEnterpriseService) { _dbContext = dbContext; _userService = userService; @@ -34,6 +35,7 @@ public AdminController(AppDbContext dbContext, IUserService userService, IIdenti _sshService = sshService; _notificationService = notificationService; _secretsService = secretsService; + _aggieEnterpriseService = aggieEnterpriseService; } [HttpGet] @@ -189,6 +191,11 @@ public async Task UpdateFinancialDetails([FromBody] FinancialDeta }; } + var validateChartString = await _aggieEnterpriseService.IsChartStringValid(model.ChartString); + if (!validateChartString.IsValid) + { + return BadRequest("Invalid Chart String"); + } if (!string.IsNullOrWhiteSpace(model.FinancialSystemApiKey)) { await _secretsService.SetSecret(existingFinancialDetail.SecretAccessKey.ToString(), model.FinancialSystemApiKey); From 86926d64d1918ba7e18eee31b50f94b1c9ae56f7 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Fri, 3 May 2024 10:11:38 -0700 Subject: [PATCH 026/301] Show validation messages --- Hippo.Web/Controllers/AdminController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hippo.Web/Controllers/AdminController.cs b/Hippo.Web/Controllers/AdminController.cs index 774ffd76..d8049ab0 100644 --- a/Hippo.Web/Controllers/AdminController.cs +++ b/Hippo.Web/Controllers/AdminController.cs @@ -194,7 +194,7 @@ public async Task UpdateFinancialDetails([FromBody] FinancialDeta var validateChartString = await _aggieEnterpriseService.IsChartStringValid(model.ChartString); if (!validateChartString.IsValid) { - return BadRequest("Invalid Chart String"); + return BadRequest($"Invalid Chart String Errors: {validateChartString.Message}"); } if (!string.IsNullOrWhiteSpace(model.FinancialSystemApiKey)) { From f4f05d1567128115f451d72db08554ca456a3eeb Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Fri, 3 May 2024 10:12:10 -0700 Subject: [PATCH 027/301] Ignore for PPM if not supplied --- Hippo.Core/Services/AggieEnterpriseService.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Hippo.Core/Services/AggieEnterpriseService.cs b/Hippo.Core/Services/AggieEnterpriseService.cs index 32c303e5..d2ee8dd6 100644 --- a/Hippo.Core/Services/AggieEnterpriseService.cs +++ b/Hippo.Core/Services/AggieEnterpriseService.cs @@ -131,11 +131,14 @@ public async Task IsChartStringValid(string chartStr await GetPpmAccountManager(rtValue); - - if (rtValue.PpmSegments.ExpenditureType != AeSettings.NaturalAccount) + if (!string.IsNullOrWhiteSpace(AeSettings.NaturalAccount)) { - rtValue.Messages.Add($"Expenditure Type must be {AeSettings.NaturalAccount}"); - rtValue.IsValid = false; + + if (rtValue.PpmSegments.ExpenditureType != AeSettings.NaturalAccount) + { + rtValue.Messages.Add($"Expenditure Type must be {AeSettings.NaturalAccount}"); + rtValue.IsValid = false; + } } return rtValue; From 7493767f8e78197eb6f8f6f5a95f9ddcad75671d Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Fri, 3 May 2024 10:13:40 -0700 Subject: [PATCH 028/301] finjector --- .../components/Financial/FinancialDetail.tsx | 70 ++++++++++++++++++- Hippo.Web/Views/Shared/_Layout.cshtml | 5 ++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx index 7131619b..6c94b119 100644 --- a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -4,6 +4,11 @@ import { authenticatedFetch, parseBadRequest } from "../../util/api"; import { useParams } from "react-router-dom"; import { usePromiseNotification } from "../../util/Notifications"; +declare const window: Window & + typeof globalThis & { + Finjector: any; + }; + const FinancialDetail: React.FC = () => { const [financialDetail, setFinancialDetail] = useState(null); @@ -64,6 +69,57 @@ const FinancialDetail: React.FC = () => { } }; + const lookupcoa = async () => { + const chart = await window.Finjector.findChartSegmentString(); + + if (chart.status === "success") { + //alert("Chart Segment: " + chart.data); + + financialDetail.chartString = chart.data; + setFinancialDetail((prevFinancialDetail) => ({ + ...prevFinancialDetail, + chartString: chart.data, + })); + + //Copied from Harvest. Keeping for now in case we call an api end point to validate the chart string here instead of in the backend + // const response = await authenticatedFetch( + // `/api/financialaccount/get?account=${chart.data}` + // ); + + // if (response.ok) { + // if (response.status === 204) { + // alert("Account Selected is not valid"); + // return; + // } else { + // var result = await response.json(); + + // if (result.success === false) { + // alert("Account Selected is not valid: " + result.error); + // return; + // } + + // const accountInfo: ProjectAccount = result; + + // if (accounts.some((a) => a.number === accountInfo.number)) { + // alert("Account already selected -- choose a different account"); + // return; + // } else { + // alert(undefined); + // } + + // if (accounts.length === 0) { + // // if it's our first account, default to 100% + // accountInfo.percentage = 100.0; + // } + + // setAccounts([...accounts, accountInfo]); + // } + //} + } else { + alert("Failed!"); + } + }; + if (!financialDetail) { return
Loading...
; } @@ -88,7 +144,16 @@ const FinancialDetail: React.FC = () => {
- + {" "} + {financialDetail.chartString && ( + + {financialDetail.chartString} + + )} { required />
+
diff --git a/Hippo.Web/Views/Shared/_Layout.cshtml b/Hippo.Web/Views/Shared/_Layout.cshtml index 9c4defcb..aa077513 100644 --- a/Hippo.Web/Views/Shared/_Layout.cshtml +++ b/Hippo.Web/Views/Shared/_Layout.cshtml @@ -47,6 +47,7 @@ All rights reserved.
Questions? See contact info for each cluster.

+ + + + + @RenderSection("Scripts", required: false) From 8363f0f90cf84bc35bfdee3dcd011a66f19dc80c Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Fri, 3 May 2024 13:16:02 -0700 Subject: [PATCH 029/301] WIP validation --- .../Models/ChartStringValidationModel.cs | 16 ++++++++++- Hippo.Core/Services/AggieEnterpriseService.cs | 14 +++++++--- Hippo.Web/Controllers/OrderController.cs | 27 +++++++++++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 Hippo.Web/Controllers/OrderController.cs diff --git a/Hippo.Core/Models/ChartStringValidationModel.cs b/Hippo.Core/Models/ChartStringValidationModel.cs index ba4a24af..c079341f 100644 --- a/Hippo.Core/Models/ChartStringValidationModel.cs +++ b/Hippo.Core/Models/ChartStringValidationModel.cs @@ -16,7 +16,6 @@ public class ChartStringValidationModel public string AccountManagerEmail { get; set; } public string Description { get; set; } //Description of COA - public string DisplayName { get; set; } /// @@ -37,5 +36,20 @@ public string Message } } public List Messages { get; set; } = new List(); + + public string Warning + { + get + { + if (Warnings.Count <= 0) + { + return string.Empty; + } + + //select the warnings into a string of key - Value and return it + return string.Join(" ", Warnings.Select(w => $"{w.Key} - {w.Value}")); + + } + } } } diff --git a/Hippo.Core/Services/AggieEnterpriseService.cs b/Hippo.Core/Services/AggieEnterpriseService.cs index d2ee8dd6..53c9c045 100644 --- a/Hippo.Core/Services/AggieEnterpriseService.cs +++ b/Hippo.Core/Services/AggieEnterpriseService.cs @@ -46,7 +46,7 @@ public async Task IsChartStringValid(string chartStr if (segmentStringType == FinancialChartStringType.Gl) { - chartString = ReplaceNaturalAccount(chartString, AeSettings.NaturalAccount); + chartString = ReplaceNaturalAccount(chartString, AeSettings.NaturalAccount, rtValue); rtValue.ChartString = chartString; var result = await _aggieClient.GlValidateChartstring.ExecuteAsync(chartString, validateCVRs); @@ -97,7 +97,7 @@ public async Task IsChartStringValid(string chartStr if (segmentStringType == FinancialChartStringType.Ppm) { - chartString = ReplaceNaturalAccount(chartString, AeSettings.NaturalAccount); + chartString = ReplaceNaturalAccount(chartString, AeSettings.NaturalAccount, rtValue); rtValue.ChartString = chartString; var result = await _aggieClient.PpmSegmentStringValidate.ExecuteAsync(chartString); @@ -150,7 +150,7 @@ public async Task IsChartStringValid(string chartStr return rtValue; } - public string ReplaceNaturalAccount(string chartString, string naturalAccount) + public string ReplaceNaturalAccount(string chartString, string naturalAccount, ChartStringValidationModel model) { if(string.IsNullOrWhiteSpace(naturalAccount)) { @@ -161,12 +161,20 @@ public string ReplaceNaturalAccount(string chartString, string naturalAccount) if (segmentStringType == FinancialChartStringType.Gl) { var segments = FinancialChartValidation.GetGlSegments(chartString); + if(segments.Account != naturalAccount) + { + model.Warnings.Add(new KeyValuePair("Account", $"Natural Account {segments.Account} replaced with {naturalAccount}")); + } segments.Account = naturalAccount; return segments.ToSegmentString(); } if (segmentStringType == FinancialChartStringType.Ppm) { var segments = FinancialChartValidation.GetPpmSegments(chartString); + if (segments.ExpenditureType != naturalAccount) + { + model.Warnings.Add(new KeyValuePair("Expenditure Type", $"Natural Account {segments.ExpenditureType} replaced with {naturalAccount}")); + } segments.ExpenditureType = naturalAccount; return segments.ToSegmentString(); } diff --git a/Hippo.Web/Controllers/OrderController.cs b/Hippo.Web/Controllers/OrderController.cs new file mode 100644 index 00000000..cef0d809 --- /dev/null +++ b/Hippo.Web/Controllers/OrderController.cs @@ -0,0 +1,27 @@ +using Hippo.Core.Models; +using Hippo.Core.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Hippo.Web.Controllers +{ + + [Authorize] + public class OrderController : SuperController + { + private IAggieEnterpriseService _aggieEnterpriseService; + + public OrderController(IAggieEnterpriseService aggieEnterpriseService) + { + _aggieEnterpriseService = aggieEnterpriseService; + } + + [HttpGet] + [Route("api/order/validate-chart-string/{chartString}")] + public async Task ValidateChartString(string chartString) + { + return await _aggieEnterpriseService.IsChartStringValid(chartString); + } + + } +} From d0fe86f7aed01f96e81695343477212bd3808fc9 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 6 May 2024 08:40:00 -0700 Subject: [PATCH 030/301] WIP validation --- .../components/Financial/FinancialDetail.tsx | 53 +++++++++++++++++-- Hippo.Web/ClientApp/src/types.ts | 8 +++ Hippo.Web/Controllers/OrderController.cs | 3 +- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx index 6c94b119..5b1354e1 100644 --- a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { FinancialDetailModel } from "../../types"; +import { ChartStringValidationModel, FinancialDetailModel } from "../../types"; import { authenticatedFetch, parseBadRequest } from "../../util/api"; import { useParams } from "react-router-dom"; import { usePromiseNotification } from "../../util/Notifications"; @@ -14,6 +14,8 @@ const FinancialDetail: React.FC = () => { useState(null); const { cluster: clusterName } = useParams(); const [notification, setNotification] = usePromiseNotification(); + const [chartStringValidation, setChartStringValidation] = + useState(null); useEffect(() => { // Fetch financial detail data from API or any other data source @@ -35,6 +37,7 @@ const FinancialDetail: React.FC = () => { const handleInputChange = (event: React.ChangeEvent) => { const { name, value } = event.target; + alert(name + " " + value); setFinancialDetail((prevFinancialDetail) => ({ ...prevFinancialDetail, [name]: value, @@ -76,11 +79,26 @@ const FinancialDetail: React.FC = () => { //alert("Chart Segment: " + chart.data); financialDetail.chartString = chart.data; + setFinancialDetail((prevFinancialDetail) => ({ ...prevFinancialDetail, chartString: chart.data, })); + //call api/order/validate-chart-string/{chart.data} to validate the chart string + let response = await authenticatedFetch( + `/api/order/validate-chart-string/${chart.data}`, + { + method: "GET", + }, + ); + //console.log(response); + if (response.ok) { + const result = await response.json(); + console.log(result); + setChartStringValidation(result); + } + //Copied from Harvest. Keeping for now in case we call an api end point to validate the chart string here instead of in the backend // const response = await authenticatedFetch( // `/api/financialaccount/get?account=${chart.data}` @@ -163,10 +181,37 @@ const FinancialDetail: React.FC = () => { onChange={handleInputChange} required /> + + {chartStringValidation && ( +
+
Chart String Validation:
+
+ Is Valid: {chartStringValidation.isValid ? "Yes" : "No"} +
+
Description: {chartStringValidation.description}
+ {chartStringValidation.accountManager && ( +
+
+ Account Manager: {chartStringValidation.accountManager} +
+
+ Account Manager Email:{" "} + {chartStringValidation.accountManagerEmail} +
+
+ )} + {chartStringValidation.message && ( +
Message: {chartStringValidation.message}
+ )} + + {chartStringValidation.warning && ( +
Warning: {chartStringValidation.warning}
+ )} +
+ )}
-
diff --git a/Hippo.Web/ClientApp/src/types.ts b/Hippo.Web/ClientApp/src/types.ts index a58d5381..a2b79ac9 100644 --- a/Hippo.Web/ClientApp/src/types.ts +++ b/Hippo.Web/ClientApp/src/types.ts @@ -220,3 +220,11 @@ export interface FinancialDetailModel { autoApprove: boolean; maskedApiKey: string; } +export interface ChartStringValidationModel { + isValid: boolean; + description: string; + accountManager: string; + accountManagerEmail: string; + message: string; + warning: string; +} diff --git a/Hippo.Web/Controllers/OrderController.cs b/Hippo.Web/Controllers/OrderController.cs index cef0d809..f9e6b558 100644 --- a/Hippo.Web/Controllers/OrderController.cs +++ b/Hippo.Web/Controllers/OrderController.cs @@ -1,4 +1,4 @@ -using Hippo.Core.Models; +using Hippo.Core.Models; using Hippo.Core.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -21,6 +21,7 @@ public OrderController(IAggieEnterpriseService aggieEnterpriseService) public async Task ValidateChartString(string chartString) { return await _aggieEnterpriseService.IsChartStringValid(chartString); + } } From 9cd1c366f4d1006d84de2d963fedd17cfebef8bf Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 6 May 2024 08:48:47 -0700 Subject: [PATCH 031/301] ChartString validation --- .../components/Financial/FinancialDetail.tsx | 65 +++++-------------- 1 file changed, 17 insertions(+), 48 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx index 5b1354e1..55a30c4c 100644 --- a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -27,6 +27,7 @@ const FinancialDetail: React.FC = () => { ); // Replace with your API endpoint const data = await response.json(); setFinancialDetail(data); + await validateChartString(data.chartString); } catch (error) { console.error("Error fetching financial detail:", error); } @@ -85,59 +86,27 @@ const FinancialDetail: React.FC = () => { chartString: chart.data, })); - //call api/order/validate-chart-string/{chart.data} to validate the chart string - let response = await authenticatedFetch( - `/api/order/validate-chart-string/${chart.data}`, - { - method: "GET", - }, - ); - //console.log(response); - if (response.ok) { - const result = await response.json(); - console.log(result); - setChartStringValidation(result); - } - - //Copied from Harvest. Keeping for now in case we call an api end point to validate the chart string here instead of in the backend - // const response = await authenticatedFetch( - // `/api/financialaccount/get?account=${chart.data}` - // ); - - // if (response.ok) { - // if (response.status === 204) { - // alert("Account Selected is not valid"); - // return; - // } else { - // var result = await response.json(); - - // if (result.success === false) { - // alert("Account Selected is not valid: " + result.error); - // return; - // } - - // const accountInfo: ProjectAccount = result; - - // if (accounts.some((a) => a.number === accountInfo.number)) { - // alert("Account already selected -- choose a different account"); - // return; - // } else { - // alert(undefined); - // } - - // if (accounts.length === 0) { - // // if it's our first account, default to 100% - // accountInfo.percentage = 100.0; - // } - - // setAccounts([...accounts, accountInfo]); - // } - //} + await validateChartString(chart.data); } else { alert("Failed!"); } }; + const validateChartString = async (chartString: string) => { + let response = await authenticatedFetch( + `/api/order/validate-chart-string/${chartString}`, + { + method: "GET", + }, + ); + //console.log(response); + if (response.ok) { + const result = await response.json(); + console.log(result); + setChartStringValidation(result); + } + }; + if (!financialDetail) { return
Loading...
; } From 2577086885eda288711cc13c5274ac72e8753508 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 6 May 2024 09:04:40 -0700 Subject: [PATCH 032/301] cleanup and validate on blur --- .../src/components/Financial/FinancialDetail.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx index 55a30c4c..c81ab02c 100644 --- a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -38,7 +38,6 @@ const FinancialDetail: React.FC = () => { const handleInputChange = (event: React.ChangeEvent) => { const { name, value } = event.target; - alert(name + " " + value); setFinancialDetail((prevFinancialDetail) => ({ ...prevFinancialDetail, [name]: value, @@ -73,7 +72,7 @@ const FinancialDetail: React.FC = () => { } }; - const lookupcoa = async () => { + const lookupChartString = async () => { const chart = await window.Finjector.findChartSegmentString(); if (chart.status === "success") { @@ -148,9 +147,16 @@ const FinancialDetail: React.FC = () => { name="chartString" value={financialDetail.chartString} onChange={handleInputChange} + onBlur={(e) => { + validateChartString(e.target.value); + }} required /> - {chartStringValidation && ( From 4735a5eaae287251037ccd37a32d4a478123861f Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 6 May 2024 09:11:42 -0700 Subject: [PATCH 033/301] magnifying glass --- .../components/Financial/FinancialDetail.tsx | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx index c81ab02c..8e6bd4a7 100644 --- a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -140,25 +140,27 @@ const FinancialDetail: React.FC = () => { {financialDetail.chartString} )} - { - validateChartString(e.target.value); - }} - required - /> - +
+ { + validateChartString(e.target.value); + }} + required + /> + +
{chartStringValidation && (
Chart String Validation:
@@ -221,7 +223,7 @@ const FinancialDetail: React.FC = () => { disabled={notification.pending} type="submit" > - Submit + Submit
From 808c3b516d417c2f156d1ff8936d69335b1daa21 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 6 May 2024 13:28:33 -0700 Subject: [PATCH 034/301] WIP Products --- Hippo.Web/Controllers/OrderController.cs | 12 ++- Hippo.Web/Controllers/ProductController.cs | 104 +++++++++++++++++++++ 2 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 Hippo.Web/Controllers/ProductController.cs diff --git a/Hippo.Web/Controllers/OrderController.cs b/Hippo.Web/Controllers/OrderController.cs index f9e6b558..d27249f0 100644 --- a/Hippo.Web/Controllers/OrderController.cs +++ b/Hippo.Web/Controllers/OrderController.cs @@ -1,7 +1,10 @@ +using Hippo.Core.Data; +using Hippo.Core.Domain; using Hippo.Core.Models; using Hippo.Core.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; namespace Hippo.Web.Controllers { @@ -9,13 +12,18 @@ namespace Hippo.Web.Controllers [Authorize] public class OrderController : SuperController { - private IAggieEnterpriseService _aggieEnterpriseService; + private readonly AppDbContext _dbContext; + private readonly IAggieEnterpriseService _aggieEnterpriseService; - public OrderController(IAggieEnterpriseService aggieEnterpriseService) + + public OrderController(AppDbContext dbContext, IAggieEnterpriseService aggieEnterpriseService) { + _dbContext = dbContext; _aggieEnterpriseService = aggieEnterpriseService; } + + [HttpGet] [Route("api/order/validate-chart-string/{chartString}")] public async Task ValidateChartString(string chartString) diff --git a/Hippo.Web/Controllers/ProductController.cs b/Hippo.Web/Controllers/ProductController.cs new file mode 100644 index 00000000..1cbbac1c --- /dev/null +++ b/Hippo.Web/Controllers/ProductController.cs @@ -0,0 +1,104 @@ +using Hippo.Core.Data; +using Hippo.Core.Domain; +using Hippo.Core.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace Hippo.Web.Controllers +{ + [Authorize] + public class ProductController : SuperController + { + private readonly AppDbContext _dbContext; + + public ProductController(AppDbContext dbContext) + { + _dbContext = dbContext; + } + + + public async Task Index() + { + var products = await _dbContext.Products.Where(a => a.Cluster.Name == Cluster).ToListAsync(); //Filters out inactive products + return View(); + } + + [HttpPost] + [Authorize(Policy = AccessCodes.ClusterAdminAccess)] + public async Task CreateProduct(Product model) + { + var cluster = await _dbContext.Clusters.FirstAsync(a => a.Name == Cluster); + + if (!ModelState.IsValid) + { + return BadRequest("Invalid"); + } + + var procuct = new Product + { + Name = model.Name, + Description = model.Description, + Category = model.Category, + UnitPrice = model.UnitPrice, + Units = model.Units, + Cluster = cluster, + Installments = model.Installments + }; + _dbContext.Products.Add(procuct); + await _dbContext.SaveChangesAsync(); + + return View(); + } + + [HttpGet] + public async Task GetProduct(int id) + { + var product = await _dbContext.Products.FirstOrDefaultAsync(a => a.Id == id && a.Cluster.Name == Cluster); + if (product == null) + { + return NotFound(); + } + return Ok(product); + } + + [HttpPost] + [Authorize(Policy = AccessCodes.ClusterAdminAccess)] + public async Task UpdateProduct(Product model) + { + var product = await _dbContext.Products.FirstOrDefaultAsync(a => a.Id == model.Id && a.Cluster.Name == Cluster); + if (product == null) + { + return NotFound(); + } + + product.Name = model.Name; + product.Description = model.Description; + product.Category = model.Category; + product.UnitPrice = model.UnitPrice; + product.Units = model.Units; + product.Installments = model.Installments; + + await _dbContext.SaveChangesAsync(); + + return Ok(); + } + + [HttpPost] + [Authorize(Policy = AccessCodes.ClusterAdminAccess)] + public async Task DeleteProduct(int id) + { + var product = await _dbContext.Products.FirstOrDefaultAsync(a => a.Id == id && a.Cluster.Name == Cluster); + if (product == null) + { + return NotFound(); + } + + product.IsActive = false; + + await _dbContext.SaveChangesAsync(); + + return Ok(); + } + } +} From a461a97fdf9ea5a1834a2ddf7e4e34dbce3ff615 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 7 May 2024 11:10:36 -0700 Subject: [PATCH 035/301] WIP Products page --- Hippo.Web/ClientApp/src/App.tsx | 2 + Hippo.Web/ClientApp/src/AppNav.tsx | 10 ++ .../components/Financial/FinancialDetail.tsx | 57 +++++---- .../src/components/Product/Products.tsx | 111 ++++++++++++++++++ Hippo.Web/ClientApp/src/types.ts | 10 ++ Hippo.Web/Controllers/ProductController.cs | 4 +- 6 files changed, 163 insertions(+), 31 deletions(-) create mode 100644 Hippo.Web/ClientApp/src/components/Product/Products.tsx diff --git a/Hippo.Web/ClientApp/src/App.tsx b/Hippo.Web/ClientApp/src/App.tsx index 815d257d..9001eaa4 100644 --- a/Hippo.Web/ClientApp/src/App.tsx +++ b/Hippo.Web/ClientApp/src/App.tsx @@ -20,6 +20,7 @@ import { Clusters as AdminClusters } from "./components/ClusterAdmin/Clusters"; import { Groups } from "./components/Admin/Groups"; import { ShowFor } from "./Shared/ShowFor"; import FinancialDetail from "./components/Financial/FinancialDetail"; +import { Products } from "./components/Product/Products"; declare var Hippo: AppContextShape; @@ -101,6 +102,7 @@ const App = () => { } /> + } />
diff --git a/Hippo.Web/ClientApp/src/AppNav.tsx b/Hippo.Web/ClientApp/src/AppNav.tsx index dff2b8e4..e0962c59 100644 --- a/Hippo.Web/ClientApp/src/AppNav.tsx +++ b/Hippo.Web/ClientApp/src/AppNav.tsx @@ -117,6 +117,16 @@ export const AppNav = () => { Financial + + isActive ? { fontWeight: "bold" } : {} + } + > + Products +
diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx index 8e6bd4a7..86abd1d0 100644 --- a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -129,6 +129,34 @@ const FinancialDetail: React.FC = () => { />
+
+ + +
+ +
+ + + setFinancialDetail((prevFinancialDetail) => ({ + ...prevFinancialDetail, + autoApprove: e.target.checked, + })) + } + /> +
{" "} {financialDetail.chartString && ( @@ -189,35 +217,6 @@ const FinancialDetail: React.FC = () => {
)}
- -
- - -
- -
- - - setFinancialDetail((prevFinancialDetail) => ({ - ...prevFinancialDetail, - autoApprove: e.target.checked, - })) - } - /> -
{" "} + + {" "} + + + + ), + }, + ], + [cluster], + ); + + if (products === undefined) { + return ( +
+
Loading...
+
+ ); + } else { + return ( +
+ +
+
+ {" "} + +
+
+
+
+
+
+ +
+
+
+ ); + } +}; diff --git a/Hippo.Web/ClientApp/src/types.ts b/Hippo.Web/ClientApp/src/types.ts index a2b79ac9..7702356f 100644 --- a/Hippo.Web/ClientApp/src/types.ts +++ b/Hippo.Web/ClientApp/src/types.ts @@ -228,3 +228,13 @@ export interface ChartStringValidationModel { message: string; warning: string; } + +export interface ProductModel { + id: number; + category: string; + name: string; + description: string; + units: string; + unitPrice: number; + installments: number; +} diff --git a/Hippo.Web/Controllers/ProductController.cs b/Hippo.Web/Controllers/ProductController.cs index 1cbbac1c..15c33481 100644 --- a/Hippo.Web/Controllers/ProductController.cs +++ b/Hippo.Web/Controllers/ProductController.cs @@ -17,11 +17,11 @@ public ProductController(AppDbContext dbContext) _dbContext = dbContext; } - + [HttpGet] public async Task Index() { var products = await _dbContext.Products.Where(a => a.Cluster.Name == Cluster).ToListAsync(); //Filters out inactive products - return View(); + return Ok(products); } [HttpPost] From 1417cf343e6e0fec8a9303ca188390083f2ce87a Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 7 May 2024 13:09:05 -0700 Subject: [PATCH 036/301] wip create product --- .../src/components/Product/Products.tsx | 193 +++++++++++++++++- Hippo.Web/ClientApp/src/types.ts | 3 +- Hippo.Web/Controllers/ProductController.cs | 8 +- 3 files changed, 196 insertions(+), 8 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Product/Products.tsx b/Hippo.Web/ClientApp/src/components/Product/Products.tsx index 46997cad..7da15bf4 100644 --- a/Hippo.Web/ClientApp/src/components/Product/Products.tsx +++ b/Hippo.Web/ClientApp/src/components/Product/Products.tsx @@ -1,13 +1,33 @@ -import { useEffect, useState, useMemo, useCallback } from "react"; +import { useEffect, useState, useMemo, useCallback, useContext } from "react"; import { useParams } from "react-router-dom"; import { ReactTable } from "../../Shared/ReactTable"; import { Column } from "react-table"; import { ProductModel } from "../../types"; -import { authenticatedFetch } from "../../util/api"; +import { authenticatedFetch, parseBadRequest } from "../../util/api"; import { ShowFor } from "../../Shared/ShowFor"; +import { usePromiseNotification } from "../../util/Notifications"; +import { useConfirmationDialog } from "../../Shared/ConfirmationDialog"; +import { notEmptyOrFalsey } from "../../util/ValueChecks"; +//import AppContext from "../../Shared/AppContext"; + +const defaultProduct: ProductModel = { + id: 0, + name: "", + category: "Memory", + description: "", + unitPrice: "0.00", + units: "", + installments: 60, +}; export const Products = () => { + const [notification, setNotification] = usePromiseNotification(); + const [editProductModel, setEditProductModel] = useState({ + ...defaultProduct, + }); + const [editConfirmationTitle, setEditConfirmationTitle] = useState(""); + //const [context, setContext] = useContext(AppContext); //need? const [products, setProducts] = useState(); const { cluster } = useParams(); @@ -76,6 +96,170 @@ export const Products = () => { [cluster], ); + const [getEditConfirmation] = useConfirmationDialog( + { + title: editConfirmationTitle, + message: (setReturn) => ( + <> +
+ + { + const model: ProductModel = { + ...editProductModel, + name: e.target.value, + }; + setEditProductModel(model); + setReturn(model); + }} + /> +
+
+ + { + const model: ProductModel = { + ...editProductModel, + description: e.target.value, + }; + setEditProductModel(model); + setReturn(model); + }} + /> +
+
+ + { + const model: ProductModel = { + ...editProductModel, + category: e.target.value, + }; + setEditProductModel(model); + setReturn(model); + }} + /> +
+
+ + { + const value = e.target.value; + if (/^\d*\.?\d*$/.test(value) || /^\d*\.$/.test(value)) { + // This regex checks for a valid decimal or integer + const model: ProductModel = { + ...editProductModel, + unitPrice: value, + }; + setEditProductModel(model); + setReturn(model); + } + }} + /> +
+
+ + { + const model: ProductModel = { + ...editProductModel, + units: e.target.value, + }; + setEditProductModel(model); + setReturn(model); + }} + /> +
+
+ + { + const model: ProductModel = { + ...editProductModel, + installments: parseInt(e.target.value), + }; + setEditProductModel(model); + setReturn(model); + }} + /> +
+ + ), + canConfirm: + notEmptyOrFalsey(editProductModel.name) && + !notification.pending && + parseFloat(editProductModel.unitPrice) > 0 && + parseFloat(editProductModel.unitPrice).toString() === + editProductModel.unitPrice && + editProductModel.installments > 0, + }, + [], + ); + + const handleCreate = async () => { + setEditProductModel({ ...defaultProduct }); + setEditConfirmationTitle("Add Product"); + const [confirmed, newModel] = await getEditConfirmation(); + + if (!confirmed) { + return; + } + + const req = authenticatedFetch(`/api/${cluster}/product/CreateProduct`, { + method: "POST", + body: JSON.stringify(newModel), + }); + + setNotification(req, "Saving", "Cluster Created", async (r) => { + if (r.status === 400) { + const errors = await parseBadRequest(response); + return errors; + } else { + return "An error happened, please try again."; + } + }); + + const response = await req; + + if (response.ok) { + //refresh the page + window.location.reload(); + + // const newProduct = (await response.json()) as ProductModel; + // setContext((c) => ({ + // ...c, + // products: [...c.products, newProduct].sort((a, b) => + // a.name.localeCompare(b.name), + // ), + // })); + // setEditProductModel((r) => ({ ...r, name: "" })); + } + }; + if (products === undefined) { return (
@@ -88,7 +272,10 @@ export const Products = () => {
- {" "} + {" "}
diff --git a/Hippo.Web/ClientApp/src/types.ts b/Hippo.Web/ClientApp/src/types.ts index 7702356f..0af0df79 100644 --- a/Hippo.Web/ClientApp/src/types.ts +++ b/Hippo.Web/ClientApp/src/types.ts @@ -98,6 +98,7 @@ export interface AppContextShape { clusters: ClusterModel[]; openRequests: RequestModel[]; lastPuppetSync?: string; + //products: ProductModel[]; } export interface Permission { @@ -235,6 +236,6 @@ export interface ProductModel { name: string; description: string; units: string; - unitPrice: number; + unitPrice: string; installments: number; } diff --git a/Hippo.Web/Controllers/ProductController.cs b/Hippo.Web/Controllers/ProductController.cs index 15c33481..899ba94a 100644 --- a/Hippo.Web/Controllers/ProductController.cs +++ b/Hippo.Web/Controllers/ProductController.cs @@ -26,7 +26,7 @@ public async Task Index() [HttpPost] [Authorize(Policy = AccessCodes.ClusterAdminAccess)] - public async Task CreateProduct(Product model) + public async Task CreateProduct([FromBody] Product model) { var cluster = await _dbContext.Clusters.FirstAsync(a => a.Name == Cluster); @@ -35,7 +35,7 @@ public async Task CreateProduct(Product model) return BadRequest("Invalid"); } - var procuct = new Product + var product = new Product { Name = model.Name, Description = model.Description, @@ -45,10 +45,10 @@ public async Task CreateProduct(Product model) Cluster = cluster, Installments = model.Installments }; - _dbContext.Products.Add(procuct); + _dbContext.Products.Add(product); await _dbContext.SaveChangesAsync(); - return View(); + return Ok(product); } [HttpGet] From 1b2821a8740570c6797f84c93ebb1ba745c8a98b Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 7 May 2024 14:13:05 -0700 Subject: [PATCH 037/301] WIP adding product --- .../src/components/Product/Products.tsx | 20 ++++--------------- Hippo.Web/ClientApp/src/types.ts | 1 - 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Product/Products.tsx b/Hippo.Web/ClientApp/src/components/Product/Products.tsx index 7da15bf4..a14573f0 100644 --- a/Hippo.Web/ClientApp/src/components/Product/Products.tsx +++ b/Hippo.Web/ClientApp/src/components/Product/Products.tsx @@ -9,7 +9,6 @@ import { ShowFor } from "../../Shared/ShowFor"; import { usePromiseNotification } from "../../util/Notifications"; import { useConfirmationDialog } from "../../Shared/ConfirmationDialog"; import { notEmptyOrFalsey } from "../../util/ValueChecks"; -//import AppContext from "../../Shared/AppContext"; const defaultProduct: ProductModel = { id: 0, @@ -27,7 +26,6 @@ export const Products = () => { ...defaultProduct, }); const [editConfirmationTitle, setEditConfirmationTitle] = useState(""); - //const [context, setContext] = useContext(AppContext); //need? const [products, setProducts] = useState(); const { cluster } = useParams(); @@ -213,8 +211,6 @@ export const Products = () => { notEmptyOrFalsey(editProductModel.name) && !notification.pending && parseFloat(editProductModel.unitPrice) > 0 && - parseFloat(editProductModel.unitPrice).toString() === - editProductModel.unitPrice && editProductModel.installments > 0, }, [], @@ -234,7 +230,7 @@ export const Products = () => { body: JSON.stringify(newModel), }); - setNotification(req, "Saving", "Cluster Created", async (r) => { + setNotification(req, "Saving", "Product Added", async (r) => { if (r.status === 400) { const errors = await parseBadRequest(response); return errors; @@ -246,17 +242,9 @@ export const Products = () => { const response = await req; if (response.ok) { - //refresh the page - window.location.reload(); - - // const newProduct = (await response.json()) as ProductModel; - // setContext((c) => ({ - // ...c, - // products: [...c.products, newProduct].sort((a, b) => - // a.name.localeCompare(b.name), - // ), - // })); - // setEditProductModel((r) => ({ ...r, name: "" })); + const data = await response.json(); + //add data to the projects + setProducts([...products, data]); } }; diff --git a/Hippo.Web/ClientApp/src/types.ts b/Hippo.Web/ClientApp/src/types.ts index 0af0df79..4cce7fb1 100644 --- a/Hippo.Web/ClientApp/src/types.ts +++ b/Hippo.Web/ClientApp/src/types.ts @@ -98,7 +98,6 @@ export interface AppContextShape { clusters: ClusterModel[]; openRequests: RequestModel[]; lastPuppetSync?: string; - //products: ProductModel[]; } export interface Permission { From eba2ce13f537f1ac06c1561a0c27aa089467ad81 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 13 May 2024 08:50:15 -0700 Subject: [PATCH 038/301] Closer to the edit --- .../src/components/Product/Products.tsx | 156 ++++++++++++------ Hippo.Web/Controllers/ProductController.cs | 22 +++ 2 files changed, 128 insertions(+), 50 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Product/Products.tsx b/Hippo.Web/ClientApp/src/components/Product/Products.tsx index a14573f0..5cc543a3 100644 --- a/Hippo.Web/ClientApp/src/components/Product/Products.tsx +++ b/Hippo.Web/ClientApp/src/components/Product/Products.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState, useMemo, useCallback, useContext } from "react"; +import { useEffect, useState, useMemo, useCallback } from "react"; import { useParams } from "react-router-dom"; import { ReactTable } from "../../Shared/ReactTable"; @@ -46,54 +46,6 @@ export const Products = () => { fetchProducts(); }, [cluster]); - const columns = useMemo[]>( - () => [ - { - Header: "Name", - accessor: "name", - Cell: ({ row }) => ( - - {row.original.name} - - ), - }, - { - Header: "Category", - accessor: "category", - }, - { - Header: "Description", - accessor: "description", - }, - { - Header: "Unit Price", - accessor: "unitPrice", - }, - { - Header: "Units", - accessor: "units", - }, - { - Header: "Installments", - accessor: "installments", - }, - { - Header: "Actions", - accessor: "id", - Cell: ({ row }) => ( -
- {" "} - - {" "} - - -
- ), - }, - ], - [cluster], - ); - const [getEditConfirmation] = useConfirmationDialog( { title: editConfirmationTitle, @@ -213,7 +165,57 @@ export const Products = () => { parseFloat(editProductModel.unitPrice) > 0 && editProductModel.installments > 0, }, - [], + [editProductModel, notification.pending], + ); + + const handleEdit = useCallback( + async (id: number) => { + const product = products?.find((p) => p.id === id); + console.log(product); + if (product === undefined) { + alert("Product not found"); + return; + } + + setEditProductModel(product); + setEditConfirmationTitle("Edit Product"); + const [confirmed, newModel] = await getEditConfirmation(); + + if (!confirmed) { + return; + } + + const req = authenticatedFetch(`/api/${cluster}/product/EditProduct/`, { + method: "POST", + body: JSON.stringify(newModel), + }); + + setNotification(req, "Saving", "Product Updated", async (r) => { + if (r.status === 400) { + const errors = await parseBadRequest(response); + return errors; + } else { + return "An error happened, please try again."; + } + }); + + const response = await req; + + if (response.ok) { + const data = await response.json(); + //add data to the projects + setProducts( + products?.map((p) => { + if (p.id === id) { + return data; + } else { + return p; + } + }), + ); + } + }, + [products, getEditConfirmation, cluster, setNotification], ); const handleCreate = async () => { @@ -248,6 +250,60 @@ export const Products = () => { } }; + const columns = useMemo[]>( + () => [ + { + Header: "Name", + accessor: "name", + Cell: ({ row }) => ( + + {row.original.name} + + ), + }, + { + Header: "Category", + accessor: "category", + }, + { + Header: "Description", + accessor: "description", + }, + { + Header: "Unit Price", + accessor: "unitPrice", + }, + { + Header: "Units", + accessor: "units", + }, + { + Header: "Installments", + accessor: "installments", + }, + { + Header: "Actions", + accessor: "id", + Cell: ({ row }) => ( +
+ {" "} + + {" "} + + +
+ ), + }, + ], + + [cluster, handleEdit], + ); + if (products === undefined) { return (
diff --git a/Hippo.Web/Controllers/ProductController.cs b/Hippo.Web/Controllers/ProductController.cs index 899ba94a..edbdd7a2 100644 --- a/Hippo.Web/Controllers/ProductController.cs +++ b/Hippo.Web/Controllers/ProductController.cs @@ -51,6 +51,28 @@ public async Task CreateProduct([FromBody] Product model) return Ok(product); } + [HttpPost] + [Authorize(Policy = AccessCodes.ClusterAdminAccess)] + public async Task EditProduct([FromBody] Product model) + { + var product = await _dbContext.Products.FirstOrDefaultAsync(a => a.Id == model.Id && a.Cluster.Name == Cluster); + if (product == null) + { + return NotFound(); + } + + product.Name = model.Name; + product.Description = model.Description; + product.Category = model.Category; + product.UnitPrice = model.UnitPrice; + product.Units = model.Units; + product.Installments = model.Installments; + + await _dbContext.SaveChangesAsync(); + + return Ok(); + } + [HttpGet] public async Task GetProduct(int id) { From 2314635740b78297e18577d5b09cf0d2864019fe Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 13 May 2024 09:04:47 -0700 Subject: [PATCH 039/301] Return the product --- Hippo.Web/Controllers/ProductController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hippo.Web/Controllers/ProductController.cs b/Hippo.Web/Controllers/ProductController.cs index edbdd7a2..664659c8 100644 --- a/Hippo.Web/Controllers/ProductController.cs +++ b/Hippo.Web/Controllers/ProductController.cs @@ -70,7 +70,7 @@ public async Task EditProduct([FromBody] Product model) await _dbContext.SaveChangesAsync(); - return Ok(); + return Ok(product); } [HttpGet] From 68d86bd711b883e1ddbd8d90746d8a6e4e9d6830 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 13 May 2024 09:07:06 -0700 Subject: [PATCH 040/301] Cleanup --- .../src/components/Product/Products.tsx | 2 +- Hippo.Web/Controllers/ProductController.cs | 24 +------------------ 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Product/Products.tsx b/Hippo.Web/ClientApp/src/components/Product/Products.tsx index 5cc543a3..8583ef3f 100644 --- a/Hippo.Web/ClientApp/src/components/Product/Products.tsx +++ b/Hippo.Web/ClientApp/src/components/Product/Products.tsx @@ -185,7 +185,7 @@ export const Products = () => { return; } - const req = authenticatedFetch(`/api/${cluster}/product/EditProduct/`, { + const req = authenticatedFetch(`/api/${cluster}/product/UpdateProduct/`, { method: "POST", body: JSON.stringify(newModel), }); diff --git a/Hippo.Web/Controllers/ProductController.cs b/Hippo.Web/Controllers/ProductController.cs index 664659c8..1dbaa576 100644 --- a/Hippo.Web/Controllers/ProductController.cs +++ b/Hippo.Web/Controllers/ProductController.cs @@ -53,7 +53,7 @@ public async Task CreateProduct([FromBody] Product model) [HttpPost] [Authorize(Policy = AccessCodes.ClusterAdminAccess)] - public async Task EditProduct([FromBody] Product model) + public async Task UpdateProduct([FromBody] Product model) { var product = await _dbContext.Products.FirstOrDefaultAsync(a => a.Id == model.Id && a.Cluster.Name == Cluster); if (product == null) @@ -84,28 +84,6 @@ public async Task GetProduct(int id) return Ok(product); } - [HttpPost] - [Authorize(Policy = AccessCodes.ClusterAdminAccess)] - public async Task UpdateProduct(Product model) - { - var product = await _dbContext.Products.FirstOrDefaultAsync(a => a.Id == model.Id && a.Cluster.Name == Cluster); - if (product == null) - { - return NotFound(); - } - - product.Name = model.Name; - product.Description = model.Description; - product.Category = model.Category; - product.UnitPrice = model.UnitPrice; - product.Units = model.Units; - product.Installments = model.Installments; - - await _dbContext.SaveChangesAsync(); - - return Ok(); - } - [HttpPost] [Authorize(Policy = AccessCodes.ClusterAdminAccess)] public async Task DeleteProduct(int id) From 7aaad8ff1f0b607098f5c61a08235eef39efbd21 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 13 May 2024 09:36:35 -0700 Subject: [PATCH 041/301] Delete Product --- .../src/components/Product/Products.tsx | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/Hippo.Web/ClientApp/src/components/Product/Products.tsx b/Hippo.Web/ClientApp/src/components/Product/Products.tsx index 8583ef3f..9d9a0efc 100644 --- a/Hippo.Web/ClientApp/src/components/Product/Products.tsx +++ b/Hippo.Web/ClientApp/src/components/Product/Products.tsx @@ -26,6 +26,8 @@ export const Products = () => { ...defaultProduct, }); const [editConfirmationTitle, setEditConfirmationTitle] = useState(""); + const [deleteConfirmationTitle, setDeleteConfirmationTitle] = + useState("Delete Product"); const [products, setProducts] = useState(); const { cluster } = useParams(); @@ -168,6 +170,57 @@ export const Products = () => { [editProductModel, notification.pending], ); + const [getDeleteConfirmation] = useConfirmationDialog( + { + title: deleteConfirmationTitle, + message: + "Are you sure you want to delete this product? This does not effect any orders.", + }, + [deleteConfirmationTitle], + ); + + const handleDelete = useCallback( + async (id: number) => { + const product = products?.find((p) => p.id === id); + // console.log(product); + if (product === undefined) { + alert("Product not found"); + return; + } + + setDeleteConfirmationTitle(`Delete Product "${product.name}"?`); + + const [confirmed] = await getDeleteConfirmation(); + + if (!confirmed) { + return; + } + + const req = authenticatedFetch( + `/api/${cluster}/product/DeleteProduct/${id}`, + { + method: "POST", + }, + ); + + setNotification(req, "Deleting", "Product Deleted", async (r) => { + if (r.status === 400) { + const errors = await parseBadRequest(response); + return errors; + } else { + return "An error happened, please try again."; + } + }); + + const response = await req; + + if (response.ok) { + setProducts(products?.filter((p) => p.id !== id)); + } + }, + [products, getDeleteConfirmation, cluster, setNotification], + ); + const handleEdit = useCallback( async (id: number) => { const product = products?.find((p) => p.id === id); @@ -294,7 +347,12 @@ export const Products = () => { > Edit {" "} - +
), From 49e6bec9e6ec197b317cd431b0869a5dc19d046e Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 13 May 2024 09:41:00 -0700 Subject: [PATCH 042/301] cleanup --- Hippo.Web/ClientApp/src/components/Product/Products.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Product/Products.tsx b/Hippo.Web/ClientApp/src/components/Product/Products.tsx index 9d9a0efc..b5334920 100644 --- a/Hippo.Web/ClientApp/src/components/Product/Products.tsx +++ b/Hippo.Web/ClientApp/src/components/Product/Products.tsx @@ -308,11 +308,6 @@ export const Products = () => { { Header: "Name", accessor: "name", - Cell: ({ row }) => ( - - {row.original.name} - - ), }, { Header: "Category", From 696734e4c013c6e297df439a3217c0f93ecaf86a Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 13 May 2024 09:54:02 -0700 Subject: [PATCH 043/301] fix table --- Hippo.Web/ClientApp/src/components/Product/Products.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hippo.Web/ClientApp/src/components/Product/Products.tsx b/Hippo.Web/ClientApp/src/components/Product/Products.tsx index b5334920..7dd5e3bd 100644 --- a/Hippo.Web/ClientApp/src/components/Product/Products.tsx +++ b/Hippo.Web/ClientApp/src/components/Product/Products.tsx @@ -331,7 +331,7 @@ export const Products = () => { }, { Header: "Actions", - accessor: "id", + sortable: false, Cell: ({ row }) => (
{" "} From 46f21becc8775c5ccfdae11898aa507d884ca4e6 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 13 May 2024 10:27:38 -0700 Subject: [PATCH 044/301] WIP Orders --- .../components/Financial/FinancialDetail.tsx | 55 +++++++++++-------- Hippo.Web/Controllers/OrderController.cs | 2 +- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx index 86abd1d0..57a7e4bc 100644 --- a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -3,6 +3,7 @@ import { ChartStringValidationModel, FinancialDetailModel } from "../../types"; import { authenticatedFetch, parseBadRequest } from "../../util/api"; import { useParams } from "react-router-dom"; import { usePromiseNotification } from "../../util/Notifications"; +import { Card, CardBody, CardTitle } from "reactstrap"; declare const window: Window & typeof globalThis & { @@ -93,7 +94,7 @@ const FinancialDetail: React.FC = () => { const validateChartString = async (chartString: string) => { let response = await authenticatedFetch( - `/api/order/validate-chart-string/${chartString}`, + `/api/order/validateChartString/${chartString}`, { method: "GET", }, @@ -191,38 +192,46 @@ const FinancialDetail: React.FC = () => {
{chartStringValidation && (
-
Chart String Validation:
-
- Is Valid: {chartStringValidation.isValid ? "Yes" : "No"} -
-
Description: {chartStringValidation.description}
- {chartStringValidation.accountManager && ( -
+
+ + +

Chart String Details:

+
+
- Account Manager: {chartStringValidation.accountManager} + Is Valid: {chartStringValidation.isValid ? "Yes" : "No"}
-
- Account Manager Email:{" "} - {chartStringValidation.accountManagerEmail} -
-
- )} - {chartStringValidation.message && ( -
Message: {chartStringValidation.message}
- )} - - {chartStringValidation.warning && ( -
Warning: {chartStringValidation.warning}
- )} +
Description: {chartStringValidation.description}
+ {chartStringValidation.accountManager && ( +
+
+ Account Manager: {chartStringValidation.accountManager} +
+
+ Account Manager Email:{" "} + {chartStringValidation.accountManagerEmail} +
+
+ )} + {chartStringValidation.message && ( +
Message: {chartStringValidation.message}
+ )} + + {chartStringValidation.warning && ( +
Warning: {chartStringValidation.warning}
+ )} + +
)}
+
diff --git a/Hippo.Web/Controllers/OrderController.cs b/Hippo.Web/Controllers/OrderController.cs index d27249f0..c43fe0d8 100644 --- a/Hippo.Web/Controllers/OrderController.cs +++ b/Hippo.Web/Controllers/OrderController.cs @@ -25,7 +25,7 @@ public OrderController(AppDbContext dbContext, IAggieEnterpriseService aggieEnte [HttpGet] - [Route("api/order/validate-chart-string/{chartString}")] + [Route("api/order/validateChartString/{chartString}")] public async Task ValidateChartString(string chartString) { return await _aggieEnterpriseService.IsChartStringValid(chartString); From 8b56ed81ac896a15620772cee2ac2c3808c25897 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 13 May 2024 14:36:25 -0700 Subject: [PATCH 045/301] WIP create order. Probably need to clean this up a lot. --- Hippo.Core/Domain/Order.cs | 5 +++ Hippo.Web/Controllers/OrderController.cs | 56 ++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/Hippo.Core/Domain/Order.cs b/Hippo.Core/Domain/Order.cs index 25c7f641..96c3754b 100644 --- a/Hippo.Core/Domain/Order.cs +++ b/Hippo.Core/Domain/Order.cs @@ -61,6 +61,11 @@ public class Order public List MetaData { get; set; } = new(); + public void AddMetaData(string key, string value) + { + MetaData.Add(new OrderMetaData { Name = key, Value = value, Order = this }); + } + public List Payments { get; set; } = new(); [JsonIgnore] diff --git a/Hippo.Web/Controllers/OrderController.cs b/Hippo.Web/Controllers/OrderController.cs index c43fe0d8..90ad79c2 100644 --- a/Hippo.Web/Controllers/OrderController.cs +++ b/Hippo.Web/Controllers/OrderController.cs @@ -32,5 +32,61 @@ public async Task ValidateChartString(string chartSt } + [HttpPost] + public async Task CreateOrder([FromBody] Order model) + { + var cluster = await _dbContext.Clusters.FirstAsync(a => a.Name == Cluster); + User principalInvestigator = null; + //If this is created by an admin, we will use the passed PrincipalInvestigatorId, otherwise it is who created it. + if (User.IsInRole(AccessCodes.ClusterAdminAccess)) + { + principalInvestigator = await _dbContext.Users.FirstAsync(a => a.Id == model.PrincipalInvestigatorId); + } + else + { + principalInvestigator = await _dbContext.Users.FirstAsync(a => a.Email == User.Identity.Name); //TODO: Check if this is how we do it. + } + + if (!ModelState.IsValid) + { + return BadRequest("Invalid"); + } + + var order = new Order + { + Category = model.Category, + Name = model.Name, + Description = model.Description, + ExternalReference = model.ExternalReference, + Units = model.Units, + UnitPrice = model.UnitPrice, + Installments = model.Installments, + Quantity = model.Quantity, + + //Adjustment = model.Adjustment, + //AdjustmentReason = model.AdjustmentReason, + SubTotal = model.Quantity * model.UnitPrice, + Total = model.Quantity * model.UnitPrice, + BalanceRemaining = model.Quantity * model.UnitPrice, + Notes = model.Notes, + AdminNotes = model.AdminNotes, + Status = Order.Statuses.Created, + Cluster = cluster, + PrincipalInvestigator = principalInvestigator, + CreatedOn = DateTime.UtcNow + }; + // Deal with OrderMeta data + foreach (var metaData in model.MetaData) + { + order.AddMetaData(metaData.Name, metaData.Value); + } + + + _dbContext.Orders.Add(order); + await _dbContext.SaveChangesAsync(); + + return Ok(order); + } + } } From aac2cd33d87dafda4ab31b67c37d40e9e6dde820 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 14 May 2024 08:50:49 -0700 Subject: [PATCH 046/301] WIP order endpoints --- Hippo.Core/Services/HistoryService.cs | 16 +++++++++ Hippo.Web/Controllers/OrderController.cs | 44 ++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/Hippo.Core/Services/HistoryService.cs b/Hippo.Core/Services/HistoryService.cs index ea3eec98..df4860e0 100644 --- a/Hippo.Core/Services/HistoryService.cs +++ b/Hippo.Core/Services/HistoryService.cs @@ -206,5 +206,21 @@ public static async Task PuppetDataSynced(this IHistoryService historyService, i }; await historyService.AddHistory(history); } + + public static async Task OrderCreated(this IHistoryService historyService, Order order, User actedBy) + { + var history = new History + { + Order = order, + ClusterId = order.Cluster.Id, + Status = order.Status, + ActedBy = actedBy, + AdminAction = actedBy != order.PrincipalInvestigator, + Action = History.OrderActions.Created, + Details = $"Order created by {actedBy.Email}" //Dump in json of the order? //Write if it is an adhoc order? + }; + + await historyService.AddHistory(history); + } } } diff --git a/Hippo.Web/Controllers/OrderController.cs b/Hippo.Web/Controllers/OrderController.cs index 90ad79c2..a102910a 100644 --- a/Hippo.Web/Controllers/OrderController.cs +++ b/Hippo.Web/Controllers/OrderController.cs @@ -14,12 +14,16 @@ public class OrderController : SuperController { private readonly AppDbContext _dbContext; private readonly IAggieEnterpriseService _aggieEnterpriseService; + private readonly IUserService _userService; + private readonly IHistoryService _historyService; - public OrderController(AppDbContext dbContext, IAggieEnterpriseService aggieEnterpriseService) + public OrderController(AppDbContext dbContext, IAggieEnterpriseService aggieEnterpriseService, IUserService userService, IHistoryService historyService) { _dbContext = dbContext; _aggieEnterpriseService = aggieEnterpriseService; + _userService = userService; + _historyService = historyService; } @@ -32,11 +36,35 @@ public async Task ValidateChartString(string chartSt } + [HttpGet] + public async Task MyOrders() + { + var currentUser = await _userService.GetCurrentUser(); + var orders = await _dbContext.Orders.Where(a => a.Cluster.Name == Cluster && a.PrincipalInvestigatorId == currentUser.Id).ToListAsync(); //Filters out inactive orders + return Ok(orders); + } + + [HttpGet] + public async Task Get(int id) + { + var order = await _dbContext.Orders.Include(a => a.MetaData).Include(a => a.Payments).Include(a => a.PrincipalInvestigator).Include(a => a.History).SingleOrDefaultAsync(a => a.Cluster.Name == Cluster && a.Id == id); + if (order == null) + { + return NotFound(); + } + return Ok(order); + } + + [HttpPost] public async Task CreateOrder([FromBody] Order model) { var cluster = await _dbContext.Clusters.FirstAsync(a => a.Name == Cluster); User principalInvestigator = null; + + + + var currentUser = await _userService.GetCurrentUser(); //If this is created by an admin, we will use the passed PrincipalInvestigatorId, otherwise it is who created it. if (User.IsInRole(AccessCodes.ClusterAdminAccess)) { @@ -44,7 +72,7 @@ public async Task CreateOrder([FromBody] Order model) } else { - principalInvestigator = await _dbContext.Users.FirstAsync(a => a.Email == User.Identity.Name); //TODO: Check if this is how we do it. + principalInvestigator = currentUser; } if (!ModelState.IsValid) @@ -81,6 +109,18 @@ public async Task CreateOrder([FromBody] Order model) order.AddMetaData(metaData.Name, metaData.Value); } + //var history = new History + //{ + // Order = order, + // ClusterId = cluster.Id, + // Status = History.OrderActions.Created, + // ActedBy = currentUser, + // AdminAction = currentUser != principalInvestigator, + // Action = History.OrderActions.Created, + // Details = $"Order created by {currentUser.Email}" //Dump in json of the order? //Write if it is an adhoc order? + //}; + //_dbContext.Histories.Add(history); //Add it here or call history service? + await _historyService.OrderCreated(order, currentUser); _dbContext.Orders.Add(order); await _dbContext.SaveChangesAsync(); From d27829ffaced815f3bbf4940e6d1ca5ad8cd6fb5 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 14 May 2024 09:23:32 -0700 Subject: [PATCH 047/301] WIP --- Hippo.Web/Controllers/OrderController.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Hippo.Web/Controllers/OrderController.cs b/Hippo.Web/Controllers/OrderController.cs index a102910a..9b53455b 100644 --- a/Hippo.Web/Controllers/OrderController.cs +++ b/Hippo.Web/Controllers/OrderController.cs @@ -100,6 +100,7 @@ public async Task CreateOrder([FromBody] Order model) AdminNotes = model.AdminNotes, Status = Order.Statuses.Created, Cluster = cluster, + ClusterId = cluster.Id, PrincipalInvestigator = principalInvestigator, CreatedOn = DateTime.UtcNow }; From 7e363aa88aef67a69c52a94275d5218215217f53 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Tue, 14 May 2024 09:37:34 -0700 Subject: [PATCH 048/301] Fix duplicate relationship between order and history --- Hippo.Core/Domain/History.cs | 1 - ...4163033_FixHistoryRelationship.Designer.cs | 1084 +++++++++++++++++ .../20240514163033_FixHistoryRelationship.cs | 68 ++ .../AppDbContextSqlServerModelSnapshot.cs | 12 +- ...4163029_FixHistoryRelationship.Designer.cs | 1046 ++++++++++++++++ .../20240514163029_FixHistoryRelationship.cs | 68 ++ .../Sqlite/AppDbContextSqliteModelSnapshot.cs | 12 +- 7 files changed, 2268 insertions(+), 23 deletions(-) create mode 100644 Hippo.Core/Migrations/SqlServer/20240514163033_FixHistoryRelationship.Designer.cs create mode 100644 Hippo.Core/Migrations/SqlServer/20240514163033_FixHistoryRelationship.cs create mode 100644 Hippo.Core/Migrations/Sqlite/20240514163029_FixHistoryRelationship.Designer.cs create mode 100644 Hippo.Core/Migrations/Sqlite/20240514163029_FixHistoryRelationship.cs diff --git a/Hippo.Core/Domain/History.cs b/Hippo.Core/Domain/History.cs index 6525d620..db046eea 100644 --- a/Hippo.Core/Domain/History.cs +++ b/Hippo.Core/Domain/History.cs @@ -46,7 +46,6 @@ internal static void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity().HasIndex(h => h.ClusterId); modelBuilder.Entity().HasOne(h => h.ActedBy).WithMany().HasForeignKey(a => a.ActedById).OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity().HasOne(h => h.Cluster).WithMany().HasForeignKey(a => a.ClusterId).OnDelete(DeleteBehavior.Restrict); - modelBuilder.Entity().HasOne(h => h.Order).WithMany().HasForeignKey(a => a.OrderId).OnDelete(DeleteBehavior.Restrict); } public class Actions diff --git a/Hippo.Core/Migrations/SqlServer/20240514163033_FixHistoryRelationship.Designer.cs b/Hippo.Core/Migrations/SqlServer/20240514163033_FixHistoryRelationship.Designer.cs new file mode 100644 index 00000000..bb634341 --- /dev/null +++ b/Hippo.Core/Migrations/SqlServer/20240514163033_FixHistoryRelationship.Designer.cs @@ -0,0 +1,1084 @@ +// +using System; +using Hippo.Core.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hippo.Core.Migrations.SqlServer +{ + [DbContext(typeof(AppDbContextSqlServer))] + [Migration("20240514163033_FixHistoryRelationship")] + partial class FixHistoryRelationship + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.19") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.Property("AccessTypesId") + .HasColumnType("int"); + + b.Property("AccountsId") + .HasColumnType("int"); + + b.HasKey("AccessTypesId", "AccountsId"); + + b.HasIndex("AccountsId"); + + b.ToTable("AccessTypeAccount"); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.Property("AccessTypesId") + .HasColumnType("int"); + + b.Property("ClustersId") + .HasColumnType("int"); + + b.HasKey("AccessTypesId", "ClustersId"); + + b.HasIndex("ClustersId"); + + b.ToTable("AccessTypeCluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.AccessType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AccessTypes"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("SshKey") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("CreatedOn"); + + b.HasIndex("Email"); + + b.HasIndex("Kerberos"); + + b.HasIndex("Name"); + + b.HasIndex("OwnerId"); + + b.HasIndex("UpdatedOn"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Percentage") + .HasColumnType("decimal(18,2)"); + + b.Property("Updated") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Description") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Domain") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("SshKeyId") + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("SshName") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("SshUrl") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Clusters"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("ChartString") + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("FinancialSystemApiSource") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("SecretAccessKey") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId", "Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("int"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupAdminAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("int"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMemberAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ActedById") + .HasColumnType("int"); + + b.Property("ActedDate") + .HasColumnType("datetime2"); + + b.Property("Action") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("AdminAction") + .HasColumnType("bit"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ActedById"); + + b.HasIndex("ActedDate"); + + b.HasIndex("Action"); + + b.HasIndex("ClusterId"); + + b.HasIndex("OrderId"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Adjustment") + .HasColumnType("decimal(18,2)"); + + b.Property("AdjustmentReason") + .HasColumnType("nvarchar(max)"); + + b.Property("AdminNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("BalanceRemaining") + .HasColumnType("decimal(18,2)"); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("Total") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("FinancialSystemId") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("TrackingNumber") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Action") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)"); + + b.Property("RequestId") + .HasColumnType("int"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("RequestId"); + + b.HasIndex("Status"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ActorId") + .HasColumnType("int"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("Group") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("RequesterId") + .HasColumnType("int"); + + b.Property("SshKey") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("SupervisingPI") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorId"); + + b.HasIndex("ClusterId"); + + b.HasIndex("Group"); + + b.HasIndex("RequesterId"); + + b.HasIndex("Status"); + + b.ToTable("Requests"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempGroup", b => + { + b.Property("Group") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Group"); + + b.ToTable("TempGroups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempKerberos", b => + { + b.Property("Kerberos") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Kerberos"); + + b.ToTable("TempKerberos"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Email") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Iam") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("MothraId") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("Iam") + .IsUnique() + .HasFilter("[Iam] IS NOT NULL"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Account", null) + .WithMany() + .HasForeignKey("AccountsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Cluster", null) + .WithMany() + .HasForeignKey("ClustersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Accounts") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Cluster"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Groups") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.HasOne("Hippo.Core.Domain.User", "ActedBy") + .WithMany() + .HasForeignKey("ActedById") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("History") + .HasForeignKey("OrderId"); + + b.Navigation("ActedBy"); + + b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.HasOne("Hippo.Core.Domain.Request", "Request") + .WithMany("QueuedEvents") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Request"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.HasOne("Hippo.Core.Domain.User", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Requester") + .WithMany() + .HasForeignKey("RequesterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Actor"); + + b.Navigation("Cluster"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Navigation("Accounts"); + + b.Navigation("FinancialDetail"); + + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Navigation("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Orders"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Hippo.Core/Migrations/SqlServer/20240514163033_FixHistoryRelationship.cs b/Hippo.Core/Migrations/SqlServer/20240514163033_FixHistoryRelationship.cs new file mode 100644 index 00000000..2d03af25 --- /dev/null +++ b/Hippo.Core/Migrations/SqlServer/20240514163033_FixHistoryRelationship.cs @@ -0,0 +1,68 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hippo.Core.Migrations.SqlServer +{ + public partial class FixHistoryRelationship : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Histories_Orders_OrderId", + table: "Histories"); + + migrationBuilder.DropForeignKey( + name: "FK_Histories_Orders_OrderId1", + table: "Histories"); + + migrationBuilder.DropIndex( + name: "IX_Histories_OrderId1", + table: "Histories"); + + migrationBuilder.DropColumn( + name: "OrderId1", + table: "Histories"); + + migrationBuilder.AddForeignKey( + name: "FK_Histories_Orders_OrderId", + table: "Histories", + column: "OrderId", + principalTable: "Orders", + principalColumn: "Id"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Histories_Orders_OrderId", + table: "Histories"); + + migrationBuilder.AddColumn( + name: "OrderId1", + table: "Histories", + type: "int", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Histories_OrderId1", + table: "Histories", + column: "OrderId1"); + + migrationBuilder.AddForeignKey( + name: "FK_Histories_Orders_OrderId", + table: "Histories", + column: "OrderId", + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_Histories_Orders_OrderId1", + table: "Histories", + column: "OrderId1", + principalTable: "Orders", + principalColumn: "Id"); + } + } +} diff --git a/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs b/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs index d7214868..512456f4 100644 --- a/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs +++ b/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs @@ -334,9 +334,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("OrderId") .HasColumnType("int"); - b.Property("OrderId1") - .HasColumnType("int"); - b.Property("Status") .HasMaxLength(50) .HasColumnType("nvarchar(50)"); @@ -353,8 +350,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("OrderId"); - b.HasIndex("OrderId1"); - b.ToTable("Histories"); }); @@ -914,13 +909,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); b.HasOne("Hippo.Core.Domain.Order", "Order") - .WithMany() - .HasForeignKey("OrderId") - .OnDelete(DeleteBehavior.Restrict); - - b.HasOne("Hippo.Core.Domain.Order", null) .WithMany("History") - .HasForeignKey("OrderId1"); + .HasForeignKey("OrderId"); b.Navigation("ActedBy"); diff --git a/Hippo.Core/Migrations/Sqlite/20240514163029_FixHistoryRelationship.Designer.cs b/Hippo.Core/Migrations/Sqlite/20240514163029_FixHistoryRelationship.Designer.cs new file mode 100644 index 00000000..07666d04 --- /dev/null +++ b/Hippo.Core/Migrations/Sqlite/20240514163029_FixHistoryRelationship.Designer.cs @@ -0,0 +1,1046 @@ +// +using System; +using Hippo.Core.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hippo.Core.Migrations.Sqlite +{ + [DbContext(typeof(AppDbContextSqlite))] + [Migration("20240514163029_FixHistoryRelationship")] + partial class FixHistoryRelationship + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.19"); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.Property("AccessTypesId") + .HasColumnType("INTEGER"); + + b.Property("AccountsId") + .HasColumnType("INTEGER"); + + b.HasKey("AccessTypesId", "AccountsId"); + + b.HasIndex("AccountsId"); + + b.ToTable("AccessTypeAccount"); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.Property("AccessTypesId") + .HasColumnType("INTEGER"); + + b.Property("ClustersId") + .HasColumnType("INTEGER"); + + b.HasKey("AccessTypesId", "ClustersId"); + + b.HasIndex("ClustersId"); + + b.ToTable("AccessTypeCluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.AccessType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AccessTypes"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("INTEGER"); + + b.Property("SshKey") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("CreatedOn"); + + b.HasIndex("Email"); + + b.HasIndex("Kerberos"); + + b.HasIndex("Name"); + + b.HasIndex("OwnerId"); + + b.HasIndex("UpdatedOn"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Percentage") + .HasColumnType("TEXT"); + + b.Property("Updated") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Domain") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("SshKeyId") + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("SshName") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("SshUrl") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Clusters"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("ChartString") + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("FinancialSystemApiSource") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("SecretAccessKey") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DisplayName") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId", "Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.Property("AccountId") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupAdminAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.Property("AccountId") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMemberAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ActedById") + .HasColumnType("INTEGER"); + + b.Property("ActedDate") + .HasColumnType("TEXT"); + + b.Property("Action") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("AdminAction") + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ActedById"); + + b.HasIndex("ActedDate"); + + b.HasIndex("Action"); + + b.HasIndex("ClusterId"); + + b.HasIndex("OrderId"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Adjustment") + .HasColumnType("TEXT"); + + b.Property("AdjustmentReason") + .HasColumnType("TEXT"); + + b.Property("AdminNotes") + .HasColumnType("TEXT"); + + b.Property("BalanceRemaining") + .HasColumnType("TEXT"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("SubTotal") + .HasColumnType("TEXT"); + + b.Property("Total") + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("FinancialSystemId") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("TrackingNumber") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("ErrorMessage") + .HasColumnType("TEXT"); + + b.Property("RequestId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("RequestId"); + + b.HasIndex("Status"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ActorId") + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Group") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("RequesterId") + .HasColumnType("INTEGER"); + + b.Property("SshKey") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("SupervisingPI") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorId"); + + b.HasIndex("ClusterId"); + + b.HasIndex("Group"); + + b.HasIndex("RequesterId"); + + b.HasIndex("Status"); + + b.ToTable("Requests"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempGroup", b => + { + b.Property("Group") + .HasColumnType("TEXT"); + + b.HasKey("Group"); + + b.ToTable("TempGroups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempKerberos", b => + { + b.Property("Kerberos") + .HasColumnType("TEXT"); + + b.HasKey("Kerberos"); + + b.ToTable("TempKerberos"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Iam") + .HasMaxLength(10) + .HasColumnType("TEXT"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("MothraId") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("Iam") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Account", null) + .WithMany() + .HasForeignKey("AccountsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Cluster", null) + .WithMany() + .HasForeignKey("ClustersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Accounts") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Cluster"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Groups") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.HasOne("Hippo.Core.Domain.User", "ActedBy") + .WithMany() + .HasForeignKey("ActedById") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("History") + .HasForeignKey("OrderId"); + + b.Navigation("ActedBy"); + + b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.HasOne("Hippo.Core.Domain.Request", "Request") + .WithMany("QueuedEvents") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Request"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.HasOne("Hippo.Core.Domain.User", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Requester") + .WithMany() + .HasForeignKey("RequesterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Actor"); + + b.Navigation("Cluster"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Navigation("Accounts"); + + b.Navigation("FinancialDetail"); + + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Navigation("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Orders"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Hippo.Core/Migrations/Sqlite/20240514163029_FixHistoryRelationship.cs b/Hippo.Core/Migrations/Sqlite/20240514163029_FixHistoryRelationship.cs new file mode 100644 index 00000000..f0b10848 --- /dev/null +++ b/Hippo.Core/Migrations/Sqlite/20240514163029_FixHistoryRelationship.cs @@ -0,0 +1,68 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hippo.Core.Migrations.Sqlite +{ + public partial class FixHistoryRelationship : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Histories_Orders_OrderId", + table: "Histories"); + + migrationBuilder.DropForeignKey( + name: "FK_Histories_Orders_OrderId1", + table: "Histories"); + + migrationBuilder.DropIndex( + name: "IX_Histories_OrderId1", + table: "Histories"); + + migrationBuilder.DropColumn( + name: "OrderId1", + table: "Histories"); + + migrationBuilder.AddForeignKey( + name: "FK_Histories_Orders_OrderId", + table: "Histories", + column: "OrderId", + principalTable: "Orders", + principalColumn: "Id"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Histories_Orders_OrderId", + table: "Histories"); + + migrationBuilder.AddColumn( + name: "OrderId1", + table: "Histories", + type: "INTEGER", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Histories_OrderId1", + table: "Histories", + column: "OrderId1"); + + migrationBuilder.AddForeignKey( + name: "FK_Histories_Orders_OrderId", + table: "Histories", + column: "OrderId", + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_Histories_Orders_OrderId1", + table: "Histories", + column: "OrderId1", + principalTable: "Orders", + principalColumn: "Id"); + } + } +} diff --git a/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs b/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs index 5202235a..140f9c55 100644 --- a/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs +++ b/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs @@ -315,9 +315,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("OrderId") .HasColumnType("INTEGER"); - b.Property("OrderId1") - .HasColumnType("INTEGER"); - b.Property("Status") .HasMaxLength(50) .HasColumnType("TEXT"); @@ -334,8 +331,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("OrderId"); - b.HasIndex("OrderId1"); - b.ToTable("Histories"); }); @@ -876,13 +871,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); b.HasOne("Hippo.Core.Domain.Order", "Order") - .WithMany() - .HasForeignKey("OrderId") - .OnDelete(DeleteBehavior.Restrict); - - b.HasOne("Hippo.Core.Domain.Order", null) .WithMany("History") - .HasForeignKey("OrderId1"); + .HasForeignKey("OrderId"); b.Navigation("ActedBy"); From 413e978eda09b5159d54edb2e4cac36bdba5cee9 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 15 May 2024 07:34:04 -0700 Subject: [PATCH 049/301] New field in history --- Hippo.Core/Domain/History.cs | 2 + .../20240515143208_AddHistoryFlag.Designer.cs | 1087 +++++++++++++++++ .../20240515143208_AddHistoryFlag.cs | 26 + .../AppDbContextSqlServerModelSnapshot.cs | 3 + .../20240515143203_AddHistoryFlag.Designer.cs | 1049 ++++++++++++++++ .../Sqlite/20240515143203_AddHistoryFlag.cs | 26 + .../Sqlite/AppDbContextSqliteModelSnapshot.cs | 3 + 7 files changed, 2196 insertions(+) create mode 100644 Hippo.Core/Migrations/SqlServer/20240515143208_AddHistoryFlag.Designer.cs create mode 100644 Hippo.Core/Migrations/SqlServer/20240515143208_AddHistoryFlag.cs create mode 100644 Hippo.Core/Migrations/Sqlite/20240515143203_AddHistoryFlag.Designer.cs create mode 100644 Hippo.Core/Migrations/Sqlite/20240515143203_AddHistoryFlag.cs diff --git a/Hippo.Core/Domain/History.cs b/Hippo.Core/Domain/History.cs index db046eea..5d155a40 100644 --- a/Hippo.Core/Domain/History.cs +++ b/Hippo.Core/Domain/History.cs @@ -38,6 +38,8 @@ public History() [MaxLength(50)] public string Status { get; set; } + public bool ShowToUser { get; set; } = false; + internal static void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity().HasQueryFilter(h => h.Cluster.IsActive); diff --git a/Hippo.Core/Migrations/SqlServer/20240515143208_AddHistoryFlag.Designer.cs b/Hippo.Core/Migrations/SqlServer/20240515143208_AddHistoryFlag.Designer.cs new file mode 100644 index 00000000..6d88038c --- /dev/null +++ b/Hippo.Core/Migrations/SqlServer/20240515143208_AddHistoryFlag.Designer.cs @@ -0,0 +1,1087 @@ +// +using System; +using Hippo.Core.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hippo.Core.Migrations.SqlServer +{ + [DbContext(typeof(AppDbContextSqlServer))] + [Migration("20240515143208_AddHistoryFlag")] + partial class AddHistoryFlag + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.19") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.Property("AccessTypesId") + .HasColumnType("int"); + + b.Property("AccountsId") + .HasColumnType("int"); + + b.HasKey("AccessTypesId", "AccountsId"); + + b.HasIndex("AccountsId"); + + b.ToTable("AccessTypeAccount"); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.Property("AccessTypesId") + .HasColumnType("int"); + + b.Property("ClustersId") + .HasColumnType("int"); + + b.HasKey("AccessTypesId", "ClustersId"); + + b.HasIndex("ClustersId"); + + b.ToTable("AccessTypeCluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.AccessType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AccessTypes"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("SshKey") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("CreatedOn"); + + b.HasIndex("Email"); + + b.HasIndex("Kerberos"); + + b.HasIndex("Name"); + + b.HasIndex("OwnerId"); + + b.HasIndex("UpdatedOn"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Percentage") + .HasColumnType("decimal(18,2)"); + + b.Property("Updated") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Description") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Domain") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("SshKeyId") + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("SshName") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("SshUrl") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Clusters"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("ChartString") + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("FinancialSystemApiSource") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("SecretAccessKey") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId", "Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("int"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupAdminAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("int"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMemberAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ActedById") + .HasColumnType("int"); + + b.Property("ActedDate") + .HasColumnType("datetime2"); + + b.Property("Action") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("AdminAction") + .HasColumnType("bit"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("ShowToUser") + .HasColumnType("bit"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ActedById"); + + b.HasIndex("ActedDate"); + + b.HasIndex("Action"); + + b.HasIndex("ClusterId"); + + b.HasIndex("OrderId"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Adjustment") + .HasColumnType("decimal(18,2)"); + + b.Property("AdjustmentReason") + .HasColumnType("nvarchar(max)"); + + b.Property("AdminNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("BalanceRemaining") + .HasColumnType("decimal(18,2)"); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("Total") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("FinancialSystemId") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("TrackingNumber") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Action") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)"); + + b.Property("RequestId") + .HasColumnType("int"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("RequestId"); + + b.HasIndex("Status"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ActorId") + .HasColumnType("int"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("Group") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("RequesterId") + .HasColumnType("int"); + + b.Property("SshKey") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("SupervisingPI") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorId"); + + b.HasIndex("ClusterId"); + + b.HasIndex("Group"); + + b.HasIndex("RequesterId"); + + b.HasIndex("Status"); + + b.ToTable("Requests"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempGroup", b => + { + b.Property("Group") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Group"); + + b.ToTable("TempGroups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempKerberos", b => + { + b.Property("Kerberos") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Kerberos"); + + b.ToTable("TempKerberos"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Email") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Iam") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("MothraId") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("Iam") + .IsUnique() + .HasFilter("[Iam] IS NOT NULL"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Account", null) + .WithMany() + .HasForeignKey("AccountsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Cluster", null) + .WithMany() + .HasForeignKey("ClustersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Accounts") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Cluster"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Groups") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.HasOne("Hippo.Core.Domain.User", "ActedBy") + .WithMany() + .HasForeignKey("ActedById") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("History") + .HasForeignKey("OrderId"); + + b.Navigation("ActedBy"); + + b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.HasOne("Hippo.Core.Domain.Request", "Request") + .WithMany("QueuedEvents") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Request"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.HasOne("Hippo.Core.Domain.User", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Requester") + .WithMany() + .HasForeignKey("RequesterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Actor"); + + b.Navigation("Cluster"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Navigation("Accounts"); + + b.Navigation("FinancialDetail"); + + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Navigation("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Orders"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Hippo.Core/Migrations/SqlServer/20240515143208_AddHistoryFlag.cs b/Hippo.Core/Migrations/SqlServer/20240515143208_AddHistoryFlag.cs new file mode 100644 index 00000000..a505a8d7 --- /dev/null +++ b/Hippo.Core/Migrations/SqlServer/20240515143208_AddHistoryFlag.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hippo.Core.Migrations.SqlServer +{ + public partial class AddHistoryFlag : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ShowToUser", + table: "Histories", + type: "bit", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ShowToUser", + table: "Histories"); + } + } +} diff --git a/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs b/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs index 512456f4..026e61ab 100644 --- a/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs +++ b/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs @@ -334,6 +334,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("OrderId") .HasColumnType("int"); + b.Property("ShowToUser") + .HasColumnType("bit"); + b.Property("Status") .HasMaxLength(50) .HasColumnType("nvarchar(50)"); diff --git a/Hippo.Core/Migrations/Sqlite/20240515143203_AddHistoryFlag.Designer.cs b/Hippo.Core/Migrations/Sqlite/20240515143203_AddHistoryFlag.Designer.cs new file mode 100644 index 00000000..95ddf6a5 --- /dev/null +++ b/Hippo.Core/Migrations/Sqlite/20240515143203_AddHistoryFlag.Designer.cs @@ -0,0 +1,1049 @@ +// +using System; +using Hippo.Core.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hippo.Core.Migrations.Sqlite +{ + [DbContext(typeof(AppDbContextSqlite))] + [Migration("20240515143203_AddHistoryFlag")] + partial class AddHistoryFlag + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.19"); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.Property("AccessTypesId") + .HasColumnType("INTEGER"); + + b.Property("AccountsId") + .HasColumnType("INTEGER"); + + b.HasKey("AccessTypesId", "AccountsId"); + + b.HasIndex("AccountsId"); + + b.ToTable("AccessTypeAccount"); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.Property("AccessTypesId") + .HasColumnType("INTEGER"); + + b.Property("ClustersId") + .HasColumnType("INTEGER"); + + b.HasKey("AccessTypesId", "ClustersId"); + + b.HasIndex("ClustersId"); + + b.ToTable("AccessTypeCluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.AccessType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AccessTypes"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("INTEGER"); + + b.Property("SshKey") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("CreatedOn"); + + b.HasIndex("Email"); + + b.HasIndex("Kerberos"); + + b.HasIndex("Name"); + + b.HasIndex("OwnerId"); + + b.HasIndex("UpdatedOn"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Percentage") + .HasColumnType("TEXT"); + + b.Property("Updated") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Domain") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("SshKeyId") + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("SshName") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("SshUrl") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Clusters"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("ChartString") + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("FinancialSystemApiSource") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("SecretAccessKey") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DisplayName") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId", "Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.Property("AccountId") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupAdminAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.Property("AccountId") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMemberAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ActedById") + .HasColumnType("INTEGER"); + + b.Property("ActedDate") + .HasColumnType("TEXT"); + + b.Property("Action") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("AdminAction") + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("ShowToUser") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ActedById"); + + b.HasIndex("ActedDate"); + + b.HasIndex("Action"); + + b.HasIndex("ClusterId"); + + b.HasIndex("OrderId"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Adjustment") + .HasColumnType("TEXT"); + + b.Property("AdjustmentReason") + .HasColumnType("TEXT"); + + b.Property("AdminNotes") + .HasColumnType("TEXT"); + + b.Property("BalanceRemaining") + .HasColumnType("TEXT"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("SubTotal") + .HasColumnType("TEXT"); + + b.Property("Total") + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("FinancialSystemId") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("TrackingNumber") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("ErrorMessage") + .HasColumnType("TEXT"); + + b.Property("RequestId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("RequestId"); + + b.HasIndex("Status"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ActorId") + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Group") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("RequesterId") + .HasColumnType("INTEGER"); + + b.Property("SshKey") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("SupervisingPI") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorId"); + + b.HasIndex("ClusterId"); + + b.HasIndex("Group"); + + b.HasIndex("RequesterId"); + + b.HasIndex("Status"); + + b.ToTable("Requests"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempGroup", b => + { + b.Property("Group") + .HasColumnType("TEXT"); + + b.HasKey("Group"); + + b.ToTable("TempGroups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempKerberos", b => + { + b.Property("Kerberos") + .HasColumnType("TEXT"); + + b.HasKey("Kerberos"); + + b.ToTable("TempKerberos"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Iam") + .HasMaxLength(10) + .HasColumnType("TEXT"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("MothraId") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("Iam") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Account", null) + .WithMany() + .HasForeignKey("AccountsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Cluster", null) + .WithMany() + .HasForeignKey("ClustersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Accounts") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Cluster"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Groups") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.HasOne("Hippo.Core.Domain.User", "ActedBy") + .WithMany() + .HasForeignKey("ActedById") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("History") + .HasForeignKey("OrderId"); + + b.Navigation("ActedBy"); + + b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.HasOne("Hippo.Core.Domain.Request", "Request") + .WithMany("QueuedEvents") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Request"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.HasOne("Hippo.Core.Domain.User", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Requester") + .WithMany() + .HasForeignKey("RequesterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Actor"); + + b.Navigation("Cluster"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Navigation("Accounts"); + + b.Navigation("FinancialDetail"); + + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Navigation("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Orders"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Hippo.Core/Migrations/Sqlite/20240515143203_AddHistoryFlag.cs b/Hippo.Core/Migrations/Sqlite/20240515143203_AddHistoryFlag.cs new file mode 100644 index 00000000..673e4cc8 --- /dev/null +++ b/Hippo.Core/Migrations/Sqlite/20240515143203_AddHistoryFlag.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hippo.Core.Migrations.Sqlite +{ + public partial class AddHistoryFlag : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ShowToUser", + table: "Histories", + type: "INTEGER", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ShowToUser", + table: "Histories"); + } + } +} diff --git a/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs b/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs index 140f9c55..4600e93a 100644 --- a/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs +++ b/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs @@ -315,6 +315,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("OrderId") .HasColumnType("INTEGER"); + b.Property("ShowToUser") + .HasColumnType("INTEGER"); + b.Property("Status") .HasMaxLength(50) .HasColumnType("TEXT"); From 5e22fc27c9e387c056bf755067370b7bb31afb85 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 15 May 2024 07:40:56 -0700 Subject: [PATCH 050/301] Write hidden snapshot of order. --- Hippo.Core/Services/HistoryService.cs | 20 +++++++++++++++++++- Hippo.Web/Controllers/OrderController.cs | 13 ++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Hippo.Core/Services/HistoryService.cs b/Hippo.Core/Services/HistoryService.cs index df4860e0..5d37e32f 100644 --- a/Hippo.Core/Services/HistoryService.cs +++ b/Hippo.Core/Services/HistoryService.cs @@ -217,7 +217,25 @@ public static async Task OrderCreated(this IHistoryService historyService, Order ActedBy = actedBy, AdminAction = actedBy != order.PrincipalInvestigator, Action = History.OrderActions.Created, - Details = $"Order created by {actedBy.Email}" //Dump in json of the order? //Write if it is an adhoc order? + ShowToUser = true, + Details = $"Order total: {order.Total}" + }; + + await historyService.AddHistory(history); + } + + public static async Task OrderSnapshot(this IHistoryService historyService, Order order, User actedBy, string action) + { + var history = new History + { + Order = order, + ClusterId = order.Cluster.Id, + Status = order.Status, + ActedBy = actedBy, + AdminAction = actedBy != order.PrincipalInvestigator, + Action = action, + ShowToUser = false, + Details = Serialize(order) }; await historyService.AddHistory(history); diff --git a/Hippo.Web/Controllers/OrderController.cs b/Hippo.Web/Controllers/OrderController.cs index 9b53455b..35f75e65 100644 --- a/Hippo.Web/Controllers/OrderController.cs +++ b/Hippo.Web/Controllers/OrderController.cs @@ -110,18 +110,9 @@ public async Task CreateOrder([FromBody] Order model) order.AddMetaData(metaData.Name, metaData.Value); } - //var history = new History - //{ - // Order = order, - // ClusterId = cluster.Id, - // Status = History.OrderActions.Created, - // ActedBy = currentUser, - // AdminAction = currentUser != principalInvestigator, - // Action = History.OrderActions.Created, - // Details = $"Order created by {currentUser.Email}" //Dump in json of the order? //Write if it is an adhoc order? - //}; - //_dbContext.Histories.Add(history); //Add it here or call history service? + await _historyService.OrderCreated(order, currentUser); + await _historyService.OrderSnapshot(order, currentUser, History.OrderActions.Created); _dbContext.Orders.Add(order); await _dbContext.SaveChangesAsync(); From fe6ea1e07fa532bea797fe8dfb52e7662306d58f Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 15 May 2024 08:37:22 -0700 Subject: [PATCH 051/301] json ignore various fields so history works as expected. --- Hippo.Core/Domain/Billing.cs | 2 ++ Hippo.Core/Domain/Order.cs | 2 +- Hippo.Core/Domain/OrderMetaData.cs | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Hippo.Core/Domain/Billing.cs b/Hippo.Core/Domain/Billing.cs index d5dd2cd8..c5f37441 100644 --- a/Hippo.Core/Domain/Billing.cs +++ b/Hippo.Core/Domain/Billing.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace Hippo.Core.Domain { @@ -11,6 +12,7 @@ public class Billing public decimal Percentage { get; set; } = 100; [Required] public int OrderId { get; set; } + [JsonIgnore] public Order Order { get; set; } public DateTime Updated { get; set; } = DateTime.UtcNow; } diff --git a/Hippo.Core/Domain/Order.cs b/Hippo.Core/Domain/Order.cs index 96c3754b..45ada4e2 100644 --- a/Hippo.Core/Domain/Order.cs +++ b/Hippo.Core/Domain/Order.cs @@ -65,7 +65,7 @@ public void AddMetaData(string key, string value) { MetaData.Add(new OrderMetaData { Name = key, Value = value, Order = this }); } - + [JsonIgnore] public List Payments { get; set; } = new(); [JsonIgnore] diff --git a/Hippo.Core/Domain/OrderMetaData.cs b/Hippo.Core/Domain/OrderMetaData.cs index 5c2e7483..9cbd3e27 100644 --- a/Hippo.Core/Domain/OrderMetaData.cs +++ b/Hippo.Core/Domain/OrderMetaData.cs @@ -15,6 +15,7 @@ public class OrderMetaData public int Id { get; set; } [Required] public int OrderId { get; set; } + [JsonIgnore] public Order Order { get; set; } [Required] [MaxLength(128)] From 96bed6b61cf94514beff0e57055d463f580663b0 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 15 May 2024 09:05:54 -0700 Subject: [PATCH 052/301] Use a History Type field instead of a flag. --- Hippo.Core/Domain/History.cs | 16 +- ...0515155511_ReplaceFlagWithType.Designer.cs | 1090 +++++++++++++++++ .../20240515155511_ReplaceFlagWithType.cs | 46 + .../AppDbContextSqlServerModelSnapshot.cs | 9 +- ...0515155507_ReplaceFlagWithType.Designer.cs | 1052 ++++++++++++++++ .../20240515155507_ReplaceFlagWithType.cs | 46 + .../Sqlite/AppDbContextSqliteModelSnapshot.cs | 9 +- Hippo.Core/Services/HistoryService.cs | 4 +- 8 files changed, 2263 insertions(+), 9 deletions(-) create mode 100644 Hippo.Core/Migrations/SqlServer/20240515155511_ReplaceFlagWithType.Designer.cs create mode 100644 Hippo.Core/Migrations/SqlServer/20240515155511_ReplaceFlagWithType.cs create mode 100644 Hippo.Core/Migrations/Sqlite/20240515155507_ReplaceFlagWithType.Designer.cs create mode 100644 Hippo.Core/Migrations/Sqlite/20240515155507_ReplaceFlagWithType.cs diff --git a/Hippo.Core/Domain/History.cs b/Hippo.Core/Domain/History.cs index 5d155a40..2ff2e1d6 100644 --- a/Hippo.Core/Domain/History.cs +++ b/Hippo.Core/Domain/History.cs @@ -38,7 +38,8 @@ public History() [MaxLength(50)] public string Status { get; set; } - public bool ShowToUser { get; set; } = false; + [MaxLength(50)] + public string Type { get; set; } = HistoryTypes.Detail; internal static void OnModelCreating(ModelBuilder modelBuilder) { @@ -46,6 +47,7 @@ internal static void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity().HasIndex(h => h.ActedDate); modelBuilder.Entity().HasIndex(h => h.Action); modelBuilder.Entity().HasIndex(h => h.ClusterId); + modelBuilder.Entity().HasIndex(h => h.Type); modelBuilder.Entity().HasOne(h => h.ActedBy).WithMany().HasForeignKey(a => a.ActedById).OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity().HasOne(h => h.Cluster).WithMany().HasForeignKey(a => a.ClusterId).OnDelete(DeleteBehavior.Restrict); } @@ -107,5 +109,17 @@ public class OrderActions ChartStringUpdated }.ToList(); } + + public class HistoryTypes + { + public const string Primary = "Primary"; + public const string Detail = "Detail"; + + public static List TypeList = new List + { + Primary, + Detail + }.ToList(); + } } } diff --git a/Hippo.Core/Migrations/SqlServer/20240515155511_ReplaceFlagWithType.Designer.cs b/Hippo.Core/Migrations/SqlServer/20240515155511_ReplaceFlagWithType.Designer.cs new file mode 100644 index 00000000..94674ce3 --- /dev/null +++ b/Hippo.Core/Migrations/SqlServer/20240515155511_ReplaceFlagWithType.Designer.cs @@ -0,0 +1,1090 @@ +// +using System; +using Hippo.Core.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hippo.Core.Migrations.SqlServer +{ + [DbContext(typeof(AppDbContextSqlServer))] + [Migration("20240515155511_ReplaceFlagWithType")] + partial class ReplaceFlagWithType + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.19") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.Property("AccessTypesId") + .HasColumnType("int"); + + b.Property("AccountsId") + .HasColumnType("int"); + + b.HasKey("AccessTypesId", "AccountsId"); + + b.HasIndex("AccountsId"); + + b.ToTable("AccessTypeAccount"); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.Property("AccessTypesId") + .HasColumnType("int"); + + b.Property("ClustersId") + .HasColumnType("int"); + + b.HasKey("AccessTypesId", "ClustersId"); + + b.HasIndex("ClustersId"); + + b.ToTable("AccessTypeCluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.AccessType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AccessTypes"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("SshKey") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("CreatedOn"); + + b.HasIndex("Email"); + + b.HasIndex("Kerberos"); + + b.HasIndex("Name"); + + b.HasIndex("OwnerId"); + + b.HasIndex("UpdatedOn"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Percentage") + .HasColumnType("decimal(18,2)"); + + b.Property("Updated") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Description") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Domain") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("SshKeyId") + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("SshName") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("SshUrl") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Clusters"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("ChartString") + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("FinancialSystemApiSource") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("SecretAccessKey") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId", "Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("int"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupAdminAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.Property("AccountId") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("int"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMemberAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ActedById") + .HasColumnType("int"); + + b.Property("ActedDate") + .HasColumnType("datetime2"); + + b.Property("Action") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("AdminAction") + .HasColumnType("bit"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ActedById"); + + b.HasIndex("ActedDate"); + + b.HasIndex("Action"); + + b.HasIndex("ClusterId"); + + b.HasIndex("OrderId"); + + b.HasIndex("Type"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Adjustment") + .HasColumnType("decimal(18,2)"); + + b.Property("AdjustmentReason") + .HasColumnType("nvarchar(max)"); + + b.Property("AdminNotes") + .HasColumnType("nvarchar(max)"); + + b.Property("BalanceRemaining") + .HasColumnType("decimal(18,2)"); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("SubTotal") + .HasColumnType("decimal(18,2)"); + + b.Property("Total") + .HasColumnType("decimal(18,2)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Details") + .HasColumnType("nvarchar(max)"); + + b.Property("FinancialSystemId") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderId") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("nvarchar(max)"); + + b.Property("TrackingNumber") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Category") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Installments") + .HasColumnType("int"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UnitPrice") + .HasColumnType("decimal(18,2)"); + + b.Property("Units") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Action") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)"); + + b.Property("RequestId") + .HasColumnType("int"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("RequestId"); + + b.HasIndex("Status"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ActorId") + .HasColumnType("int"); + + b.Property("ClusterId") + .HasColumnType("int"); + + b.Property("CreatedOn") + .HasColumnType("datetime2"); + + b.Property("Data") + .HasColumnType("nvarchar(max)"); + + b.Property("Group") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("RequesterId") + .HasColumnType("int"); + + b.Property("SshKey") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("SupervisingPI") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorId"); + + b.HasIndex("ClusterId"); + + b.HasIndex("Group"); + + b.HasIndex("RequesterId"); + + b.HasIndex("Status"); + + b.ToTable("Requests"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempGroup", b => + { + b.Property("Group") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Group"); + + b.ToTable("TempGroups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempKerberos", b => + { + b.Property("Kerberos") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Kerberos"); + + b.ToTable("TempKerberos"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Email") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Iam") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("MothraId") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("Iam") + .IsUnique() + .HasFilter("[Iam] IS NOT NULL"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Account", null) + .WithMany() + .HasForeignKey("AccountsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Cluster", null) + .WithMany() + .HasForeignKey("ClustersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Accounts") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Cluster"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Groups") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.HasOne("Hippo.Core.Domain.User", "ActedBy") + .WithMany() + .HasForeignKey("ActedById") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("History") + .HasForeignKey("OrderId"); + + b.Navigation("ActedBy"); + + b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.HasOne("Hippo.Core.Domain.Request", "Request") + .WithMany("QueuedEvents") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Request"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.HasOne("Hippo.Core.Domain.User", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Requester") + .WithMany() + .HasForeignKey("RequesterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Actor"); + + b.Navigation("Cluster"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Navigation("Accounts"); + + b.Navigation("FinancialDetail"); + + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Navigation("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Orders"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Hippo.Core/Migrations/SqlServer/20240515155511_ReplaceFlagWithType.cs b/Hippo.Core/Migrations/SqlServer/20240515155511_ReplaceFlagWithType.cs new file mode 100644 index 00000000..f7d9c6a2 --- /dev/null +++ b/Hippo.Core/Migrations/SqlServer/20240515155511_ReplaceFlagWithType.cs @@ -0,0 +1,46 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hippo.Core.Migrations.SqlServer +{ + public partial class ReplaceFlagWithType : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ShowToUser", + table: "Histories"); + + migrationBuilder.AddColumn( + name: "Type", + table: "Histories", + type: "nvarchar(50)", + maxLength: 50, + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Histories_Type", + table: "Histories", + column: "Type"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Histories_Type", + table: "Histories"); + + migrationBuilder.DropColumn( + name: "Type", + table: "Histories"); + + migrationBuilder.AddColumn( + name: "ShowToUser", + table: "Histories", + type: "bit", + nullable: false, + defaultValue: false); + } + } +} diff --git a/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs b/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs index 026e61ab..4c5672f7 100644 --- a/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs +++ b/Hippo.Core/Migrations/SqlServer/AppDbContextSqlServerModelSnapshot.cs @@ -334,13 +334,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("OrderId") .HasColumnType("int"); - b.Property("ShowToUser") - .HasColumnType("bit"); - b.Property("Status") .HasMaxLength(50) .HasColumnType("nvarchar(50)"); + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + b.HasKey("Id"); b.HasIndex("ActedById"); @@ -353,6 +354,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("OrderId"); + b.HasIndex("Type"); + b.ToTable("Histories"); }); diff --git a/Hippo.Core/Migrations/Sqlite/20240515155507_ReplaceFlagWithType.Designer.cs b/Hippo.Core/Migrations/Sqlite/20240515155507_ReplaceFlagWithType.Designer.cs new file mode 100644 index 00000000..d900f913 --- /dev/null +++ b/Hippo.Core/Migrations/Sqlite/20240515155507_ReplaceFlagWithType.Designer.cs @@ -0,0 +1,1052 @@ +// +using System; +using Hippo.Core.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hippo.Core.Migrations.Sqlite +{ + [DbContext(typeof(AppDbContextSqlite))] + [Migration("20240515155507_ReplaceFlagWithType")] + partial class ReplaceFlagWithType + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.19"); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.Property("AccessTypesId") + .HasColumnType("INTEGER"); + + b.Property("AccountsId") + .HasColumnType("INTEGER"); + + b.HasKey("AccessTypesId", "AccountsId"); + + b.HasIndex("AccountsId"); + + b.ToTable("AccessTypeAccount"); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.Property("AccessTypesId") + .HasColumnType("INTEGER"); + + b.Property("ClustersId") + .HasColumnType("INTEGER"); + + b.HasKey("AccessTypesId", "ClustersId"); + + b.HasIndex("ClustersId"); + + b.ToTable("AccessTypeCluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.AccessType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AccessTypes"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("INTEGER"); + + b.Property("SshKey") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("CreatedOn"); + + b.HasIndex("Email"); + + b.HasIndex("Kerberos"); + + b.HasIndex("Name"); + + b.HasIndex("OwnerId"); + + b.HasIndex("UpdatedOn"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChartString") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Percentage") + .HasColumnType("TEXT"); + + b.Property("Updated") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Billings"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Domain") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("SshKeyId") + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("SshName") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("SshUrl") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Clusters"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoApprove") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("ChartString") + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("FinancialSystemApiSource") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("SecretAccessKey") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId") + .IsUnique(); + + b.ToTable("FinancialDetails"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DisplayName") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId", "Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.Property("AccountId") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupAdminAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.Property("AccountId") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.HasKey("AccountId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("GroupMemberAccount"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ActedById") + .HasColumnType("INTEGER"); + + b.Property("ActedDate") + .HasColumnType("TEXT"); + + b.Property("Action") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("AdminAction") + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ActedById"); + + b.HasIndex("ActedDate"); + + b.HasIndex("Action"); + + b.HasIndex("ClusterId"); + + b.HasIndex("OrderId"); + + b.HasIndex("Type"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Adjustment") + .HasColumnType("TEXT"); + + b.Property("AdjustmentReason") + .HasColumnType("TEXT"); + + b.Property("AdminNotes") + .HasColumnType("TEXT"); + + b.Property("BalanceRemaining") + .HasColumnType("TEXT"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("ExternalReference") + .HasMaxLength(150) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("PrincipalInvestigatorId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("SubTotal") + .HasColumnType("TEXT"); + + b.Property("Total") + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("PrincipalInvestigatorId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("OrderId", "Name", "Value"); + + b.ToTable("MetaData"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Details") + .HasColumnType("TEXT"); + + b.Property("FinancialSystemId") + .HasColumnType("TEXT"); + + b.Property("OrderId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("TrackingNumber") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Category") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.Property("Installments") + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UnitPrice") + .HasColumnType("TEXT"); + + b.Property("Units") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClusterId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("ErrorMessage") + .HasColumnType("TEXT"); + + b.Property("RequestId") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("RequestId"); + + b.HasIndex("Status"); + + b.HasIndex("UpdatedAt"); + + b.ToTable("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ActorId") + .HasColumnType("INTEGER"); + + b.Property("ClusterId") + .HasColumnType("INTEGER"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Group") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("RequesterId") + .HasColumnType("INTEGER"); + + b.Property("SshKey") + .HasColumnType("TEXT"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("SupervisingPI") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorId"); + + b.HasIndex("ClusterId"); + + b.HasIndex("Group"); + + b.HasIndex("RequesterId"); + + b.HasIndex("Status"); + + b.ToTable("Requests"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempGroup", b => + { + b.Property("Group") + .HasColumnType("TEXT"); + + b.HasKey("Group"); + + b.ToTable("TempGroups"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.TempKerberos", b => + { + b.Property("Kerberos") + .HasColumnType("TEXT"); + + b.HasKey("Kerberos"); + + b.ToTable("TempKerberos"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Iam") + .HasMaxLength(10) + .HasColumnType("TEXT"); + + b.Property("Kerberos") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("MothraId") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("Iam") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccessTypeAccount", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Account", null) + .WithMany() + .HasForeignKey("AccountsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AccessTypeCluster", b => + { + b.HasOne("Hippo.Core.Domain.AccessType", null) + .WithMany() + .HasForeignKey("AccessTypesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Cluster", null) + .WithMany() + .HasForeignKey("ClustersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Account", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Accounts") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Cluster"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Billing", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Billings") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.FinancialDetail", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithOne("FinancialDetail") + .HasForeignKey("Hippo.Core.Domain.FinancialDetail", "ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Group", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Groups") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupAdminAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.GroupMemberAccount", b => + { + b.HasOne("Hippo.Core.Domain.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.History", b => + { + b.HasOne("Hippo.Core.Domain.User", "ActedBy") + .WithMany() + .HasForeignKey("ActedById") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("History") + .HasForeignKey("OrderId"); + + b.Navigation("ActedBy"); + + b.Navigation("Cluster"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Orders") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "PrincipalInvestigator") + .WithMany("Orders") + .HasForeignKey("PrincipalInvestigatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("PrincipalInvestigator"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.OrderMetaData", b => + { + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("MetaData") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Payment", b => + { + b.HasOne("Hippo.Core.Domain.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("Hippo.Core.Domain.Order", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Permission", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Product", b => + { + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany("Products") + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Cluster"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.QueuedEvent", b => + { + b.HasOne("Hippo.Core.Domain.Request", "Request") + .WithMany("QueuedEvents") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Request"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.HasOne("Hippo.Core.Domain.User", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Hippo.Core.Domain.Cluster", "Cluster") + .WithMany() + .HasForeignKey("ClusterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Hippo.Core.Domain.User", "Requester") + .WithMany() + .HasForeignKey("RequesterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Actor"); + + b.Navigation("Cluster"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Cluster", b => + { + b.Navigation("Accounts"); + + b.Navigation("FinancialDetail"); + + b.Navigation("Groups"); + + b.Navigation("Orders"); + + b.Navigation("Products"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Order", b => + { + b.Navigation("Billings"); + + b.Navigation("History"); + + b.Navigation("MetaData"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.Request", b => + { + b.Navigation("QueuedEvents"); + }); + + modelBuilder.Entity("Hippo.Core.Domain.User", b => + { + b.Navigation("Accounts"); + + b.Navigation("Orders"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Hippo.Core/Migrations/Sqlite/20240515155507_ReplaceFlagWithType.cs b/Hippo.Core/Migrations/Sqlite/20240515155507_ReplaceFlagWithType.cs new file mode 100644 index 00000000..141b542d --- /dev/null +++ b/Hippo.Core/Migrations/Sqlite/20240515155507_ReplaceFlagWithType.cs @@ -0,0 +1,46 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hippo.Core.Migrations.Sqlite +{ + public partial class ReplaceFlagWithType : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ShowToUser", + table: "Histories"); + + migrationBuilder.AddColumn( + name: "Type", + table: "Histories", + type: "TEXT", + maxLength: 50, + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Histories_Type", + table: "Histories", + column: "Type"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Histories_Type", + table: "Histories"); + + migrationBuilder.DropColumn( + name: "Type", + table: "Histories"); + + migrationBuilder.AddColumn( + name: "ShowToUser", + table: "Histories", + type: "INTEGER", + nullable: false, + defaultValue: false); + } + } +} diff --git a/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs b/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs index 4600e93a..41615c08 100644 --- a/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs +++ b/Hippo.Core/Migrations/Sqlite/AppDbContextSqliteModelSnapshot.cs @@ -315,13 +315,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("OrderId") .HasColumnType("INTEGER"); - b.Property("ShowToUser") - .HasColumnType("INTEGER"); - b.Property("Status") .HasMaxLength(50) .HasColumnType("TEXT"); + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("TEXT"); + b.HasKey("Id"); b.HasIndex("ActedById"); @@ -334,6 +335,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("OrderId"); + b.HasIndex("Type"); + b.ToTable("Histories"); }); diff --git a/Hippo.Core/Services/HistoryService.cs b/Hippo.Core/Services/HistoryService.cs index 5d37e32f..969370b0 100644 --- a/Hippo.Core/Services/HistoryService.cs +++ b/Hippo.Core/Services/HistoryService.cs @@ -217,7 +217,7 @@ public static async Task OrderCreated(this IHistoryService historyService, Order ActedBy = actedBy, AdminAction = actedBy != order.PrincipalInvestigator, Action = History.OrderActions.Created, - ShowToUser = true, + Type = HistoryTypes.Primary, Details = $"Order total: {order.Total}" }; @@ -234,7 +234,7 @@ public static async Task OrderSnapshot(this IHistoryService historyService, Orde ActedBy = actedBy, AdminAction = actedBy != order.PrincipalInvestigator, Action = action, - ShowToUser = false, + Type = HistoryTypes.Detail, Details = Serialize(order) }; From 5ab7044cab933f1ac87996f3ee12ab6b2ce43eee Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 15 May 2024 09:21:37 -0700 Subject: [PATCH 053/301] cleanup --- .../src/components/Product/Products.tsx | 2 +- Hippo.Web/Controllers/OrderController.cs | 39 ++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Product/Products.tsx b/Hippo.Web/ClientApp/src/components/Product/Products.tsx index 7dd5e3bd..1adaf1b3 100644 --- a/Hippo.Web/ClientApp/src/components/Product/Products.tsx +++ b/Hippo.Web/ClientApp/src/components/Product/Products.tsx @@ -354,7 +354,7 @@ export const Products = () => { }, ], - [cluster, handleEdit], + [handleDelete, handleEdit], ); if (products === undefined) { diff --git a/Hippo.Web/Controllers/OrderController.cs b/Hippo.Web/Controllers/OrderController.cs index 35f75e65..27334e84 100644 --- a/Hippo.Web/Controllers/OrderController.cs +++ b/Hippo.Web/Controllers/OrderController.cs @@ -60,8 +60,43 @@ public async Task Get(int id) public async Task CreateOrder([FromBody] Order model) { var cluster = await _dbContext.Clusters.FirstAsync(a => a.Name == Cluster); + User principalInvestigator = null; + //Just for testing, will remove + //model = new Order + //{ + // Category = "Cat 123", + // Name = "The name of the order", + // Description = "The desc", + // ExternalReference = "This would be a link", + // Units = "TeraByte", + // UnitPrice = 0.51m, + // Installments = 60, + // Quantity = 400, + + // Notes = "A note worthy test", + // AdminNotes = "Wouldn't have an admin note here", + // Status = Order.Statuses.Created, + // Cluster = cluster, + // ClusterId = cluster.Id, + // CreatedOn = DateTime.UtcNow + //}; + + //model.AddMetaData("key", "value"); + //model.AddMetaData("key2", "value2"); + + //model.Billings.Add(new Billing + //{ + // ChartString = "123456", + // Percentage = 10 + //}); + //model.Billings.Add(new Billing + //{ + // ChartString = "123xxx456", + // Percentage = 90 + //}); + var currentUser = await _userService.GetCurrentUser(); @@ -90,6 +125,7 @@ public async Task CreateOrder([FromBody] Order model) UnitPrice = model.UnitPrice, Installments = model.Installments, Quantity = model.Quantity, + Billings = model.Billings, //Adjustment = model.Adjustment, //AdjustmentReason = model.AdjustmentReason, @@ -110,13 +146,14 @@ public async Task CreateOrder([FromBody] Order model) order.AddMetaData(metaData.Name, metaData.Value); } + await _dbContext.Orders.AddAsync(order); await _historyService.OrderCreated(order, currentUser); await _historyService.OrderSnapshot(order, currentUser, History.OrderActions.Created); - _dbContext.Orders.Add(order); await _dbContext.SaveChangesAsync(); + return Ok(order); } From 4505858bb85480097b34311d57546d0618de0191 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 15 May 2024 09:26:24 -0700 Subject: [PATCH 054/301] Ignore the cluster --- Hippo.Core/Domain/Order.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Hippo.Core/Domain/Order.cs b/Hippo.Core/Domain/Order.cs index 45ada4e2..94a55b13 100644 --- a/Hippo.Core/Domain/Order.cs +++ b/Hippo.Core/Domain/Order.cs @@ -48,6 +48,7 @@ public class Order [Required] public int ClusterId { get; set; } + [JsonIgnore] public Cluster Cluster { get; set; } From ad2ab51d4806557a4c8f8932a3eab96c300d2db8 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 15 May 2024 09:57:57 -0700 Subject: [PATCH 055/301] Cleanup --- Hippo.Web/ClientApp/src/App.tsx | 2 +- .../ClientApp/src/components/Financial/FinancialDetail.tsx | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Hippo.Web/ClientApp/src/App.tsx b/Hippo.Web/ClientApp/src/App.tsx index 9001eaa4..d7eef695 100644 --- a/Hippo.Web/ClientApp/src/App.tsx +++ b/Hippo.Web/ClientApp/src/App.tsx @@ -19,7 +19,7 @@ import { Clusters } from "./components/Account/Clusters"; import { Clusters as AdminClusters } from "./components/ClusterAdmin/Clusters"; import { Groups } from "./components/Admin/Groups"; import { ShowFor } from "./Shared/ShowFor"; -import FinancialDetail from "./components/Financial/FinancialDetail"; +import { FinancialDetail } from "./components/Financial/FinancialDetail"; import { Products } from "./components/Product/Products"; declare var Hippo: AppContextShape; diff --git a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx index 57a7e4bc..7d95a430 100644 --- a/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx +++ b/Hippo.Web/ClientApp/src/components/Financial/FinancialDetail.tsx @@ -10,7 +10,7 @@ declare const window: Window & Finjector: any; }; -const FinancialDetail: React.FC = () => { +export const FinancialDetail = () => { const [financialDetail, setFinancialDetail] = useState(null); const { cluster: clusterName } = useParams(); @@ -237,5 +237,3 @@ const FinancialDetail: React.FC = () => { ); }; - -export default FinancialDetail; From 15a06ad8b568990541dcc6f6ab994a36667c09ac Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 15 May 2024 09:58:16 -0700 Subject: [PATCH 056/301] First pass at the order type for react --- Hippo.Web/ClientApp/src/types.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Hippo.Web/ClientApp/src/types.ts b/Hippo.Web/ClientApp/src/types.ts index 4cce7fb1..774591cf 100644 --- a/Hippo.Web/ClientApp/src/types.ts +++ b/Hippo.Web/ClientApp/src/types.ts @@ -238,3 +238,25 @@ export interface ProductModel { unitPrice: string; installments: number; } + +export interface OrderMetadataModel { + id: number; + key: string; + value: string; +} + +export interface OrderBillingModel { + id: number; + chartString: string; + percent: string; + chartStringValidation: ChartStringValidationModel; +} + +export interface OrderModel { + id: number; + product: ProductModel; + quantity: number; + status: string; + metadata: OrderMetadataModel[]; + billing: OrderBillingModel[]; +} From 70bbda1988bbfd372327151969bd1c7fcd05efbc Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 15 May 2024 10:53:33 -0700 Subject: [PATCH 057/301] Order list model with projection --- Hippo.Web/Controllers/OrderController.cs | 4 +- .../Models/OrderModels/OrderListModel.cs | 37 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 Hippo.Web/Models/OrderModels/OrderListModel.cs diff --git a/Hippo.Web/Controllers/OrderController.cs b/Hippo.Web/Controllers/OrderController.cs index 27334e84..ff9cc74b 100644 --- a/Hippo.Web/Controllers/OrderController.cs +++ b/Hippo.Web/Controllers/OrderController.cs @@ -2,6 +2,7 @@ using Hippo.Core.Domain; using Hippo.Core.Models; using Hippo.Core.Services; +using Hippo.Web.Models.OrderModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -40,7 +41,8 @@ public async Task ValidateChartString(string chartSt public async Task MyOrders() { var currentUser = await _userService.GetCurrentUser(); - var orders = await _dbContext.Orders.Where(a => a.Cluster.Name == Cluster && a.PrincipalInvestigatorId == currentUser.Id).ToListAsync(); //Filters out inactive orders + var orders = await _dbContext.Orders.Where(a => a.Cluster.Name == Cluster && a.PrincipalInvestigatorId == currentUser.Id).Select(OrderListModel.Projection()).ToListAsync(); //Filters out inactive orders + return Ok(orders); } diff --git a/Hippo.Web/Models/OrderModels/OrderListModel.cs b/Hippo.Web/Models/OrderModels/OrderListModel.cs new file mode 100644 index 00000000..01f2bdc2 --- /dev/null +++ b/Hippo.Web/Models/OrderModels/OrderListModel.cs @@ -0,0 +1,37 @@ +using Hippo.Core.Extensions; +using System.Linq.Expressions; + +namespace Hippo.Web.Models.OrderModels +{ + public class OrderListModel + { + + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Units { get; set; } + public decimal Quantity { get; set; } + public DateTime CreatedOn { get; set; } + public string Status { get; set; } + public decimal Total { get; set; } + public decimal InstallmentAmount { get; set; } + public decimal BalanceRemaining { get; set; } + + public static Expression> Projection() + { + return order => new OrderListModel + { + Id = order.Id, + Name = order.Name, + Description = order.Description, + Units = order.Units, + Quantity = order.Quantity, + CreatedOn = order.CreatedOn.ToPacificTime(), + Status = order.Status, + Total = order.Total, + InstallmentAmount = order.InstallmentAmount, + BalanceRemaining = order.BalanceRemaining + }; + } + } +} From de08333c49dd1cb784cda9e827beade2bb54b73e Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 15 May 2024 13:11:01 -0700 Subject: [PATCH 058/301] WIP my orders --- Hippo.Web/ClientApp/src/App.tsx | 2 + Hippo.Web/ClientApp/src/AppNav.tsx | 10 ++ .../ClientApp/src/components/Order/Orders.tsx | 108 ++++++++++++++++++ .../src/components/Product/Products.tsx | 2 +- Hippo.Web/ClientApp/src/types.ts | 13 +++ Hippo.Web/Controllers/OrderController.cs | 6 +- 6 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 Hippo.Web/ClientApp/src/components/Order/Orders.tsx diff --git a/Hippo.Web/ClientApp/src/App.tsx b/Hippo.Web/ClientApp/src/App.tsx index d7eef695..9901bd89 100644 --- a/Hippo.Web/ClientApp/src/App.tsx +++ b/Hippo.Web/ClientApp/src/App.tsx @@ -21,6 +21,7 @@ import { Groups } from "./components/Admin/Groups"; import { ShowFor } from "./Shared/ShowFor"; import { FinancialDetail } from "./components/Financial/FinancialDetail"; import { Products } from "./components/Product/Products"; +import { Orders } from "./components/Order/Orders"; declare var Hippo: AppContextShape; @@ -103,6 +104,7 @@ const App = () => { } /> } /> + } /> diff --git a/Hippo.Web/ClientApp/src/AppNav.tsx b/Hippo.Web/ClientApp/src/AppNav.tsx index e0962c59..af7b2966 100644 --- a/Hippo.Web/ClientApp/src/AppNav.tsx +++ b/Hippo.Web/ClientApp/src/AppNav.tsx @@ -127,6 +127,16 @@ export const AppNav = () => { > Products
+ + isActive ? { fontWeight: "bold" } : {} + } + > + My Orders + diff --git a/Hippo.Web/ClientApp/src/components/Order/Orders.tsx b/Hippo.Web/ClientApp/src/components/Order/Orders.tsx new file mode 100644 index 00000000..ca26c673 --- /dev/null +++ b/Hippo.Web/ClientApp/src/components/Order/Orders.tsx @@ -0,0 +1,108 @@ +import React, { useEffect, useMemo, useState } from "react"; +import { OrderListModel } from "../../types"; +import { useParams } from "react-router-dom"; +import { authenticatedFetch } from "../../util/api"; +import { Column } from "react-table"; +import { ShowFor } from "../../Shared/ShowFor"; +import { ReactTable } from "../../Shared/ReactTable"; + +export const Orders = () => { + const [orders, setOrders] = useState(); + const { cluster } = useParams(); + + useEffect(() => { + const fetchOrders = async () => { + const response = await authenticatedFetch( + `/api/${cluster}/order/myorders`, + ); + + if (response.ok) { + const data = await response.json(); + setOrders(data); + } else { + alert("Error fetching orders"); + } + }; + + fetchOrders(); + }, [cluster]); + //add columns with useMemo + const columns = useMemo[]>( + () => [ + { + Header: "Order Status", + accessor: "status", + }, + { + Header: "Order Name", + accessor: "name", + }, + { + Header: "Description", + accessor: "description", + }, + { + Header: "Units", + accessor: "units", + }, + { + Header: "Quantity", + accessor: "quantity", + }, + { + Header: "Total", + accessor: "total", + }, + { + Header: "Installment Amount", + accessor: "installmentAmount", + }, + { + Header: "Balance Remaining", + accessor: "balanceRemaining", + }, + { + Header: "Order Created", + accessor: "createdOn", + }, + { + Header: "Actions", + sortable: false, + Cell: ({ row }) => ( +
+ {" "} + + {" "} + + +
+ ), + }, + ], + [], + ); + + if (orders === undefined) { + return ( +
+
Loading...
+
+ ); + } else { + return ( +
+
+
+ +
+
+
+ ); + } +}; diff --git a/Hippo.Web/ClientApp/src/components/Product/Products.tsx b/Hippo.Web/ClientApp/src/components/Product/Products.tsx index 1adaf1b3..d9fa7baf 100644 --- a/Hippo.Web/ClientApp/src/components/Product/Products.tsx +++ b/Hippo.Web/ClientApp/src/components/Product/Products.tsx @@ -41,7 +41,7 @@ export const Products = () => { const data = await response.json(); setProducts(data); } else { - alert("Error fetching groups"); + alert("Error fetching products"); } }; diff --git a/Hippo.Web/ClientApp/src/types.ts b/Hippo.Web/ClientApp/src/types.ts index 774591cf..06237974 100644 --- a/Hippo.Web/ClientApp/src/types.ts +++ b/Hippo.Web/ClientApp/src/types.ts @@ -260,3 +260,16 @@ export interface OrderModel { metadata: OrderMetadataModel[]; billing: OrderBillingModel[]; } + +export interface OrderListModel { + id: number; + name: string; + description: string; + units: string; + quantity: number; + createdOn: string; + status: string; + total: string; + installmentAmount: string; + balanceRemaining: string; +} diff --git a/Hippo.Web/Controllers/OrderController.cs b/Hippo.Web/Controllers/OrderController.cs index ff9cc74b..7db3d0fe 100644 --- a/Hippo.Web/Controllers/OrderController.cs +++ b/Hippo.Web/Controllers/OrderController.cs @@ -41,9 +41,11 @@ public async Task ValidateChartString(string chartSt public async Task MyOrders() { var currentUser = await _userService.GetCurrentUser(); - var orders = await _dbContext.Orders.Where(a => a.Cluster.Name == Cluster && a.PrincipalInvestigatorId == currentUser.Id).Select(OrderListModel.Projection()).ToListAsync(); //Filters out inactive orders + var model = await _dbContext.Orders.Where(a => a.Cluster.Name == Cluster && a.PrincipalInvestigatorId == currentUser.Id).Select(OrderListModel.Projection()).ToListAsync(); //Filters out inactive orders - return Ok(orders); + return Ok(model); + + //TODO: Need to create a page for this. } [HttpGet] From 3887cdaf9dc954cffe2c3966c86ebde300120ec5 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Wed, 15 May 2024 14:02:33 -0700 Subject: [PATCH 059/301] WIP, Order list page --- .../ClientApp/src/components/Order/Orders.tsx | 21 +++++-------------- Hippo.Web/ClientApp/src/types.ts | 1 - .../Models/OrderModels/OrderListModel.cs | 14 ++++++------- 3 files changed, 11 insertions(+), 25 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Order/Orders.tsx b/Hippo.Web/ClientApp/src/components/Order/Orders.tsx index ca26c673..52a128cd 100644 --- a/Hippo.Web/ClientApp/src/components/Order/Orders.tsx +++ b/Hippo.Web/ClientApp/src/components/Order/Orders.tsx @@ -30,17 +30,13 @@ export const Orders = () => { const columns = useMemo[]>( () => [ { - Header: "Order Status", + Header: "Status", accessor: "status", }, { Header: "Order Name", accessor: "name", }, - { - Header: "Description", - accessor: "description", - }, { Header: "Units", accessor: "units", @@ -54,15 +50,11 @@ export const Orders = () => { accessor: "total", }, { - Header: "Installment Amount", - accessor: "installmentAmount", - }, - { - Header: "Balance Remaining", + Header: "Balance", accessor: "balanceRemaining", }, { - Header: "Order Created", + Header: "Created On", accessor: "createdOn", }, { @@ -70,11 +62,8 @@ export const Orders = () => { sortable: false, Cell: ({ row }) => (
- {" "} - - {" "} - - + {" "} + {" "}
), }, diff --git a/Hippo.Web/ClientApp/src/types.ts b/Hippo.Web/ClientApp/src/types.ts index 06237974..3a1fb463 100644 --- a/Hippo.Web/ClientApp/src/types.ts +++ b/Hippo.Web/ClientApp/src/types.ts @@ -270,6 +270,5 @@ export interface OrderListModel { createdOn: string; status: string; total: string; - installmentAmount: string; balanceRemaining: string; } diff --git a/Hippo.Web/Models/OrderModels/OrderListModel.cs b/Hippo.Web/Models/OrderModels/OrderListModel.cs index 01f2bdc2..ad3bf1ff 100644 --- a/Hippo.Web/Models/OrderModels/OrderListModel.cs +++ b/Hippo.Web/Models/OrderModels/OrderListModel.cs @@ -11,11 +11,10 @@ public class OrderListModel public string Description { get; set; } public string Units { get; set; } public decimal Quantity { get; set; } - public DateTime CreatedOn { get; set; } + public string CreatedOn { get; set; } public string Status { get; set; } - public decimal Total { get; set; } - public decimal InstallmentAmount { get; set; } - public decimal BalanceRemaining { get; set; } + public string Total { get; set; } + public string BalanceRemaining { get; set; } public static Expression> Projection() { @@ -26,11 +25,10 @@ public class OrderListModel Description = order.Description, Units = order.Units, Quantity = order.Quantity, - CreatedOn = order.CreatedOn.ToPacificTime(), + CreatedOn = order.CreatedOn.ToPacificTime().ToShortDateString(), Status = order.Status, - Total = order.Total, - InstallmentAmount = order.InstallmentAmount, - BalanceRemaining = order.BalanceRemaining + Total = order.Total.ToString("C"), + BalanceRemaining = order.BalanceRemaining.ToString("C") }; } } From e032b026e5f3190c4013d6519896405508bec028 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Thu, 16 May 2024 11:04:31 -0700 Subject: [PATCH 060/301] WIP order details --- Hippo.Web/ClientApp/src/App.tsx | 5 +++ .../src/components/Order/Details.tsx | 40 +++++++++++++++++++ .../ClientApp/src/components/Order/Orders.tsx | 9 ++++- Hippo.Web/ClientApp/src/types.ts | 25 +++++++++++- 4 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 Hippo.Web/ClientApp/src/components/Order/Details.tsx diff --git a/Hippo.Web/ClientApp/src/App.tsx b/Hippo.Web/ClientApp/src/App.tsx index 9901bd89..a1e9ac2c 100644 --- a/Hippo.Web/ClientApp/src/App.tsx +++ b/Hippo.Web/ClientApp/src/App.tsx @@ -22,6 +22,7 @@ import { ShowFor } from "./Shared/ShowFor"; import { FinancialDetail } from "./components/Financial/FinancialDetail"; import { Products } from "./components/Product/Products"; import { Orders } from "./components/Order/Orders"; +import { Details } from "./components/Order/Details"; declare var Hippo: AppContextShape; @@ -105,6 +106,10 @@ const App = () => { /> } /> } /> + } + /> diff --git a/Hippo.Web/ClientApp/src/components/Order/Details.tsx b/Hippo.Web/ClientApp/src/components/Order/Details.tsx new file mode 100644 index 00000000..bfe4c63e --- /dev/null +++ b/Hippo.Web/ClientApp/src/components/Order/Details.tsx @@ -0,0 +1,40 @@ +import React, { useEffect, useState } from "react"; +import { useParams } from "react-router-dom"; +import { OrderModel } from "../../types"; +import { authenticatedFetch } from "../../util/api"; + +export const Details = () => { + const { cluster, orderId } = useParams(); + const [order, setOrder] = useState(null); + + useEffect(() => { + const fetchOrder = async () => { + const response = await authenticatedFetch( + `/api/${cluster}/order/get/${orderId}`, + ); + + if (response.ok) { + const data = await response.json(); + setOrder(data); + } else { + alert("Error fetching order"); + } + }; + + fetchOrder(); + }, [cluster, orderId]); + + if (!order) { + return
Loading...
; + } + + return ( +
+

Order Details

+

Order ID: {order.id}

+ +

Order Name: {order.name}

+ {/* Add more details as needed */} +
+ ); +}; diff --git a/Hippo.Web/ClientApp/src/components/Order/Orders.tsx b/Hippo.Web/ClientApp/src/components/Order/Orders.tsx index 52a128cd..e6acd422 100644 --- a/Hippo.Web/ClientApp/src/components/Order/Orders.tsx +++ b/Hippo.Web/ClientApp/src/components/Order/Orders.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useMemo, useState } from "react"; import { OrderListModel } from "../../types"; -import { useParams } from "react-router-dom"; +import { Link, useParams } from "react-router-dom"; import { authenticatedFetch } from "../../util/api"; import { Column } from "react-table"; import { ShowFor } from "../../Shared/ShowFor"; @@ -62,7 +62,12 @@ export const Orders = () => { sortable: false, Cell: ({ row }) => (
- {" "} + + Details + {" "} {" "}
), diff --git a/Hippo.Web/ClientApp/src/types.ts b/Hippo.Web/ClientApp/src/types.ts index 3a1fb463..d1ef17f7 100644 --- a/Hippo.Web/ClientApp/src/types.ts +++ b/Hippo.Web/ClientApp/src/types.ts @@ -252,13 +252,36 @@ export interface OrderBillingModel { chartStringValidation: ChartStringValidationModel; } +export interface PaymentModel { + id: number; + amount: string; + status: string; + createdOn: string; + //Possibly have the chart string(s) and percent here +} +export interface HistoryModel { + id: number; + actedBy: User; + action: string; + status: string; + details: string; + actedDate: string; +} + export interface OrderModel { id: number; - product: ProductModel; + category: string; + name: string; + description: string; + units: string; + unitPrice: string; + installments: number; quantity: number; status: string; metadata: OrderMetadataModel[]; billing: OrderBillingModel[]; + payments: PaymentModel[]; + history: HistoryModel[]; } export interface OrderListModel { From 2057f72728c666a458607327bc2a6edbf9931f99 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Thu, 16 May 2024 14:36:47 -0700 Subject: [PATCH 061/301] WIP, projection to get json ignored info from order --- .../src/components/Order/Details.tsx | 4 ++ Hippo.Web/ClientApp/src/types.ts | 2 +- Hippo.Web/Controllers/OrderController.cs | 10 ++-- .../Models/OrderModels/OrderDetailModel.cs | 46 +++++++++++++++++++ 4 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 Hippo.Web/Models/OrderModels/OrderDetailModel.cs diff --git a/Hippo.Web/ClientApp/src/components/Order/Details.tsx b/Hippo.Web/ClientApp/src/components/Order/Details.tsx index bfe4c63e..0a977199 100644 --- a/Hippo.Web/ClientApp/src/components/Order/Details.tsx +++ b/Hippo.Web/ClientApp/src/components/Order/Details.tsx @@ -28,12 +28,16 @@ export const Details = () => { return
Loading...
; } + console.log(order); + return (

Order Details

Order ID: {order.id}

Order Name: {order.name}

+

History 1 : {order.history[0].details}

+

History 2 : {order.history[0].actedBy.email}

{/* Add more details as needed */}
); diff --git a/Hippo.Web/ClientApp/src/types.ts b/Hippo.Web/ClientApp/src/types.ts index d1ef17f7..b8cc8faf 100644 --- a/Hippo.Web/ClientApp/src/types.ts +++ b/Hippo.Web/ClientApp/src/types.ts @@ -279,7 +279,7 @@ export interface OrderModel { quantity: number; status: string; metadata: OrderMetadataModel[]; - billing: OrderBillingModel[]; + billings: OrderBillingModel[]; payments: PaymentModel[]; history: HistoryModel[]; } diff --git a/Hippo.Web/Controllers/OrderController.cs b/Hippo.Web/Controllers/OrderController.cs index 7db3d0fe..6e18047d 100644 --- a/Hippo.Web/Controllers/OrderController.cs +++ b/Hippo.Web/Controllers/OrderController.cs @@ -51,12 +51,16 @@ public async Task MyOrders() [HttpGet] public async Task Get(int id) { - var order = await _dbContext.Orders.Include(a => a.MetaData).Include(a => a.Payments).Include(a => a.PrincipalInvestigator).Include(a => a.History).SingleOrDefaultAsync(a => a.Cluster.Name == Cluster && a.Id == id); - if (order == null) + var model = await _dbContext.Orders.Where(a => a.Cluster.Name == Cluster && a.Id == id) + .Include(a => a.MetaData).Include(a => a.Payments).Include(a => a.PrincipalInvestigator) + .Include(a => a.History.Where(w => w.Type == History.HistoryTypes.Primary)).ThenInclude(a => a.ActedBy) + .Select(OrderDetailModel.Projection()) + .SingleOrDefaultAsync(); + if (model == null) { return NotFound(); } - return Ok(order); + return Ok(model); } diff --git a/Hippo.Web/Models/OrderModels/OrderDetailModel.cs b/Hippo.Web/Models/OrderModels/OrderDetailModel.cs new file mode 100644 index 00000000..4d45572c --- /dev/null +++ b/Hippo.Web/Models/OrderModels/OrderDetailModel.cs @@ -0,0 +1,46 @@ +using Hippo.Core.Domain; +using System.Linq.Expressions; + +namespace Hippo.Web.Models.OrderModels +{ + public class OrderDetailModel + { + public int Id { get; set; } + public string Category { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string Units { get; set; } = string.Empty; + public decimal UnitPrice { get; set; } + public int Installments { get; set; } + public decimal Quantity { get; set; } + public string Status { get; set; } = string.Empty; + public string ExternalReference { get; set; } = string.Empty; + + public List MetaData { get; set; } = new(); + public List History { get; set; } = new(); + public List Billings { get; set; } = new(); + public List Payments { get; set; } = new(); + //TODO: will need to add more + + public static Expression> Projection() + { + return order => new OrderDetailModel + { + Id = order.Id, + Category = order.Category, + Name = order.Name, + Description = order.Description, + Units = order.Units, + UnitPrice = order.UnitPrice, + Installments = order.Installments, + Quantity = order.Quantity, + Status = order.Status, + ExternalReference = order.ExternalReference, + MetaData = order.MetaData, + History = order.History, + Billings = order.Billings, + Payments = order.Payments + }; + } + } +} From bfcbe434c8fe83606391fc077cabbd59a1a25108 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Thu, 16 May 2024 15:06:22 -0700 Subject: [PATCH 062/301] WIP --- .../src/components/Order/Details.tsx | 45 ++++++++++++++++--- .../Models/OrderModels/OrderDetailModel.cs | 2 +- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Order/Details.tsx b/Hippo.Web/ClientApp/src/components/Order/Details.tsx index 0a977199..c7d0a274 100644 --- a/Hippo.Web/ClientApp/src/components/Order/Details.tsx +++ b/Hippo.Web/ClientApp/src/components/Order/Details.tsx @@ -1,7 +1,9 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { useParams } from "react-router-dom"; -import { OrderModel } from "../../types"; +import { HistoryModel, OrderModel } from "../../types"; import { authenticatedFetch } from "../../util/api"; +import { Column } from "react-table"; +import { ReactTable } from "../../Shared/ReactTable"; export const Details = () => { const { cluster, orderId } = useParams(); @@ -24,6 +26,33 @@ export const Details = () => { fetchOrder(); }, [cluster, orderId]); + const historyColumns = useMemo[]>( + () => [ + { + Header: "Date", + accessor: "actedDate", + }, + { + Header: "Actor", + accessor: "actedBy", + Cell: ({ value }) => ( + + {value.firstName} {value.lastName} ({value.email}) + + ), + }, + { + Header: "Status", + accessor: "status", + }, + { + Header: "Details", + accessor: "details", + }, + ], + [], + ); + if (!order) { return
Loading...
; } @@ -36,9 +65,15 @@ export const Details = () => {

Order ID: {order.id}

Order Name: {order.name}

-

History 1 : {order.history[0].details}

-

History 2 : {order.history[0].actedBy.email}

- {/* Add more details as needed */} + +

History

+ ); }; diff --git a/Hippo.Web/Models/OrderModels/OrderDetailModel.cs b/Hippo.Web/Models/OrderModels/OrderDetailModel.cs index 4d45572c..b5cb3cab 100644 --- a/Hippo.Web/Models/OrderModels/OrderDetailModel.cs +++ b/Hippo.Web/Models/OrderModels/OrderDetailModel.cs @@ -37,7 +37,7 @@ public static Expression> Projection() Status = order.Status, ExternalReference = order.ExternalReference, MetaData = order.MetaData, - History = order.History, + History = (List)order.History.Where(a => a.Type == Hippo.Core.Domain.History.HistoryTypes.Primary), Billings = order.Billings, Payments = order.Payments }; From 53830d44a5d1df8e1af6393ee16c42ddb8ac4f6d Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Thu, 16 May 2024 16:05:28 -0700 Subject: [PATCH 063/301] Trying to validate --- .../src/components/Order/Details.tsx | 91 ++++++++++++++++--- Hippo.Web/ClientApp/src/types.ts | 8 +- 2 files changed, 84 insertions(+), 15 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Order/Details.tsx b/Hippo.Web/ClientApp/src/components/Order/Details.tsx index c7d0a274..071c5988 100644 --- a/Hippo.Web/ClientApp/src/components/Order/Details.tsx +++ b/Hippo.Web/ClientApp/src/components/Order/Details.tsx @@ -1,6 +1,11 @@ import React, { useEffect, useMemo, useState } from "react"; import { useParams } from "react-router-dom"; -import { HistoryModel, OrderModel } from "../../types"; +import { + HistoryModel, + OrderBillingModel, + OrderMetadataModel, + OrderModel, +} from "../../types"; import { authenticatedFetch } from "../../util/api"; import { Column } from "react-table"; import { ReactTable } from "../../Shared/ReactTable"; @@ -26,11 +31,28 @@ export const Details = () => { fetchOrder(); }, [cluster, orderId]); + let validateChartString = async (chartString: string) => { + let response = await authenticatedFetch( + `/api/order/validateChartString/${chartString}`, + { + method: "GET", + }, + ); + //console.log(response); + if (response.ok) { + const result = await response.json(); + console.log(result); + //setChartStringValidation(result); + return result.isValid; + } + }; + const historyColumns = useMemo[]>( () => [ { Header: "Date", accessor: "actedDate", + Cell: ({ value }) => {new Date(value).toLocaleString()}, }, { Header: "Actor", @@ -53,6 +75,41 @@ export const Details = () => { [], ); + const billingColumns = useMemo[]>( + () => [ + { + Header: "Chart String", + accessor: "chartString", + }, + { + Header: "Percent", + accessor: "percentage", + }, + { + Header: "Chart String Validation", + accessor: async (row) => await validateChartString(row.chartString), + Cell: ({ value }) => ( + {value === true ? "Valid" : "Invalid"} + ), + }, + ], + [], + ); + + const metadataColumns = useMemo[]>( + () => [ + { + Header: "Name", + accessor: "name", + }, + { + Header: "Value", + accessor: "value", + }, + ], + [], + ); + if (!order) { return
Loading...
; } @@ -61,19 +118,29 @@ export const Details = () => { return (
-

Order Details

-

Order ID: {order.id}

+
+
+

Order Details

+

Order ID: {order.id}

+ +

Order Name: {order.name}

+ +

Chart Strings

+ -

Order Name: {order.name}

+

Metadata

+ -

History

- +

History

+ +
+
); }; diff --git a/Hippo.Web/ClientApp/src/types.ts b/Hippo.Web/ClientApp/src/types.ts index b8cc8faf..5fdddf8c 100644 --- a/Hippo.Web/ClientApp/src/types.ts +++ b/Hippo.Web/ClientApp/src/types.ts @@ -241,14 +241,14 @@ export interface ProductModel { export interface OrderMetadataModel { id: number; - key: string; + name: string; value: string; } export interface OrderBillingModel { id: number; chartString: string; - percent: string; + percentage: string; chartStringValidation: ChartStringValidationModel; } @@ -278,7 +278,9 @@ export interface OrderModel { installments: number; quantity: number; status: string; - metadata: OrderMetadataModel[]; + createdOn: string; + externalReference: string; + metaData: OrderMetadataModel[]; billings: OrderBillingModel[]; payments: PaymentModel[]; history: HistoryModel[]; From 7fa5f529f1aa0ccec0aee184e4ea06a9452ee3e3 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Fri, 17 May 2024 07:39:36 -0700 Subject: [PATCH 064/301] wip --- Hippo.Web/ClientApp/src/components/Order/Details.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hippo.Web/ClientApp/src/components/Order/Details.tsx b/Hippo.Web/ClientApp/src/components/Order/Details.tsx index 071c5988..731dc9c1 100644 --- a/Hippo.Web/ClientApp/src/components/Order/Details.tsx +++ b/Hippo.Web/ClientApp/src/components/Order/Details.tsx @@ -31,7 +31,7 @@ export const Details = () => { fetchOrder(); }, [cluster, orderId]); - let validateChartString = async (chartString: string) => { + const validateChartString = async (chartString: string) => { let response = await authenticatedFetch( `/api/order/validateChartString/${chartString}`, { From 143f6f95381f500e65bf78f93911c442a39e55e9 Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Fri, 17 May 2024 11:13:34 -0700 Subject: [PATCH 065/301] River's awesome fixes --- .../Order/ChartStringValidation.tsx | 78 +++++++++++++++++++ .../src/components/Order/Details.tsx | 57 +++++--------- 2 files changed, 97 insertions(+), 38 deletions(-) create mode 100644 Hippo.Web/ClientApp/src/components/Order/ChartStringValidation.tsx diff --git a/Hippo.Web/ClientApp/src/components/Order/ChartStringValidation.tsx b/Hippo.Web/ClientApp/src/components/Order/ChartStringValidation.tsx new file mode 100644 index 00000000..59d9c328 --- /dev/null +++ b/Hippo.Web/ClientApp/src/components/Order/ChartStringValidation.tsx @@ -0,0 +1,78 @@ +import React from "react"; +import { authenticatedFetch } from "../../util/api"; +import { ChartStringValidationModel } from "../../types"; +import { faCircleNotch } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +interface ChartStringValidationProps { + chartString: string; +} + +type ChartStringStatus = "loading" | "error" | "success" | undefined; + +const ChartStringValidation: React.FC = ({ + chartString, +}) => { + const [chartStringValidation, setChartStringValidation] = + React.useState(null); + const [status, setStatus] = React.useState(undefined); + + React.useEffect(() => { + if (!chartString) { + setStatus(undefined); + return; + } + + const validateChartString = async () => { + setStatus("loading"); + try { + let response = await authenticatedFetch( + `/api/order/validateChartString/${chartString}`, + { + method: "GET", + }, + ); + if (response.ok) { + const result: ChartStringValidationModel = await response.json(); + setChartStringValidation(result); + setStatus("success"); + } else { + setStatus("error"); + } + } catch (error) { + setStatus("error"); + } + }; + + validateChartString(); + }, [chartString]); + + // default to showing loading state on mount + if (status === "loading" || status === undefined) { + return ( + + + + ); + } + + if (status === "error") { + return Error loading chart string validation; + } + + return ( + + {chartStringValidation.isValid ? ( + + {chartStringValidation.description} + + ) : ( + + {chartStringValidation.message} + + )} + + ); +}; + +export default ChartStringValidation; diff --git a/Hippo.Web/ClientApp/src/components/Order/Details.tsx b/Hippo.Web/ClientApp/src/components/Order/Details.tsx index 731dc9c1..c3685dd0 100644 --- a/Hippo.Web/ClientApp/src/components/Order/Details.tsx +++ b/Hippo.Web/ClientApp/src/components/Order/Details.tsx @@ -9,6 +9,7 @@ import { import { authenticatedFetch } from "../../util/api"; import { Column } from "react-table"; import { ReactTable } from "../../Shared/ReactTable"; +import ChartStringValidation from "./ChartStringValidation"; export const Details = () => { const { cluster, orderId } = useParams(); @@ -31,22 +32,6 @@ export const Details = () => { fetchOrder(); }, [cluster, orderId]); - const validateChartString = async (chartString: string) => { - let response = await authenticatedFetch( - `/api/order/validateChartString/${chartString}`, - { - method: "GET", - }, - ); - //console.log(response); - if (response.ok) { - const result = await response.json(); - console.log(result); - //setChartStringValidation(result); - return result.isValid; - } - }; - const historyColumns = useMemo[]>( () => [ { @@ -75,27 +60,6 @@ export const Details = () => { [], ); - const billingColumns = useMemo[]>( - () => [ - { - Header: "Chart String", - accessor: "chartString", - }, - { - Header: "Percent", - accessor: "percentage", - }, - { - Header: "Chart String Validation", - accessor: async (row) => await validateChartString(row.chartString), - Cell: ({ value }) => ( - {value === true ? "Valid" : "Invalid"} - ), - }, - ], - [], - ); - const metadataColumns = useMemo[]>( () => [ { @@ -126,7 +90,24 @@ export const Details = () => {

Order Name: {order.name}

Chart Strings

- + + + + + + + + + + {order.billings.map((billing) => ( + + + + + + ))} + +
Chart StringPercentChart String Validation
{billing.chartString}{billing.percentage}

Metadata

From 141a4ccf5e8241f8153c82a762b48b1bee0f490e Mon Sep 17 00:00:00 2001 From: Jason Sylvestre Date: Mon, 20 May 2024 08:31:07 -0700 Subject: [PATCH 066/301] Add more details --- .../src/components/Order/Details.tsx | 114 +++++++++++++++--- Hippo.Web/ClientApp/src/types.ts | 3 + .../Models/OrderModels/OrderDetailModel.cs | 8 ++ 3 files changed, 111 insertions(+), 14 deletions(-) diff --git a/Hippo.Web/ClientApp/src/components/Order/Details.tsx b/Hippo.Web/ClientApp/src/components/Order/Details.tsx index c3685dd0..f78ba9bb 100644 --- a/Hippo.Web/ClientApp/src/components/Order/Details.tsx +++ b/Hippo.Web/ClientApp/src/components/Order/Details.tsx @@ -84,10 +84,94 @@ export const Details = () => {
-

Order Details

-

Order ID: {order.id}

+

Order Details: Id {order.id}

+
+ + +
+
+ +