From 21fb4b02aaac82b2fd3144c6d836b1c35277b8fa Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Mon, 2 Feb 2026 13:49:10 -0800 Subject: [PATCH 01/42] AB#31067: Show non-published form versions in the Parent Form dropdown --- .../ApplicationForms/ApplicationFormAppService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs index a26a91a97..0dfdaca42 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs @@ -257,7 +257,6 @@ public async Task> GetParentFormLookupAsync( var query = from form in formsQueryable join version in versionsQueryable on form.Id equals version.ApplicationFormId - where version.Published select new { form, version }; if (input.ExcludeFormId.HasValue) From 0beb5078b391012aa3053eb022599771460cef37 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Wed, 4 Feb 2026 16:11:53 -0800 Subject: [PATCH 02/42] AB#31067: Deduct paid/pending child amounts from parent amount --- .../CreatePaymentRequests.cshtml | 2 ++ .../CreatePaymentRequests.cshtml.cs | 23 +++++++++++++++++-- .../CreatePaymentRequestsModal.js | 6 ++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml index 751f452ef..10a747240 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml @@ -163,6 +163,8 @@ (function () { if (window.jQuery) { $('.unity-currency-input').maskMoney(); + // Validate payment amounts on initial page load + validateAllPaymentAmounts(); } })(); diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs index d54ee06cf..a75b7ff6b 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs @@ -214,9 +214,28 @@ private async Task GetRemainingAmountAllowedByApplicationAsync(GrantApp { decimal approvedAmmount = application.ApprovedAmount; decimal totalFutureRequested = await paymentRequestAppService.GetTotalPaymentRequestAmountByCorrelationIdAsync(application.Id); - if (approvedAmmount > totalFutureRequested) + + // If this application has children, include their paid/pending amounts too + decimal childrenTotalPaidPending = 0; + var applicationLinks = await applicationLinksService.GetListByApplicationAsync(application.Id); + var childLinks = applicationLinks.Where(link => link.LinkType == ApplicationLinkType.Child).ToList(); + + if (childLinks.Count > 0) + { + // This is a parent application, sum up all children's paid/pending payments + foreach (var childLink in childLinks) + { + decimal childTotal = await paymentRequestAppService + .GetTotalPaymentRequestAmountByCorrelationIdAsync(childLink.ApplicationId); + childrenTotalPaidPending += childTotal; + } + } + + // Calculate remaining: Approved - (Parent Paid/Pending + Children Paid/Pending) + decimal totalConsumed = totalFutureRequested + childrenTotalPaidPending; + if (approvedAmmount > totalConsumed) { - remainingAmount = approvedAmmount - totalFutureRequested; + remainingAmount = approvedAmmount - totalConsumed; } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequestsModal.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequestsModal.js index c9a8f1315..f07bfd6cd 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequestsModal.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequestsModal.js @@ -221,11 +221,11 @@ function validateParentChildAmounts(correlationId) { let errorMessage = $(`#parent_child_error_message_${memberId}`); if (hasError) { - let message = `Parent-child total (${formatCurrency( + let message = `The payment amount (${formatCurrency( groupTotal - )}) exceeds maximum allowed by parent (${formatCurrency( + )}) exceeds the parent's approved amount (${formatCurrency( maximumAllowed - )})`; + )}).`; errorMessage.text(message); errorDiv.css('display', 'block'); } else { From 56defc04e59566703c1c827ba7d38f8e8f9c7461 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Wed, 4 Feb 2026 18:12:45 -0800 Subject: [PATCH 03/42] AB#31067: Form Hierarchy is no longer dependent to Application Form Version Form Hierarchy in Payment Configuration is no longer dependent to the Application Form Version --- .../CreatePaymentRequests.cshtml.cs | 10 +- .../PaymentRequestAppService_Tests.cs | 4 +- .../FormPaymentConfiguration.cs | 1 - .../ApplicationForms/ParentFormLookupDto.cs | 2 - .../ApplicationFormAppService.cs | 34 +- .../GrantManagerDomainErrorCodes.cs | 2 - .../Localization/GrantManager/en.json | 2 - .../Applications/ApplicationForm.cs | 1 - .../GrantTenantDbContext.cs | 6 - ...914_Remove_ParentFormVersionId.Designer.cs | 4569 +++++++++++++++++ ...260205015914_Remove_ParentFormVersionId.cs | 55 + .../GrantTenantDbContextModelSnapshot.cs | 10 - .../PaymentConfiguration/Default.cshtml | 9 +- .../PaymentConfiguration/Default.js | 45 +- .../PaymentConfigurationViewComponent.cs | 8 +- .../PaymentConfigurationViewModel.cs | 1 - .../PaymentConfigurationValidationTests.cs | 34 +- 17 files changed, 4659 insertions(+), 134 deletions(-) create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260205015914_Remove_ParentFormVersionId.Designer.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260205015914_Remove_ParentFormVersionId.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs index a75b7ff6b..04dcb568d 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs @@ -276,9 +276,8 @@ private async Task GetRemainingAmountAllowedByApplicationAsync(GrantApp return (errors, parentReferenceNo); // No validation needed } - // Check if ParentFormId and ParentFormVersionId are set - if (!applicationForm.ParentFormId.HasValue || - !applicationForm.ParentFormVersionId.HasValue) + // Check if ParentFormId is set + if (!applicationForm.ParentFormId.HasValue) { // Configuration issue - should not happen if validation works return (errors, parentReferenceNo); @@ -303,11 +302,10 @@ private async Task GetRemainingAmountAllowedByApplicationAsync(GrantApp var parentApplication = await applicationService.GetAsync(parentLink.ApplicationId); parentReferenceNo = parentApplication.ReferenceNo; - // Validate both ParentFormId and ParentFormVersionId + // Validate ParentFormId matches bool formIdMatches = parentFormDetails.ApplicationFormId == applicationForm.ParentFormId.Value; - bool versionIdMatches = parentFormDetails.ApplicationFormVersionId == applicationForm.ParentFormVersionId.Value; - if (!formIdMatches || !versionIdMatches) + if (!formIdMatches) { errors.Add("The selected parent form in Payment Configuration does not match the application's linked parent. Please verify and try again."); return (errors, parentReferenceNo); diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/BatchPaymentRequests/PaymentRequestAppService_Tests.cs b/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/BatchPaymentRequests/PaymentRequestAppService_Tests.cs index 162fa4f7d..876e854b7 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/BatchPaymentRequests/PaymentRequestAppService_Tests.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/BatchPaymentRequests/PaymentRequestAppService_Tests.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; -using Shouldly; +using Shouldly; using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -8,7 +7,6 @@ using Unity.Payments.Domain.Suppliers.ValueObjects; using Unity.Payments.Enums; using Volo.Abp.Uow; -using Volo.Abp.Users; using Xunit; namespace Unity.Payments.PaymentRequests; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/FormPaymentConfiguration.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/FormPaymentConfiguration.cs index f2d177262..7991d7d21 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/FormPaymentConfiguration.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/FormPaymentConfiguration.cs @@ -13,7 +13,6 @@ public class FormPaymentConfigurationDto public decimal? PaymentApprovalThreshold { get; set; } public FormHierarchyType? FormHierarchy { get; set; } public Guid? ParentFormId { get; set; } - public Guid? ParentFormVersionId { get; set; } public PaymentGroup? DefaultPaymentGroup { get; set; } } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ParentFormLookupDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ParentFormLookupDto.cs index e5d61d1de..969b87337 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ParentFormLookupDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ParentFormLookupDto.cs @@ -20,8 +20,6 @@ public ParentFormLookupRequestDto() public class ParentFormLookupDto { public Guid ApplicationFormId { get; set; } - public Guid ApplicationFormVersionId { get; set; } public string ApplicationFormName { get; set; } = string.Empty; - public int? Version { get; set; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs index 0dfdaca42..4733ad469 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs @@ -206,11 +206,6 @@ public async Task SavePaymentConfiguration(FormPaymentConfigurationDto dto) throw new BusinessException(GrantManagerDomainErrorCodes.ChildFormRequiresParentForm); } - if (!dto.ParentFormVersionId.HasValue) - { - throw new BusinessException(GrantManagerDomainErrorCodes.ChildFormRequiresParentFormVersion); - } - if (dto.ParentFormId.Value == appForm.Id) { throw new BusinessException(GrantManagerDomainErrorCodes.ChildFormCannotReferenceSelf); @@ -221,12 +216,6 @@ public async Task SavePaymentConfiguration(FormPaymentConfigurationDto dto) { throw new BusinessException(GrantManagerDomainErrorCodes.ChildFormRequiresParentForm); } - - var parentFormVersion = await _applicationFormVersionRepository.FindAsync(dto.ParentFormVersionId.Value); - if (parentFormVersion is null || parentFormVersion.ApplicationFormId != parentForm.Id) - { - throw new BusinessException(GrantManagerDomainErrorCodes.ParentFormVersionMismatch); - } } } @@ -236,7 +225,6 @@ public async Task SavePaymentConfiguration(FormPaymentConfigurationDto dto) appForm.PaymentApprovalThreshold = dto.PaymentApprovalThreshold; appForm.FormHierarchy = dto.FormHierarchy; appForm.ParentFormId = dto.ParentFormId; - appForm.ParentFormVersionId = dto.ParentFormVersionId; var resolvedDefaultPaymentGroup = dto.DefaultPaymentGroup ?? PaymentGroup.EFT; appForm.DefaultPaymentGroup = dto.Payable ? (int?)resolvedDefaultPaymentGroup : null; await Repository.UpdateAsync(appForm); @@ -252,42 +240,34 @@ public async Task> GetParentFormLookupAsync( var normalizedFilter = string.IsNullOrWhiteSpace(input.Filter) ? null : input.Filter.Trim(); var formsQueryable = await Repository.GetQueryableAsync(); - var versionsQueryable = await _applicationFormVersionRepository.GetQueryableAsync(); - - var query = - from form in formsQueryable - join version in versionsQueryable on form.Id equals version.ApplicationFormId - select new { form, version }; + var query = formsQueryable.AsQueryable(); if (input.ExcludeFormId.HasValue) { - query = query.Where(x => x.form.Id != input.ExcludeFormId.Value); + query = query.Where(x => x.Id != input.ExcludeFormId.Value); } if (!string.IsNullOrWhiteSpace(normalizedFilter)) { var loweredFilter = normalizedFilter.ToLowerInvariant(); query = query.Where(x => - x.form.ApplicationFormName != null && - x.form.ApplicationFormName.ToLower().Contains(loweredFilter)); + x.ApplicationFormName != null && + x.ApplicationFormName.ToLower().Contains(loweredFilter)); } var totalCount = await AsyncExecuter.CountAsync(query); var items = await AsyncExecuter.ToListAsync( query - .OrderBy(x => x.form.ApplicationFormName) - .ThenByDescending(x => x.version.Version) + .OrderBy(x => x.ApplicationFormName) .Skip(skipCount) .Take(maxResultCount) ); var results = items.Select(x => new ParentFormLookupDto { - ApplicationFormId = x.form.Id, - ApplicationFormVersionId = x.version.Id, - ApplicationFormName = x.form.ApplicationFormName ?? string.Empty, - Version = x.version.Version + ApplicationFormId = x.Id, + ApplicationFormName = x.ApplicationFormName ?? string.Empty }).ToList(); return new PagedResultDto(totalCount, results); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/GrantManagerDomainErrorCodes.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/GrantManagerDomainErrorCodes.cs index e85a4e601..b06c20bc5 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/GrantManagerDomainErrorCodes.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/GrantManagerDomainErrorCodes.cs @@ -20,7 +20,5 @@ public static class GrantManagerDomainErrorCodes /* PAYMENT CONFIGURATION */ public const string PayableFormRequiresHierarchy = "GrantManager:PayableFormRequiresHierarchy"; public const string ChildFormRequiresParentForm = "GrantManager:ChildFormRequiresParentForm"; - public const string ChildFormRequiresParentFormVersion = "GrantManager:ChildFormRequiresParentFormVersion"; - public const string ParentFormVersionMismatch = "GrantManager:ParentFormVersionMismatch"; public const string ChildFormCannotReferenceSelf = "GrantManager:ChildFormCannotReferenceSelf"; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Localization/GrantManager/en.json b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Localization/GrantManager/en.json index fa18b68a3..528b36c85 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Localization/GrantManager/en.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Localization/GrantManager/en.json @@ -246,8 +246,6 @@ "GrantManager:CantCreateAssessmentForFinalStateApplication": "Business Exception: You cannot create an assessment for an application in final state.", "GrantManager:PayableFormRequiresHierarchy": "Please select a form hierarchy before saving a payable form.", "GrantManager:ChildFormRequiresParentForm": "Please select a parent form when the form hierarchy is set to Child.", - "GrantManager:ChildFormRequiresParentFormVersion": "Please select a parent form version when the form hierarchy is set to Child.", - "GrantManager:ParentFormVersionMismatch": "The selected parent form version does not belong to the chosen parent form.", "GrantManager:ChildFormCannotReferenceSelf": "A form cannot reference itself as the parent.", "AssessmentResultsView:ApprovalTitle": "Approval", diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/ApplicationForm.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/ApplicationForm.cs index 62629517e..b60d8264f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/ApplicationForm.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/ApplicationForm.cs @@ -31,7 +31,6 @@ public class ApplicationForm : FullAuditedAggregateRoot, IMultiTenant public int? DefaultPaymentGroup { get; set; } public FormHierarchyType? FormHierarchy { get; set; } public Guid? ParentFormId { get; set; } - public Guid? ParentFormVersionId { get; set; } public bool RenderFormIoToHtml { get; set; } = false; public bool IsDirectApproval { get; set; } = false; public string? Prefix { get; set; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantTenantDbContext.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantTenantDbContext.cs index 4d697f4f9..a30f57c11 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantTenantDbContext.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantTenantDbContext.cs @@ -105,12 +105,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .HasForeignKey(x => x.ParentFormId) .IsRequired(false) .OnDelete(DeleteBehavior.NoAction); - - b.HasOne() - .WithMany() - .HasForeignKey(x => x.ParentFormVersionId) - .IsRequired(false) - .OnDelete(DeleteBehavior.NoAction); }); modelBuilder.Entity(b => diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260205015914_Remove_ParentFormVersionId.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260205015914_Remove_ParentFormVersionId.Designer.cs new file mode 100644 index 000000000..e0e934de6 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260205015914_Remove_ParentFormVersionId.Designer.cs @@ -0,0 +1,4569 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Unity.GrantManager.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + [DbContext(typeof(GrantTenantDbContext))] + [Migration("20260205015914_Remove_ParentFormVersionId")] + partial class Remove_ParentFormVersionId + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "9.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ScoresheetId"); + + b.ToTable("ScoresheetInstances", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Answer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("QuestionId") + .HasColumnType("uuid"); + + b.Property("ScoresheetInstanceId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("QuestionId"); + + b.HasIndex("ScoresheetInstanceId"); + + b.ToTable("Answers", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Definition") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("SectionId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("Questions", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Scoresheet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("Scoresheets", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ScoresheetId"); + + b.ToTable("ScoresheetSections", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.CustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("CustomFieldId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("WorksheetInstanceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetInstanceId"); + + b.ToTable("CustomFieldValues", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UiAnchor") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetCorrelationId") + .HasColumnType("uuid"); + + b.Property("WorksheetCorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("WorksheetInstances", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetLinks.WorksheetLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UiAnchor") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetId"); + + b.ToTable("WorksheetLinks", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Definition") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("Key") + .IsRequired() + .HasColumnType("text"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("SectionId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("CustomFields", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.Worksheet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("Worksheets", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetId"); + + b.ToTable("WorksheetSections", "Flex"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Applicant", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantName") + .IsRequired() + .HasMaxLength(600) + .HasColumnType("character varying(600)"); + + b.Property("ApproxNumberOfEmployees") + .HasColumnType("text"); + + b.Property("BusinessNumber") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FiscalDay") + .HasColumnType("integer"); + + b.Property("FiscalMonth") + .HasColumnType("text"); + + b.Property("IndigenousOrgInd") + .HasColumnType("text"); + + b.Property("IsDuplicated") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MatchPercentage") + .HasColumnType("numeric"); + + b.Property("NonRegOrgName") + .HasColumnType("text"); + + b.Property("NonRegisteredBusinessName") + .HasColumnType("text"); + + b.Property("OrgName") + .HasColumnType("text"); + + b.Property("OrgNumber") + .HasColumnType("text"); + + b.Property("OrgStatus") + .HasColumnType("text"); + + b.Property("OrganizationSize") + .HasColumnType("text"); + + b.Property("OrganizationType") + .HasColumnType("text"); + + b.Property("RedStop") + .HasColumnType("boolean"); + + b.Property("Sector") + .HasColumnType("text"); + + b.Property("SectorSubSectorIndustryDesc") + .HasColumnType("text"); + + b.Property("SiteId") + .HasColumnType("uuid"); + + b.Property("StartedOperatingDate") + .HasColumnType("date"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("SubSector") + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UnityApplicantId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantName"); + + b.ToTable("Applicants", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAddress", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AddressType") + .HasColumnType("integer"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Postal") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("Street") + .HasColumnType("text"); + + b.Property("Street2") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Unit") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicantAddresses", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAgent", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("BceidBusinessGuid") + .HasColumnType("uuid"); + + b.Property("BceidBusinessName") + .HasColumnType("text"); + + b.Property("BceidUserGuid") + .HasColumnType("uuid"); + + b.Property("BceidUserName") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactOrder") + .HasColumnType("integer"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IdentityEmail") + .HasColumnType("text"); + + b.Property("IdentityName") + .HasColumnType("text"); + + b.Property("IdentityProvider") + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsConfirmed") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OidcSubUser") + .HasColumnType("text"); + + b.Property("Phone") + .HasColumnType("text"); + + b.Property("Phone2") + .HasColumnType("text"); + + b.Property("Phone2Extension") + .HasColumnType("text"); + + b.Property("PhoneExtension") + .HasColumnType("text"); + + b.Property("RoleForApplicant") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationId") + .IsUnique(); + + b.ToTable("ApplicantAgents", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AIAnalysis") + .HasColumnType("text"); + + b.Property("AIScoresheetAnswers") + .HasColumnType("jsonb"); + + b.Property("Acquisition") + .HasColumnType("text"); + + b.Property("ApplicantElectoralDistrict") + .HasColumnType("text"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("ApplicationStatusId") + .HasColumnType("uuid"); + + b.Property("ApprovedAmount") + .HasColumnType("numeric"); + + b.Property("AssessmentResultDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AssessmentResultStatus") + .HasColumnType("text"); + + b.Property("AssessmentStartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Community") + .HasColumnType("text"); + + b.Property("CommunityPopulation") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContractExecutionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ContractNumber") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeclineRational") + .HasColumnType("text"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("DueDate") + .HasColumnType("timestamp without time zone"); + + b.Property("DueDiligenceStatus") + .HasColumnType("text"); + + b.Property("EconomicRegion") + .HasColumnType("text"); + + b.Property("ElectoralDistrict") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinalDecisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Forestry") + .HasColumnType("text"); + + b.Property("ForestryFocus") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LikelihoodOfFunding") + .HasColumnType("text"); + + b.Property("Notes") + .HasColumnType("text"); + + b.Property("NotificationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("OwnerId") + .HasColumnType("uuid"); + + b.Property("Payload") + .HasColumnType("jsonb"); + + b.Property("PercentageTotalProjectBudget") + .HasColumnType("double precision"); + + b.Property("Place") + .HasColumnType("text"); + + b.Property("ProjectEndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ProjectFundingTotal") + .HasColumnType("numeric"); + + b.Property("ProjectName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ProjectStartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ProjectSummary") + .HasColumnType("text"); + + b.Property("ProposalDate") + .HasColumnType("timestamp without time zone"); + + b.Property("RecommendedAmount") + .HasColumnType("numeric"); + + b.Property("ReferenceNo") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegionalDistrict") + .HasColumnType("text"); + + b.Property("RequestedAmount") + .HasColumnType("numeric"); + + b.Property("RiskRanking") + .HasColumnType("text"); + + b.Property("SigningAuthorityBusinessPhone") + .HasColumnType("text"); + + b.Property("SigningAuthorityCellPhone") + .HasColumnType("text"); + + b.Property("SigningAuthorityEmail") + .HasColumnType("text"); + + b.Property("SigningAuthorityFullName") + .HasColumnType("text"); + + b.Property("SigningAuthorityTitle") + .HasColumnType("text"); + + b.Property("SubStatus") + .HasColumnType("text"); + + b.Property("SubmissionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TotalProjectBudget") + .HasColumnType("numeric"); + + b.Property("TotalScore") + .HasColumnType("integer"); + + b.Property("UnityApplicationId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationFormId"); + + b.HasIndex("ApplicationStatusId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Applications", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAssignment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AssigneeId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Duty") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("AssigneeId"); + + b.ToTable("ApplicationAssignments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationChefsFileAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AISummary") + .HasColumnType("text"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChefsFileId") + .HasColumnType("text"); + + b.Property("ChefsSubmissionId") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationChefsFileAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationContact", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactEmail") + .HasColumnType("text"); + + b.Property("ContactFullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ContactMobilePhone") + .HasColumnType("text"); + + b.Property("ContactTitle") + .HasColumnType("text"); + + b.Property("ContactType") + .IsRequired() + .HasColumnType("text"); + + b.Property("ContactWorkPhone") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationContact", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationForm", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccountCodingId") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasColumnType("text"); + + b.Property("ApplicationFormDescription") + .HasColumnType("text"); + + b.Property("ApplicationFormName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AttemptedConnectionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AvailableChefsFields") + .HasColumnType("text"); + + b.Property("Category") + .HasColumnType("text"); + + b.Property("ChefsApplicationFormGuid") + .HasColumnType("text"); + + b.Property("ChefsCriteriaFormGuid") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ConnectionHttpStatus") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DefaultPaymentGroup") + .HasColumnType("integer"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ElectoralDistrictAddressType") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormHierarchy") + .HasColumnType("integer"); + + b.Property("IntakeId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsDirectApproval") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ParentFormId") + .HasColumnType("uuid"); + + b.Property("Payable") + .HasColumnType("boolean"); + + b.Property("PaymentApprovalThreshold") + .HasColumnType("numeric"); + + b.Property("Prefix") + .HasColumnType("text"); + + b.Property("PreventPayment") + .HasColumnType("boolean"); + + b.Property("RenderFormIoToHtml") + .HasColumnType("boolean"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("SuffixType") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IntakeId"); + + b.HasIndex("ParentFormId"); + + b.ToTable("ApplicationForms", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormVersionId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChefsSubmissionGuid") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormVersionId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OidcSub") + .IsRequired() + .HasColumnType("text"); + + b.Property("RenderedHTML") + .HasColumnType("text"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Submission") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationFormId"); + + b.ToTable("ApplicationFormSubmissions", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormVersion", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("AvailableChefsFields") + .HasColumnType("text"); + + b.Property("ChefsApplicationFormGuid") + .HasColumnType("text"); + + b.Property("ChefsFormVersionGuid") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormSchema") + .HasColumnType("jsonb"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SubmissionHeaderMapping") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationFormId"); + + b.ToTable("ApplicationFormVersion", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationLink", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LinkType") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasDefaultValue("Related"); + + b.Property("LinkedApplicationId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationLinks", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationStatus", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExternalStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InternalStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("StatusCode") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("StatusCode") + .IsUnique(); + + b.ToTable("ApplicationStatuses", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationTags", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TagId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("TagId"); + + b.ToTable("ApplicationTags", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.AssessmentAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AssessmentId"); + + b.ToTable("AssessmentAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Assessments.Assessment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ApprovalRecommended") + .HasColumnType("boolean"); + + b.Property("AssessorId") + .HasColumnType("uuid"); + + b.Property("CleanGrowth") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("EconomicImpact") + .HasColumnType("integer"); + + b.Property("EndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinancialAnalysis") + .HasColumnType("integer"); + + b.Property("InclusiveGrowth") + .HasColumnType("integer"); + + b.Property("IsComplete") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("AssessorId"); + + b.ToTable("Assessments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.ApplicationComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("text"); + + b.Property("CommenterId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PinDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("CommenterId"); + + b.ToTable("ApplicationComments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.AssessmentComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("text"); + + b.Property("CommenterId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PinDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AssessmentId"); + + b.HasIndex("CommenterId"); + + b.ToTable("AssessmentComments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Contacts.Contact", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Email") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("HomePhoneNumber") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MobilePhoneNumber") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("WorkPhoneExtension") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("WorkPhoneNumber") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.ToTable("Contacts", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Contacts.ContactLink", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsPrimary") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("RelatedEntityId") + .HasColumnType("uuid"); + + b.Property("RelatedEntityType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Role") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RelatedEntityType", "RelatedEntityId"); + + b.HasIndex("ContactId", "RelatedEntityType", "RelatedEntityId"); + + b.ToTable("ContactLinks", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.GlobalTag.Tag", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Tags", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Identity.Person", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Badge") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OidcDisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("OidcSub") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("OidcSub"); + + b.ToTable("Persons", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Intakes.Intake", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Budget") + .HasColumnType("double precision"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IntakeName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("StartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Intakes", (string)null); + }); + + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EmailGroups", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroupUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.ToTable("EmailGroupUsers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Emails.EmailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("BCC") + .IsRequired() + .HasColumnType("text"); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyType") + .IsRequired() + .HasColumnType("text"); + + b.Property("CC") + .IsRequired() + .HasColumnType("text"); + + b.Property("ChesHttpStatusCode") + .HasColumnType("text"); + + b.Property("ChesMsgId") + .HasColumnType("uuid"); + + b.Property("ChesResponse") + .IsRequired() + .HasColumnType("text"); + + b.Property("ChesStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FromAddress") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PaymentRequestIds") + .IsRequired() + .HasColumnType("text"); + + b.Property("Priority") + .IsRequired() + .HasColumnType("text"); + + b.Property("RetryAttempts") + .HasColumnType("integer"); + + b.Property("SendOnDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("SentDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("Tag") + .IsRequired() + .HasColumnType("text"); + + b.Property("TemplateName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("ToAddress") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EmailLogs", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Emails.EmailLogAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("EmailLogId") + .HasColumnType("uuid"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("EmailLogId"); + + b.HasIndex("S3ObjectKey"); + + b.ToTable("EmailLogAttachments", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.EmailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BodyHTML") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyText") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SendFrom") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("EmailTemplates", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.Subscriber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Subscribers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("SubscriptionGroups", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroupSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("SubscriberId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.HasIndex("SubscriberId"); + + b.ToTable("SubscriptionGroupSubscribers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.TemplateVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MapTo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Token") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("TemplateVariables", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.Trigger", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InternalName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Triggers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.TriggerSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("SubscriptionGroupId") + .HasColumnType("uuid"); + + b.Property("TemplateId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TriggerId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SubscriptionGroupId"); + + b.HasIndex("TemplateId"); + + b.HasIndex("TriggerId"); + + b.ToTable("TriggerSubscriptions", "Notifications"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.AccountCodings.AccountCoding", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(35) + .HasColumnType("character varying(35)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MinistryClient") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProjectNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("Responsibility") + .IsRequired() + .HasColumnType("text"); + + b.Property("ServiceLine") + .IsRequired() + .HasColumnType("text"); + + b.Property("Stob") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AccountCodings", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentConfigurations.PaymentConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DefaultAccountCodingId") + .HasColumnType("uuid"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PaymentIdPrefix") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("PaymentConfigurations", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.ExpenseApproval", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DecisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("DecisionUserId") + .HasColumnType("uuid"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PaymentRequestId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PaymentRequestId"); + + b.ToTable("ExpenseApprovals", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountCodingId") + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("BatchName") + .IsRequired() + .HasColumnType("text"); + + b.Property("BatchNumber") + .HasColumnType("numeric"); + + b.Property("CasHttpStatusCode") + .HasColumnType("integer"); + + b.Property("CasResponse") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContractNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FsbApNotified") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("FsbNotificationEmailLogId") + .HasColumnType("uuid"); + + b.Property("FsbNotificationSentDate") + .HasColumnType("timestamp without time zone"); + + b.Property("InvoiceNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("InvoiceStatus") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsRecon") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Note") + .HasColumnType("text"); + + b.Property("PayeeName") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentDate") + .HasColumnType("text"); + + b.Property("PaymentNumber") + .HasColumnType("text"); + + b.Property("PaymentStatus") + .HasColumnType("text"); + + b.Property("ReferenceNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequesterName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SiteId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("SubmissionConfirmationCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("SupplierName") + .HasColumnType("text"); + + b.Property("SupplierNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AccountCodingId"); + + b.HasIndex("FsbNotificationEmailLogId"); + + b.HasIndex("ReferenceNumber") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.ToTable("PaymentRequests", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentTags.PaymentTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PaymentRequestId") + .HasColumnType("uuid"); + + b.Property("TagId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("PaymentRequestId"); + + b.HasIndex("TagId"); + + b.ToTable("PaymentTags", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentThresholds.PaymentThreshold", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Threshold") + .HasColumnType("numeric"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("PaymentThresholds", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddressLine1") + .HasColumnType("text"); + + b.Property("AddressLine2") + .HasColumnType("text"); + + b.Property("AddressLine3") + .HasColumnType("text"); + + b.Property("BankAccount") + .HasColumnType("text"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EFTAdvicePref") + .HasColumnType("text"); + + b.Property("EmailAddress") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedInCas") + .HasColumnType("timestamp without time zone"); + + b.Property("MarkDeletedInUse") + .HasColumnType("boolean"); + + b.Property("Number") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentGroup") + .HasColumnType("integer"); + + b.Property("PostalCode") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("SiteProtected") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("SupplierId"); + + b.ToTable("Sites", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Supplier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessNumber") + .HasColumnType("text"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedInCAS") + .HasColumnType("timestamp without time zone"); + + b.Property("MailingAddress") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("text"); + + b.Property("PostalCode") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("SIN") + .HasColumnType("text"); + + b.Property("StandardIndustryClassification") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("Subcategory") + .HasColumnType("text"); + + b.Property("SupplierProtected") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Suppliers", "Payments"); + }); + + modelBuilder.Entity("Unity.Reporting.Domain.Configuration.ReportColumnsMap", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Mapping") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("RoleStatus") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("ViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ViewStatus") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("ReportColumnsMaps", "Reporting"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Scoresheet", "Scoresheet") + .WithMany("Instances") + .HasForeignKey("ScoresheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Scoresheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Answer", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Question", "Question") + .WithMany("Answers") + .HasForeignKey("QuestionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", null) + .WithMany("Answers") + .HasForeignKey("ScoresheetInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Question"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.ScoresheetSection", "Section") + .WithMany("Fields") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Scoresheet", "Scoresheet") + .WithMany("Sections") + .HasForeignKey("ScoresheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Scoresheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.CustomFieldValue", b => + { + b.HasOne("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", null) + .WithMany("Values") + .HasForeignKey("WorksheetInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetLinks.WorksheetLink", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.Worksheet", "Worksheet") + .WithMany("Links") + .HasForeignKey("WorksheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Worksheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.CustomField", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.WorksheetSection", "Section") + .WithMany("Fields") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.Worksheet", "Worksheet") + .WithMany("Sections") + .HasForeignKey("WorksheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Worksheet"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAddress", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", "Applicant") + .WithMany("ApplicantAddresses") + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicantAddresses") + .HasForeignKey("ApplicationId"); + + b.Navigation("Applicant"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAgent", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithOne("ApplicantAgent") + .HasForeignKey("Unity.GrantManager.Applications.ApplicantAgent", "ApplicationId"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", "Applicant") + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", "ApplicationForm") + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationStatus", "ApplicationStatus") + .WithMany("Applications") + .HasForeignKey("ApplicationStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Applicant"); + + b.Navigation("ApplicationForm"); + + b.Navigation("ApplicationStatus"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAssignment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicationAssignments") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", "Assignee") + .WithMany() + .HasForeignKey("AssigneeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Application"); + + b.Navigation("Assignee"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationChefsFileAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationContact", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationForm", b => + { + b.HasOne("Unity.GrantManager.Intakes.Intake", null) + .WithMany() + .HasForeignKey("IntakeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ParentFormId") + .OnDelete(DeleteBehavior.NoAction); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormVersion", b => + { + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationLink", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationTags", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicationTags") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.GlobalTag.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Application"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.AssessmentAttachment", b => + { + b.HasOne("Unity.GrantManager.Assessments.Assessment", null) + .WithMany() + .HasForeignKey("AssessmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Assessments.Assessment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("Assessments") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("AssessorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.ApplicationComment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.AssessmentComment", b => + { + b.HasOne("Unity.GrantManager.Assessments.Assessment", null) + .WithMany() + .HasForeignKey("AssessmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Contacts.ContactLink", b => + { + b.HasOne("Unity.GrantManager.Contacts.Contact", null) + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroupUser", b => + { + b.HasOne("Unity.Notifications.EmailGroups.EmailGroup", null) + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Notifications.Emails.EmailLogAttachment", b => + { + b.HasOne("Unity.Notifications.Emails.EmailLog", null) + .WithMany() + .HasForeignKey("EmailLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroupSubscription", b => + { + b.HasOne("Unity.Notifications.Templates.SubscriptionGroup", "SubscriptionGroup") + .WithMany() + .HasForeignKey("GroupId"); + + b.HasOne("Unity.Notifications.Templates.Subscriber", "Subscriber") + .WithMany() + .HasForeignKey("SubscriberId"); + + b.Navigation("Subscriber"); + + b.Navigation("SubscriptionGroup"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.TriggerSubscription", b => + { + b.HasOne("Unity.Notifications.Templates.SubscriptionGroup", "SubscriptionGroup") + .WithMany() + .HasForeignKey("SubscriptionGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Notifications.Templates.EmailTemplate", "EmailTemplate") + .WithMany() + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Notifications.Templates.Trigger", "Trigger") + .WithMany() + .HasForeignKey("TriggerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EmailTemplate"); + + b.Navigation("SubscriptionGroup"); + + b.Navigation("Trigger"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.ExpenseApproval", b => + { + b.HasOne("Unity.Payments.Domain.PaymentRequests.PaymentRequest", "PaymentRequest") + .WithMany("ExpenseApprovals") + .HasForeignKey("PaymentRequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PaymentRequest"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.HasOne("Unity.Payments.Domain.AccountCodings.AccountCoding", "AccountCoding") + .WithMany() + .HasForeignKey("AccountCodingId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("Unity.Payments.Domain.Suppliers.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("AccountCoding"); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentTags.PaymentTag", b => + { + b.HasOne("Unity.Payments.Domain.PaymentRequests.PaymentRequest", null) + .WithMany("PaymentTags") + .HasForeignKey("PaymentRequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.GlobalTag.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => + { + b.HasOne("Unity.Payments.Domain.Suppliers.Supplier", "Supplier") + .WithMany("Sites") + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supplier"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Scoresheet", b => + { + b.Navigation("Instances"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.Navigation("Fields"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", b => + { + b.Navigation("Values"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.Worksheet", b => + { + b.Navigation("Links"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.Navigation("Fields"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Applicant", b => + { + b.Navigation("ApplicantAddresses"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.Navigation("ApplicantAddresses"); + + b.Navigation("ApplicantAgent"); + + b.Navigation("ApplicationAssignments"); + + b.Navigation("ApplicationTags"); + + b.Navigation("Assessments"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationStatus", b => + { + b.Navigation("Applications"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.Navigation("ExpenseApprovals"); + + b.Navigation("PaymentTags"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Supplier", b => + { + b.Navigation("Sites"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260205015914_Remove_ParentFormVersionId.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260205015914_Remove_ParentFormVersionId.cs new file mode 100644 index 000000000..df2cec23d --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260205015914_Remove_ParentFormVersionId.cs @@ -0,0 +1,55 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + /// + public partial class Remove_ParentFormVersionId : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + // Drop FK constraint first + migrationBuilder.DropForeignKey( + name: "FK_ApplicationForms_ApplicationFormVersion_ParentFormVersionId", + table: "ApplicationForms"); + + // Drop index + migrationBuilder.DropIndex( + name: "IX_ApplicationForms_ParentFormVersionId", + table: "ApplicationForms"); + + // Drop column + migrationBuilder.DropColumn( + name: "ParentFormVersionId", + table: "ApplicationForms"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + // Add column back + migrationBuilder.AddColumn( + name: "ParentFormVersionId", + table: "ApplicationForms", + type: "uuid", + nullable: true); + + // Recreate index + migrationBuilder.CreateIndex( + name: "IX_ApplicationForms_ParentFormVersionId", + table: "ApplicationForms", + column: "ParentFormVersionId"); + + // Recreate FK constraint + migrationBuilder.AddForeignKey( + name: "FK_ApplicationForms_ApplicationFormVersion_ParentFormVersionId", + table: "ApplicationForms", + column: "ParentFormVersionId", + principalTable: "ApplicationFormVersion", + principalColumn: "Id"); + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs index e86fc2dd8..fd2aa8373 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs @@ -1660,9 +1660,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ParentFormId") .HasColumnType("uuid"); - b.Property("ParentFormVersionId") - .HasColumnType("uuid"); - b.Property("Payable") .HasColumnType("boolean"); @@ -1697,8 +1694,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("ParentFormId"); - b.HasIndex("ParentFormVersionId"); - b.ToTable("ApplicationForms", (string)null); }); @@ -4256,11 +4251,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .WithMany() .HasForeignKey("ParentFormId") .OnDelete(DeleteBehavior.NoAction); - - b.HasOne("Unity.GrantManager.Applications.ApplicationFormVersion", null) - .WithMany() - .HasForeignKey("ParentFormVersionId") - .OnDelete(DeleteBehavior.NoAction); }); modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml index 04a43c8e3..2687324c2 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml @@ -14,7 +14,6 @@
-
@@ -105,11 +104,11 @@ - + + @if (Model.ParentFormId.HasValue) { - + } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js index aa342b57d..b18ebb8dd 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js @@ -22,8 +22,7 @@ formHierarchySection: $('#form-hierarchy-section'), formHierarchy: $('#FormHierarchy'), parentFormColumn: $('#parent-form-column'), - parentFormSelect: $('#ParentForm'), - parentFormId: $('#ParentFormId') + parentFormSelect: $('#ParentForm') }; init(); @@ -65,7 +64,7 @@ UIElements.parentFormSelect.select2({ width: '100%', allowClear: true, - placeholder: UIElements.parentFormSelect.data('placeholder') || 'Please choose...(Form Name V1.0)', + placeholder: UIElements.parentFormSelect.data('placeholder') || 'Please choose a parent form', minimumInputLength: 2, ajax: { transport: function (params, success, failure) { @@ -82,9 +81,8 @@ params.page = params.page || 1; const items = (data.items || []).map(function (item) { return { - id: item.applicationFormVersionId, - text: `${item.applicationFormName}${formatVersion(item.version)}`, - parentFormId: item.applicationFormId + id: item.applicationFormId, + text: item.applicationFormName }; }); @@ -99,29 +97,14 @@ }); UIElements.parentFormSelect.on('select2:select', function (e) { - const data = e.params?.data ?? {}; - setParentFormId(data.parentFormId); enableSaveButton(); }); UIElements.parentFormSelect.on('select2:clear', function () { - setParentFormId(''); enableSaveButton(); }); UIElements.parentFormSelect.on('change', enableSaveButton); - - applyInitialParentFormSelection(); - } - - function applyInitialParentFormSelection() { - const selectedOption = UIElements.parentFormSelect.find('option:selected'); - if (selectedOption.length) { - const parentIdFromOption = selectedOption.data('parentFormId'); - if (parentIdFromOption) { - setParentFormId(parentIdFromOption); - } - } } function toggleFormHierarchySection() { @@ -160,11 +143,6 @@ function resetParentFormSelection() { UIElements.parentFormSelect.val(null).trigger('change'); - setParentFormId(''); - } - - function setParentFormId(value) { - UIElements.parentFormId.val(value || ''); } function preventDecimalKeyPress(e) { @@ -202,13 +180,8 @@ } if (hierarchyValue === String(FormHierarchyType.Child)) { - if (!UIElements.parentFormId.val()) { - abp.notify.error(l('GrantManager:ChildFormRequiresParentForm')); - return false; - } - if (!UIElements.parentFormSelect.val()) { - abp.notify.error(l('GrantManager:ChildFormRequiresParentFormVersion')); + abp.notify.error(l('GrantManager:ChildFormRequiresParentForm')); return false; } } @@ -223,7 +196,7 @@ const hierarchyValue = UIElements.formHierarchy.val(); const formHierarchy = hierarchyValue ? parseInt(hierarchyValue, 10) : null; - const parentFormVersionId = UIElements.parentFormSelect.val(); + const parentFormId = UIElements.parentFormSelect.val(); const defaultPaymentGroupValue = UIElements.payable.is(':checked') ? (UIElements.defaultPaymentGroup.val() || '1') : null; @@ -236,8 +209,7 @@ payable: UIElements.payable.is(':checked'), paymentApprovalThreshold: UIElements.paymentApprovalThreshold.val() === '' ? null : UIElements.paymentApprovalThreshold.val(), formHierarchy: Number.isNaN(formHierarchy) ? null : formHierarchy, - parentFormId: UIElements.parentFormId.val() || null, - parentFormVersionId: parentFormVersionId || null, + parentFormId: parentFormId || null, defaultPaymentGroup: defaultPaymentGroupValue }) .then(() => { @@ -286,7 +258,4 @@ } } - function formatVersion(version) { - return version ? ` V${version}.0` : ''; - } }); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs index cbdd67553..47a3b8d81 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs @@ -43,18 +43,16 @@ public async Task InvokeAsync(Guid formId) model.AccountCode = applicationForm?.AccountCodingId; model.FormHierarchy = applicationForm?.FormHierarchy; model.ParentFormId = applicationForm?.ParentFormId; - model.ParentFormVersionId = applicationForm?.ParentFormVersionId; model.DefaultPaymentGroup = applicationForm?.DefaultPaymentGroup ?? (int)PaymentGroup.EFT; // Load parent form display name if parent form is selected - if (model.ParentFormId.HasValue && model.ParentFormVersionId.HasValue) + if (model.ParentFormId.HasValue) { var parentForm = await applicationFormRepository.FindAsync(model.ParentFormId.Value); - var parentFormVersion = await applicationFormVersionRepository.FindAsync(model.ParentFormVersionId.Value); - if (parentForm != null && parentFormVersion != null) + if (parentForm != null) { - model.ParentFormDisplayName = $"{parentForm.ApplicationFormName} V{parentFormVersion.Version}.0"; + model.ParentFormDisplayName = parentForm.ApplicationFormName ?? string.Empty; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewModel.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewModel.cs index 1d01a4fb6..8019ae8c6 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewModel.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewModel.cs @@ -34,7 +34,6 @@ public PaymentConfigurationViewModel() public FormHierarchyType? FormHierarchy { get; set; } public Guid? ParentFormId { get; set; } - public Guid? ParentFormVersionId { get; set; } public string ParentFormDisplayName { get; set; } = string.Empty; public decimal? PaymentApprovalThreshold { get; set; } diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/ApplicationForms/PaymentConfigurationValidationTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/ApplicationForms/PaymentConfigurationValidationTests.cs index 31b46f365..f59f8f8a1 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/ApplicationForms/PaymentConfigurationValidationTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/ApplicationForms/PaymentConfigurationValidationTests.cs @@ -57,49 +57,33 @@ public async Task SavePaymentConfiguration_ShouldRejectSelfReference() ApplicationFormId = GrantManagerTestData.ApplicationForm1_Id, Payable = true, FormHierarchy = FormHierarchyType.Child, - ParentFormId = GrantManagerTestData.ApplicationForm1_Id, - ParentFormVersionId = Guid.NewGuid() + ParentFormId = GrantManagerTestData.ApplicationForm1_Id })); exception.Code.ShouldBe(GrantManagerDomainErrorCodes.ChildFormCannotReferenceSelf); } [Fact] - public async Task SavePaymentConfiguration_ShouldValidateParentVersion() + public async Task SavePaymentConfiguration_ShouldAcceptValidParentForm() { var parentForm = await _applicationFormRepository.InsertAsync(new ApplicationForm { IntakeId = GrantManagerTestData.Intake1_Id, ApplicationFormName = "Parent Form For Validation", - Payable = true - }, autoSave: true); - - var parentVersion = await _applicationFormVersionRepository.InsertAsync(new ApplicationFormVersion - { - ApplicationFormId = parentForm.Id, - Version = 1, - Published = true + Payable = true, + FormHierarchy = FormHierarchyType.Parent }, autoSave: true); - var mismatchException = await Should.ThrowAsync( - _applicationFormAppService.SavePaymentConfiguration(new FormPaymentConfigurationDto - { - ApplicationFormId = GrantManagerTestData.ApplicationForm1_Id, - Payable = true, - FormHierarchy = FormHierarchyType.Child, - ParentFormId = parentForm.Id, - ParentFormVersionId = Guid.NewGuid() - })); - - mismatchException.Code.ShouldBe(GrantManagerDomainErrorCodes.ParentFormVersionMismatch); - await _applicationFormAppService.SavePaymentConfiguration(new FormPaymentConfigurationDto { ApplicationFormId = GrantManagerTestData.ApplicationForm1_Id, Payable = true, FormHierarchy = FormHierarchyType.Child, - ParentFormId = parentForm.Id, - ParentFormVersionId = parentVersion.Id + ParentFormId = parentForm.Id }); + + var savedForm = await _applicationFormRepository.GetAsync(GrantManagerTestData.ApplicationForm1_Id); + savedForm.ParentFormId.ShouldBe(parentForm.Id); + savedForm.FormHierarchy.ShouldBe(FormHierarchyType.Child); } } From 8790f7476e2a878f20a5009d31903711ac0deb48 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Wed, 4 Feb 2026 18:51:38 -0800 Subject: [PATCH 04/42] AB#31066: Search Form Hierarchy Parent Form By Category --- .../ApplicationForms/ParentFormLookupDto.cs | 1 + .../ApplicationForms/ApplicationFormAppService.cs | 9 ++++++--- .../Components/PaymentConfiguration/Default.cshtml | 4 ++-- .../Shared/Components/PaymentConfiguration/Default.js | 7 +++++-- .../PaymentConfigurationViewComponent.cs | 6 +++++- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ParentFormLookupDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ParentFormLookupDto.cs index 969b87337..8c61da69f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ParentFormLookupDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ParentFormLookupDto.cs @@ -21,5 +21,6 @@ public class ParentFormLookupDto { public Guid ApplicationFormId { get; set; } public string ApplicationFormName { get; set; } = string.Empty; + public string? Category { get; set; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs index 4733ad469..6ab35fd94 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs @@ -251,8 +251,10 @@ public async Task> GetParentFormLookupAsync( { var loweredFilter = normalizedFilter.ToLowerInvariant(); query = query.Where(x => - x.ApplicationFormName != null && - x.ApplicationFormName.ToLower().Contains(loweredFilter)); + (x.ApplicationFormName != null && + x.ApplicationFormName.ToLower().Contains(loweredFilter)) || + (x.Category != null && + x.Category.ToLower().Contains(loweredFilter))); } var totalCount = await AsyncExecuter.CountAsync(query); @@ -267,7 +269,8 @@ public async Task> GetParentFormLookupAsync( var results = items.Select(x => new ParentFormLookupDto { ApplicationFormId = x.Id, - ApplicationFormName = x.ApplicationFormName ?? string.Empty + ApplicationFormName = x.ApplicationFormName ?? string.Empty, + Category = x.Category }).ToList(); return new PagedResultDto(totalCount, results); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml index 2687324c2..feb209af5 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml @@ -104,8 +104,8 @@ - + @if (Model.ParentFormId.HasValue) { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js index b18ebb8dd..598cb245c 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js @@ -64,7 +64,7 @@ UIElements.parentFormSelect.select2({ width: '100%', allowClear: true, - placeholder: UIElements.parentFormSelect.data('placeholder') || 'Please choose a parent form', + placeholder: UIElements.parentFormSelect.data('placeholder') || 'Please choose...', minimumInputLength: 2, ajax: { transport: function (params, success, failure) { @@ -80,9 +80,12 @@ processResults: function (data, params) { params.page = params.page || 1; const items = (data.items || []).map(function (item) { + const displayText = item.category + ? `${item.applicationFormName} - ${item.category}` + : item.applicationFormName; return { id: item.applicationFormId, - text: item.applicationFormName + text: displayText }; }); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs index 47a3b8d81..2d1a990f8 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs @@ -52,7 +52,11 @@ public async Task InvokeAsync(Guid formId) if (parentForm != null) { - model.ParentFormDisplayName = parentForm.ApplicationFormName ?? string.Empty; + var formName = parentForm.ApplicationFormName ?? string.Empty; + var category = parentForm.Category; + model.ParentFormDisplayName = !string.IsNullOrEmpty(category) + ? $"{formName} - {category}" + : formName; } } From ed795f163020a5052a5fed579d9a89174ebe7fc4 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Wed, 4 Feb 2026 19:08:19 -0800 Subject: [PATCH 05/42] AB#31067: Fix sonarqube issues --- .../ApplicationForms/ApplicationFormAppService.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs index 6ab35fd94..d95d45758 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs @@ -250,11 +250,14 @@ public async Task> GetParentFormLookupAsync( if (!string.IsNullOrWhiteSpace(normalizedFilter)) { var loweredFilter = normalizedFilter.ToLowerInvariant(); +#pragma warning disable CA1862 // Use the 'StringComparison' method overloads to perform case-insensitive string comparisons + // Need to suppress this because EF Core does not support StringComparison query = query.Where(x => (x.ApplicationFormName != null && x.ApplicationFormName.ToLower().Contains(loweredFilter)) || (x.Category != null && x.Category.ToLower().Contains(loweredFilter))); +#pragma warning restore CA1862 // Use the 'StringComparison' method overloads to perform case-insensitive string comparisons } var totalCount = await AsyncExecuter.CountAsync(query); From 9a8c80667db0ab83b185e8f90fe3159e2e896683 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Wed, 4 Feb 2026 19:59:28 -0800 Subject: [PATCH 06/42] AB#31067: Fix sonarqube issue --- .../PaymentConfiguration/PaymentConfigurationViewComponent.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs index 2d1a990f8..f2163fc97 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs @@ -23,8 +23,7 @@ namespace Unity.GrantManager.Web.Views.Shared.Components.PaymentConfiguration AutoInitialize = true)] public class PaymentConfigurationViewComponent( IAccountCodingRepository accountCodingRepository, - IApplicationFormRepository applicationFormRepository, - IApplicationFormVersionRepository applicationFormVersionRepository, + IApplicationFormRepository applicationFormRepository, IPermissionChecker permissionChecker, PaymentConfigurationAppService paymentConfigurationAppService) : AbpViewComponent { From 35f26423dcb7c0174326b5a2f55d4740d15334b0 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Thu, 5 Feb 2026 16:13:04 -0800 Subject: [PATCH 07/42] AB#30069: Change parent-child amount validation error message --- .../PaymentRequests/CreatePaymentRequests.cshtml | 1 + .../PaymentRequests/CreatePaymentRequests.cshtml.cs | 2 ++ .../PaymentRequests/CreatePaymentRequestsModal.js | 12 ++++++++++-- .../Pages/PaymentRequests/PaymentsModel.cs | 1 + 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml index 10a747240..25b48a75e 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml @@ -93,6 +93,7 @@ + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs index 04dcb568d..ca7ea9728 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs @@ -471,6 +471,7 @@ private async Task PopulateParentChildValidationData() { child.MaximumAllowedAmount = maximumPaymentAmount; child.IsPartOfParentChildGroup = true; + child.ParentApprovedAmount = approvedAmount; } // Apply validation data to parent if in submission @@ -478,6 +479,7 @@ private async Task PopulateParentChildValidationData() { parentInSubmission.MaximumAllowedAmount = maximumPaymentAmount; parentInSubmission.IsPartOfParentChildGroup = true; + parentInSubmission.ParentApprovedAmount = approvedAmount; } } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequestsModal.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequestsModal.js index f07bfd6cd..8c2ef8440 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequestsModal.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequestsModal.js @@ -169,9 +169,15 @@ function validateParentChildAmounts(correlationId) { let maximumAllowedInput = $( `input[name="ApplicationPaymentRequestForm[${index}].MaximumAllowedAmount"]` ).val(); + let parentApprovedAmount = $( + `input[name="ApplicationPaymentRequestForm[${index}].ParentApprovedAmount"]` + ).val(); let maximumAllowed = maximumAllowedInput ? parseFloat(maximumAllowedInput) : 0; + let approvedAmount = parentApprovedAmount + ? parseFloat(parentApprovedAmount) + : 0; // Determine if this is a parent or child let isChild = parentRefNo && parentRefNo.trim() !== ''; @@ -223,9 +229,11 @@ function validateParentChildAmounts(correlationId) { if (hasError) { let message = `The payment amount (${formatCurrency( groupTotal - )}) exceeds the parent's approved amount (${formatCurrency( + )}) exceeds the remaining balance (${formatCurrency( maximumAllowed - )}).`; + )}) of the approved amount (${formatCurrency( + approvedAmount + )}) for the application or its parent application.`; errorMessage.text(message); errorDiv.css('display', 'block'); } else { diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/PaymentsModel.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/PaymentsModel.cs index 3c951a240..30fcfd50a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/PaymentsModel.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/PaymentsModel.cs @@ -37,6 +37,7 @@ public class PaymentsModel public Guid? AccountCodingId { get; set; } public string? ParentReferenceNo { get; set; } public decimal? MaximumAllowedAmount { get; set; } + public decimal? ParentApprovedAmount { get; set; } public bool IsPartOfParentChildGroup { get; set; } } } From 1c6e32221a352bd18e6b4de28150fb41ab68f2e7 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Thu, 5 Feb 2026 19:24:10 -0800 Subject: [PATCH 08/42] AB#30069: Group parent-child payment requests with a pink outline --- .../CreatePaymentRequests.cshtml | 93 +++++++++++++++---- .../CreatePaymentRequestsModal.js | 40 ++++---- 2 files changed, 94 insertions(+), 39 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml index 25b48a75e..ea1a8ec86 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml @@ -26,6 +26,28 @@ color: var(--lpx-danger); border-color: var(--lpx-danger); } + + .parent-child-group { + border: 2px solid #e91e8c; + border-radius: 8px; + padding: 0; + margin-bottom: 16px; + overflow: hidden; + } + + .parent-child-group .single-payment { + border: none; + border-bottom: 1px solid var(--bs-border-color); + } + + .parent-child-group .single-payment:last-of-type { + border-bottom: none; + } + + .parent-child-group-error { + padding: 4px 12px 4px 12px; + background-color: #FEEAEA; + } @@ -60,24 +82,48 @@ + @{ + string? currentGroupKey = null; + bool groupOpen = false; + } @for (var i = 0; i < Model.ApplicationPaymentRequestForm?.Count; i++) { -
+ var item = Model.ApplicationPaymentRequestForm[i]; + string? itemGroupKey = item.IsPartOfParentChildGroup + ? (!string.IsNullOrEmpty(item.ParentReferenceNo) ? item.ParentReferenceNo : item.SubmissionConfirmationCode) + : null; + + string? nextGroupKey = null; + if (i + 1 < Model.ApplicationPaymentRequestForm.Count) + { + var next = Model.ApplicationPaymentRequestForm[i + 1]; + nextGroupKey = next.IsPartOfParentChildGroup + ? (!string.IsNullOrEmpty(next.ParentReferenceNo) ? next.ParentReferenceNo : next.SubmissionConfirmationCode) + : null; + } + + if (itemGroupKey != null && itemGroupKey != currentGroupKey) + { + @:
+ groupOpen = true; + } + +
- @Model.ApplicationPaymentRequestForm[i].ApplicantName/@Model.ApplicationPaymentRequestForm[i].InvoiceNumber - @if (!string.IsNullOrEmpty(Model.ApplicationPaymentRequestForm[i].ParentReferenceNo)) + @item.ApplicantName/@item.InvoiceNumber + @if (!string.IsNullOrEmpty(item.ParentReferenceNo)) { -   (Parent Id: @Model.ApplicationPaymentRequestForm[i].ParentReferenceNo) +   (Parent Id: @item.ParentReferenceNo) }
- + data-parameter="@item.CorrelationId" />
@@ -98,38 +144,45 @@ - + - + disabled="@item.DisableFields" + onchange='checkMaxValueRequest("@item.CorrelationId",this, @item.RemainingAmount)' /> - + - + -
+ + if (groupOpen && nextGroupKey != itemGroupKey) + { + @: + @:
+ groupOpen = false; + } + + currentGroupKey = itemGroupKey; }
@foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties()) diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js index d1ec54885..6345358b2 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js @@ -279,15 +279,29 @@ }); }); - $(document).ready(function () { - $('.cas-client-select').on('change', function () { - const selectedOption = $(this).find('option:selected'); - const ministryValue = selectedOption.data('ministry') || ''; - const targetInput = $($(this).data('ministry-target')); - - if (targetInput.length) { - targetInput.val(ministryValue); + // Use event delegation to handle dynamically loaded elements + $(document).on('change', '.cas-client-select', function() { + const $select = $(this); + const selectedOption = $select.find('option:selected'); + + // Handle ministry field update + const ministryValue = selectedOption.data('ministry') || ''; + const ministryTarget = $select.data('ministry-target'); + if (ministryTarget) { + const $targetInput = $(ministryTarget); + if ($targetInput.length) { + $targetInput.val(ministryValue); } - }); + } + + // Handle CAS client code update + const casClientCode = selectedOption.data('cas-client-code'); + if (casClientCode) { + const $container = $select.closest('form, .modal-body'); + const $hiddenField = $container.find('input[name="CasClientCode"]'); + if ($hiddenField.length) { + $hiddenField.val(casClientCode); + } + } }); })(); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs index e66ece046..838ea1525 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs @@ -130,10 +130,10 @@ public GrantManagerApplicationAutoMapperProfile() // Add the tenant management mapping here CreateMap() - .ForMember(dest => dest.CasClientCode, opt => opt.MapFrom(src => GetExtraPropertyAsString(src, "CasClientCode"))) - .ForMember(dest => dest.Division, opt => opt.MapFrom(src => GetExtraPropertyAsString(src, "Division"))) - .ForMember(dest => dest.Branch, opt => opt.MapFrom(src => GetExtraPropertyAsString(src, "Branch"))) - .ForMember(dest => dest.Description, opt => opt.MapFrom(src => GetExtraPropertyAsString(src, "Description"))); + .ForMember(dest => dest.CasClientCode, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("CasClientCode") ? (string?)src.ExtraProperties["CasClientCode"] : null)) + .ForMember(dest => dest.Division, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("Division") ? (string?)src.ExtraProperties["Division"] : null)) + .ForMember(dest => dest.Branch, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("Branch") ? (string?)src.ExtraProperties["Branch"] : null)) + .ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("Description") ? (string?)src.ExtraProperties["Description"] : null)); } private static bool? ConvertIndigenousOrgIndToBool(string indigenousOrgInd) @@ -156,14 +156,6 @@ public GrantManagerApplicationAutoMapperProfile() }; } - private static string GetExtraPropertyAsString(Tenant tenant, string propertyName) - { - if (tenant.ExtraProperties?.ContainsKey(propertyName) == true) - { - return tenant.ExtraProperties[propertyName]?.ToString() ?? string.Empty; - } - return string.Empty; - } } // Extension methods for reusable mapping configurations diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Integrations/CasClientCodeAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Integrations/CasClientCodeAppService.cs index 069f49871..c2f51e114 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Integrations/CasClientCodeAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Integrations/CasClientCodeAppService.cs @@ -2,13 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; using Unity.GrantManager.Applications; +using Volo.Abp; using Volo.Abp.Application.Services; namespace Unity.GrantManager.Integrations { - [AllowAnonymous] + [RemoteService(false)] public class CasClientCodeLookupService(ICasClientCodeRepository repository) : ApplicationService, ICasClientCodeLookupService { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Integrations/Endpoints/EndpointManagementAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Integrations/Endpoints/EndpointManagementAppService.cs index 21cb718ec..59f7fa3a8 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Integrations/Endpoints/EndpointManagementAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Integrations/Endpoints/EndpointManagementAppService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Caching.Distributed; using Volo.Abp; using Volo.Abp.Application.Dtos; @@ -64,6 +65,8 @@ private async Task RemoveFromKeySetAsync(string cacheKey, Guid? tenantId) } [UnitOfWork] + [RemoteService(false)] + [AllowAnonymous] public async Task GetChefsApiBaseUrlAsync() { var url = await GetUrlByKeyNameInternalAsync(DynamicUrlKeyNames.INTAKE_API_BASE, tenantSpecific: false); @@ -75,6 +78,8 @@ public async Task GetChefsApiBaseUrlAsync() } [UnitOfWork] + [RemoteService(false)] + [AllowAnonymous] public async Task GetUgmUrlByKeyNameAsync(string keyName) { var url = await GetUrlByKeyNameInternalAsync(keyName, tenantSpecific: false); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json index 5ed005005..452a5ac1d 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json @@ -1,7 +1,7 @@ { "ConnectionStrings": { - "Default": "Host=localhost;port=5432;Database=UnityGrantManager;Username=postgres;Password=admin;", - "Tenant": "Host=localhost;port=5432;Database=UnityGrantTenant;Username=postgres;Password=admin;" + "Default": "Host=localhost;port=5432;Database=UnityGrantManager;Username=postgres", + "Tenant": "Host=localhost;port=5432;Database=UnityGrantTenant;Username=postgres" }, "Redis": { "Configuration": "127.0.0.1" diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Integrations/CasClientCode.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Integrations/CasClientCode.cs index 667ef04b5..c6ff0602f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Integrations/CasClientCode.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Integrations/CasClientCode.cs @@ -1,16 +1,21 @@ using System; +using System.ComponentModel.DataAnnotations; using Volo.Abp.Domain.Entities.Auditing; namespace Unity.GrantManager.Integrations; -public class CasClientCode : AuditedEntity +public class CasClientCode : FullAuditedAggregateRoot { + [MaxLength(3)] public string ClientCode { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + + [MaxLength(3)] public string MinistryPrefix { get; set; } = string.Empty; + public string? FinancialMinistry { get; set; } public string? ClientId { get; set; } public bool IsActive { get; set; } = true; public DateTimeOffset? LastUpdatedTime { get; set; } - public string ConcurrencyStamp { get; set; } = string.Empty; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebAutoMapperProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebAutoMapperProfile.cs deleted file mode 100644 index 517163f42..000000000 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebAutoMapperProfile.cs +++ /dev/null @@ -1,31 +0,0 @@ -using AutoMapper; -using Unity.TenantManagement; -using Unity.TenantManagement.Web.Pages.TenantManagement.Tenants; - -namespace Unity.GrantManager.Web -{ - public class GrantManagerWebAutoMapperProfile : Profile - { - public GrantManagerWebAutoMapperProfile() - { - // Web-specific mappings only - CreateMap() - .ForMember(dest => dest.CasClientCode, opt => opt.MapFrom(src => src.CasClientCode)) - .ForMember(dest => dest.Division, opt => opt.MapFrom(src => src.Division)) - .ForMember(dest => dest.Branch, opt => opt.MapFrom(src => src.Branch)) - .ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description)); - - CreateMap() - .ForMember(dest => dest.CasClientCode, opt => opt.MapFrom(src => src.CasClientCode)) - .ForMember(dest => dest.Division, opt => opt.MapFrom(src => src.Division)) - .ForMember(dest => dest.Branch, opt => opt.MapFrom(src => src.Branch)) - .ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description)); - - CreateMap() - .ForMember(dest => dest.CasClientCode, opt => opt.MapFrom(src => src.CasClientCode)) - .ForMember(dest => dest.Division, opt => opt.MapFrom(src => src.Division)) - .ForMember(dest => dest.Branch, opt => opt.MapFrom(src => src.Branch)) - .ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description)); - } - } -} \ No newline at end of file From c8c72c2ac5450104b9acd4cd2b5f1f164d3a1f70 Mon Sep 17 00:00:00 2001 From: JamesPasta Date: Thu, 12 Feb 2026 13:28:57 -0800 Subject: [PATCH 23/42] feature/AB#31672-AddTenantFields --- .../UnityTenantManagementApplicationModule.cs | 29 ++++++++++--------- .../UnityTenantManagementAutoMapperProfile.cs | 18 ++++++++++++ ...rantManagerApplicationAutoMapperProfile.cs | 9 ------ 3 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementApplicationModule.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementApplicationModule.cs index 32bb2462f..7b1d7a961 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementApplicationModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementApplicationModule.cs @@ -1,23 +1,26 @@ using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Application; using Volo.Abp.AutoMapper; using Volo.Abp.Modularity; using Volo.Abp.TenantManagement; -namespace Unity.TenantManagement; - -[DependsOn(typeof(AbpTenantManagementDomainModule))] -[DependsOn(typeof(AbpTenantManagementApplicationModule))] -[DependsOn(typeof(UnityTenantManagementApplicationContractsModule))] -[DependsOn(typeof(AbpDddApplicationModule))] -public class UnityTenantManagementApplicationModule : AbpModule +namespace Unity.TenantManagement { - public override void ConfigureServices(ServiceConfigurationContext context) + [DependsOn( + typeof(AbpTenantManagementDomainModule), + typeof(UnityTenantManagementApplicationContractsModule), + typeof(AbpTenantManagementApplicationModule), + typeof(AbpAutoMapperModule) + )] + public class UnityTenantManagementApplicationModule : AbpModule { - context.Services.AddAutoMapperObjectMapper(); - Configure(options => + public override void ConfigureServices(ServiceConfigurationContext context) { - options.AddProfile(validate: true); - }); + context.Services.AddAutoMapperObjectMapper(); + + Configure(options => + { + options.AddMaps(validate: true); + }); + } } } diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs new file mode 100644 index 000000000..f39f50b08 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs @@ -0,0 +1,18 @@ +using AutoMapper; +using Volo.Abp.TenantManagement; + +namespace Unity.TenantManagement +{ + public class UnityTenantManagementAutoMapperProfile : Profile + { + public UnityTenantManagementAutoMapperProfile() + { + // Add the tenant management mapping here + CreateMap() + .ForMember(dest => dest.CasClientCode, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("CasClientCode") ? (string?)src.ExtraProperties["CasClientCode"] : null)) + .ForMember(dest => dest.Division, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("Division") ? (string?)src.ExtraProperties["Division"] : null)) + .ForMember(dest => dest.Branch, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("Branch") ? (string?)src.ExtraProperties["Branch"] : null)) + .ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("Description") ? (string?)src.ExtraProperties["Description"] : null)); + } + } +} \ No newline at end of file diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs index 838ea1525..fd3459abe 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs @@ -1,8 +1,5 @@ using AutoMapper; using System; -using System.Collections.Generic; -using Unity.TenantManagement; -using Volo.Abp.TenantManagement; using Unity.GrantManager.ApplicationForms; using Unity.GrantManager.Applications; using Unity.GrantManager.Assessments; @@ -128,12 +125,6 @@ public GrantManagerApplicationAutoMapperProfile() .ForMember(dest => dest.Postal, opt => opt.MapFrom(src => src.PostalCode)) .IgnoreNullAndDefaultValues(); - // Add the tenant management mapping here - CreateMap() - .ForMember(dest => dest.CasClientCode, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("CasClientCode") ? (string?)src.ExtraProperties["CasClientCode"] : null)) - .ForMember(dest => dest.Division, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("Division") ? (string?)src.ExtraProperties["Division"] : null)) - .ForMember(dest => dest.Branch, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("Branch") ? (string?)src.ExtraProperties["Branch"] : null)) - .ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("Description") ? (string?)src.ExtraProperties["Description"] : null)); } private static bool? ConvertIndigenousOrgIndToBool(string indigenousOrgInd) From cb4de543ea3ee0bfec76b3f7ea6e249452c5a77b Mon Sep 17 00:00:00 2001 From: JamesPasta Date: Thu, 12 Feb 2026 13:53:51 -0800 Subject: [PATCH 24/42] feature/AB#31672-AddTenantFields-Sonar --- .../UnityTenantManagementAutoMapperProfile.cs | 2 ++ .../Pages/TenantManagement/Tenants/Index.js | 4 ++-- .../Integrations/CasClientCodeAppService.cs | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs index f39f50b08..72a801530 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs @@ -1,3 +1,5 @@ +#nullable enable + using AutoMapper; using Volo.Abp.TenantManagement; diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js index 6345358b2..049537e2f 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js @@ -117,8 +117,8 @@ render: function (data, type, row) { if (type === 'display') { const code = row.casClientCode || ''; - const displayValue = globalThis.casClientCodeHash && globalThis.casClientCodeHash[code] ? globalThis.casClientCodeHash[code] : ''; - return displayValue || ''; + const displayValue = globalThis.casClientCodeHash?.[code] || ''; + return displayValue; } return data; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Integrations/CasClientCodeAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Integrations/CasClientCodeAppService.cs index c2f51e114..d1d72f89f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Integrations/CasClientCodeAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Integrations/CasClientCodeAppService.cs @@ -34,10 +34,9 @@ public async Task> GetActiveOptionsAsync() return null; } - var normalizedCode = casClientCode.Trim().ToUpper(); var queryable = await repository.GetQueryableAsync(); var code = await AsyncExecuter.FirstOrDefaultAsync( - queryable.Where(x => x.ClientCode.ToUpper() == normalizedCode) + queryable.Where(x => x.ClientCode == casClientCode) ); return code?.ClientId; From 9bb20c0cfc33f23e45b8409cffb42cafd1747572 Mon Sep 17 00:00:00 2001 From: JamesPasta Date: Thu, 12 Feb 2026 14:32:38 -0800 Subject: [PATCH 25/42] feature/AB#31672-AddTenantFields-Sonar --- .../UnityTenantManagementAutoMapperProfile.cs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs index 72a801530..8c11a3282 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs @@ -9,12 +9,20 @@ public class UnityTenantManagementAutoMapperProfile : Profile { public UnityTenantManagementAutoMapperProfile() { - // Add the tenant management mapping here - CreateMap() - .ForMember(dest => dest.CasClientCode, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("CasClientCode") ? (string?)src.ExtraProperties["CasClientCode"] : null)) - .ForMember(dest => dest.Division, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("Division") ? (string?)src.ExtraProperties["Division"] : null)) - .ForMember(dest => dest.Branch, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("Branch") ? (string?)src.ExtraProperties["Branch"] : null)) - .ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.ExtraProperties.ContainsKey("Description") ? (string?)src.ExtraProperties["Description"] : null)); + CreateMap() + .ForMember(dest => dest.CasClientCode, opt => opt.MapFrom(src => + GetExtraProperty(src, "CasClientCode"))) + .ForMember(dest => dest.Division, opt => opt.MapFrom(src => + GetExtraProperty(src, "Division"))) + .ForMember(dest => dest.Branch, opt => opt.MapFrom(src => + GetExtraProperty(src, "Branch"))) + .ForMember(dest => dest.Description, opt => opt.MapFrom(src => + GetExtraProperty(src, "Description"))); + } + + private static string? GetExtraProperty(Tenant tenant, string key) + { + return tenant.ExtraProperties.TryGetValue(key, out var value) ? value?.ToString() : null; } } } \ No newline at end of file From 46ff608b08626a6895deadad1198e412ae7570df Mon Sep 17 00:00:00 2001 From: JamesPasta Date: Thu, 12 Feb 2026 14:49:22 -0800 Subject: [PATCH 26/42] feature/AB#31672-AddTenantFields-Sonar --- .../Permissions/GrantApplicationPermissions.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs index b3997090f..2363a1d3e 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs @@ -105,6 +105,22 @@ public static class ApplicantInfo public const string DeleteAdditionalContact = Default + ".AdditionalContact" + Operation.Delete; } + public static class Payments + { + public const string Default = GroupName + ".Payments"; + public const string Create = Default + ".Create"; + public const string Edit = Default + ".Edit"; + public const string Delete = Default + ".Delete"; + + public static class PaymentRequests + { + public const string PaymentRequestsDefault = Payments.Default + ".PaymentRequests"; + public const string Create = PaymentRequestsDefault + ".Create"; + public const string Edit = PaymentRequestsDefault + ".Edit"; + public const string Delete = PaymentRequestsDefault + ".Delete"; + } + } + public static string[] GetAll() { return ReflectionHelper.GetPublicConstantsRecursively(typeof(GrantApplicationPermissions)); From e93a8217a3b5e0caa379b29a756fca7b1a504df9 Mon Sep 17 00:00:00 2001 From: JamesPasta Date: Thu, 12 Feb 2026 15:23:49 -0800 Subject: [PATCH 27/42] feature/AB#31672-AddTenantFields-Sonar --- .../Permissions/GrantApplicationPermissions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs index 2363a1d3e..03034afe8 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs @@ -114,10 +114,10 @@ public static class Payments public static class PaymentRequests { - public const string PaymentRequestsDefault = Payments.Default + ".PaymentRequests"; - public const string Create = PaymentRequestsDefault + ".Create"; - public const string Edit = PaymentRequestsDefault + ".Edit"; - public const string Delete = PaymentRequestsDefault + ".Delete"; + public const string Default = Payments.Default + ".PaymentRequests"; + public const string Create = Default + Operation.Create; + public const string Update = Default + Operation.Update; + public const string Delete = Default + Operation.Delete; } } From 6cf918c2a970744c1db05a41717d924097a4387e Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Thu, 12 Feb 2026 15:34:21 -0800 Subject: [PATCH 28/42] AB#31896 profile request services --- .../Applicants/ApplicantProfileDto.cs | 8 +- .../Applicants/ApplicantProfileRequest.cs | 9 +- .../Applicants/IApplicantProfileAppService.cs | 2 +- .../ProfileData/ApplicantAddressInfoDto.cs | 6 + .../ProfileData/ApplicantContactInfoDto.cs | 6 + .../ProfileData/ApplicantOrgInfoDto.cs | 6 + .../ProfileData/ApplicantPaymentInfoDto.cs | 6 + .../ProfileData/ApplicantProfileDataDto.cs | 6 + .../ProfileData/ApplicantSubmissionInfoDto.cs | 6 + .../AddressInfoDataProvider.cs | 18 ++ .../ApplicantProfile/ApplicantProfileKeys.cs | 11 ++ .../ContactInfoDataProvider.cs | 18 ++ .../IApplicantProfileDataProvider.cs | 11 ++ .../ApplicantProfile/OrgInfoDataProvider.cs | 18 ++ .../PaymentInfoDataProvider.cs | 18 ++ .../SubmissionInfoDataProvider.cs | 18 ++ .../Applicants/ApplicantProfileAppService.cs | 29 +++- .../Controllers/ApplicantProfileController.cs | 2 +- .../ApplicantProfileAppServiceTests.cs | 163 ++++++++++++++++++ .../ApplicantProfileDataProviderTests.cs | 117 +++++++++++++ 20 files changed, 462 insertions(+), 16 deletions(-) create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantAddressInfoDto.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantContactInfoDto.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantOrgInfoDto.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantPaymentInfoDto.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantProfileDataDto.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantSubmissionInfoDto.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/AddressInfoDataProvider.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ApplicantProfileKeys.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ContactInfoDataProvider.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/IApplicantProfileDataProvider.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/OrgInfoDataProvider.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/PaymentInfoDataProvider.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs create mode 100644 applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Applicants/ApplicantProfileAppServiceTests.cs create mode 100644 applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Applicants/ApplicantProfileDataProviderTests.cs diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ApplicantProfileDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ApplicantProfileDto.cs index 30e2c1335..9ec81114f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ApplicantProfileDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ApplicantProfileDto.cs @@ -1,12 +1,14 @@ using System; +using Unity.GrantManager.Applicants.ProfileData; namespace Unity.GrantManager.Applicants { public class ApplicantProfileDto { public Guid ProfileId { get; set; } - public string Subject { get; set; } = string.Empty; - public string Email { get; set; } = string.Empty; - public string DisplayName { get; set; } = string.Empty; + public string Subject { get; set; } = string.Empty; + public string Key { get; set; } = string.Empty; + public Guid TenantId { get; set; } + public ApplicantProfileDataDto? Data { get; set; } } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ApplicantProfileRequest.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ApplicantProfileRequest.cs index 3e5e2b610..9f65d31cd 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ApplicantProfileRequest.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ApplicantProfileRequest.cs @@ -4,12 +4,13 @@ namespace Unity.GrantManager.Applicants { public class ApplicantProfileRequest { - public Guid ProfileId { get; set; } = Guid.NewGuid(); - public string Subject { get; set; } = string.Empty; + public Guid ProfileId { get; set; } = Guid.Empty; + public string Subject { get; set; } = string.Empty; } - public class TenantedApplicantProfileRequest : ApplicantProfileRequest + public class ApplicantProfileInfoRequest : ApplicantProfileRequest { - public Guid TenantId { get; set; } + public Guid TenantId { get; set; } = Guid.Empty; + public string Key { get; set; } = string.Empty; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/IApplicantProfileAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/IApplicantProfileAppService.cs index bab1f950c..968cef47f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/IApplicantProfileAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/IApplicantProfileAppService.cs @@ -5,7 +5,7 @@ namespace Unity.GrantManager.Applicants { public interface IApplicantProfileAppService { - Task GetApplicantProfileAsync(ApplicantProfileRequest request); + Task GetApplicantProfileAsync(ApplicantProfileInfoRequest request); Task> GetApplicantTenantsAsync(ApplicantProfileRequest request); Task<(int Created, int Updated)> ReconcileApplicantTenantMapsAsync(); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantAddressInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantAddressInfoDto.cs new file mode 100644 index 000000000..5a3206043 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantAddressInfoDto.cs @@ -0,0 +1,6 @@ +namespace Unity.GrantManager.Applicants.ProfileData +{ + public class ApplicantAddressInfoDto : ApplicantProfileDataDto + { + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantContactInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantContactInfoDto.cs new file mode 100644 index 000000000..f89c87388 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantContactInfoDto.cs @@ -0,0 +1,6 @@ +namespace Unity.GrantManager.Applicants.ProfileData +{ + public class ApplicantContactInfoDto : ApplicantProfileDataDto + { + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantOrgInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantOrgInfoDto.cs new file mode 100644 index 000000000..e8b6d6115 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantOrgInfoDto.cs @@ -0,0 +1,6 @@ +namespace Unity.GrantManager.Applicants.ProfileData +{ + public class ApplicantOrgInfoDto : ApplicantProfileDataDto + { + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantPaymentInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantPaymentInfoDto.cs new file mode 100644 index 000000000..996fe0b49 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantPaymentInfoDto.cs @@ -0,0 +1,6 @@ +namespace Unity.GrantManager.Applicants.ProfileData +{ + public class ApplicantPaymentInfoDto : ApplicantProfileDataDto + { + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantProfileDataDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantProfileDataDto.cs new file mode 100644 index 000000000..b7ce18235 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantProfileDataDto.cs @@ -0,0 +1,6 @@ +namespace Unity.GrantManager.Applicants.ProfileData +{ + public abstract class ApplicantProfileDataDto + { + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantSubmissionInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantSubmissionInfoDto.cs new file mode 100644 index 000000000..e74e994bb --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantSubmissionInfoDto.cs @@ -0,0 +1,6 @@ +namespace Unity.GrantManager.Applicants.ProfileData +{ + public class ApplicantSubmissionInfoDto : ApplicantProfileDataDto + { + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/AddressInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/AddressInfoDataProvider.cs new file mode 100644 index 000000000..89b5b2020 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/AddressInfoDataProvider.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Unity.GrantManager.Applicants.ProfileData; +using Volo.Abp.DependencyInjection; + +namespace Unity.GrantManager.Applicants.ApplicantProfile +{ + [ExposeServices(typeof(IApplicantProfileDataProvider))] + public class AddressInfoDataProvider : IApplicantProfileDataProvider, ITransientDependency + { + public string Key => ApplicantProfileKeys.AddressInfo; + + public Task GetDataAsync(ApplicantProfileInfoRequest request) + { + // TODO: Implement address info retrieval + return Task.FromResult(new ApplicantAddressInfoDto()); + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ApplicantProfileKeys.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ApplicantProfileKeys.cs new file mode 100644 index 000000000..4b232c453 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ApplicantProfileKeys.cs @@ -0,0 +1,11 @@ +namespace Unity.GrantManager.Applicants.ApplicantProfile +{ + public static class ApplicantProfileKeys + { + public const string ContactInfo = "CONTACTINFO"; + public const string OrgInfo = "ORGINFO"; + public const string AddressInfo = "ADDRESSINFO"; + public const string SubmissionInfo = "SUBMISSIONINFO"; + public const string PaymentInfo = "PAYMENTINFO"; + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ContactInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ContactInfoDataProvider.cs new file mode 100644 index 000000000..50693fbe7 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ContactInfoDataProvider.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Unity.GrantManager.Applicants.ProfileData; +using Volo.Abp.DependencyInjection; + +namespace Unity.GrantManager.Applicants.ApplicantProfile +{ + [ExposeServices(typeof(IApplicantProfileDataProvider))] + public class ContactInfoDataProvider : IApplicantProfileDataProvider, ITransientDependency + { + public string Key => ApplicantProfileKeys.ContactInfo; + + public Task GetDataAsync(ApplicantProfileInfoRequest request) + { + // TODO: Implement contact info retrieval + return Task.FromResult(new ApplicantContactInfoDto()); + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/IApplicantProfileDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/IApplicantProfileDataProvider.cs new file mode 100644 index 000000000..b72f60d06 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/IApplicantProfileDataProvider.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using Unity.GrantManager.Applicants.ProfileData; + +namespace Unity.GrantManager.Applicants.ApplicantProfile +{ + public interface IApplicantProfileDataProvider + { + string Key { get; } + Task GetDataAsync(ApplicantProfileInfoRequest request); + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/OrgInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/OrgInfoDataProvider.cs new file mode 100644 index 000000000..5a36a0a5b --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/OrgInfoDataProvider.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Unity.GrantManager.Applicants.ProfileData; +using Volo.Abp.DependencyInjection; + +namespace Unity.GrantManager.Applicants.ApplicantProfile +{ + [ExposeServices(typeof(IApplicantProfileDataProvider))] + public class OrgInfoDataProvider : IApplicantProfileDataProvider, ITransientDependency + { + public string Key => ApplicantProfileKeys.OrgInfo; + + public Task GetDataAsync(ApplicantProfileInfoRequest request) + { + // TODO: Implement organization info retrieval + return Task.FromResult(new ApplicantOrgInfoDto()); + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/PaymentInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/PaymentInfoDataProvider.cs new file mode 100644 index 000000000..925940ae0 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/PaymentInfoDataProvider.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Unity.GrantManager.Applicants.ProfileData; +using Volo.Abp.DependencyInjection; + +namespace Unity.GrantManager.Applicants.ApplicantProfile +{ + [ExposeServices(typeof(IApplicantProfileDataProvider))] + public class PaymentInfoDataProvider : IApplicantProfileDataProvider, ITransientDependency + { + public string Key => ApplicantProfileKeys.PaymentInfo; + + public Task GetDataAsync(ApplicantProfileInfoRequest request) + { + // TODO: Implement payment info retrieval + return Task.FromResult(new ApplicantPaymentInfoDto()); + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs new file mode 100644 index 000000000..6151e9483 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Unity.GrantManager.Applicants.ProfileData; +using Volo.Abp.DependencyInjection; + +namespace Unity.GrantManager.Applicants.ApplicantProfile +{ + [ExposeServices(typeof(IApplicantProfileDataProvider))] + public class SubmissionInfoDataProvider : IApplicantProfileDataProvider, ITransientDependency + { + public string Key => ApplicantProfileKeys.SubmissionInfo; + + public Task GetDataAsync(ApplicantProfileInfoRequest request) + { + // TODO: Implement submission info retrieval + return Task.FromResult(new ApplicantSubmissionInfoDto()); + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfileAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfileAppService.cs index 7f7066a0f..f99b1e9ce 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfileAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfileAppService.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; +using Unity.GrantManager.Applicants.ApplicantProfile; using Unity.GrantManager.Applications; using Volo.Abp; using Volo.Abp.Application.Services; @@ -18,9 +19,12 @@ public class ApplicantProfileAppService( ICurrentTenant currentTenant, ITenantRepository tenantRepository, IRepository applicantTenantMapRepository, - IRepository applicationFormSubmissionRepository) + IRepository applicationFormSubmissionRepository, + IEnumerable dataProviders) : ApplicationService, IApplicantProfileAppService { + private readonly Dictionary _providersByKey + = dataProviders.ToDictionary(p => p.Key, StringComparer.OrdinalIgnoreCase); /// /// Retrieves the applicant's profile information based on the specified request. @@ -28,15 +32,26 @@ public class ApplicantProfileAppService( /// An object containing the criteria used to identify the applicant profile to retrieve. Must not be null. /// A task that represents the asynchronous operation. The task result contains an with the applicant's profile data. - public async Task GetApplicantProfileAsync(ApplicantProfileRequest request) + public async Task GetApplicantProfileAsync(ApplicantProfileInfoRequest request) { - return await Task.FromResult(new ApplicantProfileDto + var dto = new ApplicantProfileDto { ProfileId = request.ProfileId, - Subject = request.Subject, - Email = string.Empty, - DisplayName = string.Empty - }); + Subject = request.Subject, + TenantId = request.TenantId, + Key = request.Key + }; + + if (_providersByKey.TryGetValue(request.Key, out var provider)) + { + dto.Data = await provider.GetDataAsync(request); + } + else + { + Logger.LogWarning("Unknown applicant profile key: {Key}", request.Key); + } + + return dto; } /// diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Controllers/ApplicantProfileController.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Controllers/ApplicantProfileController.cs index 61dee526b..bff4d0f6b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Controllers/ApplicantProfileController.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Controllers/ApplicantProfileController.cs @@ -14,7 +14,7 @@ public class ApplicantProfileController(IApplicantProfileAppService applicantPro [HttpGet] [Route("profile")] - public async Task GetApplicantProfileAsync([FromQuery] TenantedApplicantProfileRequest applicantProfileRequest) + public async Task GetApplicantProfileAsync([FromQuery] ApplicantProfileInfoRequest applicantProfileRequest) { var profile = await applicantProfileAppService.GetApplicantProfileAsync(applicantProfileRequest); return Ok(profile); diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Applicants/ApplicantProfileAppServiceTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Applicants/ApplicantProfileAppServiceTests.cs new file mode 100644 index 000000000..acc04712a --- /dev/null +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Applicants/ApplicantProfileAppServiceTests.cs @@ -0,0 +1,163 @@ +using NSubstitute; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Unity.GrantManager.Applicants.ApplicantProfile; +using Unity.GrantManager.Applicants.ProfileData; +using Unity.GrantManager.Applications; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.MultiTenancy; +using Volo.Abp.TenantManagement; +using Xunit; + +namespace Unity.GrantManager.Applicants +{ + public class ApplicantProfileAppServiceTests + { + private readonly ICurrentTenant _currentTenant; + private readonly ITenantRepository _tenantRepository; + private readonly IRepository _applicantTenantMapRepository; + private readonly IRepository _applicationFormSubmissionRepository; + + public ApplicantProfileAppServiceTests() + { + _currentTenant = Substitute.For(); + _tenantRepository = Substitute.For(); + _applicantTenantMapRepository = Substitute.For>(); + _applicationFormSubmissionRepository = Substitute.For>(); + } + + private ApplicantProfileAppService CreateService(IEnumerable providers) + { + return new ApplicantProfileAppService( + _currentTenant, + _tenantRepository, + _applicantTenantMapRepository, + _applicationFormSubmissionRepository, + providers); + } + + private static ApplicantProfileInfoRequest CreateRequest(string key) => new() + { + ProfileId = Guid.NewGuid(), + Subject = "testuser@idir", + TenantId = Guid.NewGuid(), + Key = key + }; + + [Theory] + [InlineData(ApplicantProfileKeys.ContactInfo)] + [InlineData(ApplicantProfileKeys.OrgInfo)] + [InlineData(ApplicantProfileKeys.AddressInfo)] + [InlineData(ApplicantProfileKeys.SubmissionInfo)] + [InlineData(ApplicantProfileKeys.PaymentInfo)] + public async Task GetApplicantProfileAsync_WithValidKey_ShouldReturnDataFromProvider(string key) + { + // Arrange + var expectedData = Substitute.For(); + var mockProvider = Substitute.For(); + mockProvider.Key.Returns(key); + mockProvider.GetDataAsync(Arg.Any()).Returns(expectedData); + + var service = CreateService([mockProvider]); + var request = CreateRequest(key); + + // Act + var result = await service.GetApplicantProfileAsync(request); + + // Assert + result.ShouldNotBeNull(); + result.Key.ShouldBe(key); + result.Data.ShouldBe(expectedData); + result.ProfileId.ShouldBe(request.ProfileId); + result.Subject.ShouldBe(request.Subject); + result.TenantId.ShouldBe(request.TenantId); + await mockProvider.Received(1).GetDataAsync(Arg.Is(r => r.Key == key)); + } + + [Fact] + public async Task GetApplicantProfileAsync_WithUnknownKey_ShouldReturnNullData() + { + // Arrange + var service = CreateService([]); + var request = CreateRequest("UNKNOWNKEY"); + + // Act + var result = await service.GetApplicantProfileAsync(request); + + // Assert + result.ShouldNotBeNull(); + result.Key.ShouldBe("UNKNOWNKEY"); + result.Data.ShouldBeNull(); + } + + [Fact] + public async Task GetApplicantProfileAsync_KeyLookupIsCaseInsensitive() + { + // Arrange + var expectedData = Substitute.For(); + var mockProvider = Substitute.For(); + mockProvider.Key.Returns(ApplicantProfileKeys.ContactInfo); + mockProvider.GetDataAsync(Arg.Any()).Returns(expectedData); + + var service = CreateService([mockProvider]); + var request = CreateRequest("contactinfo"); + + // Act + var result = await service.GetApplicantProfileAsync(request); + + // Assert + result.Data.ShouldBe(expectedData); + } + + [Fact] + public async Task GetApplicantProfileAsync_WithMultipleProviders_ShouldDispatchToCorrectOne() + { + // Arrange + var contactData = new ApplicantContactInfoDto(); + var orgData = new ApplicantOrgInfoDto(); + + var contactProvider = Substitute.For(); + contactProvider.Key.Returns(ApplicantProfileKeys.ContactInfo); + contactProvider.GetDataAsync(Arg.Any()).Returns(contactData); + + var orgProvider = Substitute.For(); + orgProvider.Key.Returns(ApplicantProfileKeys.OrgInfo); + orgProvider.GetDataAsync(Arg.Any()).Returns(orgData); + + var service = CreateService([contactProvider, orgProvider]); + + // Act + var result = await service.GetApplicantProfileAsync(CreateRequest(ApplicantProfileKeys.OrgInfo)); + + // Assert + result.Data.ShouldBeOfType(); + await contactProvider.DidNotReceive().GetDataAsync(Arg.Any()); + await orgProvider.Received(1).GetDataAsync(Arg.Any()); + } + + [Fact] + public async Task GetApplicantProfileAsync_AlwaysReturnsRequestFieldsOnDto() + { + // Arrange + var service = CreateService([]); + var request = new ApplicantProfileInfoRequest + { + ProfileId = Guid.NewGuid(), + Subject = "someuser@bceid", + TenantId = Guid.NewGuid(), + Key = "NONEXISTENT" + }; + + // Act + var result = await service.GetApplicantProfileAsync(request); + + // Assert + result.ProfileId.ShouldBe(request.ProfileId); + result.Subject.ShouldBe(request.Subject); + result.TenantId.ShouldBe(request.TenantId); + result.Key.ShouldBe(request.Key); + } + } +} diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Applicants/ApplicantProfileDataProviderTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Applicants/ApplicantProfileDataProviderTests.cs new file mode 100644 index 000000000..c9fa64a0f --- /dev/null +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Applicants/ApplicantProfileDataProviderTests.cs @@ -0,0 +1,117 @@ +using Shouldly; +using System; +using System.Linq; +using System.Threading.Tasks; +using Unity.GrantManager.Applicants.ApplicantProfile; +using Unity.GrantManager.Applicants.ProfileData; +using Xunit; + +namespace Unity.GrantManager.Applicants +{ + public class ApplicantProfileDataProviderTests + { + private static ApplicantProfileInfoRequest CreateRequest(string key) => new() + { + ProfileId = Guid.NewGuid(), + Subject = "testuser@idir", + TenantId = Guid.NewGuid(), + Key = key + }; + + [Fact] + public void ContactInfoDataProvider_Key_ShouldMatchExpected() + { + var provider = new ContactInfoDataProvider(); + provider.Key.ShouldBe(ApplicantProfileKeys.ContactInfo); + } + + [Fact] + public async Task ContactInfoDataProvider_GetDataAsync_ShouldReturnContactInfoDto() + { + var provider = new ContactInfoDataProvider(); + var result = await provider.GetDataAsync(CreateRequest(ApplicantProfileKeys.ContactInfo)); + result.ShouldNotBeNull(); + result.ShouldBeOfType(); + } + + [Fact] + public void OrgInfoDataProvider_Key_ShouldMatchExpected() + { + var provider = new OrgInfoDataProvider(); + provider.Key.ShouldBe(ApplicantProfileKeys.OrgInfo); + } + + [Fact] + public async Task OrgInfoDataProvider_GetDataAsync_ShouldReturnOrgInfoDto() + { + var provider = new OrgInfoDataProvider(); + var result = await provider.GetDataAsync(CreateRequest(ApplicantProfileKeys.OrgInfo)); + result.ShouldNotBeNull(); + result.ShouldBeOfType(); + } + + [Fact] + public void AddressInfoDataProvider_Key_ShouldMatchExpected() + { + var provider = new AddressInfoDataProvider(); + provider.Key.ShouldBe(ApplicantProfileKeys.AddressInfo); + } + + [Fact] + public async Task AddressInfoDataProvider_GetDataAsync_ShouldReturnAddressInfoDto() + { + var provider = new AddressInfoDataProvider(); + var result = await provider.GetDataAsync(CreateRequest(ApplicantProfileKeys.AddressInfo)); + result.ShouldNotBeNull(); + result.ShouldBeOfType(); + } + + [Fact] + public void SubmissionInfoDataProvider_Key_ShouldMatchExpected() + { + var provider = new SubmissionInfoDataProvider(); + provider.Key.ShouldBe(ApplicantProfileKeys.SubmissionInfo); + } + + [Fact] + public async Task SubmissionInfoDataProvider_GetDataAsync_ShouldReturnSubmissionInfoDto() + { + var provider = new SubmissionInfoDataProvider(); + var result = await provider.GetDataAsync(CreateRequest(ApplicantProfileKeys.SubmissionInfo)); + result.ShouldNotBeNull(); + result.ShouldBeOfType(); + } + + [Fact] + public void PaymentInfoDataProvider_Key_ShouldMatchExpected() + { + var provider = new PaymentInfoDataProvider(); + provider.Key.ShouldBe(ApplicantProfileKeys.PaymentInfo); + } + + [Fact] + public async Task PaymentInfoDataProvider_GetDataAsync_ShouldReturnPaymentInfoDto() + { + var provider = new PaymentInfoDataProvider(); + var result = await provider.GetDataAsync(CreateRequest(ApplicantProfileKeys.PaymentInfo)); + result.ShouldNotBeNull(); + result.ShouldBeOfType(); + } + + [Fact] + public void AllProviders_ShouldHaveUniqueKeys() + { + IApplicantProfileDataProvider[] providers = + [ + new ContactInfoDataProvider(), + new OrgInfoDataProvider(), + new AddressInfoDataProvider(), + new SubmissionInfoDataProvider(), + new PaymentInfoDataProvider() + ]; + + var keys = providers.Select(p => p.Key).ToList(); + keys.Count.ShouldBe(keys.Distinct(StringComparer.OrdinalIgnoreCase).Count()); + } + } +} From 459bf4949078a58926747840035dad49e877f28f Mon Sep 17 00:00:00 2001 From: JamesPasta Date: Thu, 12 Feb 2026 15:34:37 -0800 Subject: [PATCH 29/42] feature/AB#31672-AddTenantFields-Sonar --- .../Permissions/GrantApplicationPermissions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs index 03034afe8..afdbc8c02 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs @@ -115,9 +115,9 @@ public static class Payments public static class PaymentRequests { public const string Default = Payments.Default + ".PaymentRequests"; - public const string Create = Default + Operation.Create; - public const string Update = Default + Operation.Update; - public const string Delete = Default + Operation.Delete; + public const string CreatePaymentRequest = Default + ".Create"; + public const string EditPaymentRequest = Default + ".Edit"; + public const string DeletePaymentRequest = Default + ".Delete"; } } From ba0ca64c93e3ddaabe754c7e42109861ece026c0 Mon Sep 17 00:00:00 2001 From: JamesPasta Date: Thu, 12 Feb 2026 16:01:47 -0800 Subject: [PATCH 30/42] feature/AB#31672-AddTenantFields-Sonar --- .../Permissions/GrantApplicationPermissions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs index afdbc8c02..b46f5c310 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/GrantApplicationPermissions.cs @@ -114,7 +114,7 @@ public static class Payments public static class PaymentRequests { - public const string Default = Payments.Default + ".PaymentRequests"; + public const string PaymentRequestDefault = Payments.Default + ".PaymentRequests"; public const string CreatePaymentRequest = Default + ".Create"; public const string EditPaymentRequest = Default + ".Edit"; public const string DeletePaymentRequest = Default + ".Delete"; From 47b22ab57fa47c8ab5c502d7152bd0f28533aa4b Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Thu, 12 Feb 2026 16:04:17 -0800 Subject: [PATCH 31/42] AB#31896 sonarQ cleanup --- .../ProfileData/ApplicantAddressInfoDto.cs | 1 + .../ProfileData/ApplicantContactInfoDto.cs | 1 + .../ProfileData/ApplicantOrgInfoDto.cs | 1 + .../ProfileData/ApplicantPaymentInfoDto.cs | 1 + .../ProfileData/ApplicantProfileDataDto.cs | 1 + .../ProfileData/ApplicantSubmissionInfoDto.cs | 1 + .../ApplicantProfileAppServiceTests.cs | 104 ++++++------------ 7 files changed, 37 insertions(+), 73 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantAddressInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantAddressInfoDto.cs index 5a3206043..fde1734a0 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantAddressInfoDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantAddressInfoDto.cs @@ -2,5 +2,6 @@ namespace Unity.GrantManager.Applicants.ProfileData { public class ApplicantAddressInfoDto : ApplicantProfileDataDto { + public override string DataType => "ADDRESSINFO"; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantContactInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantContactInfoDto.cs index f89c87388..74c15630b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantContactInfoDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantContactInfoDto.cs @@ -2,5 +2,6 @@ namespace Unity.GrantManager.Applicants.ProfileData { public class ApplicantContactInfoDto : ApplicantProfileDataDto { + public override string DataType => "CONTACTINFO"; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantOrgInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantOrgInfoDto.cs index e8b6d6115..c14ac0413 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantOrgInfoDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantOrgInfoDto.cs @@ -2,5 +2,6 @@ namespace Unity.GrantManager.Applicants.ProfileData { public class ApplicantOrgInfoDto : ApplicantProfileDataDto { + public override string DataType => "ORGINFO"; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantPaymentInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantPaymentInfoDto.cs index 996fe0b49..a6f7b77c3 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantPaymentInfoDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantPaymentInfoDto.cs @@ -2,5 +2,6 @@ namespace Unity.GrantManager.Applicants.ProfileData { public class ApplicantPaymentInfoDto : ApplicantProfileDataDto { + public override string DataType => "PAYMENTINFO"; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantProfileDataDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantProfileDataDto.cs index b7ce18235..8aa8b98ab 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantProfileDataDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantProfileDataDto.cs @@ -2,5 +2,6 @@ namespace Unity.GrantManager.Applicants.ProfileData { public abstract class ApplicantProfileDataDto { + public abstract string DataType { get; } } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantSubmissionInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantSubmissionInfoDto.cs index e74e994bb..4c0a0ba60 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantSubmissionInfoDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantSubmissionInfoDto.cs @@ -2,5 +2,6 @@ namespace Unity.GrantManager.Applicants.ProfileData { public class ApplicantSubmissionInfoDto : ApplicantProfileDataDto { + public override string DataType => "SUBMISSIONINFO"; } } diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Applicants/ApplicantProfileAppServiceTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Applicants/ApplicantProfileAppServiceTests.cs index acc04712a..29cde4344 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Applicants/ApplicantProfileAppServiceTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Applicants/ApplicantProfileAppServiceTests.cs @@ -1,41 +1,20 @@ -using NSubstitute; using Shouldly; using System; -using System.Collections.Generic; using System.Threading.Tasks; using Unity.GrantManager.Applicants.ApplicantProfile; using Unity.GrantManager.Applicants.ProfileData; -using Unity.GrantManager.Applications; -using Volo.Abp.Domain.Repositories; -using Volo.Abp.MultiTenancy; -using Volo.Abp.TenantManagement; using Xunit; +using Xunit.Abstractions; namespace Unity.GrantManager.Applicants { - public class ApplicantProfileAppServiceTests + public class ApplicantProfileAppServiceTests : GrantManagerApplicationTestBase { - private readonly ICurrentTenant _currentTenant; - private readonly ITenantRepository _tenantRepository; - private readonly IRepository _applicantTenantMapRepository; - private readonly IRepository _applicationFormSubmissionRepository; + private readonly ApplicantProfileAppService _service; - public ApplicantProfileAppServiceTests() + public ApplicantProfileAppServiceTests(ITestOutputHelper outputHelper) : base(outputHelper) { - _currentTenant = Substitute.For(); - _tenantRepository = Substitute.For(); - _applicantTenantMapRepository = Substitute.For>(); - _applicationFormSubmissionRepository = Substitute.For>(); - } - - private ApplicantProfileAppService CreateService(IEnumerable providers) - { - return new ApplicantProfileAppService( - _currentTenant, - _tenantRepository, - _applicantTenantMapRepository, - _applicationFormSubmissionRepository, - providers); + _service = GetRequiredService(); } private static ApplicantProfileInfoRequest CreateRequest(string key) => new() @@ -52,96 +31,75 @@ private ApplicantProfileAppService CreateService(IEnumerable(); - var mockProvider = Substitute.For(); - mockProvider.Key.Returns(key); - mockProvider.GetDataAsync(Arg.Any()).Returns(expectedData); - - var service = CreateService([mockProvider]); var request = CreateRequest(key); // Act - var result = await service.GetApplicantProfileAsync(request); + var result = await _service.GetApplicantProfileAsync(request); // Assert result.ShouldNotBeNull(); result.Key.ShouldBe(key); - result.Data.ShouldBe(expectedData); + result.Data.ShouldNotBeNull(); result.ProfileId.ShouldBe(request.ProfileId); result.Subject.ShouldBe(request.Subject); result.TenantId.ShouldBe(request.TenantId); - await mockProvider.Received(1).GetDataAsync(Arg.Is(r => r.Key == key)); } - [Fact] - public async Task GetApplicantProfileAsync_WithUnknownKey_ShouldReturnNullData() + [Theory] + [InlineData(ApplicantProfileKeys.ContactInfo, typeof(ApplicantContactInfoDto))] + [InlineData(ApplicantProfileKeys.OrgInfo, typeof(ApplicantOrgInfoDto))] + [InlineData(ApplicantProfileKeys.AddressInfo, typeof(ApplicantAddressInfoDto))] + [InlineData(ApplicantProfileKeys.SubmissionInfo, typeof(ApplicantSubmissionInfoDto))] + [InlineData(ApplicantProfileKeys.PaymentInfo, typeof(ApplicantPaymentInfoDto))] + public async Task GetApplicantProfileAsync_WithValidKey_ShouldReturnCorrectDataType(string key, Type expectedType) { // Arrange - var service = CreateService([]); - var request = CreateRequest("UNKNOWNKEY"); + var request = CreateRequest(key); // Act - var result = await service.GetApplicantProfileAsync(request); + var result = await _service.GetApplicantProfileAsync(request); // Assert - result.ShouldNotBeNull(); - result.Key.ShouldBe("UNKNOWNKEY"); - result.Data.ShouldBeNull(); + result.Data.ShouldNotBeNull(); + result.Data.ShouldBeOfType(expectedType); } [Fact] - public async Task GetApplicantProfileAsync_KeyLookupIsCaseInsensitive() + public async Task GetApplicantProfileAsync_WithUnknownKey_ShouldReturnNullData() { // Arrange - var expectedData = Substitute.For(); - var mockProvider = Substitute.For(); - mockProvider.Key.Returns(ApplicantProfileKeys.ContactInfo); - mockProvider.GetDataAsync(Arg.Any()).Returns(expectedData); - - var service = CreateService([mockProvider]); - var request = CreateRequest("contactinfo"); + var request = CreateRequest("UNKNOWNKEY"); // Act - var result = await service.GetApplicantProfileAsync(request); + var result = await _service.GetApplicantProfileAsync(request); // Assert - result.Data.ShouldBe(expectedData); + result.ShouldNotBeNull(); + result.Key.ShouldBe("UNKNOWNKEY"); + result.Data.ShouldBeNull(); } [Fact] - public async Task GetApplicantProfileAsync_WithMultipleProviders_ShouldDispatchToCorrectOne() + public async Task GetApplicantProfileAsync_KeyLookupIsCaseInsensitive() { // Arrange - var contactData = new ApplicantContactInfoDto(); - var orgData = new ApplicantOrgInfoDto(); - - var contactProvider = Substitute.For(); - contactProvider.Key.Returns(ApplicantProfileKeys.ContactInfo); - contactProvider.GetDataAsync(Arg.Any()).Returns(contactData); - - var orgProvider = Substitute.For(); - orgProvider.Key.Returns(ApplicantProfileKeys.OrgInfo); - orgProvider.GetDataAsync(Arg.Any()).Returns(orgData); - - var service = CreateService([contactProvider, orgProvider]); + var request = CreateRequest("contactinfo"); // Act - var result = await service.GetApplicantProfileAsync(CreateRequest(ApplicantProfileKeys.OrgInfo)); + var result = await _service.GetApplicantProfileAsync(request); // Assert - result.Data.ShouldBeOfType(); - await contactProvider.DidNotReceive().GetDataAsync(Arg.Any()); - await orgProvider.Received(1).GetDataAsync(Arg.Any()); + result.Data.ShouldNotBeNull(); + result.Data.ShouldBeOfType(); } [Fact] public async Task GetApplicantProfileAsync_AlwaysReturnsRequestFieldsOnDto() { // Arrange - var service = CreateService([]); var request = new ApplicantProfileInfoRequest { ProfileId = Guid.NewGuid(), @@ -151,7 +109,7 @@ public async Task GetApplicantProfileAsync_AlwaysReturnsRequestFieldsOnDto() }; // Act - var result = await service.GetApplicantProfileAsync(request); + var result = await _service.GetApplicantProfileAsync(request); // Assert result.ProfileId.ShouldBe(request.ProfileId); From cc7d88d532ed7c7225e02b1b5daae6b732f9a2ff Mon Sep 17 00:00:00 2001 From: Stephan McColm Date: Thu, 12 Feb 2026 16:32:49 -0800 Subject: [PATCH 32/42] feature/AB#31826-New-IT-Statements-Applications-Actions-Bar - Added 2 it statements, and fixed a selector issue to be compatible with DEV --- .../cypress/e2e/ApplicationsActionBar.cy.ts | 1123 +++++++++-------- 1 file changed, 628 insertions(+), 495 deletions(-) diff --git a/applications/Unity.AutoUI/cypress/e2e/ApplicationsActionBar.cy.ts b/applications/Unity.AutoUI/cypress/e2e/ApplicationsActionBar.cy.ts index a6dc210c5..6d3cdd6ea 100644 --- a/applications/Unity.AutoUI/cypress/e2e/ApplicationsActionBar.cy.ts +++ b/applications/Unity.AutoUI/cypress/e2e/ApplicationsActionBar.cy.ts @@ -3,512 +3,645 @@ import { loginIfNeeded } from "../support/auth"; describe("Unity Login and check data from CHEFS", () => { - const STANDARD_TIMEOUT = 20000; - - function switchToDefaultGrantsProgramIfAvailable() { - cy.get("body").then(($body) => { - const hasUserInitials = $body.find(".unity-user-initials").length > 0; - - if (!hasUserInitials) { - cy.log("Skipping tenant switch: no user initials menu found"); - return; - } - - cy.get(".unity-user-initials").click(); - - cy.get("body").then(($body2) => { - const switchLink = $body2 - .find("#user-dropdown a.dropdown-item") - .filter((_, el) => { - return (el.textContent || "").trim() === "Switch Grant Programs"; - }); - - if (switchLink.length === 0) { - cy.log( - 'Skipping tenant switch: "Switch Grant Programs" not present for this user/session', - ); - cy.get("body").click(0, 0); - return; - } - - cy.wrap(switchLink.first()).click(); - - cy.url({ timeout: STANDARD_TIMEOUT }).should( - "include", - "/GrantPrograms", - ); - - cy.get("#search-grant-programs", { timeout: STANDARD_TIMEOUT }) - .should("be.visible") - .clear() - .type("Default Grants Program"); - - // Flatten nested `within` usage to satisfy S2004 (limit nesting depth) - cy.contains( - "#UserGrantProgramsTable tbody tr", - "Default Grants Program", - { timeout: STANDARD_TIMEOUT }, - ) - .should("exist") - .within(() => { - cy.contains("button", "Select").should("be.enabled").click(); - }); - - cy.location("pathname", { timeout: STANDARD_TIMEOUT }).should((p) => { - expect( - p.indexOf("/GrantApplications") >= 0 || p.indexOf("/auth/") >= 0, - ).to.eq(true); + const STANDARD_TIMEOUT = 20000; + + function switchToDefaultGrantsProgramIfAvailable() { + cy.get("body").then(($body) => { + const hasUserInitials = $body.find(".unity-user-initials").length > 0; + + if (!hasUserInitials) { + cy.log("Skipping tenant switch: no user initials menu found"); + return; + } + + cy.get(".unity-user-initials").click(); + + cy.get("body").then(($body2) => { + const switchLink = $body2 + .find("#user-dropdown a.dropdown-item") + .filter((_, el) => { + return (el.textContent || "").trim() === "Switch Grant Programs"; + }); + + if (switchLink.length === 0) { + cy.log( + 'Skipping tenant switch: "Switch Grant Programs" not present for this user/session', + ); + cy.get("body").click(0, 0); + return; + } + + cy.wrap(switchLink.first()).click(); + + cy.url({ timeout: STANDARD_TIMEOUT }).should( + "include", + "/GrantPrograms", + ); + + cy.get("#search-grant-programs", { timeout: STANDARD_TIMEOUT }) + .should("be.visible") + .clear() + .type("Default Grants Program"); + + // Flatten nested `within` usage to satisfy S2004 (limit nesting depth) + cy.contains( + "#UserGrantProgramsTable tbody tr", + "Default Grants Program", + { timeout: STANDARD_TIMEOUT }, + ) + .should("exist") + .within(() => { + cy.contains("button", "Select").should("be.enabled").click(); + }); + + cy.location("pathname", { timeout: STANDARD_TIMEOUT }).should((p) => { + expect( + p.indexOf("/GrantApplications") >= 0 || p.indexOf("/auth/") >= 0, + ).to.eq(true); + }); + }); }); - }); + } + + // TEST renders the Submission tab inside an open shadow root (Form.io). + // Enabling this makes cy.get / cy.contains pierce shadow DOM consistently across envs. + before(() => { + Cypress.config("includeShadowDom", true); + loginIfNeeded({ timeout: STANDARD_TIMEOUT }); }); - } - - // TEST renders the Submission tab inside an open shadow root (Form.io). - // Enabling this makes cy.get / cy.contains pierce shadow DOM consistently across envs. - before(() => { - Cypress.config("includeShadowDom", true); - loginIfNeeded({ timeout: STANDARD_TIMEOUT }); - }); - - it("Switch to Default Grants Program if available", () => { - switchToDefaultGrantsProgramIfAvailable(); - }); - - it("Tests the existence and functionality of the Submitted Date From and Submitted Date To filters", () => { - const pad2 = (n: number) => String(n).padStart(2, "0"); - - const todayIsoLocal = () => { - const d = new Date(); - return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`; - }; - - const waitForRefresh = () => { - // S3923 fix: remove identical branches; assert spinner is hidden when present. - cy.get('div.spinner-grow[role="status"]', { - timeout: STANDARD_TIMEOUT, - }).then(($s) => { - cy.wrap($s) - .should("have.attr", "style") - .and("contain", "display: none"); - }); - }; - - // --- Submitted Date From --- - cy.get("input#submittedFromDate", { timeout: STANDARD_TIMEOUT }) - .click({ force: true }) - .clear({ force: true }) - .type("2022-01-01", { force: true }) - .trigger("change", { force: true }) - .blur({ force: true }) - .should("have.value", "2022-01-01"); - - waitForRefresh(); - - // --- Submitted Date To --- - const today = todayIsoLocal(); - - cy.get("input#submittedToDate", { timeout: STANDARD_TIMEOUT }) - .click({ force: true }) - .clear({ force: true }) - .type(today, { force: true }) - .trigger("change", { force: true }) - .blur({ force: true }) - .should("have.value", today); - - waitForRefresh(); - }); - - // With no rows selected verify the visibility of Filter, Export, Save View, and Columns. - it("Verify the action buttons are visible with no rows selected", () => {}); - - // With one row selected verify the visibility of Filter, Export, Save View, and Columns. - it("Verify the action buttons are visible with one row selected", () => {}); - - it("Clicks Payment and force-closes the modal", () => { - const BUTTON_TIMEOUT = 60000; - - // Ensure table has rows - cy.get(".dt-scroll-body tbody tr", { timeout: STANDARD_TIMEOUT }).should( - "have.length.greaterThan", - 1, - ); - - // Select two rows using non-link cells - const clickSelectableCell = (rowIdx: number, withCtrl = false) => { - cy.get(".dt-scroll-body tbody tr", { timeout: STANDARD_TIMEOUT }) - .eq(rowIdx) - .find("td") - .not(":has(a)") - .first() - .click({ force: true, ctrlKey: withCtrl }); - }; - clickSelectableCell(0); - clickSelectableCell(1, true); - - // ActionBar - cy.get("#app_custom_buttons", { timeout: STANDARD_TIMEOUT }) - .should("exist") - .scrollIntoView(); - - // Click Payment - cy.get("#applicationPaymentRequest", { timeout: BUTTON_TIMEOUT }) - .should("be.visible") - .and("not.be.disabled") - .click({ force: true }); - - // Wait until modal is shown - cy.get("#payment-modal", { timeout: STANDARD_TIMEOUT }) - .should("be.visible") - .and("have.class", "show"); - - // Attempt graceful closes first - cy.get("body").type("{esc}", { force: true }); // Bootstrap listens to ESC - cy.get(".modal-backdrop", { timeout: STANDARD_TIMEOUT }).then(($bd) => { - if ($bd.length) { - cy.wrap($bd).click("topLeft", { force: true }); - } + + it("Switch to Default Grants Program if available", () => { + switchToDefaultGrantsProgramIfAvailable(); }); - // Try footer Cancel if available (avoid .catch on Cypress chainable) - cy.contains("#payment-modal .modal-footer button", "Cancel", { - timeout: STANDARD_TIMEOUT, - }).then(($btn) => { - if ($btn && $btn.length > 0) { - cy.wrap($btn).scrollIntoView().click({ force: true }); - } else { - cy.log("Cancel button not present, proceeding to hard-close fallback"); - } + it("Tests the existence and functionality of the Submitted Date From and Submitted Date To filters", () => { + const pad2 = (n: number) => String(n).padStart(2, "0"); + + const todayIsoLocal = () => { + const d = new Date(); + return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`; + }; + + const waitForRefresh = () => { + // S3923 fix: remove identical branches; assert spinner is hidden when present. + cy.get('div.spinner-grow[role="status"]', { + timeout: STANDARD_TIMEOUT, + }).then(($s) => { + cy.wrap($s) + .should("have.attr", "style") + .and("contain", "display: none"); + }); + }; + + // --- Submitted Date From --- + cy.get("input#submittedFromDate", { timeout: STANDARD_TIMEOUT }) + .click({ force: true }) + .clear({ force: true }) + .type("2022-01-01", { force: true }) + .trigger("change", { force: true }) + .blur({ force: true }) + .should("have.value", "2022-01-01"); + + waitForRefresh(); + + // --- Submitted Date To --- + const today = todayIsoLocal(); + + cy.get("input#submittedToDate", { timeout: STANDARD_TIMEOUT }) + .click({ force: true }) + .clear({ force: true }) + .type(today, { force: true }) + .trigger("change", { force: true }) + .blur({ force: true }) + .should("have.value", today); + + waitForRefresh(); }); - // Use window API (if present), then hard-close fallback - cy.window().then((win: any) => { - try { - if (typeof win.closePaymentModal === "function") { - win.closePaymentModal(); - } - } catch { - /* ignore */ - } - - // HARD CLOSE: forcibly hide modal and remove backdrop - const $ = (win as any).jQuery || (win as any).$; - if ($) { - try { - $("#payment-modal") - .removeClass("show") - .attr("aria-hidden", "true") - .css("display", "none"); - $(".modal-backdrop").remove(); - $("body").removeClass("modal-open").css("overflow", ""); // restore scroll - } catch { - /* ignore */ - } - } + // With no rows selected verify the visibility of Filter, Export, Save View, and Columns. + it("Verifies the expected action buttons are visible when no rows are selected", () => { + cy.get("#GrantApplicationsTable", { timeout: STANDARD_TIMEOUT }).should( + "exist", + ); + + // Ensure we start from a clean selection state (0 selected) + // (Using same "select all / deselect all" toggle approach as the working 1-row test) + cy.get("div.dt-scroll-head thead input", { timeout: STANDARD_TIMEOUT }) + .should("exist") + .click({ force: true }) + .click({ force: true }); + + cy.get("#GrantApplicationsTable tbody tr.selected", { + timeout: STANDARD_TIMEOUT, + }).should("have.length", 0); + + // Filter button (left action bar group) + cy.get("#btn-toggle-filter", { timeout: STANDARD_TIMEOUT }).should( + "be.visible", + ); + + // Right-side buttons + cy.contains( + "#dynamicButtonContainerId .dt-buttons button span", + "Export", + { timeout: STANDARD_TIMEOUT }, + ).should("be.visible"); + cy.contains("#dynamicButtonContainerId button.grp-savedStates", "Save View", { + timeout: STANDARD_TIMEOUT, + }).should("be.visible"); + cy.contains( + "#dynamicButtonContainerId .dt-buttons button span", + "Columns", + { timeout: STANDARD_TIMEOUT }, + ).should("be.visible"); + + // Optional sanity: action buttons that require selection should be disabled when none selected + cy.get("#externalLink", { timeout: STANDARD_TIMEOUT }).should( + "be.disabled", + ); // Open + cy.get("#assignApplication", { timeout: STANDARD_TIMEOUT }).should( + "be.disabled", + ); // Assign + cy.get("#approveApplications", { timeout: STANDARD_TIMEOUT }).should( + "be.disabled", + ); // Approve + cy.get("#tagApplication", { timeout: STANDARD_TIMEOUT }).should( + "be.disabled", + ); // Tags + cy.get("#applicationPaymentRequest", { + timeout: STANDARD_TIMEOUT, + }).should("be.disabled"); // Payment + cy.get("#applicationLink", { timeout: STANDARD_TIMEOUT }).should( + "be.disabled", + ); // Info }); - // Verify modal/backdrop gone (be tolerant: assert non-interference instead of visibility only) - cy.get("#payment-modal", { timeout: STANDARD_TIMEOUT }).should(($m) => { - const isHidden = !$m.is(":visible") || !$m.hasClass("show"); - expect(isHidden, "payment-modal hidden or not shown").to.eq(true); + // With one row selected verify the visibility of Open, Assign, Approve, Tags, Payment, Info, Filter, Export, Save View, and Columns. + it("Verifies the expected action buttons are visible when only one row is selected", () => { + cy.get("#GrantApplicationsTable", { timeout: STANDARD_TIMEOUT }).should( + "exist", + ); + + //Ensure we start from a clean selection state (0 selected) + cy.get("div.dt-scroll-head thead input", { timeout: STANDARD_TIMEOUT }) + .should("exist") + .click({ force: true }) + .click({ force: true }); + + cy.get("#GrantApplicationsTable tbody tr.selected", { + timeout: STANDARD_TIMEOUT, + }).should("have.length", 0); + + // Select exactly 1 row (click a non-link cell, matching your earlier helper logic) + cy.get("#GrantApplicationsTable tbody tr", { timeout: STANDARD_TIMEOUT }) + .should("have.length.greaterThan", 0) + .first() + .find("td") + .not(":has(a)") + .first() + .click({ force: true }); + + cy.get("#GrantApplicationsTable tbody tr.selected", { + timeout: STANDARD_TIMEOUT, + }).should("have.length", 1); + + // Action bar (left group) + cy.get("#app_custom_buttons", { timeout: STANDARD_TIMEOUT }) + .should("exist") + .scrollIntoView(); + + // Left-side action buttons (actual IDs on this page) + cy.get("#externalLink", { timeout: STANDARD_TIMEOUT }).should("be.visible"); // Open + cy.get("#assignApplication", { timeout: STANDARD_TIMEOUT }).should( + "be.visible", + ); // Assign + cy.get("#approveApplications", { timeout: STANDARD_TIMEOUT }).should( + "be.visible", + ); // Approve + cy.get("#tagApplication", { timeout: STANDARD_TIMEOUT }).should("be.visible"); // Tags + cy.get("#applicationPaymentRequest", { + timeout: STANDARD_TIMEOUT, + }).should("be.visible"); // Payment + cy.get("#applicationLink", { timeout: STANDARD_TIMEOUT }).should( + "be.visible", + ); // Info + + // Filter button + cy.get("#btn-toggle-filter", { timeout: STANDARD_TIMEOUT }).should( + "be.visible", + ); + + // Right-side buttons + cy.contains( + "#dynamicButtonContainerId .dt-buttons button span", + "Export", + { timeout: STANDARD_TIMEOUT }, + ).should("be.visible"); + cy.contains("#dynamicButtonContainerId button.grp-savedStates", "Save View", { + timeout: STANDARD_TIMEOUT, + }).should("be.visible"); + cy.contains( + "#dynamicButtonContainerId .dt-buttons button span", + "Columns", + { timeout: STANDARD_TIMEOUT }, + ).should("be.visible"); }); - cy.get(".modal-backdrop", { timeout: STANDARD_TIMEOUT }).should( - "not.exist", - ); - - // Right-side buttons usable - cy.get("#dynamicButtonContainerId", { timeout: STANDARD_TIMEOUT }) - .should("exist") - .scrollIntoView(); - - cy.contains("#dynamicButtonContainerId .dt-buttons button span", "Export", { - timeout: STANDARD_TIMEOUT, - }).should("be.visible"); - cy.contains( - "#dynamicButtonContainerId button.grp-savedStates", - "Save View", - { timeout: STANDARD_TIMEOUT }, - ).should("be.visible"); - cy.contains( - "#dynamicButtonContainerId .dt-buttons button span", - "Columns", - { timeout: STANDARD_TIMEOUT }, - ).should("be.visible"); - }); - - // Walk the Columns menu and toggle each column on, verifying the column is visible. - it("Verify all columns in the menu are visible when and toggled on.", () => { - const clickColumnsItem = (label: string) => { - cy.contains("a.dropdown-item", label, { timeout: STANDARD_TIMEOUT }) - .should("exist") - .scrollIntoView() - .click({ force: true }); - }; - - const getVisibleHeaderTitles = () => { - return cy - .get(".dt-scroll-head span.dt-column-title", { - timeout: STANDARD_TIMEOUT, - }) - .then(($els) => { - const titles = Cypress.$($els) - .toArray() - .map((el) => (el.textContent || "").replace(/\s+/g, " ").trim()) - .filter((t) => t.length > 0); - return titles; + + it("Verifies the expected action buttons are visible when two rows are selected", () => { + const BUTTON_TIMEOUT = 60000; + + // Ensure table has rows + cy.get(".dt-scroll-body tbody tr", { timeout: STANDARD_TIMEOUT }).should( + "have.length.greaterThan", + 1, + ); + + // Select two rows using non-link cells + const clickSelectableCell = (rowIdx: number, withCtrl = false) => { + cy.get(".dt-scroll-body tbody tr", { timeout: STANDARD_TIMEOUT }) + .eq(rowIdx) + .find("td") + .not(":has(a)") + .first() + .click({ force: true, ctrlKey: withCtrl }); + }; + clickSelectableCell(0); + clickSelectableCell(1, true); + + // ActionBar + cy.get("#app_custom_buttons", { timeout: STANDARD_TIMEOUT }) + .should("exist") + .scrollIntoView(); + + // Click Payment + cy.get("#applicationPaymentRequest", { timeout: BUTTON_TIMEOUT }) + .should("be.visible") + .and("not.be.disabled") + .click({ force: true }); + + // Wait until modal is shown + cy.get("#payment-modal", { timeout: STANDARD_TIMEOUT }) + .should("be.visible") + .and("have.class", "show"); + + // Attempt graceful closes first + cy.get("body").type("{esc}", { force: true }); // Bootstrap listens to ESC + cy.get(".modal-backdrop", { timeout: STANDARD_TIMEOUT }).then(($bd) => { + if ($bd.length) { + cy.wrap($bd).click("topLeft", { force: true }); + } }); - }; - const assertVisibleHeadersInclude = (expected: string[]) => { - getVisibleHeaderTitles().then((titles) => { - expected.forEach((e) => { - expect(titles, `visible headers should include "${e}"`).to.include(e); + // Try footer Cancel if available (avoid .catch on Cypress chainable) + cy.contains("#payment-modal .modal-footer button", "Cancel", { + timeout: STANDARD_TIMEOUT, + }).then(($btn) => { + if ($btn && $btn.length > 0) { + cy.wrap($btn).scrollIntoView().click({ force: true }); + } else { + cy.log("Cancel button not present, proceeding to hard-close fallback"); + } + }); + + // Use window API (if present), then hard-close fallback + cy.window().then((win: any) => { + try { + if (typeof win.closePaymentModal === "function") { + win.closePaymentModal(); + } + } catch { + /* ignore */ + } + + // HARD CLOSE: forcibly hide modal and remove backdrop + const $ = (win as any).jQuery || (win as any).$; + if ($) { + try { + $("#payment-modal") + .removeClass("show") + .attr("aria-hidden", "true") + .css("display", "none"); + $(".modal-backdrop").remove(); + $("body").removeClass("modal-open").css("overflow", ""); // restore scroll + } catch { + /* ignore */ + } + } + }); + + // Verify modal/backdrop gone (be tolerant: assert non-interference instead of visibility only) + cy.get("#payment-modal", { timeout: STANDARD_TIMEOUT }).should(($m) => { + const isHidden = !$m.is(":visible") || !$m.hasClass("show"); + expect(isHidden, "payment-modal hidden or not shown").to.eq(true); + }); + cy.get(".modal-backdrop", { timeout: STANDARD_TIMEOUT }).should("not.exist"); + + // Right-side buttons usable + cy.get("#dynamicButtonContainerId", { timeout: STANDARD_TIMEOUT }) + .should("exist") + .scrollIntoView(); + + cy.contains("#dynamicButtonContainerId .dt-buttons button span", "Export", { + timeout: STANDARD_TIMEOUT, + }).should("be.visible"); + cy.contains( + "#dynamicButtonContainerId button.grp-savedStates", + "Save View", + { timeout: STANDARD_TIMEOUT }, + ).should("be.visible"); + cy.contains( + "#dynamicButtonContainerId .dt-buttons button span", + "Columns", + { timeout: STANDARD_TIMEOUT }, + ).should("be.visible"); + }); + + // Walk the Columns menu and toggle each column on, verifying the column is visible. + it("Verify all columns in the menu are visible when and toggled on.", () => { + const escapeRegex = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + + const clickColumnsItem = (label: string) => { + // Case-insensitive exact match so DEV "ID" and PROD "Id" both work + const re = new RegExp(`^\\s*${escapeRegex(label)}\\s*$`, "i"); + cy.contains("a.dropdown-item", re, { timeout: STANDARD_TIMEOUT }) + .should("exist") + .scrollIntoView() + .click({ force: true }); + }; + + const normalize = (s: string) => + (s || "").replace(/\s+/g, " ").trim().toLowerCase(); + + const getVisibleHeaderTitles = () => { + return cy + .get(".dt-scroll-head span.dt-column-title", { + timeout: STANDARD_TIMEOUT, + }) + .then(($els) => { + const titles = Cypress.$($els) + .toArray() + .map((el) => (el.textContent || "").replace(/\s+/g, " ").trim()) + .filter((t) => t.length > 0); + return titles; + }); + }; + + const assertVisibleHeadersInclude = (expected: string[]) => { + getVisibleHeaderTitles().then((titles) => { + const normTitles = titles.map(normalize); + expected.forEach((e) => { + const target = normalize(e); + expect( + normTitles, + `visible headers should include "${e}" (case-insensitive)`, + ).to.include(target); + }); + }); + }; + + const scrollX = (x: number) => { + cy.get(".dt-scroll-body", { timeout: STANDARD_TIMEOUT }) + .should("exist") + .scrollTo(x, 0, { duration: 0, ensureScrollable: false }); + }; + + // Close any open dropdowns/modals first + cy.get("body").then(($body) => { + if ($body.find(".dt-button-background").length > 0) { + cy.get(".dt-button-background").click({ force: true }); + } }); - }); - }; - - const scrollX = (x: number) => { - cy.get(".dt-scroll-body", { timeout: STANDARD_TIMEOUT }) - .should("exist") - .scrollTo(x, 0, { duration: 0, ensureScrollable: false }); - }; - - // Close any open dropdowns/modals first - cy.get("body").then(($body) => { - if ($body.find(".dt-button-background").length > 0) { - cy.get(".dt-button-background").click({ force: true }); - } + + // Open the "Save View" dropdown + cy.get("button.grp-savedStates", { timeout: STANDARD_TIMEOUT }) + .should("be.visible") + .and("contain.text", "Save View") + .click(); + + // Click "Reset to Default View" + cy.contains("a.dropdown-item", "Reset to Default View", { + timeout: STANDARD_TIMEOUT, + }) + .should("exist") + .click({ force: true }); + + // Wait for table to rebuild after reset - check for default columns + cy.get(".dt-scroll-head span.dt-column-title", { + timeout: STANDARD_TIMEOUT, + }).should("have.length.gt", 5); + + // Open Columns menu + cy.contains("span", "Columns", { timeout: STANDARD_TIMEOUT }) + .should("be.visible") + .click(); + + // Wait for columns dropdown to be fully populated + cy.get("a.dropdown-item", { timeout: STANDARD_TIMEOUT }).should( + "have.length.gt", + 50, + ); + + clickColumnsItem("% of Total Project Budget"); + clickColumnsItem("Acquisition"); + clickColumnsItem("Applicant Electoral District"); + + clickColumnsItem("Applicant Id"); + clickColumnsItem("Applicant Id"); + + clickColumnsItem("Applicant Name"); + clickColumnsItem("Applicant Name"); + + clickColumnsItem("Approved Amount"); + clickColumnsItem("Approved Amount"); + + clickColumnsItem("Assessment Result"); + + clickColumnsItem("Assignee"); + clickColumnsItem("Assignee"); + + clickColumnsItem("Business Number"); + + clickColumnsItem("Category"); + clickColumnsItem("Category"); + + clickColumnsItem("City"); + + clickColumnsItem("Community"); + clickColumnsItem("Community"); + + clickColumnsItem("Community Population"); + clickColumnsItem("Contact Business Phone"); + clickColumnsItem("Contact Cell Phone"); + clickColumnsItem("Contact Email"); + clickColumnsItem("Contact Full Name"); + clickColumnsItem("Contact Title"); + clickColumnsItem("Decision Date"); + clickColumnsItem("Decline Rationale"); + clickColumnsItem("Due Date"); + clickColumnsItem("Due Diligence Status"); + clickColumnsItem("Economic Region"); + clickColumnsItem("Forestry Focus"); + clickColumnsItem("Forestry or Non-Forestry"); + clickColumnsItem("FYE Day"); + clickColumnsItem("FYE Month"); + clickColumnsItem("Indigenous"); + clickColumnsItem("Likelihood of Funding"); + clickColumnsItem("Non-Registered Organization Name"); + clickColumnsItem("Notes"); + clickColumnsItem("Org Book Status"); + clickColumnsItem("Organization Type"); + clickColumnsItem("Other Sector/Sub/Industry Description"); + clickColumnsItem("Owner"); + clickColumnsItem("Payout"); + clickColumnsItem("Place"); + clickColumnsItem("Project Electoral District"); + clickColumnsItem("Project End Date"); + + clickColumnsItem("Project Name"); + clickColumnsItem("Project Name"); + + clickColumnsItem("Project Start Date"); + clickColumnsItem("Project Summary"); + clickColumnsItem("Projected Funding Total"); + clickColumnsItem("Recommended Amount"); + clickColumnsItem("Red-Stop"); + clickColumnsItem("Regional District"); + clickColumnsItem("Registered Organization Name"); + clickColumnsItem("Registered Organization Number"); + + clickColumnsItem("Requested Amount"); + clickColumnsItem("Requested Amount"); + + clickColumnsItem("Risk Ranking"); + clickColumnsItem("Sector"); + clickColumnsItem("Signing Authority Business Phone"); + clickColumnsItem("Signing Authority Cell Phone"); + clickColumnsItem("Signing Authority Email"); + clickColumnsItem("Signing Authority Full Name"); + clickColumnsItem("Signing Authority Title"); + + clickColumnsItem("Status"); + clickColumnsItem("Status"); + + clickColumnsItem("Sub-Status"); + clickColumnsItem("Sub-Status"); + + clickColumnsItem("Submission #"); + clickColumnsItem("Submission #"); + + clickColumnsItem("Submission Date"); + clickColumnsItem("Submission Date"); + + clickColumnsItem("SubSector"); + + clickColumnsItem("Tags"); + clickColumnsItem("Tags"); + + clickColumnsItem("Total Paid Amount $"); + clickColumnsItem("Total Project Budget"); + clickColumnsItem("Total Score"); + clickColumnsItem("Unity Application Id"); + + // Close the menu and wait until the overlay is gone + cy.get("div.dt-button-background", { timeout: STANDARD_TIMEOUT }) + .should("exist") + .click({ force: true }); + + cy.get("div.dt-button-background", { timeout: STANDARD_TIMEOUT }).should( + "not.exist", + ); + + // Assertions by horizontal scroll segments (human-style scan) + scrollX(0); + assertVisibleHeadersInclude([ + "Applicant Name", + "Category", + "Submission #", + "Submission Date", + "Status", + "Sub-Status", + "Community", + "Requested Amount", + "Approved Amount", + "Project Name", + "Applicant Id", + ]); + + scrollX(1500); + assertVisibleHeadersInclude([ + "Tags", + "Assignee", + "SubSector", + "Economic Region", + "Regional District", + "Registered Organization Number", + "Org Book Status", + ]); + + scrollX(3000); + assertVisibleHeadersInclude([ + "Project Start Date", + "Project End Date", + "Projected Funding Total", + "Total Paid Amount $", + "Project Electoral District", + "Applicant Electoral District", + ]); + + scrollX(4500); + assertVisibleHeadersInclude([ + "Forestry or Non-Forestry", + "Forestry Focus", + "Acquisition", + "City", + "Community Population", + "Likelihood of Funding", + "Total Score", + ]); + + scrollX(6000); + assertVisibleHeadersInclude([ + "Assessment Result", + "Recommended Amount", + "Due Date", + "Owner", + "Decision Date", + "Project Summary", + "Organization Type", + "Business Number", + ]); + + scrollX(7500); + assertVisibleHeadersInclude([ + "Due Diligence Status", + "Decline Rationale", + "Contact Full Name", + "Contact Title", + "Contact Email", + "Contact Business Phone", + "Contact Cell Phone", + ]); + + scrollX(9000); + assertVisibleHeadersInclude([ + "Signing Authority Full Name", + "Signing Authority Title", + "Signing Authority Email", + "Signing Authority Business Phone", + "Signing Authority Cell Phone", + "Place", + "Risk Ranking", + "Notes", + "Red-Stop", + "Indigenous", + "FYE Day", + "FYE Month", + "Payout", + "Unity Application Id", + ]); }); - // Open the "Save View" dropdown - cy.get("button.grp-savedStates", { timeout: STANDARD_TIMEOUT }) - .should("be.visible") - .and("contain.text", "Save View") - .click(); - - // Click "Reset to Default View" - cy.contains("a.dropdown-item", "Reset to Default View", { - timeout: STANDARD_TIMEOUT, - }) - .should("exist") - .click({ force: true }); - - // Wait for table to rebuild after reset - check for default columns - cy.get(".dt-scroll-head span.dt-column-title", { - timeout: STANDARD_TIMEOUT, - }).should("have.length.gt", 5); - - // Open Columns menu - cy.contains("span", "Columns", { timeout: STANDARD_TIMEOUT }) - .should("be.visible") - .click(); - - // Wait for columns dropdown to be fully populated - cy.get("a.dropdown-item", { timeout: STANDARD_TIMEOUT }).should( - "have.length.gt", - 50, - ); - - clickColumnsItem("% of Total Project Budget"); - clickColumnsItem("Acquisition"); - clickColumnsItem("Applicant Electoral District"); - - clickColumnsItem("Applicant Id"); - clickColumnsItem("Applicant Id"); - - clickColumnsItem("Applicant Name"); - clickColumnsItem("Applicant Name"); - - clickColumnsItem("Approved Amount"); - clickColumnsItem("Approved Amount"); - - clickColumnsItem("Assessment Result"); - - clickColumnsItem("Assignee"); - clickColumnsItem("Assignee"); - - clickColumnsItem("Business Number"); - - clickColumnsItem("Category"); - clickColumnsItem("Category"); - - clickColumnsItem("City"); - - clickColumnsItem("Community"); - clickColumnsItem("Community"); - - clickColumnsItem("Community Population"); - clickColumnsItem("Contact Business Phone"); - clickColumnsItem("Contact Cell Phone"); - clickColumnsItem("Contact Email"); - clickColumnsItem("Contact Full Name"); - clickColumnsItem("Contact Title"); - clickColumnsItem("Decision Date"); - clickColumnsItem("Decline Rationale"); - clickColumnsItem("Due Date"); - clickColumnsItem("Due Diligence Status"); - clickColumnsItem("Economic Region"); - clickColumnsItem("Forestry Focus"); - clickColumnsItem("Forestry or Non-Forestry"); - clickColumnsItem("FYE Day"); - clickColumnsItem("FYE Month"); - clickColumnsItem("Indigenous"); - clickColumnsItem("Likelihood of Funding"); - clickColumnsItem("Non-Registered Organization Name"); - clickColumnsItem("Notes"); - clickColumnsItem("Org Book Status"); - clickColumnsItem("Organization Type"); - clickColumnsItem("Other Sector/Sub/Industry Description"); - clickColumnsItem("Owner"); - clickColumnsItem("Payout"); - clickColumnsItem("Place"); - clickColumnsItem("Project Electoral District"); - clickColumnsItem("Project End Date"); - - clickColumnsItem("Project Name"); - clickColumnsItem("Project Name"); - - clickColumnsItem("Project Start Date"); - clickColumnsItem("Project Summary"); - clickColumnsItem("Projected Funding Total"); - clickColumnsItem("Recommended Amount"); - clickColumnsItem("Red-Stop"); - clickColumnsItem("Regional District"); - clickColumnsItem("Registered Organization Name"); - clickColumnsItem("Registered Organization Number"); - - clickColumnsItem("Requested Amount"); - clickColumnsItem("Requested Amount"); - - clickColumnsItem("Risk Ranking"); - clickColumnsItem("Sector"); - clickColumnsItem("Signing Authority Business Phone"); - clickColumnsItem("Signing Authority Cell Phone"); - clickColumnsItem("Signing Authority Email"); - clickColumnsItem("Signing Authority Full Name"); - clickColumnsItem("Signing Authority Title"); - - clickColumnsItem("Status"); - clickColumnsItem("Status"); - - clickColumnsItem("Sub-Status"); - clickColumnsItem("Sub-Status"); - - clickColumnsItem("Submission #"); - clickColumnsItem("Submission #"); - - clickColumnsItem("Submission Date"); - clickColumnsItem("Submission Date"); - - clickColumnsItem("SubSector"); - - clickColumnsItem("Tags"); - clickColumnsItem("Tags"); - - clickColumnsItem("Total Paid Amount $"); - clickColumnsItem("Total Project Budget"); - clickColumnsItem("Total Score"); - clickColumnsItem("Unity Application Id"); - - // Close the menu and wait until the overlay is gone - cy.get("div.dt-button-background", { timeout: STANDARD_TIMEOUT }) - .should("exist") - .click({ force: true }); - - cy.get("div.dt-button-background", { timeout: STANDARD_TIMEOUT }).should( - "not.exist", - ); - - // Assertions by horizontal scroll segments (human-style scan) - scrollX(0); - assertVisibleHeadersInclude([ - "Applicant Name", - "Category", - "Submission #", - "Submission Date", - "Status", - "Sub-Status", - "Community", - "Requested Amount", - "Approved Amount", - "Project Name", - "Applicant Id", - ]); - - scrollX(1500); - assertVisibleHeadersInclude([ - "Tags", - "Assignee", - "SubSector", - "Economic Region", - "Regional District", - "Registered Organization Number", - "Org Book Status", - ]); - - scrollX(3000); - assertVisibleHeadersInclude([ - "Project Start Date", - "Project End Date", - "Projected Funding Total", - "Total Paid Amount $", - "Project Electoral District", - "Applicant Electoral District", - ]); - - scrollX(4500); - assertVisibleHeadersInclude([ - "Forestry or Non-Forestry", - "Forestry Focus", - "Acquisition", - "City", - "Community Population", - "Likelihood of Funding", - "Total Score", - ]); - - scrollX(6000); - assertVisibleHeadersInclude([ - "Assessment Result", - "Recommended Amount", - "Due Date", - "Owner", - "Decision Date", - "Project Summary", - "Organization Type", - "Business Number", - ]); - - scrollX(7500); - assertVisibleHeadersInclude([ - "Due Diligence Status", - "Decline Rationale", - "Contact Full Name", - "Contact Title", - "Contact Email", - "Contact Business Phone", - "Contact Cell Phone", - ]); - - scrollX(9000); - assertVisibleHeadersInclude([ - "Signing Authority Full Name", - "Signing Authority Title", - "Signing Authority Email", - "Signing Authority Business Phone", - "Signing Authority Cell Phone", - "Place", - "Risk Ranking", - "Notes", - "Red-Stop", - "Indigenous", - "FYE Day", - "FYE Month", - "Payout", - "Unity Application Id", - ]); - }); - - it("Verify Logout", () => { - cy.logout(); - }); -}); + it("Verify Logout", () => { + cy.logout(); + }); +}); \ No newline at end of file From 957b6512d350103fc6fb1c755ea2b2b3ad50b86a Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Thu, 12 Feb 2026 17:18:46 -0800 Subject: [PATCH 33/42] AB#31896 sonarQ --- .../Applicants/ProfileData/ApplicantProfileDataDto.cs | 4 ++-- .../Applicants/ApplicantProfile/AddressInfoDataProvider.cs | 3 +-- .../Applicants/ApplicantProfile/ContactInfoDataProvider.cs | 3 +-- .../Applicants/ApplicantProfile/PaymentInfoDataProvider.cs | 3 +-- .../Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs | 3 +-- 5 files changed, 6 insertions(+), 10 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantProfileDataDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantProfileDataDto.cs index 8aa8b98ab..3c717b28b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantProfileDataDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Applicants/ProfileData/ApplicantProfileDataDto.cs @@ -1,7 +1,7 @@ namespace Unity.GrantManager.Applicants.ProfileData { - public abstract class ApplicantProfileDataDto + public class ApplicantProfileDataDto { - public abstract string DataType { get; } + public virtual string DataType { get; } = ""; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/AddressInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/AddressInfoDataProvider.cs index 89b5b2020..6a7223f6d 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/AddressInfoDataProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/AddressInfoDataProvider.cs @@ -10,8 +10,7 @@ public class AddressInfoDataProvider : IApplicantProfileDataProvider, ITransient public string Key => ApplicantProfileKeys.AddressInfo; public Task GetDataAsync(ApplicantProfileInfoRequest request) - { - // TODO: Implement address info retrieval + { return Task.FromResult(new ApplicantAddressInfoDto()); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ContactInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ContactInfoDataProvider.cs index 50693fbe7..db24541d2 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ContactInfoDataProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ContactInfoDataProvider.cs @@ -10,8 +10,7 @@ public class ContactInfoDataProvider : IApplicantProfileDataProvider, ITransient public string Key => ApplicantProfileKeys.ContactInfo; public Task GetDataAsync(ApplicantProfileInfoRequest request) - { - // TODO: Implement contact info retrieval + { return Task.FromResult(new ApplicantContactInfoDto()); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/PaymentInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/PaymentInfoDataProvider.cs index 925940ae0..0fe6eedb5 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/PaymentInfoDataProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/PaymentInfoDataProvider.cs @@ -10,8 +10,7 @@ public class PaymentInfoDataProvider : IApplicantProfileDataProvider, ITransient public string Key => ApplicantProfileKeys.PaymentInfo; public Task GetDataAsync(ApplicantProfileInfoRequest request) - { - // TODO: Implement payment info retrieval + { return Task.FromResult(new ApplicantPaymentInfoDto()); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs index 6151e9483..bd8bc7950 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs @@ -10,8 +10,7 @@ public class SubmissionInfoDataProvider : IApplicantProfileDataProvider, ITransi public string Key => ApplicantProfileKeys.SubmissionInfo; public Task GetDataAsync(ApplicantProfileInfoRequest request) - { - // TODO: Implement submission info retrieval + { return Task.FromResult(new ApplicantSubmissionInfoDto()); } } From 104e3f8c81d65a0227d1bbb05e124d52a6d0d939 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Thu, 12 Feb 2026 19:38:49 -0800 Subject: [PATCH 34/42] AB#31417: Display Started Operating Date in Applicant Profile --- .../GrantApplications/UpdateApplicantSummaryDto.cs | 7 +++++-- .../ApplicantOrganizationInfoViewComponent.cs | 3 ++- .../ApplicantOrganizationInfoViewModel.cs | 3 +++ .../Components/ApplicantOrganizationInfo/Default.cshtml | 2 +- .../Shared/Components/ApplicantOrganizationInfo/Default.js | 1 + 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantSummaryDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantSummaryDto.cs index 6114bd34c..0571deb1a 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantSummaryDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantSummaryDto.cs @@ -1,4 +1,6 @@ -namespace Unity.GrantManager.GrantApplications; +using System; + +namespace Unity.GrantManager.GrantApplications; public class UpdateApplicantSummaryDto { @@ -17,5 +19,6 @@ public class UpdateApplicantSummaryDto public bool? IndigenousOrgInd { get; set; } public string? UnityApplicantId { get; set; } public string? FiscalDay { get; set; } - public string? FiscalMonth { get; set; } + public string? FiscalMonth { get; set; } + public DateOnly? StartedOperatingDate { get; set; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/ApplicantOrganizationInfoViewComponent.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/ApplicantOrganizationInfoViewComponent.cs index 85b1d6204..a193691a4 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/ApplicantOrganizationInfoViewComponent.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/ApplicantOrganizationInfoViewComponent.cs @@ -67,7 +67,8 @@ public async Task InvokeAsync(Guid applicantId) // Financial Information FiscalMonth = applicant.FiscalMonth ?? string.Empty, - FiscalDay = applicant.FiscalDay?.ToString() ?? string.Empty, + FiscalDay = applicant.FiscalDay?.ToString() ?? string.Empty, + StartedOperatingDate = applicant.StartedOperatingDate?.ToDateTime(TimeOnly.MinValue), RedStop = applicant.RedStop == true }; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/ApplicantOrganizationInfoViewModel.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/ApplicantOrganizationInfoViewModel.cs index 78939818c..3c40725eb 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/ApplicantOrganizationInfoViewModel.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/ApplicantOrganizationInfoViewModel.cs @@ -69,6 +69,9 @@ public class ApplicantOrganizationInfoViewModel [Display(Name = "Fiscal Year End Day")] public string FiscalDay { get; set; } = string.Empty; + [Display(Name = "Started Operating Date")] + public DateTime? StartedOperatingDate { get; set; } + [Display(Name = "Red-Stop")] public bool RedStop { get; set; } = false; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/Default.cshtml index 12f0a856d..0c7366d67 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/Default.cshtml @@ -139,7 +139,7 @@ - + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/Default.js index fbb249569..9cb38766d 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantOrganizationInfo/Default.js @@ -22,6 +22,7 @@ 'SectorSubSectorIndustryDesc', 'FiscalMonth', 'FiscalDay', + 'StartedOperatingDate', 'RedStop' ]); From 7777b166070e2807afaa17a787dd6eb3cbea6b9a Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Thu, 12 Feb 2026 20:17:42 -0800 Subject: [PATCH 35/42] AB#31849: Remove Save View menu in Submissions Tab --- .../ApplicantSubmissions/Default.css | 100 ------------------ .../ApplicantSubmissions/Default.js | 83 --------------- 2 files changed, 183 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/Default.css b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/Default.css index 3504ec6cd..295de3ccd 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/Default.css +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/Default.css @@ -134,103 +134,3 @@ overflow-y: auto !important; overflow-x: auto !important; } - -/**CSS for dataTable stateRestore - Save View**/ -.applicant-submissions-widget .dtsr-background { - background: rgba(0, 0, 0, 0.5) !important; -} - -.cstm-save-view .dt-button-collection { - width: 230px; -} - -.cstm-save-view .dt-button-split a { - line-height: 35px; -} - -.cstm-save-view .dt-button-collection .dt-button-active.dt-button-split > *:first-child:after { - margin-top: -18px; -} - -.applicant-submissions-widget .dtsr-creation .dtsr-creation-form .dtsr-form-row:nth-of-type(2) { - display: none; -} - -.applicant-submissions-widget .dtsr-creation-title, -.applicant-submissions-widget .dtsr-confirmation-title { - font-weight: 700; - font-size: 1.25rem; -} - -.applicant-submissions-widget .dtsr-confirmation .dtsr-creation-form .dtsr-form-row label, -.applicant-submissions-widget .dtsr-creation .dtsr-creation-form .dtsr-form-row label { - width: 100%; - text-align: left; -} - -.applicant-submissions-widget .dtsr-confirmation .dtsr-creation-form .dtsr-form-row .dtsr-input, -.applicant-submissions-widget .dtsr-creation .dtsr-creation-form .dtsr-form-row .dtsr-input, -.applicant-submissions-widget .dtsr-creation-form input[type=text] { - width: 100% !important; -} - -.applicant-submissions-widget .dtsr-confirmation input[type=text], -.applicant-submissions-widget .dtsr-creation input[type=text] { - padding: 0.375rem 0.75rem; - width: 100%; -} - -.applicant-submissions-widget .dtsr-name-label { - font-size: 13px; - font-weight: 700; -} - -.applicant-submissions-widget .dtsr-creation input, -.applicant-submissions-widget .dtsr-rename-modal input { - font-size: var(--bc-font-size); - color: var(--bc-colors-grey-text-500); - border-radius: 4px !important; - border: 2px solid var(--bc-colors-blue-primary); - text-overflow: ellipsis; -} - -.applicant-submissions-widget .dtsr-confirmation .dtsr-creation-form .dtsr-form-row, -.applicant-submissions-widget .dtsr-creation .dtsr-creation-form .dtsr-form-row { - display: inherit; -} - -.applicant-submissions-widget div.dtsr-confirmation div.dtsr-modal-foot, -.applicant-submissions-widget div.dtsr-confirmation div.dtsr-confirmation-buttons, -.applicant-submissions-widget div.dtsr-creation div.dtsr-modal-foot, -.applicant-submissions-widget div.dtsr-creation div.dtsr-confirmation-buttons { - text-align: left; -} - -.applicant-submissions-widget div.dtsr-confirmation button, -.applicant-submissions-widget div.dtsr-creation button, -.applicant-submissions-widget div.dtsr-confirmation-buttons button { - color: var(--bc-colors-white-primary-500); - background-color: var(--bc-colors-blue-primary); - --bs-btn-active-color: var(--bc-colors-blue-primary-500); - --bs-btn-active-bg: var(--bc-colors-white-primary); - --bs-btn-disabled-color: var(--bc-colors-grey-text-100); - --bs-btn-disabled-bg: var(--bc-colors-white-primary-500); -} - -.applicant-submissions-widget .dtsr-confirmation button, -.applicant-submissions-widget .dtsr-creation button:hover, -.applicant-submissions-widget .dtsr-confirmation-buttons button:hover { - background-color: var(--bc-colors-primary-hover); - box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.18); - border-color: var(--bc-colors-blue-primary); -} - -.applicant-submissions-widget .dt-button-split { - border-radius: inherit; -} - -.dt-button-collection.shift-left { - left: unset !important; - right: 0px !important; -} -/**end**/ diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/Default.js index a38cd2686..198501272 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/Default.js @@ -8,28 +8,6 @@ $(function () { const formatter = createNumberFormatter(); const l = abp.localization.getResource('GrantManager'); - // Language configuration for SavedStates - let languageSetValues = { - buttons: { - stateRestore: 'View %d' - }, - stateRestore: { - creationModal: { - title: 'Create View', - name: 'Name', - button: 'Save', - }, - emptyStates: 'No saved views', - renameTitle: 'Rename View', - renameLabel: 'New name for "%s"', - removeTitle: 'Delete View', - removeConfirm: 'Are you sure you want to delete "%s"?', - removeSubmit: 'Delete', - duplicateError: 'A view with this name already exists.', - removeError: 'Failed to remove view.', - } - }; - // Default visible columns const defaultVisibleColumns = [ 'select', @@ -57,62 +35,6 @@ $(function () { attr: { id: 'btn-toggle-filter' } - }, - { - extend: 'savedStates', - className: 'custom-table-btn flex-none btn btn-secondary grp-savedStates', - config: { - creationModal: true, - splitSecondaries: [ - { extend: 'updateState', text: ' Update'}, - { extend: 'renameState', text: ' Rename'}, - { extend: 'removeState', text: ' Delete'} - ] - }, - buttons: [ - { extend: 'createState', text: 'Save As View' }, - { - text: "Reset to Default View", - action: function (e, dt, node, config) { - dt.columns().visible(false); - - // List of all columns not including default columns - const allColumnNames = dt.settings()[0].aoColumns.map(col => col.name).filter(colName => !defaultVisibleColumns.includes(colName)); - const orderedIndexes = []; - - // Set the visible columns, and collect id's for the reorder - defaultVisibleColumns.forEach((colName) => { - const colIdx = dt.column(`${colName}:name`).index(); - if (colIdx !== undefined && colIdx !== -1) { - dt.column(colIdx).visible(true); - orderedIndexes.push(colIdx); - } - }); - - // Column reorder only works if all columns included in new order, so get the rest of the columns - allColumnNames.forEach((colName) => { - const colIdx = dt.column(`${colName}:name`).index(); - if (colIdx !== undefined && colIdx !== -1) { - orderedIndexes.push(colIdx); - } - }); - dt.colReorder.order(orderedIndexes); - - $('#submissions-search, .custom-filter-input').val(''); - dt.columns().search(''); - dt.search(''); - dt.order([[3, 'desc']]).draw(); // submissionDate column - - // Close the dropdown - dt.buttons('.grp-savedStates') - .container() - .find('.dt-button-collection') - .hide(); - $('div.dt-button-background').trigger('click'); - } - }, - { extend: 'removeAllStates', text: 'Delete All Views' } - ] } ]; @@ -171,7 +93,6 @@ $(function () { serverSideEnabled: false, pagingEnabled: true, reorderEnabled: true, - languageSetValues: languageSetValues, dataTableName: 'ApplicantSubmissionsTable', dynamicButtonContainerId: 'submissionsDynamicButtonContainerId' }); @@ -205,10 +126,6 @@ $(function () { // Initialize button state updateOpenButtonState(); - // For savedStates - $('.grp-savedStates').text('Save View'); - $('.grp-savedStates').closest('.btn-group').addClass('cstm-save-view'); - // Column getter functions (from Application List) function getColumns() { let columnIndex = 0; From de698ab9184ef38330eae34cced076de71b9e3c2 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Fri, 13 Feb 2026 08:33:37 -0800 Subject: [PATCH 36/42] AB#31896 OrgInfoDataProvider SQ --- .../Applicants/ApplicantProfile/OrgInfoDataProvider.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/OrgInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/OrgInfoDataProvider.cs index 5a36a0a5b..049507553 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/OrgInfoDataProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/OrgInfoDataProvider.cs @@ -10,8 +10,7 @@ public class OrgInfoDataProvider : IApplicantProfileDataProvider, ITransientDepe public string Key => ApplicantProfileKeys.OrgInfo; public Task GetDataAsync(ApplicantProfileInfoRequest request) - { - // TODO: Implement organization info retrieval + { return Task.FromResult(new ApplicantOrgInfoDto()); } } From 641316f86d80771dbd8b7c8111bb7a26c71dbce4 Mon Sep 17 00:00:00 2001 From: JamesPasta Date: Fri, 13 Feb 2026 08:56:46 -0800 Subject: [PATCH 37/42] feature/AB#31672-AddTenantFields-FixKeys --- .../Integrations/Cas/CasTokenService.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/CasTokenService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/CasTokenService.cs index 37f4153c7..8a55d6ad5 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/CasTokenService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/CasTokenService.cs @@ -45,10 +45,7 @@ public async Task GetAuthTokenAsync(Guid tenantId) var casClientId = await casClientCodeLookupService.GetClientIdByCasClientCodeAsync(casClientCode) ?? throw new UserFriendlyException($"No CAS client configuration found for CAS client code: {casClientCode}"); - var casApiKeys = configuration.GetSection("CAS_API_KEYS").Get>() ?? []; - var clientSecret = casApiKeys.TryGetValue($"CAS_API_KEY_{casClientCode.ToUpper()}", out var value) - ? value - : throw new UserFriendlyException($"No CAS API key configured for CAS client code: {casClientCode}. Expected configuration key: CAS_API_KEY_{casClientCode.ToUpper()}"); + var clientSecret = configuration.GetValue($"CAS_API_KEY_{casClientCode.ToUpper()}") ?? string.Empty; return await new TokenService(httpClientFactory, chesTokenCache, Logger).GetAuthTokenAsync(new ClientOptions { From 0545343c525177933664ce5a243c913289ebff47 Mon Sep 17 00:00:00 2001 From: JamesPasta Date: Fri, 13 Feb 2026 08:57:27 -0800 Subject: [PATCH 38/42] feature/AB#31672-AddTenantFields-FixKeys --- .../src/Unity.GrantManager.Web/appsettings.json | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.json b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.json index e10a279d6..7d5da8e4b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.json @@ -57,12 +57,10 @@ "ClientSecret": "", "Env": "dev" }, - "CAS_API_KEYS": { - "CAS_API_KEY_130": "KEY1", - "CAS_API_KEY_034": "KEY2", - "CAS_API_KEY_125": "KEY3", - "CAS_API_KEY_126": "KEY3" - }, + "CAS_API_KEY_130": "KEY1", + "CAS_API_KEY_034": "KEY2", + "CAS_API_KEY_125": "KEY3", + "CAS_API_KEY_126": "KEY3", "S3": { "AccessKeyId": "", "Bucket": "", From be6e8c02f079cc7bbfc9a67bc2d6beed6b2b2dd8 Mon Sep 17 00:00:00 2001 From: Andre Goncalves <98196495+AndreGAot@users.noreply.github.com> Date: Fri, 13 Feb 2026 09:21:06 -0800 Subject: [PATCH 39/42] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../ApplicantProfile/AddressInfoDataProvider.cs | 2 +- .../ApplicantProfile/ContactInfoDataProvider.cs | 2 +- .../IApplicantProfileDataProvider.cs | 16 ++++++++++++++++ .../ApplicantProfile/OrgInfoDataProvider.cs | 2 +- .../ApplicantProfile/PaymentInfoDataProvider.cs | 2 +- .../SubmissionInfoDataProvider.cs | 2 +- 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/AddressInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/AddressInfoDataProvider.cs index 6a7223f6d..693a28994 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/AddressInfoDataProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/AddressInfoDataProvider.cs @@ -10,7 +10,7 @@ public class AddressInfoDataProvider : IApplicantProfileDataProvider, ITransient public string Key => ApplicantProfileKeys.AddressInfo; public Task GetDataAsync(ApplicantProfileInfoRequest request) - { + { return Task.FromResult(new ApplicantAddressInfoDto()); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ContactInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ContactInfoDataProvider.cs index db24541d2..71539ca65 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ContactInfoDataProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/ContactInfoDataProvider.cs @@ -10,7 +10,7 @@ public class ContactInfoDataProvider : IApplicantProfileDataProvider, ITransient public string Key => ApplicantProfileKeys.ContactInfo; public Task GetDataAsync(ApplicantProfileInfoRequest request) - { + { return Task.FromResult(new ApplicantContactInfoDto()); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/IApplicantProfileDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/IApplicantProfileDataProvider.cs index b72f60d06..6a1b6b691 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/IApplicantProfileDataProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/IApplicantProfileDataProvider.cs @@ -3,9 +3,25 @@ namespace Unity.GrantManager.Applicants.ApplicantProfile { + /// + /// Defines a contract for components that can provide applicant profile data + /// based on an . + /// public interface IApplicantProfileDataProvider { + /// + /// Gets the unique key that identifies this applicant profile data provider. + /// string Key { get; } + + /// + /// Asynchronously retrieves applicant profile data for the specified request. + /// + /// The request containing the information needed to resolve the applicant profile. + /// + /// A task that, when completed successfully, returns an + /// containing the resolved applicant profile data. + /// Task GetDataAsync(ApplicantProfileInfoRequest request); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/OrgInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/OrgInfoDataProvider.cs index 049507553..6d7f3c7cc 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/OrgInfoDataProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/OrgInfoDataProvider.cs @@ -10,7 +10,7 @@ public class OrgInfoDataProvider : IApplicantProfileDataProvider, ITransientDepe public string Key => ApplicantProfileKeys.OrgInfo; public Task GetDataAsync(ApplicantProfileInfoRequest request) - { + { return Task.FromResult(new ApplicantOrgInfoDto()); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/PaymentInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/PaymentInfoDataProvider.cs index 0fe6eedb5..5684f158e 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/PaymentInfoDataProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/PaymentInfoDataProvider.cs @@ -10,7 +10,7 @@ public class PaymentInfoDataProvider : IApplicantProfileDataProvider, ITransient public string Key => ApplicantProfileKeys.PaymentInfo; public Task GetDataAsync(ApplicantProfileInfoRequest request) - { + { return Task.FromResult(new ApplicantPaymentInfoDto()); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs index bd8bc7950..7af7e641f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfile/SubmissionInfoDataProvider.cs @@ -10,7 +10,7 @@ public class SubmissionInfoDataProvider : IApplicantProfileDataProvider, ITransi public string Key => ApplicantProfileKeys.SubmissionInfo; public Task GetDataAsync(ApplicantProfileInfoRequest request) - { + { return Task.FromResult(new ApplicantSubmissionInfoDto()); } } From b28f9a8cf5794dc8f8f4da70f5eade2664b6353a Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Fri, 13 Feb 2026 10:14:29 -0800 Subject: [PATCH 40/42] AB#31896 remove profile key log --- .../Applicants/ApplicantProfileAppService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfileAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfileAppService.cs index f99b1e9ce..057b27d90 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfileAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantProfileAppService.cs @@ -48,7 +48,7 @@ public async Task GetApplicantProfileAsync(ApplicantProfile } else { - Logger.LogWarning("Unknown applicant profile key: {Key}", request.Key); + Logger.LogWarning("Unknown applicant profile key provided"); } return dto; From a6ce5f8b3c423e04d3458394911e8af5863ad10c Mon Sep 17 00:00:00 2001 From: JamesPasta Date: Fri, 13 Feb 2026 15:09:18 -0800 Subject: [PATCH 41/42] feature/AB#31672-AddTenantFields-Sonar --- .../Integrations/Cas/CasTokenService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/CasTokenService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/CasTokenService.cs index 8a55d6ad5..225fb33fd 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/CasTokenService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/CasTokenService.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; From d3f8890c64fa6d0bd5fd5bae52dc5dfd82de780f Mon Sep 17 00:00:00 2001 From: David Bright Date: Fri, 13 Feb 2026 15:33:56 -0800 Subject: [PATCH 42/42] bug/AB#31901-inverted-parent-child-links-in-display Fixed inverted bug from AB#31004 --- .../Pages/GrantApplications/Index.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js index 6f84b18c1..3ebe15233 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js @@ -1049,15 +1049,21 @@ const listColumns = getColumns(); function getLinkRelationshipType(columnIndex) { return { - title: 'Application Links', + title: 'Link Types', name: 'applicationLinks', data: 'applicationLinks', className: 'data-table-header', render: function (data) { const linkNames = Array.from(new Set((data || []) .filter(x => x?.linkType) - .map(x => x.linkType) - .sort((a, b) => a.localeCompare(b)))); + .map(x => { + // If this app has child links, display it as a parent (and vice versa) in the Application List. + // Not elegant but avoids additional database queries + if (x.linkType === "Parent") return "Child"; + else if (x.linkType === "Child") return "Parent"; + else return x.linkType; + }) + .sort((a, b) => a.localeCompare(b)))); return linkNames.join(', '); }, index: columnIndex