From 76713d05c1f88e4db13ea5d2d80dd0b573a466b8 Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Fri, 26 Jun 2026 08:31:46 -0700 Subject: [PATCH 01/61] AB#32307 store AI runtime configuration in database --- .../Prompts/AIPromptDto.cs | 7 +- .../Prompts/AIPromptVersionDto.cs | 12 +- .../Prompts/CreateUpdateAIPromptDto.cs | 17 +- .../Prompts/CreateUpdateAIPromptVersionDto.cs | 30 +- .../AI/Runtime/AIPromptTemplateProvider.cs | 23 +- .../AI/Runtime/AIPromptTemplateRenderer.cs | 5 - .../AI/Runtime/AIPromptTemplateSnapshot.cs | 2 +- .../AI/Runtime/AIProviderPayloadValidator.cs | 19 + .../AI/Runtime/OpenAIConfigurationResolver.cs | 302 +++++++++---- .../AI/Runtime/OpenAIRuntimeService.cs | 55 ++- .../AI/Runtime/OpenAITransportService.cs | 89 +++- .../AIApplicationMapperlyProfile.cs | 34 +- .../DataSeed/AIModelDataSeeder.cs | 106 +++++ .../DataSeed/AIOperationDataSeeder.cs | 199 ++++++++ .../DataSeed/AIPromptDataSeeder.cs | 99 +--- .../Unity.AI.Application/Domain/AIModel.cs | 24 + .../Domain/AIModelSettings.cs | 8 + .../Domain/AIOperation.cs | 36 ++ .../Unity.AI.Application/Domain/AIPrompt.cs | 25 +- .../Domain/AIPromptVersion.cs | 50 -- .../AIDbContextModelCreatingExtensions.cs | 78 +++- .../Prompts/AIPromptAppService.cs | 19 +- .../Prompts/AIPromptVersionAppService.cs | 53 ++- .../Localization/AI/en.json | 12 +- .../Pages/Prompts/EditModal.cshtml.cs | 6 +- .../Unity.AI.Web/Pages/Prompts/Index.cshtml | 48 +- .../src/Unity.AI.Web/Pages/Prompts/Index.js | 85 ++-- .../Versions/CreateVersionModal.cshtml.cs | 3 +- .../Versions/EditVersionModal.cshtml.cs | 14 +- .../AI/DataSeed/AIModelDataSeederTests.cs | 72 +++ .../AI/DataSeed/AIOperationDataSeederTests.cs | 113 +++++ .../Runtime/AIPromptTemplateProviderTests.cs | 35 +- .../Runtime/AIPromptTemplateRendererTests.cs | 16 +- .../AIProviderPayloadValidatorTests.cs | 59 +++ .../OpenAIConfigurationResolverTests.cs | 426 ++++++++++++------ .../AI/Runtime/OpenAIRuntimeServiceTests.cs | 65 +++ 36 files changed, 1561 insertions(+), 685 deletions(-) create mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIModelDataSeeder.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIOperationDataSeeder.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIModel.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIModelSettings.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIOperation.cs delete mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIPromptVersion.cs create mode 100644 applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIModelDataSeederTests.cs create mode 100644 applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIOperationDataSeederTests.cs create mode 100644 applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIRuntimeServiceTests.cs diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptDto.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptDto.cs index 0bdff63a08..5903cdc248 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptDto.cs @@ -7,8 +7,9 @@ namespace Unity.AI.Prompts; public class AIPromptDto : AuditedEntityDto { public string Name { get; set; } = string.Empty; - public string? Description { get; set; } - public PromptType Type { get; set; } + public int VersionNumber { get; set; } + public string SystemPrompt { get; set; } = string.Empty; + public string UserPrompt { get; set; } = string.Empty; + public string? MetadataJson { get; set; } public bool IsActive { get; set; } - public List Versions { get; set; } = new(); } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptVersionDto.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptVersionDto.cs index a9ed4e50a8..f21d2e8d4e 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptVersionDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptVersionDto.cs @@ -5,16 +5,10 @@ namespace Unity.AI.Prompts; public class AIPromptVersionDto : AuditedEntityDto { - public Guid PromptId { get; set; } + public string Name { get; set; } = string.Empty; public int VersionNumber { get; set; } public string SystemPrompt { get; set; } = string.Empty; - public string UserPromptTemplate { get; set; } = string.Empty; - public string? DeveloperNotes { get; set; } - public string? TargetModel { get; set; } - public string? TargetProvider { get; set; } - public double Temperature { get; set; } - public int? MaxTokens { get; set; } - public bool IsPublished { get; set; } - public bool IsDeprecated { get; set; } + public string UserPrompt { get; set; } = string.Empty; public string? MetadataJson { get; set; } + public bool IsActive { get; set; } } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptDto.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptDto.cs index 6d361fd3ba..37435424f7 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptDto.cs @@ -10,12 +10,19 @@ public class CreateUpdateAIPromptDto [DisplayName("PromptName")] public string Name { get; set; } = string.Empty; - [MaxLength(2000)] - [DisplayName("PromptDescription")] - public string? Description { get; set; } + [DisplayName("VersionNumber")] + public int VersionNumber { get; set; } - [DisplayName("PromptType")] - public PromptType Type { get; set; } + [Required] + [DisplayName("SystemPrompt")] + public string SystemPrompt { get; set; } = string.Empty; + + [Required] + [DisplayName("UserPrompt")] + public string UserPrompt { get; set; } = string.Empty; + + [DisplayName("MetadataJson")] + public string? MetadataJson { get; set; } [DisplayName("PromptIsActive")] public bool IsActive { get; set; } = true; diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptVersionDto.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptVersionDto.cs index 8e3414943f..9ce8423b96 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptVersionDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptVersionDto.cs @@ -16,32 +16,12 @@ public class CreateUpdateAIPromptVersionDto public string SystemPrompt { get; set; } = string.Empty; [Required] - [DisplayName("UserPromptTemplate")] - public string UserPromptTemplate { get; set; } = string.Empty; - - [DisplayName("DeveloperNotes")] - public string? DeveloperNotes { get; set; } - - [MaxLength(100)] - [DisplayName("TargetModel")] - public string? TargetModel { get; set; } - - [MaxLength(100)] - [DisplayName("TargetProvider")] - public string? TargetProvider { get; set; } - - [DisplayName("Temperature")] - public double Temperature { get; set; } = 0.2; - - [DisplayName("MaxTokens")] - public int? MaxTokens { get; set; } - - [DisplayName("IsPublished")] - public bool IsPublished { get; set; } - - [DisplayName("IsDeprecated")] - public bool IsDeprecated { get; set; } + [DisplayName("UserPrompt")] + public string UserPrompt { get; set; } = string.Empty; [DisplayName("MetadataJson")] public string? MetadataJson { get; set; } + + [DisplayName("PromptIsActive")] + public bool IsActive { get; set; } = true; } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateProvider.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateProvider.cs index de92cd64b7..d744c67c6b 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateProvider.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateProvider.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Unity.AI.Domain; using Volo.Abp.DependencyInjection; +using Volo.Abp.Data; using Volo.Abp.Domain.Repositories; using Volo.Abp.MultiTenancy; @@ -10,8 +11,7 @@ namespace Unity.AI.Runtime; public class AIPromptTemplateProvider( IRepository promptRepository, - IRepository promptVersionRepository, - ICurrentTenant currentTenant) : IAIPromptTemplateProvider, ITransientDependency + IDataFilter multiTenantDataFilter) : IAIPromptTemplateProvider, ITransientDependency { public async Task GetRequiredPromptAsync( string promptType, @@ -21,27 +21,20 @@ public async Task GetRequiredPromptAsync( var normalizedPromptVersion = OpenAIPromptRenderer.ResolvePromptVersion(promptVersion); var versionNumber = OpenAIPromptRenderer.ResolvePromptVersionNumber(normalizedPromptVersion); - using (currentTenant.Change(null)) + using (multiTenantDataFilter.Disable()) { - var prompt = await promptRepository.FindAsync(p => p.Name == promptType); + var prompt = await promptRepository.FindAsync(p => p.Name == promptType && p.VersionNumber == versionNumber); if (prompt == null || !prompt.IsActive) - { - throw new InvalidOperationException($"AI prompt '{promptType}' is not configured."); - } - - var version = await promptVersionRepository.FindAsync( - v => v.PromptId == prompt.Id && v.VersionNumber == versionNumber); - if (version == null || !version.IsPublished || version.IsDeprecated) { throw new InvalidOperationException( - $"AI prompt version '{normalizedPromptVersion}' for prompt '{promptType}' is not configured."); + $"AI prompt '{promptType}' version '{normalizedPromptVersion}' is not configured."); } return new AIPromptTemplateSnapshot( normalizedPromptVersion, - version.SystemPrompt, - version.UserPromptTemplate, - version.MetadataJson); + prompt.SystemPrompt, + prompt.UserPrompt, + prompt.MetadataJson); } } } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateRenderer.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateRenderer.cs index b6fc24cd60..da342fe04e 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateRenderer.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateRenderer.cs @@ -116,11 +116,6 @@ private static Dictionary ExtractMetadataSections(string? metada return new Dictionary(StringComparer.Ordinal); } - if (root.TryGetProperty("sections", out var sections) && sections.ValueKind == JsonValueKind.Object) - { - return ExtractStringProperties(sections); - } - return ExtractStringProperties(root); } catch (JsonException ex) diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateSnapshot.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateSnapshot.cs index fb60ccdde6..89be54c5bf 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateSnapshot.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateSnapshot.cs @@ -3,5 +3,5 @@ namespace Unity.AI.Runtime; public sealed record AIPromptTemplateSnapshot( string PromptVersion, string SystemPrompt, - string UserPromptTemplate, + string UserPrompt, string? MetadataJson); diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIProviderPayloadValidator.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIProviderPayloadValidator.cs index b49d718e15..99ecee6f77 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIProviderPayloadValidator.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIProviderPayloadValidator.cs @@ -26,6 +26,13 @@ public static AIResponseValidationResult ValidateApplicationAnalysisJson(string return AIResponseValidationResult.Invalid($"Application analysis response is missing or invalid required field '{AIJsonKeys.Decision}' (expected string)."); } + var normalizedDecision = (decision.GetString() ?? string.Empty).Trim().ToUpperInvariant(); + if (normalizedDecision != "PROCEED" && normalizedDecision != "HOLD") + { + return AIResponseValidationResult.Invalid( + $"Application analysis response has invalid '{AIJsonKeys.Decision}' value. Expected 'PROCEED' or 'HOLD'."); + } + if (!root.TryGetProperty(AIJsonKeys.Errors, out var errors) || errors.ValueKind != JsonValueKind.Array) { return AIResponseValidationResult.Invalid($"Application analysis response is missing or invalid required field '{AIJsonKeys.Errors}' (expected array)."); @@ -46,6 +53,18 @@ public static AIResponseValidationResult ValidateApplicationAnalysisJson(string return AIResponseValidationResult.Invalid($"Application analysis response is missing or invalid required field '{AIJsonKeys.Recommendations}' (expected array)."); } + var hasAnyFindings = + errors.GetArrayLength() > 0 + || warnings.GetArrayLength() > 0 + || summaries.GetArrayLength() > 0 + || recommendations.GetArrayLength() > 0; + + if (!hasAnyFindings) + { + return AIResponseValidationResult.Invalid( + "Application analysis response did not include any findings. At least one finding is required."); + } + return AIResponseValidationResult.Success(); } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIConfigurationResolver.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIConfigurationResolver.cs index d608869f30..a1fbefa6dc 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIConfigurationResolver.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIConfigurationResolver.cs @@ -1,168 +1,262 @@ using Microsoft.Extensions.Configuration; using System; -using System.Globalization; +using System.Linq; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Unity.AI.Domain; +using Unity.AI.Operations; +using Volo.Abp.Data; using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.MultiTenancy; namespace Unity.AI.Runtime; -public class OpenAIConfigurationResolver(IConfiguration configuration) : ITransientDependency +public class OpenAIConfigurationResolver( + IRepository modelRepository, + IRepository operationRepository, + IRepository promptRepository, + IConfiguration configuration, + IDataFilter multiTenantDataFilter) : ITransientDependency { + private const string DefaultOperationName = "Default"; + private static readonly JsonSerializerOptions JsonOptions = new() + { + PropertyNameCaseInsensitive = true + }; + + private readonly IRepository _modelRepository = modelRepository; + private readonly IRepository _operationRepository = operationRepository; + private readonly IRepository _promptRepository = promptRepository; private readonly IConfiguration _configuration = configuration; + private readonly IDataFilter _multiTenantDataFilter = multiTenantDataFilter; + + public string ResolveProviderName() => Required("Azure:Operations:Defaults:Provider"); - public string ResolveProviderName(string? operationName = null) + public Task ResolveApiKeyAsync(string? modelName = null, CancellationToken cancellationToken = default) { - if (!string.IsNullOrWhiteSpace(operationName)) + var providerName = Required("Azure:Operations:Defaults:Provider"); + return Task.FromResult(Required($"Azure:{providerName}:ApiKey")); + } + + public async Task ResolveOperationSettingsAsync( + string operationName, + CancellationToken cancellationToken = default) + { + var operation = await ResolveOperationAsync(operationName, cancellationToken); + if (operation == null) { - var operationProvider = Optional($"Azure:Operations:{operationName}:Provider"); - if (operationProvider != null) - { - return operationProvider; - } + throw new InvalidOperationException($"AI operation '{operationName}' is not configured."); } - return Required("Azure:Operations:Defaults:Provider"); - } + var model = await _modelRepository.GetAsync(operation.AIModelId, cancellationToken: cancellationToken); + if (!model.IsActive) + { + throw new InvalidOperationException($"AI model '{model.Name}' is inactive."); + } - public string ResolveApiKey(string? operationName = null) - { - var providerName = ResolveProviderName(operationName); - return Required($"Azure:{providerName}:ApiKey"); - } + var modelSettings = ResolveModelSettings(model); + var providerName = Required("Azure:Operations:Defaults:Provider"); + var endpoint = Required($"Azure:{providerName}:Endpoint"); + var prompt = await LoadPromptAsync(operation.AIPromptId, cancellationToken); + if (!prompt.IsActive) + { + throw new InvalidOperationException($"AI prompt '{prompt.Name}' v{prompt.VersionNumber} is not active."); + } - public OpenAIOperationSettings ResolveOperationSettings(string operationName) - { - var providerName = ResolveProviderName(operationName); - var profileName = ResolveProfileName(operationName); - var apiKey = Required($"Azure:{providerName}:ApiKey"); - var endpoint = ResolveEndpointUri(providerName); - var deploymentName = RequiredProfile(providerName, profileName, "DeploymentName"); - var promptVersion = Optional($"Azure:Operations:{operationName}:PromptVersion") - ?? Required("Azure:Operations:Defaults:PromptVersion"); + if (operation.CompletionTokens <= 0) + { + throw new InvalidOperationException($"AI operation '{operation.Name}' must define a positive CompletionTokens value."); + } + var apiKey = Required($"Azure:{providerName}:ApiKey"); return new OpenAIOperationSettings( providerName, - profileName, + model.Name, apiKey, - endpoint, - deploymentName, - ResolveMaxOutputTokenCountSupported(operationName), - ResolveConfiguredTemperature(operationName), - ResolveCompletionTokens(operationName), - promptVersion); + new Uri(endpoint), + Required($"Azure:{providerName}:Profiles:{model.Name}:DeploymentName"), + modelSettings.MaxOutputTokenCountSupported, + modelSettings.Temperature, + operation.CompletionTokens, + $"v{prompt.VersionNumber}"); } - public double? ResolveConfiguredTemperature(string? operationName = null) + public async Task ResolveConfiguredTemperatureAsync(string? modelName = null, CancellationToken cancellationToken = default) { - var providerName = ResolveProviderName(operationName); - var profileName = ResolveProfileName(operationName); - var profileTemperature = OptionalProfile(providerName, profileName, "Temperature"); - if (profileTemperature != null - && double.TryParse(profileTemperature, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsedTemperature)) + var modelConfiguration = await ResolveModelConfigurationAsync(modelName, cancellationToken); + if (modelConfiguration != null) { - return parsedTemperature; + return modelConfiguration.Value.Settings.Temperature; } - return null; + throw new InvalidOperationException("AI model is not configured."); } - public bool ResolveMaxOutputTokenCountSupported(string? operationName = null) + public async Task ResolveMaxOutputTokenCountSupportedAsync(string? modelName = null, CancellationToken cancellationToken = default) { - var providerName = ResolveProviderName(operationName); - var profileName = ResolveProfileName(operationName); - var key = ProfileKey(providerName, profileName, "MaxOutputTokenCountSupported"); - var configuredValue = Optional(key); - if (configuredValue == null) + var modelConfiguration = await ResolveModelConfigurationAsync(modelName, cancellationToken); + if (modelConfiguration != null) { - return true; - } + var providerName = Required("Azure:Operations:Defaults:Provider"); + var profileName = modelConfiguration.Value.Model.Name; + var configuredValue = Optional($"Azure:{providerName}:Profiles:{profileName}:MaxOutputTokenCountSupported"); + if (configuredValue != null) + { + if (bool.TryParse(configuredValue, out var parsedValue)) + { + return parsedValue; + } - if (bool.TryParse(configuredValue, out var parsedValue)) - { - return parsedValue; + throw new InvalidOperationException($"Azure:{providerName}:Profiles:{profileName}:MaxOutputTokenCountSupported is not a valid boolean."); + } + + return modelConfiguration.Value.Settings.MaxOutputTokenCountSupported; } - throw new InvalidOperationException($"{key} must be 'true' or 'false'."); + throw new InvalidOperationException("AI model is not configured."); } - public int ResolveCompletionTokens(string operationName) + public async Task ResolveCompletionTokensAsync(string operationName, CancellationToken cancellationToken = default) { - var configuredValue = OptionalPositiveInt($"Azure:Operations:{operationName}:MaxCompletionTokens"); - if (configuredValue is > 0) + var operation = await ResolveOperationAsync(operationName, cancellationToken); + if (operation == null) { - return configuredValue.Value; + throw new InvalidOperationException($"AI operation '{operationName}' is not configured."); } - var defaultConfiguredValue = OptionalPositiveInt("Azure:Operations:Defaults:MaxCompletionTokens"); - if (defaultConfiguredValue is > 0) + var model = await _modelRepository.GetAsync(operation.AIModelId, cancellationToken: cancellationToken); + if (!model.IsActive) { - return defaultConfiguredValue.Value; + throw new InvalidOperationException($"AI model '{model.Name}' is inactive."); } - throw new InvalidOperationException($"AI max completion tokens are not configured for operation '{operationName}'."); + if (operation.CompletionTokens <= 0) + { + throw new InvalidOperationException($"AI operation '{operation.Name}' must define a positive CompletionTokens value."); + } + + return operation.CompletionTokens; } - public string ResolvePromptVersion(string operationName) + public Task ResolvePromptVersionAsync(string operationName, CancellationToken cancellationToken = default) { - return Optional($"Azure:Operations:{operationName}:PromptVersion") - ?? Required("Azure:Operations:Defaults:PromptVersion"); + return ResolvePromptVersionAsyncCore(operationName, cancellationToken); } - public Uri ResolveEndpoint(string? operationName = null) + public async Task ResolveEndpointAsync(string? modelName = null, CancellationToken cancellationToken = default) { - var providerName = ResolveProviderName(operationName); - return ResolveEndpointUri(providerName); + var modelConfiguration = await ResolveModelConfigurationAsync(modelName, cancellationToken); + if (modelConfiguration != null) + { + var providerName = Required("Azure:Operations:Defaults:Provider"); + return new Uri(Required($"Azure:{providerName}:Endpoint")); + } + + throw new InvalidOperationException("AI model is not configured."); } - public string ResolveDeploymentName(string? operationName = null) + public async Task ResolveDeploymentNameAsync(string? modelName = null, CancellationToken cancellationToken = default) { - var providerName = ResolveProviderName(operationName); - var profileName = ResolveProfileName(operationName); - return RequiredProfile(providerName, profileName, "DeploymentName"); + var modelConfiguration = await ResolveModelConfigurationAsync(modelName, cancellationToken); + if (modelConfiguration != null) + { + var providerName = Required("Azure:Operations:Defaults:Provider"); + return Required($"Azure:{providerName}:Profiles:{modelConfiguration.Value.Model.Name}:DeploymentName"); + } + + throw new InvalidOperationException("AI model is not configured."); } - private string ResolveProfileName(string? operationName) + public async Task ResolveProfileNameAsync(string? modelName = null, CancellationToken cancellationToken = default) { - if (!string.IsNullOrWhiteSpace(operationName)) + var modelConfiguration = await ResolveModelConfigurationAsync(modelName, cancellationToken); + if (modelConfiguration != null) { - var operationProfile = Optional($"Azure:Operations:{operationName}:Profile"); - if (operationProfile != null) - { - return operationProfile; - } + return modelConfiguration.Value.Model.Name; } - return Required("Azure:Operations:Defaults:Profile"); + throw new InvalidOperationException("AI model is not configured."); } - private string RequiredProfile(string providerName, string profileName, string settingName) + private async Task<(AIModel Model, AIModelSettings Settings)?> ResolveModelConfigurationAsync( + string? modelName, + CancellationToken cancellationToken) { - var key = ProfileKey(providerName, profileName, settingName); - return Required(key); + var model = await ResolveModelAsync(modelName, cancellationToken); + if (model == null) + { + return null; + } + + var settings = JsonSerializer.Deserialize(model.SettingsJson, JsonOptions); + if (settings == null) + { + throw new InvalidOperationException($"AI model '{model.Name}' has invalid settings JSON."); + } + + return (model, settings); } - private string? OptionalProfile(string providerName, string profileName, string settingName) + private async Task ResolveOperationAsync(string operationName, CancellationToken cancellationToken) { - return Optional(ProfileKey(providerName, profileName, settingName)); + var activeOperations = await _operationRepository.GetListAsync(operation => operation.IsActive); + + var specificOperation = activeOperations.FirstOrDefault(operation => + string.Equals(operation.Name, operationName, StringComparison.OrdinalIgnoreCase)); + if (specificOperation != null) + { + return specificOperation; + } + + return activeOperations.FirstOrDefault(operation => + string.Equals(operation.Name, DefaultOperationName, StringComparison.OrdinalIgnoreCase)); } - private string Required(string key) + private static AIModelSettings ResolveModelSettings(AIModel model) { - return Optional(key) ?? throw new InvalidOperationException($"{key} is not configured."); + var settings = JsonSerializer.Deserialize(model.SettingsJson, JsonOptions); + if (settings == null) + { + throw new InvalidOperationException($"AI model '{model.Name}' has invalid settings JSON."); + } + + return settings; } - private Uri ResolveEndpointUri(string providerName) + private async Task ResolveModelAsync(string? modelName, CancellationToken cancellationToken) { - var key = $"Azure:{providerName}:Endpoint"; - var endpoint = Required(key); + var activeModels = await _modelRepository.GetListAsync(model => model.IsActive); + if (activeModels.Count == 0) + { + return null; + } - try + if (!string.IsNullOrWhiteSpace(modelName)) { - return new Uri(endpoint); + return activeModels.FirstOrDefault(model => + string.Equals(model.Name, modelName, StringComparison.OrdinalIgnoreCase)); } - catch (UriFormatException ex) + + var configuredDefaultProfile = Optional("Azure:Operations:Defaults:Profile"); + if (!string.IsNullOrWhiteSpace(configuredDefaultProfile)) { - throw new InvalidOperationException($"{key} must be a valid absolute URI.", ex); + var configuredDefaultModel = activeModels.FirstOrDefault(model => + string.Equals(model.Name, configuredDefaultProfile, StringComparison.OrdinalIgnoreCase)); + if (configuredDefaultModel != null) + { + return configuredDefaultModel; + } } + + return activeModels.FirstOrDefault(model => + string.Equals(model.Name, "Default", StringComparison.OrdinalIgnoreCase)); + } + + private string Required(string key) + { + return Optional(key) ?? throw new InvalidOperationException($"{key} is not configured."); } private string? Optional(string key) @@ -171,14 +265,28 @@ private Uri ResolveEndpointUri(string providerName) return string.IsNullOrWhiteSpace(value) ? null : value.Trim(); } - private int? OptionalPositiveInt(string key) + private async Task ResolvePromptVersionAsyncCore(string operationName, CancellationToken cancellationToken) { - var value = _configuration.GetValue(key); - return value is > 0 ? value : null; + var operation = await ResolveOperationAsync(operationName, cancellationToken); + if (operation == null) + { + throw new InvalidOperationException($"AI operation '{operationName}' is not configured."); + } + + var prompt = await LoadPromptAsync(operation.AIPromptId, cancellationToken); + if (!prompt.IsActive) + { + throw new InvalidOperationException($"AI prompt '{prompt.Name}' v{prompt.VersionNumber} is not active."); + } + + return $"v{prompt.VersionNumber}"; } - private static string ProfileKey(string providerName, string profileName, string settingName) + private async Task LoadPromptAsync(Guid promptId, CancellationToken cancellationToken) { - return $"Azure:{providerName}:Profiles:{profileName}:{settingName}"; + using (_multiTenantDataFilter.Disable()) + { + return await _promptRepository.GetAsync(promptId, cancellationToken: cancellationToken); + } } } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIRuntimeService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIRuntimeService.cs index d7f6f35e64..9094a14330 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIRuntimeService.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIRuntimeService.cs @@ -42,16 +42,7 @@ public OpenAIRuntimeService( public Task IsAvailableAsync() { - try - { - _openAIConfigurationResolver.ResolveApiKey(); - return Task.FromResult(true); - } - catch (InvalidOperationException ex) - { - _logger.LogWarning(ex, "AI is unavailable because the OpenAI configuration could not be resolved."); - return Task.FromResult(false); - } + return IsAvailableCoreAsync(); } public async Task GenerateApplicationAnalysisAsync(ApplicationAnalysisRequest request, CancellationToken cancellationToken = default) @@ -59,7 +50,7 @@ public async Task GenerateApplicationAnalysisAsync( try { ArgumentNullException.ThrowIfNull(request); - var settings = _openAIConfigurationResolver.ResolveOperationSettings(ApplicationAnalysisPromptType); + var settings = await _openAIConfigurationResolver.ResolveOperationSettingsAsync(ApplicationAnalysisPromptType, cancellationToken); var promptTemplate = await _promptTemplateProvider.GetRequiredPromptAsync( ApplicationAnalysisPromptType, request.PromptVersion ?? settings.PromptVersion, @@ -79,7 +70,7 @@ public async Task GenerateApplicationAnalysisAsync( var attachments = JsonSerializer.Serialize(attachmentsPayload, AIJsonDefaults.Indented); var systemPrompt = promptTemplate.SystemPrompt; var applicationAnalysisContent = AIPromptTemplateRenderer.BuildApplicationAnalysisUserPrompt( - promptTemplate.UserPromptTemplate, + promptTemplate.UserPrompt, schema, data, attachments, @@ -101,7 +92,21 @@ public async Task GenerateApplicationAnalysisAsync( if (result.Outcome != AIOperationOutcome.Success) { - return new ApplicationAnalysisResponse(); + var providerDetails = result.Response?.RawResponse; + if (string.IsNullOrWhiteSpace(providerDetails)) + { + providerDetails = result.Response?.Content; + } + + if (!string.IsNullOrWhiteSpace(providerDetails) && providerDetails.Length > 400) + { + providerDetails = providerDetails[..400]; + } + + throw new InvalidOperationException( + $"Application analysis generation failed with outcome '{result.Outcome}' and failure category '{result.FailureCategory}'. " + + $"HTTP status: {(result.Response?.HttpStatusCode?.ToString() ?? "n/a")}. " + + $"Provider details: {providerDetails ?? "n/a"}"); } return OpenAIResponseParser.ParseApplicationAnalysisResponse(result.Content); @@ -113,7 +118,7 @@ public async Task GenerateApplicationAnalysisAsync( catch (Exception ex) { _logger.LogError(ex, "Error generating application analysis."); - return new ApplicationAnalysisResponse(); + throw; } } @@ -125,7 +130,7 @@ public async Task GenerateAttachmentSummaryAsync(Atta try { - var settings = _openAIConfigurationResolver.ResolveOperationSettings(AttachmentSummaryPromptType); + var settings = await _openAIConfigurationResolver.ResolveOperationSettingsAsync(AttachmentSummaryPromptType, cancellationToken); var promptTemplate = await _promptTemplateProvider.GetRequiredPromptAsync( AttachmentSummaryPromptType, request.PromptVersion ?? settings.PromptVersion, @@ -152,7 +157,7 @@ public async Task GenerateAttachmentSummaryAsync(Atta }; var attachment = JsonSerializer.Serialize(attachmentPayload, AIJsonDefaults.Indented); var contentToAnalyze = AIPromptTemplateRenderer.BuildAttachmentSummaryUserPrompt( - promptTemplate.UserPromptTemplate, + promptTemplate.UserPrompt, attachment, promptTemplate.MetadataJson); @@ -201,7 +206,7 @@ public async Task GenerateApplicationScoringAsync(Ap ArgumentNullException.ThrowIfNull(request); try { - var settings = _openAIConfigurationResolver.ResolveOperationSettings(ApplicationScoringPromptType); + var settings = await _openAIConfigurationResolver.ResolveOperationSettingsAsync(ApplicationScoringPromptType, cancellationToken); var promptTemplate = await _promptTemplateProvider.GetRequiredPromptAsync( ApplicationScoringPromptType, request.PromptVersion ?? settings.PromptVersion, @@ -228,7 +233,7 @@ public async Task GenerateApplicationScoringAsync(Ap } var applicationScoringContent = AIPromptTemplateRenderer.BuildApplicationScoringUserPrompt( - promptTemplate.UserPromptTemplate, + promptTemplate.UserPrompt, dataJson, attachments, section, @@ -337,6 +342,20 @@ private async Task GenerateWithRetryAsync( return lastResult; } + private async Task IsAvailableCoreAsync() + { + try + { + await _openAIConfigurationResolver.ResolveApiKeyAsync(); + return true; + } + catch (InvalidOperationException ex) + { + _logger.LogWarning(ex, "AI is unavailable because the OpenAI configuration could not be resolved."); + return false; + } + } + private static string ResolveNarrativeContent(AIOperationResult result) { return result.Outcome switch diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAITransportService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAITransportService.cs index db1cf6fdd2..769a538af1 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAITransportService.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAITransportService.cs @@ -37,23 +37,16 @@ public async Task GenerateSummaryAsync( ? "You are a professional grant analyst for the BC Government." : systemPrompt; - var options = new ChatCompletionOptions(); - if (settings.MaxOutputTokenCountSupported) + var messages = new List { - options.MaxOutputTokenCount = maxTokens; - } - - if (settings.Temperature.HasValue) - { - options.Temperature = (float)settings.Temperature.Value; - } - - var result = await _chatClientFactory.Create(settings).CompleteChatAsync( - [ - new SystemChatMessage(resolvedSystemPrompt), - new UserChatMessage(content ?? string.Empty) - ], - options, + new SystemChatMessage(resolvedSystemPrompt), + new UserChatMessage(content ?? string.Empty) + }; + + var result = await CompleteChatWithTemperatureFallbackAsync( + settings, + messages, + maxTokens, cancellationToken); var completion = result.Value; @@ -110,6 +103,70 @@ public async Task GenerateSummaryAsync( } } + private async Task> CompleteChatWithTemperatureFallbackAsync( + OpenAIOperationSettings settings, + IReadOnlyList messages, + int maxTokens, + CancellationToken cancellationToken) + { + try + { + return await _chatClientFactory.Create(settings).CompleteChatAsync( + messages, + BuildOptions(settings, maxTokens, includeTemperature: true), + cancellationToken); + } + catch (ClientResultException ex) + { + var responseContent = ex.GetRawResponse()?.Content?.ToString() ?? ex.Message; + if (!ShouldRetryWithoutTemperature(settings, ex.Status, responseContent)) + { + throw; + } + + _logger.LogWarning( + ex, + "Retrying OpenAI request without temperature after provider rejected the temperature parameter for profile {ProfileName}.", + settings.ProfileName); + + return await _chatClientFactory.Create(settings).CompleteChatAsync( + messages, + BuildOptions(settings, maxTokens, includeTemperature: false), + cancellationToken); + } + } + + private static ChatCompletionOptions BuildOptions(OpenAIOperationSettings settings, int maxTokens, bool includeTemperature) + { + var options = new ChatCompletionOptions(); + if (settings.MaxOutputTokenCountSupported) + { + options.MaxOutputTokenCount = maxTokens; + } + + if (includeTemperature && settings.Temperature.HasValue) + { + options.Temperature = (float)settings.Temperature.Value; + } + + return options; + } + + private static bool ShouldRetryWithoutTemperature(OpenAIOperationSettings settings, int statusCode, string responseContent) + { + if (!settings.Temperature.HasValue || statusCode != 400 || string.IsNullOrWhiteSpace(responseContent)) + { + return false; + } + + var lowered = responseContent.ToLowerInvariant(); + return lowered.Contains("temperature") + && (lowered.Contains("unsupported") + || lowered.Contains("not supported") + || lowered.Contains("not allowed") + || lowered.Contains("invalid")); + } + private static AIOperationResult MapFailureOutcome(HttpStatusCode statusCode, AIProviderResult response) { var statusCodeValue = (int)statusCode; diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationMapperlyProfile.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationMapperlyProfile.cs index 092ea879d1..589ac6aea2 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationMapperlyProfile.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationMapperlyProfile.cs @@ -21,7 +21,6 @@ public partial class CreateUpdateAIPromptDtoToAIPromptMapper : MapperBase (AIPrompt)RuntimeHelpers.GetUninitializedObject(typeof(AIPrompt)); - [MapperIgnoreTarget(nameof(AIPrompt.Versions))] [MapperIgnoreTarget(nameof(AIPrompt.TenantId))] [MapperIgnoreTarget(nameof(AIPrompt.ConcurrencyStamp))] [MapperIgnoreTarget(nameof(AIPrompt.CreationTime))] @@ -30,7 +29,6 @@ private static AIPrompt CreateAIPrompt() => [MapperIgnoreTarget(nameof(AIPrompt.LastModifierId))] public override partial AIPrompt Map(CreateUpdateAIPromptDto source); - [MapperIgnoreTarget(nameof(AIPrompt.Versions))] [MapperIgnoreTarget(nameof(AIPrompt.TenantId))] [MapperIgnoreTarget(nameof(AIPrompt.ConcurrencyStamp))] [MapperIgnoreTarget(nameof(AIPrompt.CreationTime))] @@ -41,35 +39,9 @@ private static AIPrompt CreateAIPrompt() => } [Mapper] -public partial class AIPromptVersionToAIPromptVersionDtoMapper : MapperBase +public partial class AIPromptToAIPromptVersionDtoMapper : MapperBase { - public override partial AIPromptVersionDto Map(AIPromptVersion source); + public override partial AIPromptVersionDto Map(AIPrompt source); - public override partial void Map(AIPromptVersion source, AIPromptVersionDto destination); -} - -[Mapper] -public partial class CreateUpdateAIPromptVersionDtoToAIPromptVersionMapper : MapperBase -{ - [ObjectFactory] - private static AIPromptVersion CreateAIPromptVersion() => - (AIPromptVersion)RuntimeHelpers.GetUninitializedObject(typeof(AIPromptVersion)); - - [MapperIgnoreTarget(nameof(AIPromptVersion.Prompt))] - [MapperIgnoreTarget(nameof(AIPromptVersion.TenantId))] - [MapperIgnoreTarget(nameof(AIPromptVersion.ConcurrencyStamp))] - [MapperIgnoreTarget(nameof(AIPromptVersion.CreationTime))] - [MapperIgnoreTarget(nameof(AIPromptVersion.CreatorId))] - [MapperIgnoreTarget(nameof(AIPromptVersion.LastModificationTime))] - [MapperIgnoreTarget(nameof(AIPromptVersion.LastModifierId))] - public override partial AIPromptVersion Map(CreateUpdateAIPromptVersionDto source); - - [MapperIgnoreTarget(nameof(AIPromptVersion.Prompt))] - [MapperIgnoreTarget(nameof(AIPromptVersion.TenantId))] - [MapperIgnoreTarget(nameof(AIPromptVersion.ConcurrencyStamp))] - [MapperIgnoreTarget(nameof(AIPromptVersion.CreationTime))] - [MapperIgnoreTarget(nameof(AIPromptVersion.CreatorId))] - [MapperIgnoreTarget(nameof(AIPromptVersion.LastModificationTime))] - [MapperIgnoreTarget(nameof(AIPromptVersion.LastModifierId))] - public override partial void Map(CreateUpdateAIPromptVersionDto source, AIPromptVersion destination); + public override partial void Map(AIPrompt source, AIPromptVersionDto destination); } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIModelDataSeeder.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIModelDataSeeder.cs new file mode 100644 index 0000000000..68cce573ed --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIModelDataSeeder.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Unity.AI.Domain; +using Unity.AI.Prompts; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; + +namespace Unity.AI.DataSeed; + +public class AIModelDataSeeder( + IRepository modelRepository, + IConfiguration configuration) : IDataSeedContributor, ITransientDependency +{ + public async Task SeedAsync(DataSeedContext context) + { + if (context.TenantId != null) + { + return; + } + + var providerName = Optional("Azure:Operations:Defaults:Provider"); + var defaultProfileName = Optional("Azure:Operations:Defaults:Profile"); + if (providerName == null || defaultProfileName == null) + { + return; + } + + var profilesSection = configuration.GetSection($"Azure:{providerName}:Profiles"); + var profileNames = profilesSection + .GetChildren() + .Select(section => section.Key) + .Where(name => !string.IsNullOrWhiteSpace(name)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + if (!profileNames.Contains(defaultProfileName, StringComparer.OrdinalIgnoreCase)) + { + profileNames.Add(defaultProfileName); + } + + foreach (var profileName in profileNames) + { + var deploymentName = Optional($"Azure:{providerName}:Profiles:{profileName}:DeploymentName"); + if (deploymentName == null) + { + continue; + } + + await EnsureModelAsync( + profileName, + new AIModelSettings + { + MaxOutputTokenCountSupported = OptionalBool($"Azure:{providerName}:Profiles:{profileName}:MaxOutputTokenCountSupported") ?? true, + Temperature = OptionalDouble($"Azure:{providerName}:Profiles:{profileName}:Temperature") + }); + } + + } + + private async Task EnsureModelAsync(string modelName, AIModelSettings settings) + { + var existing = await modelRepository.FirstOrDefaultAsync(model => model.Name == modelName); + if (existing != null) + { + existing.IsActive = true; + existing.SettingsJson = JsonSerializer.Serialize(settings); + await modelRepository.UpdateAsync(existing); + return; + } + + await modelRepository.InsertAsync( + new AIModel(Guid.CreateVersion7(), modelName) + { + IsActive = true, + SettingsJson = JsonSerializer.Serialize(settings) + }); + } + + private string? Optional(string key) + { + var value = configuration[key]; + return string.IsNullOrWhiteSpace(value) ? null : value.Trim(); + } + + private bool? OptionalBool(string key) + { + var value = Optional(key); + return value != null && bool.TryParse(value, out var parsedValue) + ? parsedValue + : null; + } + + private double? OptionalDouble(string key) + { + var value = Optional(key); + return value != null && double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsedValue) + ? parsedValue + : null; + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIOperationDataSeeder.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIOperationDataSeeder.cs new file mode 100644 index 0000000000..ed22ba9ca4 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIOperationDataSeeder.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using System.Threading.Tasks; +using Unity.AI.Domain; +using Unity.AI.Operations; +using Unity.AI.Prompts; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.MultiTenancy; + +namespace Unity.AI.DataSeed; + +public class AIOperationDataSeeder( + IRepository operationRepository, + IRepository modelRepository, + IRepository promptRepository, + IConfiguration configuration, + ICurrentTenant currentTenant, + ILogger logger) : IDataSeedContributor, ITransientDependency +{ + private const string DefaultOperationName = "Default"; + private const string DefaultOperationPromptType = AIPromptTypes.ApplicationAnalysis; + + public async Task SeedAsync(DataSeedContext context) + { + if (context.TenantId != null) + { + return; + } + + using (currentTenant.Change(null)) + { + var model = await EnsureConfiguredDefaultModelAsync(); + if (model == null) + { + logger.LogWarning("AI operation seeding skipped: no model is configured. Check Azure:Operations:Defaults:Provider and Azure:Operations:Defaults:Profile settings."); + return; + } + + await EnsureOperationAsync(DefaultOperationName, DefaultOperationPromptType, model, isDefaultOperation: true); + await EnsureOperationAsync(AIPromptTypes.ApplicationAnalysis, AIPromptTypes.ApplicationAnalysis, model); + await EnsureOperationAsync(AIPromptTypes.AttachmentSummary, AIPromptTypes.AttachmentSummary, model); + await EnsureOperationAsync(AIPromptTypes.ApplicationScoring, AIPromptTypes.ApplicationScoring, model); + } + } + + private async Task EnsureOperationAsync( + string operationName, + string promptName, + AIModel model, + bool isDefaultOperation = false) + { + var prompt = await ResolveLatestActivePromptAsync(promptName); + if (prompt == null) + { + if (isDefaultOperation) + { + logger.LogWarning("AI default operation seeding skipped: no active prompt found for '{PromptName}'.", promptName); + } + else + { + logger.LogWarning("AI operation seeding skipped: no active prompt found for operation '{OperationName}' and prompt '{PromptName}'.", operationName, promptName); + } + return; + } + + var completionTokens = ResolveCompletionTokens(promptName); + if (completionTokens == null) + { + if (isDefaultOperation) + { + logger.LogWarning("AI default operation seeding skipped: MaxCompletionTokens not configured for '{PromptName}'.", promptName); + } + else + { + logger.LogWarning("AI operation seeding skipped: MaxCompletionTokens not configured for operation '{OperationName}' (prompt '{PromptName}').", operationName, promptName); + } + return; + } + + var existing = await operationRepository.FirstOrDefaultAsync(op => op.Name == operationName); + if (existing != null) + { + existing.AIModelId = model.Id; + existing.AIPromptId = prompt.Id; + existing.ExecutionMode = AIExecutionMode.Sequential; + existing.CompletionTokens = completionTokens.Value; + existing.IsActive = true; + await operationRepository.UpdateAsync(existing); + return; + } + + await operationRepository.InsertAsync( + new AIOperation(Guid.CreateVersion7(), operationName, model.Id, prompt.Id) + { + ExecutionMode = AIExecutionMode.Sequential, + CompletionTokens = completionTokens.Value, + IsActive = true + }); + } + + private async Task EnsureConfiguredDefaultModelAsync() + { + var providerName = Optional("Azure:Operations:Defaults:Provider"); + var profileName = Optional("Azure:Operations:Defaults:Profile"); + if (providerName == null || profileName == null) + { + return null; + } + + var deploymentName = Optional($"Azure:{providerName}:Profiles:{profileName}:DeploymentName"); + if (deploymentName == null) + { + return null; + } + + var existing = await modelRepository.FirstOrDefaultAsync(model => model.Name == profileName && model.IsActive); + if (existing != null) + { + existing.SettingsJson = System.Text.Json.JsonSerializer.Serialize(new AIModelSettings + { + MaxOutputTokenCountSupported = OptionalBool($"Azure:{providerName}:Profiles:{profileName}:MaxOutputTokenCountSupported") ?? true, + Temperature = OptionalDouble($"Azure:{providerName}:Profiles:{profileName}:Temperature") + }); + await modelRepository.UpdateAsync(existing); + return existing; + } + + var settings = new AIModelSettings + { + MaxOutputTokenCountSupported = OptionalBool($"Azure:{providerName}:Profiles:{profileName}:MaxOutputTokenCountSupported") ?? true, + Temperature = OptionalDouble($"Azure:{providerName}:Profiles:{profileName}:Temperature") + }; + + var existingInactive = await modelRepository.FirstOrDefaultAsync(model => model.Name == profileName); + if (existingInactive != null) + { + existingInactive.IsActive = true; + existingInactive.SettingsJson = System.Text.Json.JsonSerializer.Serialize(settings); + return await modelRepository.UpdateAsync(existingInactive); + } + + var model = await modelRepository.InsertAsync( + new AIModel(Guid.CreateVersion7(), profileName) + { + IsActive = true, + SettingsJson = System.Text.Json.JsonSerializer.Serialize(settings) + }); + + return model; + } + + private async Task ResolveLatestActivePromptAsync(string promptName) + { + var prompts = await promptRepository.GetListAsync(item => item.Name == promptName && item.IsActive); + return prompts + .OrderByDescending(prompt => prompt.VersionNumber) + .FirstOrDefault(); + } + + private string? Optional(string key) + { + var value = configuration[key]; + return string.IsNullOrWhiteSpace(value) ? null : value.Trim(); + } + + private int? OptionalPositiveInt(string key) + { + var value = configuration.GetValue(key); + return value is > 0 ? value : null; + } + + private int? ResolveCompletionTokens(string operationName) + { + var value = OptionalPositiveInt($"Azure:Operations:{operationName}:MaxCompletionTokens") + ?? OptionalPositiveInt("Azure:Operations:Defaults:MaxCompletionTokens"); + return value; + } + + private bool? OptionalBool(string key) + { + var value = Optional(key); + return value != null && bool.TryParse(value, out var parsedValue) + ? parsedValue + : null; + } + + private double? OptionalDouble(string key) + { + var value = Optional(key); + return value != null && double.TryParse(value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out var parsedValue) + ? parsedValue + : null; + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIPromptDataSeeder.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIPromptDataSeeder.cs index 52c13be7e3..13e2896aae 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIPromptDataSeeder.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIPromptDataSeeder.cs @@ -13,20 +13,12 @@ namespace Unity.AI.DataSeed; /// /// Seeds the built-in AI prompts (application analysis, attachment summary, application scoring) into the host database. -/// Each prompt is seeded with two versions — v0 (original single-file prompts) and v1 (modular -/// prompts with separate rubric, score, output, and rules sections stored in MetadataJson). -/// The seeder is idempotent: it inserts fixed records when missing and does not overwrite existing records. +/// Each prompt family is represented as versioned rows in AIPrompts. /// public class AIPromptDataSeeder( IRepository promptRepository, - IRepository versionRepository, ICurrentTenant currentTenant) : IDataSeedContributor, ITransientDependency { - // Fixed deterministic GUIDs — never change these; they ensure idempotent re-seeding - private static readonly Guid AnalysisPromptId = new("4a100001-1000-4000-a000-000000000001"); - private static readonly Guid AttachmentPromptId = new("4a100001-1000-4000-a000-000000000002"); - private static readonly Guid ScoresheetPromptId = new("4a100001-1000-4000-a000-000000000003"); - public async Task SeedAsync(DataSeedContext context) { if (context.TenantId != null) return; // host database only @@ -43,24 +35,12 @@ public async Task SeedAsync(DataSeedContext context) private async Task SeedAnalysisPromptAsync() { + await EnsurePromptAsync(AIPromptTypes.ApplicationAnalysis, 0, AnalysisSystemV0, AnalysisUserV0); await EnsurePromptAsync( - AnalysisPromptId, AIPromptTypes.ApplicationAnalysis, - "Grant application analysis and review"); - - await EnsureVersionAsync( - AnalysisPromptId, - 0, - AnalysisSystemV0, - AnalysisUserV0, - "v0 — initial single-file analysis prompt"); - - await EnsureVersionAsync( - AnalysisPromptId, 1, AnalysisSystemV1, AnalysisUserV1, - "v1 — modular prompt with separate rubric, score, output, and rules sections", BuildSections( rubric: AnalysisRubric, score: AnalysisScore, @@ -73,24 +53,12 @@ await EnsureVersionAsync( private async Task SeedAttachmentPromptAsync() { + await EnsurePromptAsync(AIPromptTypes.AttachmentSummary, 0, AttachmentSystemV0, AttachmentUserV0); await EnsurePromptAsync( - AttachmentPromptId, AIPromptTypes.AttachmentSummary, - "Attachment summarization for grant review"); - - await EnsureVersionAsync( - AttachmentPromptId, - 0, - AttachmentSystemV0, - AttachmentUserV0, - "v0 — initial single-file attachment prompt"); - - await EnsureVersionAsync( - AttachmentPromptId, 1, AttachmentSystemV1, AttachmentUserV1, - "v1 — modular prompt with separate output and rules sections", BuildSections( output: AttachmentOutput, rules: AttachmentRules, @@ -101,24 +69,12 @@ await EnsureVersionAsync( private async Task SeedScoresheetPromptAsync() { + await EnsurePromptAsync(AIPromptTypes.ApplicationScoring, 0, ScoresheetSystemV0, ScoresheetUserV0); await EnsurePromptAsync( - ScoresheetPromptId, AIPromptTypes.ApplicationScoring, - "Scoresheet section answering assistant"); - - await EnsureVersionAsync( - ScoresheetPromptId, - 0, - ScoresheetSystemV0, - ScoresheetUserV0, - "v0 — initial single-file scoresheet prompt"); - - await EnsureVersionAsync( - ScoresheetPromptId, 1, ScoresheetSystemV1, ScoresheetUserV1, - "v1 — modular prompt with separate output and rules sections", BuildSections( output: ScoresheetOutput, rules: ScoresheetRules, @@ -137,50 +93,37 @@ private static string BuildSections( if (output != null) dict["OUTPUT"] = output; if (rules != null) dict["RULES"] = rules; if (commonRules != null) dict["COMMON_RULES"] = commonRules; - return JsonSerializer.Serialize(new { sections = dict }); - } - - private async Task EnsurePromptAsync(Guid promptId, string promptName, string? description) - { - var prompt = await promptRepository.FirstOrDefaultAsync(p => p.Id == promptId); - if (prompt != null) - { - return; - } - - await promptRepository.InsertAsync(new AIPrompt(promptId, promptName, PromptType.Skill) - { - Description = description, - IsActive = true - }); + return JsonSerializer.Serialize(dict); } - private async Task EnsureVersionAsync( - Guid promptId, + private async Task EnsurePromptAsync( + string promptName, int versionNumber, string systemPrompt, - string userPromptTemplate, - string developerNotes, + string userPrompt, string? metadataJson = null) { - var version = await versionRepository.FirstOrDefaultAsync( - v => v.PromptId == promptId && v.VersionNumber == versionNumber); - if (version != null) + var prompt = await promptRepository.FirstOrDefaultAsync( + p => p.Name == promptName && p.VersionNumber == versionNumber); + if (prompt != null) { + prompt.SystemPrompt = systemPrompt; + prompt.UserPrompt = userPrompt; + prompt.MetadataJson = metadataJson; + prompt.IsActive = true; + await promptRepository.UpdateAsync(prompt, autoSave: true); return; } - await versionRepository.InsertAsync(new AIPromptVersion( + await promptRepository.InsertAsync(new AIPrompt( Guid.CreateVersion7(), - promptId, + promptName, versionNumber, systemPrompt, - userPromptTemplate) + userPrompt) { - DeveloperNotes = developerNotes, - IsPublished = true, - IsDeprecated = false, - MetadataJson = metadataJson + MetadataJson = metadataJson, + IsActive = true }); } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIModel.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIModel.cs new file mode 100644 index 0000000000..511ba071ec --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIModel.cs @@ -0,0 +1,24 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; + +namespace Unity.AI.Domain; + +public class AIModel : AuditedAggregateRoot +{ + public string Name { get; set; } = default!; + + public bool IsActive { get; set; } = true; + + /// Free-form model settings stored as JSON for dynamic runtime options. + public string SettingsJson { get; set; } = "{}"; + + protected AIModel() + { + } + + public AIModel(Guid id, string name) + { + Id = id; + Name = name; + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIModelSettings.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIModelSettings.cs new file mode 100644 index 0000000000..7a9c268eac --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIModelSettings.cs @@ -0,0 +1,8 @@ +namespace Unity.AI.Domain; + +public class AIModelSettings +{ + public bool MaxOutputTokenCountSupported { get; set; } = true; + + public double? Temperature { get; set; } +} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIOperation.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIOperation.cs new file mode 100644 index 0000000000..eee9427cf2 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIOperation.cs @@ -0,0 +1,36 @@ +using System; +using Unity.AI.Operations; +using Volo.Abp.Domain.Entities.Auditing; + +namespace Unity.AI.Domain; + +public class AIOperation : AuditedAggregateRoot +{ + public string Name { get; set; } = default!; + + public Guid AIModelId { get; set; } + + public AIModel AIModel { get; set; } = default!; + + public Guid AIPromptId { get; set; } + + public AIPrompt AIPrompt { get; set; } = default!; + + public AIExecutionMode ExecutionMode { get; set; } = AIExecutionMode.Sequential; + + public int CompletionTokens { get; set; } + + public bool IsActive { get; set; } = true; + + protected AIOperation() + { + } + + public AIOperation(Guid id, string name, Guid aiModelId, Guid aiPromptId) + { + Id = id; + Name = name; + AIModelId = aiModelId; + AIPromptId = aiPromptId; + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIPrompt.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIPrompt.cs index 8aeb74d3d2..631a400961 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIPrompt.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIPrompt.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.MultiTenancy; @@ -7,25 +6,35 @@ namespace Unity.AI.Domain; public class AIPrompt : AuditedAggregateRoot, IMultiTenant { - public virtual Guid? TenantId { get; protected set; } + public Guid? TenantId { get; protected set; } public string Name { get; set; } = default!; - public string? Description { get; set; } + public int VersionNumber { get; set; } - public PromptType Type { get; set; } + public string SystemPrompt { get; set; } = default!; - public bool IsActive { get; set; } = true; + public string UserPrompt { get; set; } = default!; + + public string? MetadataJson { get; set; } - public ICollection Versions { get; set; } = new List(); + public bool IsActive { get; set; } = true; protected AIPrompt() { } - public AIPrompt(Guid id, string name, PromptType type, Guid? tenantId = null) + public AIPrompt( + Guid id, + string name, + int versionNumber, + string systemPrompt, + string userPrompt, + Guid? tenantId = null) { Id = id; Name = name; - Type = type; + VersionNumber = versionNumber; + SystemPrompt = systemPrompt; + UserPrompt = userPrompt; TenantId = tenantId; IsActive = true; } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIPromptVersion.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIPromptVersion.cs deleted file mode 100644 index 440aec6e0c..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Domain/AIPromptVersion.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using Volo.Abp.Domain.Entities.Auditing; -using Volo.Abp.MultiTenancy; - -namespace Unity.AI.Domain; - -public class AIPromptVersion : AuditedAggregateRoot, IMultiTenant -{ - public virtual Guid? TenantId { get; protected set; } - - public Guid PromptId { get; set; } - public AIPrompt? Prompt { get; set; } - - public int VersionNumber { get; set; } - - public string SystemPrompt { get; set; } = default!; - public string UserPromptTemplate { get; set; } = default!; - public string? DeveloperNotes { get; set; } - - public string? TargetModel { get; set; } - public string? TargetProvider { get; set; } - - public double Temperature { get; set; } = 0.2; - public int? MaxTokens { get; set; } - - public bool IsPublished { get; set; } - public bool IsDeprecated { get; set; } - - /// Optional JSON metadata for extensibility (stored as Postgres jsonb). - public string? MetadataJson { get; set; } - - protected AIPromptVersion() { } - - public AIPromptVersion( - Guid id, - Guid promptId, - int versionNumber, - string systemPrompt, - string userPromptTemplate, - Guid? tenantId = null) - { - Id = id; - PromptId = promptId; - VersionNumber = versionNumber; - SystemPrompt = systemPrompt; - UserPromptTemplate = userPromptTemplate; - TenantId = tenantId; - Temperature = 0.2; - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/EntityFrameworkCore/AIDbContextModelCreatingExtensions.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/EntityFrameworkCore/AIDbContextModelCreatingExtensions.cs index a23dae6f48..fcddaace58 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/EntityFrameworkCore/AIDbContextModelCreatingExtensions.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/EntityFrameworkCore/AIDbContextModelCreatingExtensions.cs @@ -21,41 +21,81 @@ public static void ConfigureAI(this ModelBuilder modelBuilder) .IsRequired() .HasMaxLength(200); - b.Property(x => x.Description) - .HasMaxLength(2000); + b.Property(x => x.VersionNumber) + .IsRequired(); + + b.Property(x => x.SystemPrompt) + .IsRequired() + .HasColumnType("text"); + + b.Property(x => x.UserPrompt) + .IsRequired() + .HasColumnType("text"); - b.Property(x => x.Type) + b.Property(x => x.MetadataJson) + .HasColumnType("jsonb"); + + b.Property(x => x.IsActive) .IsRequired(); - b.HasIndex(x => x.Name) + b.HasIndex(x => new { x.TenantId, x.Name, x.VersionNumber }) .IsUnique(); + }); + + modelBuilder.Entity(b => + { + b.ToTable(AIDbProperties.DbTablePrefix + "AIModels", AIDbProperties.DbSchema); + + b.ConfigureByConvention(); + + b.Property(x => x.Name) + .IsRequired() + .HasMaxLength(200); - b.HasMany(x => x.Versions) - .WithOne(x => x.Prompt) - .HasForeignKey(x => x.PromptId) - .OnDelete(DeleteBehavior.Cascade); + b.Property(x => x.IsActive) + .IsRequired(); + + b.Property(x => x.SettingsJson) + .IsRequired() + .HasColumnType("jsonb"); + + b.HasIndex(x => x.Name) + .IsUnique(); }); - modelBuilder.Entity(b => + modelBuilder.Entity(b => { - b.ToTable(AIDbProperties.DbTablePrefix + "AIPromptVersions", AIDbProperties.DbSchema); + b.ToTable(AIDbProperties.DbTablePrefix + "AIOperations", AIDbProperties.DbSchema); b.ConfigureByConvention(); - b.Property(x => x.SystemPrompt).IsRequired().HasColumnType("text"); - b.Property(x => x.UserPromptTemplate).IsRequired().HasColumnType("text"); + b.Property(x => x.Name) + .IsRequired() + .HasMaxLength(200); - b.Property(x => x.TargetModel) - .HasMaxLength(100); + b.Property(x => x.ExecutionMode) + .IsRequired() + .HasConversion() + .HasMaxLength(20); - b.Property(x => x.TargetProvider) - .HasMaxLength(100); + b.Property(x => x.CompletionTokens) + .IsRequired(); - b.Property(x => x.MetadataJson) - .HasColumnType("jsonb"); + b.Property(x => x.IsActive) + .IsRequired(); - b.HasIndex(x => new { x.PromptId, x.VersionNumber }) + b.HasIndex(x => x.Name) .IsUnique(); + + b.HasOne(x => x.AIModel) + .WithMany() + .HasForeignKey(x => x.AIModelId) + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne(x => x.AIPrompt) + .WithMany() + .HasForeignKey(x => x.AIPromptId) + .OnDelete(DeleteBehavior.Restrict); }); } } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptAppService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptAppService.cs index e7f11e6c33..9a3f66ec94 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptAppService.cs @@ -4,9 +4,11 @@ using System.Threading.Tasks; using Unity.AI.Domain; using Unity.Modules.Shared.Permissions; +using Volo.Abp.Data; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Domain.Repositories; +using Volo.Abp.MultiTenancy; namespace Unity.AI.Prompts; @@ -21,9 +23,14 @@ public class AIPromptAppService : CreateUpdateAIPromptDto>, IAIPromptAppService { - public AIPromptAppService(IRepository repository) + private readonly IDataFilter _multiTenantDataFilter; + + public AIPromptAppService( + IRepository repository, + IDataFilter multiTenantDataFilter) : base(repository) { + _multiTenantDataFilter = multiTenantDataFilter; GetPolicyName = IdentityConsts.ITOperationsPolicyName; GetListPolicyName = IdentityConsts.ITOperationsPolicyName; CreatePolicyName = IdentityConsts.ITOperationsPolicyName; @@ -34,7 +41,7 @@ public AIPromptAppService(IRepository repository) [HttpGet("{id}")] public override async Task GetAsync(Guid id) { - using (CurrentTenant.Change(null)) + using (_multiTenantDataFilter.Disable()) { return await base.GetAsync(id); } @@ -43,7 +50,7 @@ public override async Task GetAsync(Guid id) [HttpGet] public override async Task> GetListAsync(PagedAndSortedResultRequestDto input) { - using (CurrentTenant.Change(null)) + using (_multiTenantDataFilter.Disable()) { return await base.GetListAsync(input); } @@ -52,7 +59,7 @@ public override async Task> GetListAsync(PagedAndSor [HttpPost] public override async Task CreateAsync(CreateUpdateAIPromptDto input) { - using (CurrentTenant.Change(null)) + using (_multiTenantDataFilter.Disable()) { return await base.CreateAsync(input); } @@ -61,7 +68,7 @@ public override async Task CreateAsync(CreateUpdateAIPromptDto inpu [HttpPut("{id}")] public override async Task UpdateAsync(Guid id, CreateUpdateAIPromptDto input) { - using (CurrentTenant.Change(null)) + using (_multiTenantDataFilter.Disable()) { return await base.UpdateAsync(id, input); } @@ -70,7 +77,7 @@ public override async Task UpdateAsync(Guid id, CreateUpdateAIPromp [HttpDelete("{id}")] public override async Task DeleteAsync(Guid id) { - using (CurrentTenant.Change(null)) + using (_multiTenantDataFilter.Disable()) { await base.DeleteAsync(id); } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs index ff431bb7c6..7084c9cc10 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs @@ -6,9 +6,11 @@ using System.Threading.Tasks; using Unity.AI.Domain; using Unity.Modules.Shared.Permissions; +using Volo.Abp.Data; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Domain.Repositories; +using Volo.Abp.MultiTenancy; namespace Unity.AI.Prompts; @@ -16,16 +18,21 @@ namespace Unity.AI.Prompts; [Route("api/app/ai/prompt-versions")] public class AIPromptVersionAppService : CrudAppService< - AIPromptVersion, + AIPrompt, AIPromptVersionDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateAIPromptVersionDto>, IAIPromptVersionAppService { - public AIPromptVersionAppService(IRepository repository) + private readonly IDataFilter _multiTenantDataFilter; + + public AIPromptVersionAppService( + IRepository repository, + IDataFilter multiTenantDataFilter) : base(repository) { + _multiTenantDataFilter = multiTenantDataFilter; GetPolicyName = IdentityConsts.ITOperationsPolicyName; GetListPolicyName = IdentityConsts.ITOperationsPolicyName; CreatePolicyName = IdentityConsts.ITOperationsPolicyName; @@ -36,19 +43,20 @@ public AIPromptVersionAppService(IRepository repository) [HttpGet("by-prompt/{promptId}")] public async Task> GetByPromptAsync(Guid promptId) { - using (CurrentTenant.Change(null)) + using (_multiTenantDataFilter.Disable()) { - var items = await Repository.GetListAsync(v => v.PromptId == promptId); + var selected = await Repository.GetAsync(promptId); + var items = await Repository.GetListAsync(v => v.TenantId == selected.TenantId && v.Name == selected.Name); var sorted = items.OrderBy(v => v.VersionNumber).ToList(); return new ListResultDto( - ObjectMapper.Map, List>(sorted)); + ObjectMapper.Map, List>(sorted)); } } [HttpGet("{id}")] public override async Task GetAsync(Guid id) { - using (CurrentTenant.Change(null)) + using (_multiTenantDataFilter.Disable()) { return await base.GetAsync(id); } @@ -57,7 +65,7 @@ public override async Task GetAsync(Guid id) [HttpGet] public override async Task> GetListAsync(PagedAndSortedResultRequestDto input) { - using (CurrentTenant.Change(null)) + using (_multiTenantDataFilter.Disable()) { return await base.GetListAsync(input); } @@ -66,25 +74,46 @@ public override async Task> GetListAsync(Page [HttpPost] public override async Task CreateAsync(CreateUpdateAIPromptVersionDto input) { - using (CurrentTenant.Change(null)) + using (_multiTenantDataFilter.Disable()) { - return await base.CreateAsync(input); + var prompt = await Repository.GetAsync(input.PromptId); + var entity = await Repository.InsertAsync( + new AIPrompt( + Guid.CreateVersion7(), + prompt.Name, + input.VersionNumber, + input.SystemPrompt, + input.UserPrompt) + { + TenantId = prompt.TenantId, + MetadataJson = input.MetadataJson, + IsActive = input.IsActive + }); + + return ObjectMapper.Map(entity); } } [HttpPut("{id}")] public override async Task UpdateAsync(Guid id, CreateUpdateAIPromptVersionDto input) { - using (CurrentTenant.Change(null)) + using (_multiTenantDataFilter.Disable()) { - return await base.UpdateAsync(id, input); + var entity = await Repository.GetAsync(id); + entity.VersionNumber = input.VersionNumber; + entity.SystemPrompt = input.SystemPrompt; + entity.UserPrompt = input.UserPrompt; + entity.MetadataJson = input.MetadataJson; + entity.IsActive = input.IsActive; + entity = await Repository.UpdateAsync(entity); + return ObjectMapper.Map(entity); } } [HttpDelete("{id}")] public override async Task DeleteAsync(Guid id) { - using (CurrentTenant.Change(null)) + using (_multiTenantDataFilter.Disable()) { await base.DeleteAsync(id); } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Domain.Shared/Localization/AI/en.json b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Domain.Shared/Localization/AI/en.json index aef66e58de..2c12bd19f1 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Domain.Shared/Localization/AI/en.json +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Domain.Shared/Localization/AI/en.json @@ -34,19 +34,13 @@ "AIPrompt": "AI Prompt", "AIPromptVersion": "Prompt Version", "AIPromptVersions": "Prompt Versions", - "PromptType": "Type", "PromptName": "Name", - "PromptDescription": "Description", "PromptIsActive": "Active", "VersionNumber": "Version Number", "SystemPrompt": "System Prompt", - "UserPromptTemplate": "User Prompt Template", - "DeveloperNotes": "Developer Notes", - "TargetModel": "Target Model", - "TargetProvider": "Target Provider", + "UserPrompt": "User Prompt", + "MetadataJson": "Metadata JSON", "Temperature": "Temperature", - "MaxTokens": "Max Tokens", - "IsPublished": "Published", - "IsDeprecated": "Deprecated" + "MaxTokens": "Max Tokens" } } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/EditModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/EditModal.cshtml.cs index 1279b7a691..ea394f2c2a 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/EditModal.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/EditModal.cshtml.cs @@ -28,8 +28,10 @@ public async Task OnGetAsync() Prompt = new CreateUpdateAIPromptDto { Name = dto.Name, - Description = dto.Description, - Type = dto.Type, + VersionNumber = dto.VersionNumber, + SystemPrompt = dto.SystemPrompt, + UserPrompt = dto.UserPrompt, + MetadataJson = dto.MetadataJson, IsActive = dto.IsActive }; } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Index.cshtml b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Index.cshtml index 0099f5cf0e..1b4d2bddd8 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Index.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Index.cshtml @@ -67,36 +67,6 @@
-
- - -
-
- - -
- -
- - -
-
- - -
-
-
- - -
-
-
-
- - -
-
-
@@ -104,26 +74,28 @@
- - -
User Prompt Template is required.
+ + +
User Prompt is required.
-
- - +
+
+ + +
- + jsonb
- +
diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Index.js b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Index.js index 28062f58cf..a60c0d9f87 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Index.js @@ -1,7 +1,7 @@ $(function () { const l = abp.localization.getResource('AI'); - // Prompt-level modals (create / edit prompt metadata only) + // Prompt-level modals (create / edit prompt rows) let createModal = new abp.ModalManager(abp.appPath + 'Prompts/CreateModal'); let editModal = new abp.ModalManager(abp.appPath + 'Prompts/EditModal'); @@ -19,27 +19,32 @@ $(function () { index: 0 }, { - title: l('PromptType'), - name: 'type', - data: 'type', + title: l('VersionNumber'), + name: 'versionNumber', + data: 'versionNumber', index: 1, - render: (data) => { - const types = ['Orchestrator', 'Skill', 'Instruction', 'Agent']; - return types[data] ?? data; - } }, { - title: l('PromptDescription'), - name: 'description', - data: 'description', + title: l('SystemPrompt'), + name: 'systemPrompt', + data: 'systemPrompt', index: 2, - defaultContent: '' + defaultContent: '', + render: (data) => (data ?? '').slice(0, 80) + }, + { + title: l('UserPrompt'), + name: 'userPrompt', + data: 'userPrompt', + index: 3, + defaultContent: '', + render: (data) => (data ?? '').slice(0, 80) }, { title: l('PromptIsActive'), name: 'isActive', data: 'isActive', - index: 3, + index: 4, render: (data) => data ? 'Active' : 'Inactive' @@ -50,7 +55,7 @@ $(function () { orderable: false, className: 'text-center', name: 'rowActions', - index: 4, + index: 5, rowAction: { items: [ { @@ -78,7 +83,7 @@ $(function () { } ]; - const defaultVisibleColumns = ['name', 'type', 'description', 'isActive', 'rowActions']; + const defaultVisibleColumns = ['name', 'versionNumber', 'systemPrompt', 'userPrompt', 'isActive', 'rowActions']; const dt = $('#AIPromptsTable'); const dataTable = initializeDataTable({ @@ -177,15 +182,9 @@ $(function () { $('#versionId').val(v.id); $('#versionNumber').val(v.versionNumber); - $('#versionTargetModel').val(v.targetModel ?? ''); - $('#versionTargetProvider').val(v.targetProvider ?? ''); - $('#versionTemperature').val(v.temperature ?? 0.2); - $('#versionMaxTokens').val(v.maxTokens ?? ''); - $('#versionIsPublished').prop('checked', v.isPublished ?? false); - $('#versionIsDeprecated').prop('checked', v.isDeprecated ?? false); $('#versionSystemPrompt').val(v.systemPrompt ?? '').removeClass('is-invalid'); - $('#versionUserPromptTemplate').val(v.userPromptTemplate ?? '').removeClass('is-invalid'); - $('#versionDeveloperNotes').val(v.developerNotes ?? ''); + $('#versionUserPrompt').val(v.userPrompt ?? '').removeClass('is-invalid'); + $('#versionIsActive').prop('checked', v.isActive ?? true); // Pretty-print MetadataJson if valid let meta = v.metadataJson ?? ''; @@ -204,15 +203,9 @@ $(function () { currentVersionId = null; $('#versionId').val(''); - $('#versionTargetModel').val(''); - $('#versionTargetProvider').val(''); - $('#versionTemperature').val(0.2); - $('#versionMaxTokens').val(''); - $('#versionIsPublished').prop('checked', false); - $('#versionIsDeprecated').prop('checked', false); $('#versionSystemPrompt').val(''); - $('#versionUserPromptTemplate').val(''); - $('#versionDeveloperNotes').val(''); + $('#versionUserPrompt').val(''); + $('#versionIsActive').prop('checked', true); $('#versionMetadataJson').val(''); clearJsonError(); @@ -239,8 +232,8 @@ $(function () { if (!promptId) return; // Required-field validation - const systemPrompt = $('#versionSystemPrompt').val().trim(); - const userPromptTemplate = $('#versionUserPromptTemplate').val().trim(); + const systemPrompt = $('#versionSystemPrompt').val().trim(); + const userPrompt = $('#versionUserPrompt').val().trim(); let valid = true; if (systemPrompt) { $('#versionSystemPrompt').removeClass('is-invalid'); @@ -248,14 +241,14 @@ $(function () { $('#versionSystemPrompt').addClass('is-invalid'); valid = false; } - if (userPromptTemplate) { - $('#versionUserPromptTemplate').removeClass('is-invalid'); + if (userPrompt) { + $('#versionUserPrompt').removeClass('is-invalid'); } else { - $('#versionUserPromptTemplate').addClass('is-invalid'); + $('#versionUserPrompt').addClass('is-invalid'); valid = false; } if (!valid) { - $('#versionSystemPrompt.is-invalid, #versionUserPromptTemplate.is-invalid')[0]?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + $('#versionSystemPrompt.is-invalid, #versionUserPrompt.is-invalid')[0]?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); return; } @@ -263,18 +256,12 @@ $(function () { if (metaRaw && !validateJson(metaRaw)) return; const dto = { - promptId: promptId, - versionNumber: Number.parseInt($('#versionNumber').val()) || 0, - systemPrompt: systemPrompt, - userPromptTemplate: userPromptTemplate, - developerNotes: $('#versionDeveloperNotes').val() || null, - targetModel: $('#versionTargetModel').val() || null, - targetProvider: $('#versionTargetProvider').val() || null, - temperature: Number.parseFloat($('#versionTemperature').val()) || 0.2, - maxTokens: $('#versionMaxTokens').val() ? Number.parseInt($('#versionMaxTokens').val()) : null, - isPublished: $('#versionIsPublished').is(':checked'), - isDeprecated: $('#versionIsDeprecated').is(':checked'), - metadataJson: metaRaw || null + promptId: promptId, + versionNumber: Number.parseInt($('#versionNumber').val()) || 0, + systemPrompt: systemPrompt, + userPrompt: userPrompt, + metadataJson: metaRaw || null, + isActive: $('#versionIsActive').is(':checked') }; if (isNewVersion) { diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/CreateVersionModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/CreateVersionModal.cshtml.cs index ba49f50d0a..53b3b0c54f 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/CreateVersionModal.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/CreateVersionModal.cshtml.cs @@ -22,8 +22,7 @@ public void OnGet(Guid promptId) { Version = new CreateUpdateAIPromptVersionDto { - PromptId = promptId, - Temperature = 0.2 + PromptId = promptId }; } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/EditVersionModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/EditVersionModal.cshtml.cs index 40390dd976..cf9947f77d 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/EditVersionModal.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/EditVersionModal.cshtml.cs @@ -27,18 +27,12 @@ public async Task OnGetAsync() var dto = await _versionAppService.GetAsync(Id); Version = new CreateUpdateAIPromptVersionDto { - PromptId = dto.PromptId, + PromptId = dto.Id, VersionNumber = dto.VersionNumber, SystemPrompt = dto.SystemPrompt, - UserPromptTemplate = dto.UserPromptTemplate, - DeveloperNotes = dto.DeveloperNotes, - TargetModel = dto.TargetModel, - TargetProvider = dto.TargetProvider, - Temperature = dto.Temperature, - MaxTokens = dto.MaxTokens, - IsPublished = dto.IsPublished, - IsDeprecated = dto.IsDeprecated, - MetadataJson = dto.MetadataJson + UserPrompt = dto.UserPrompt, + MetadataJson = dto.MetadataJson, + IsActive = dto.IsActive }; } diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIModelDataSeederTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIModelDataSeederTests.cs new file mode 100644 index 0000000000..ae6380b57b --- /dev/null +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIModelDataSeederTests.cs @@ -0,0 +1,72 @@ +using Microsoft.Extensions.Configuration; +using NSubstitute; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading.Tasks; +using Unity.AI.DataSeed; +using Unity.AI.Domain; +using Volo.Abp.Data; +using Volo.Abp.Domain.Repositories; +using Xunit; + +namespace Unity.GrantManager.AI.DataSeed; + +public class AIModelDataSeederTests +{ + [Fact] + public async Task Should_Seed_All_Configured_Profiles() + { + var modelRepository = Substitute.For>(); + var insertedModels = new List(); + modelRepository + .FirstOrDefaultAsync(Arg.Any>>()) + .Returns((AIModel?)null); + modelRepository + .InsertAsync(Arg.Any()) + .Returns(callInfo => + { + var model = callInfo.Arg(); + insertedModels.Add(model); + return Task.FromResult(model); + }); + + var configuration = BuildConfiguration(new Dictionary + { + ["Azure:Operations:Defaults:Provider"] = "OpenAI", + ["Azure:Operations:Defaults:Profile"] = "Gpt5Mini", + ["Azure:OpenAI:Profiles:Gpt5Mini:DeploymentName"] = "gpt-5-mini", + ["Azure:OpenAI:Profiles:Gpt5Mini:Temperature"] = "0.15", + ["Azure:OpenAI:Profiles:Gpt5Nano:DeploymentName"] = "gpt-5-nano", + ["Azure:OpenAI:Endpoint"] = "https://example.test" + }); + + var seeder = new AIModelDataSeeder(modelRepository, configuration); + + await seeder.SeedAsync(new DataSeedContext()); + + insertedModels.Count.ShouldBe(2); + insertedModels.ShouldContain(model => model.Name == "Gpt5Mini" && model.IsActive); + insertedModels.ShouldContain(model => model.Name == "Gpt5Nano" && model.IsActive); + + var gpt5MiniModel = insertedModels.Find(model => model.Name == "Gpt5Mini"); + gpt5MiniModel.ShouldNotBeNull(); + DeserializeSettings(gpt5MiniModel.SettingsJson).MaxOutputTokenCountSupported.ShouldBeTrue(); + DeserializeSettings(gpt5MiniModel.SettingsJson).Temperature.ShouldBe(0.15); + } + + private static IConfiguration BuildConfiguration(IReadOnlyDictionary values) + { + return new ConfigurationBuilder() + .AddInMemoryCollection(values) + .Build(); + } + + private static AIModelSettings DeserializeSettings(string settingsJson) + { + var settings = JsonSerializer.Deserialize(settingsJson); + settings.ShouldNotBeNull(); + return settings; + } +} diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIOperationDataSeederTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIOperationDataSeederTests.cs new file mode 100644 index 0000000000..5cff2c9648 --- /dev/null +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIOperationDataSeederTests.cs @@ -0,0 +1,113 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Threading.Tasks; +using System.Threading; +using Unity.AI; +using Unity.AI.DataSeed; +using Unity.AI.Domain; +using Unity.AI.Prompts; +using Volo.Abp.Data; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.MultiTenancy; +using Xunit; + +namespace Unity.GrantManager.AI.DataSeed; + +public class AIOperationDataSeederTests +{ + [Fact] + public async Task Should_Seed_Configured_Default_Profile_Model_When_Missing() + { + var operationRepository = Substitute.For>(); + operationRepository + .GetQueryableAsync() + .Returns(Task.FromResult(new List().AsQueryable())); + + var modelRepository = Substitute.For>(); + var insertedModels = new List(); + modelRepository + .GetQueryableAsync() + .Returns(Task.FromResult(new List().AsQueryable())); + modelRepository + .InsertAsync(Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(callInfo => + { + var model = callInfo.Arg(); + insertedModels.Add(model); + return Task.FromResult(model); + }); + + var insertedOperations = new List(); + operationRepository + .InsertAsync(Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(callInfo => + { + var operation = callInfo.Arg(); + insertedOperations.Add(operation); + return Task.FromResult(operation); + }); + + var promptRepository = Substitute.For>(); + var prompts = new List + { + new(Guid.NewGuid(), AIPromptTypes.ApplicationAnalysis, 1, "system", "user"), + new(Guid.NewGuid(), AIPromptTypes.AttachmentSummary, 1, "system", "user"), + new(Guid.NewGuid(), AIPromptTypes.ApplicationScoring, 1, "system", "user") + }; + promptRepository + .GetListAsync(Arg.Any>>()) + .Returns(callInfo => + { + var predicate = callInfo.Arg>>().Compile(); + return Task.FromResult(prompts.Where(predicate).ToList()); + }); + + var currentTenant = Substitute.For(); + var configuration = BuildConfiguration(new Dictionary + { + ["Azure:Operations:Defaults:Provider"] = "OpenAI", + ["Azure:Operations:Defaults:Profile"] = "Gpt5Mini", + ["Azure:OpenAI:Profiles:Gpt5Mini:DeploymentName"] = "gpt-5-mini", + ["Azure:OpenAI:Endpoint"] = "https://example.test", + ["Azure:Operations:ApplicationAnalysis:MaxCompletionTokens"] = "4000", + ["Azure:Operations:AttachmentSummary:MaxCompletionTokens"] = "2000", + ["Azure:Operations:ApplicationScoring:MaxCompletionTokens"] = "8000" + }); + + var seeder = new AIOperationDataSeeder( + operationRepository, + modelRepository, + promptRepository, + configuration, + currentTenant, + Substitute.For>()); + + await seeder.SeedAsync(new DataSeedContext()); + + insertedModels.Count.ShouldBe(1); + insertedModels[0].Name.ShouldBe("Gpt5Mini"); + DeserializeSettings(insertedModels[0].SettingsJson).MaxOutputTokenCountSupported.ShouldBeTrue(); + DeserializeSettings(insertedModels[0].SettingsJson).Temperature.ShouldBeNull(); + + } + + private static IConfiguration BuildConfiguration(IReadOnlyDictionary values) + { + return new ConfigurationBuilder() + .AddInMemoryCollection(values) + .Build(); + } + + private static AIModelSettings DeserializeSettings(string settingsJson) + { + var settings = JsonSerializer.Deserialize(settingsJson); + settings.ShouldNotBeNull(); + return settings; + } +} diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/AIPromptTemplateProviderTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/AIPromptTemplateProviderTests.cs index 9e96d22241..144f2cde9e 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/AIPromptTemplateProviderTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/AIPromptTemplateProviderTests.cs @@ -6,6 +6,7 @@ using Unity.AI.Prompts; using Unity.AI.Runtime; using Unity.AI; +using Volo.Abp.Data; using Volo.Abp.Domain.Repositories; using Volo.Abp.MultiTenancy; using Xunit; @@ -17,26 +18,25 @@ public class AIPromptTemplateProviderTests [Fact] public async Task GetRequiredPromptAsync_Should_Return_Prompt_Definition_From_Database() { - var prompt = new AIPrompt(Guid.NewGuid(), AIPromptTypes.ApplicationAnalysis, PromptType.Skill); - var version = new AIPromptVersion( + var prompt = new AIPrompt( Guid.NewGuid(), - prompt.Id, + AIPromptTypes.ApplicationAnalysis, 1, "SYSTEM", "USER") { - MetadataJson = "{\"sections\":{\"RULES\":\"- rule\"}}", - IsPublished = true + MetadataJson = "{\"RULES\":\"- rule\"}", + IsActive = true }; - var provider = CreateProvider(prompt, version); + var provider = CreateProvider(prompt); var snapshot = await provider.GetRequiredPromptAsync(AIPromptTypes.ApplicationAnalysis, "v1"); snapshot.PromptVersion.ShouldBe("v1"); snapshot.SystemPrompt.ShouldBe("SYSTEM"); - snapshot.UserPromptTemplate.ShouldBe("USER"); - snapshot.MetadataJson.ShouldBe("{\"sections\":{\"RULES\":\"- rule\"}}"); + snapshot.UserPrompt.ShouldBe("USER"); + snapshot.MetadataJson.ShouldBe("{\"RULES\":\"- rule\"}"); } [Fact] @@ -51,20 +51,19 @@ public async Task GetRequiredPromptAsync_Should_Throw_When_Prompt_Is_Missing() } private static AIPromptTemplateProvider CreateProvider( - AIPrompt? prompt = null, - AIPromptVersion? version = null) + AIPrompt? prompt = null) { var promptRepository = Substitute.For>(); - var promptVersionRepository = Substitute.For>(); - var currentTenant = Substitute.For(); - currentTenant.Change(null).Returns(Substitute.For()); + var multiTenantDataFilter = Substitute.For>(); + multiTenantDataFilter.Disable().Returns(Substitute.For()); promptRepository.FindAsync(Arg.Any>>()) - .Returns(prompt); + .Returns(callInfo => + { + var predicate = callInfo.Arg>>(); + return Task.FromResult(prompt != null && predicate.Compile()(prompt) ? prompt : null); + }); - promptVersionRepository.FindAsync(Arg.Any>>()) - .Returns(version); - - return new AIPromptTemplateProvider(promptRepository, promptVersionRepository, currentTenant); + return new AIPromptTemplateProvider(promptRepository, multiTenantDataFilter); } } diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/AIPromptTemplateRendererTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/AIPromptTemplateRendererTests.cs index 551153abfb..2e24629bed 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/AIPromptTemplateRendererTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/AIPromptTemplateRendererTests.cs @@ -27,10 +27,8 @@ public void BuildApplicationAnalysisUserPrompt_Should_Render_Metadata_And_Preser const string metadataJson = """ { - "sections": { - "RULES": "- Use only provided input sections as evidence.", - "COMMON_RULES": "- If ATTACHMENTS is empty, use DATA only and do not mention missing attachments unless their absence is material." - } + "RULES": "- Use only provided input sections as evidence.", + "COMMON_RULES": "- If ATTACHMENTS is empty, use DATA only and do not mention missing attachments unless their absence is material." } """; @@ -79,10 +77,8 @@ public void BuildApplicationScoringUserPrompt_Should_Render_Metadata_Sections() const string metadataJson = """ { - "sections": { - "RULES": "- Use only DATA and ATTACHMENTS as evidence.", - "COMMON_RULES": "- Return valid JSON only." - } + "RULES": "- Use only DATA and ATTACHMENTS as evidence.", + "COMMON_RULES": "- Return valid JSON only." } """; @@ -108,9 +104,7 @@ public void BuildApplicationAnalysisUserPrompt_Should_Map_Output_Metadata_To_Res const string metadataJson = """ { - "sections": { - "OUTPUT": "{ \"decision\": \"PROCEED\" }" - } + "OUTPUT": "{ \"decision\": \"PROCEED\" }" } """; diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/AIProviderPayloadValidatorTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/AIProviderPayloadValidatorTests.cs index bbaf3981a5..e539c78852 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/AIProviderPayloadValidatorTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/AIProviderPayloadValidatorTests.cs @@ -50,6 +50,65 @@ public void ValidateApplicationScoringJson_Should_Return_InvalidOutput_When_Answ result.Reason.ShouldContain("q1"); } + [Fact] + public void ValidateApplicationAnalysisJson_Should_Return_InvalidOutput_When_Decision_Is_Not_Proceed_Or_Hold() + { + var result = AIProviderPayloadValidator.ValidateApplicationAnalysisJson( + """ + { + "decision": "unknown", + "errors": [], + "warnings": [], + "summaries": [ + { "title": "Summary", "detail": "Content" } + ], + "recommendations": [] + } + """); + + result.IsValid.ShouldBeFalse(); + result.FailureCategory.ShouldBe(AIFailureCategory.InvalidOutput); + result.Reason.ShouldContain("Expected 'PROCEED' or 'HOLD'"); + } + + [Fact] + public void ValidateApplicationAnalysisJson_Should_Return_InvalidOutput_When_All_Findings_Are_Empty() + { + var result = AIProviderPayloadValidator.ValidateApplicationAnalysisJson( + """ + { + "decision": "PROCEED", + "errors": [], + "warnings": [], + "summaries": [], + "recommendations": [] + } + """); + + result.IsValid.ShouldBeFalse(); + result.FailureCategory.ShouldBe(AIFailureCategory.InvalidOutput); + result.Reason.ShouldContain("At least one finding is required"); + } + + [Fact] + public void ValidateApplicationAnalysisJson_Should_Return_Success_For_Proceed_With_Findings() + { + var result = AIProviderPayloadValidator.ValidateApplicationAnalysisJson( + """ + { + "decision": "PROCEED", + "errors": [], + "warnings": [], + "summaries": [ + { "title": "Summary", "detail": "Looks complete." } + ], + "recommendations": [] + } + """); + + result.IsValid.ShouldBeTrue(); + } + [Fact] public void ValidateAttachmentSummaryText_Should_Return_InvalidOutput_For_Empty_Text() { diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIConfigurationResolverTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIConfigurationResolverTests.cs index 2c62d8dc35..e81d02f899 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIConfigurationResolverTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIConfigurationResolverTests.cs @@ -1,8 +1,20 @@ using Microsoft.Extensions.Configuration; +using NSubstitute; using Shouldly; using System; using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Unity.AI.Domain; +using Unity.AI.Operations; +using Unity.AI.Prompts; using Unity.AI.Runtime; +using Volo.Abp.Data; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.MultiTenancy; using Xunit; namespace Unity.GrantManager.AI.Runtime; @@ -10,212 +22,330 @@ namespace Unity.GrantManager.AI.Runtime; public class OpenAIConfigurationResolverTests { [Fact] - public void ResolveProviderName_Should_Throw_When_DefaultProvider_Is_Missing() + public async Task Should_Throw_When_Operation_Is_Missing() { - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary()) - .Build(); - - var resolver = new OpenAIConfigurationResolver(configuration); + var resolver = CreateResolver(); - var ex = Should.Throw(() => resolver.ResolveProviderName()); - ex.Message.ShouldContain("Azure:Operations:Defaults:Provider"); + var ex = await Should.ThrowAsync(() => resolver.ResolveOperationSettingsAsync(AIPromptTypes.ApplicationAnalysis)); + ex.Message.ShouldContain("AI operation"); } [Fact] - public void ResolveCompletionTokens_Should_Throw_When_Operation_And_Default_Are_Missing() + public async Task Should_Resolve_Operation_Strictly_From_Database() { - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary()) - .Build(); + var modelRepository = Substitute.For>(); + var operationRepository = Substitute.For>(); + var promptRepository = Substitute.For>(); - var resolver = new OpenAIConfigurationResolver(configuration); + var modelId = Guid.NewGuid(); + var promptId = Guid.NewGuid(); - var ex = Should.Throw(() => resolver.ResolveCompletionTokens("ApplicationAnalysis")); - ex.Message.ShouldContain("ApplicationAnalysis"); - } - - [Fact] - public void ResolvePromptVersion_Should_Use_Operation_Override_Before_Default() - { - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary + modelRepository + .GetAsync(modelId, cancellationToken: Arg.Any()) + .Returns(new AIModel(modelId, "Gpt5Mini") { - ["Azure:Operations:Defaults:PromptVersion"] = "v0", - ["Azure:Operations:ApplicationAnalysis:PromptVersion"] = "v1" - }) - .Build(); - - var resolver = new OpenAIConfigurationResolver(configuration); + IsActive = true, + SettingsJson = JsonSerializer.Serialize(new AIModelSettings + { + MaxOutputTokenCountSupported = true, + Temperature = 0.25 + }) + }); + + operationRepository + .GetListAsync(Arg.Any>>()) + .Returns(callInfo => + { + var predicate = callInfo.Arg>>(); + return Task.FromResult(new List + { + new(Guid.NewGuid(), AIPromptTypes.ApplicationAnalysis, modelId, promptId) + { + ExecutionMode = AIExecutionMode.Sequential, + CompletionTokens = 2222, + IsActive = true + } + }.Where(predicate.Compile()).ToList()); + }); + + promptRepository + .GetAsync(promptId, cancellationToken: Arg.Any()) + .Returns(Task.FromResult(new AIPrompt(promptId, AIPromptTypes.ApplicationAnalysis, 1, "system", "user") + { + IsActive = true + })); - resolver.ResolvePromptVersion("ApplicationAnalysis").ShouldBe("v1"); + var resolver = CreateResolver( + new Dictionary + { + ["Azure:OpenAI:ApiKey"] = "secret", + ["Azure:OpenAI:Profiles:Gpt5Mini:DeploymentName"] = "gpt-5-mini" + }, + modelRepository, + operationRepository, + promptRepository); + + var settings = await resolver.ResolveOperationSettingsAsync(AIPromptTypes.ApplicationAnalysis); + + settings.ProviderName.ShouldBe("OpenAI"); + settings.ProfileName.ShouldBe("Gpt5Mini"); + settings.Endpoint.ShouldBe(new Uri("https://example.test")); + settings.DeploymentName.ShouldBe("gpt-5-mini"); + settings.Temperature.ShouldBe(0.25); + settings.CompletionTokens.ShouldBe(2222); + settings.PromptVersion.ShouldBe("v1"); } [Fact] - public void ResolvePromptVersion_Should_Throw_When_Default_Is_Missing() + public async Task Should_Fallback_To_Default_Operation_When_Override_Is_Missing() { - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary()) - .Build(); + var modelRepository = Substitute.For>(); + var operationRepository = Substitute.For>(); + var promptRepository = Substitute.For>(); - var resolver = new OpenAIConfigurationResolver(configuration); + var modelId = Guid.NewGuid(); + var promptId = Guid.NewGuid(); - var ex = Should.Throw(() => resolver.ResolvePromptVersion("ApplicationAnalysis")); - ex.Message.ShouldContain("Azure:Operations:Defaults:PromptVersion"); - } - - [Fact] - public void ResolveApiKey_Should_Throw_When_Configured_Key_Is_Missing() - { - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary + modelRepository + .GetAsync(modelId, cancellationToken: Arg.Any()) + .Returns(new AIModel(modelId, "Gpt5Mini") { - ["Azure:Operations:Defaults:Provider"] = "OpenAI" - }) - .Build(); - - var resolver = new OpenAIConfigurationResolver(configuration); - - var ex = Should.Throw(() => resolver.ResolveApiKey()); - ex.Message.ShouldContain("Azure:OpenAI:ApiKey"); - } - - [Fact] - public void ResolveEndpoint_Should_Return_Configured_Provider_Endpoint() - { - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary + IsActive = true, + SettingsJson = JsonSerializer.Serialize(new AIModelSettings + { + Temperature = 0.2 + }) + }); + + operationRepository + .GetListAsync(Arg.Any>>()) + .Returns(callInfo => { - ["Azure:Operations:Defaults:Provider"] = "OpenAI", - ["Azure:OpenAI:Endpoint"] = "https://example.test" - }) - .Build(); - - var resolver = new OpenAIConfigurationResolver(configuration); - - resolver.ResolveEndpoint().ShouldBe(new Uri("https://example.test")); - } + var predicate = callInfo.Arg>>(); + return Task.FromResult(new List + { + new(Guid.NewGuid(), "Default", modelId, promptId) + { + ExecutionMode = AIExecutionMode.Sequential, + CompletionTokens = 2000, + IsActive = true + } + }.Where(predicate.Compile()).ToList()); + }); + + promptRepository + .GetAsync(promptId, cancellationToken: Arg.Any()) + .Returns(Task.FromResult(new AIPrompt(promptId, AIPromptTypes.ApplicationAnalysis, 1, "system", "user") + { + IsActive = true + })); - [Fact] - public void ResolveDeploymentName_Should_Return_Profile_DeploymentName() - { - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary + var resolver = CreateResolver( + new Dictionary { - ["Azure:Operations:Defaults:Provider"] = "OpenAI", - ["Azure:Operations:Defaults:Profile"] = "Gpt5Mini", + ["Azure:OpenAI:ApiKey"] = "secret", ["Azure:OpenAI:Profiles:Gpt5Mini:DeploymentName"] = "gpt-5-mini" - }) - .Build(); + }, + modelRepository, + operationRepository, + promptRepository); - var resolver = new OpenAIConfigurationResolver(configuration); + var settings = await resolver.ResolveOperationSettingsAsync(AIPromptTypes.ApplicationAnalysis); - resolver.ResolveDeploymentName().ShouldBe("gpt-5-mini"); + settings.ProviderName.ShouldBe("OpenAI"); + settings.PromptVersion.ShouldBe("v1"); + settings.CompletionTokens.ShouldBe(2000); } [Fact] - public void ResolveDeploymentName_Should_Use_Operation_Profile_Override() + public async Task Should_Resolve_Model_Values_Strictly_From_Database() { - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary - { - ["Azure:Operations:Defaults:Provider"] = "OpenAI", - ["Azure:Operations:Defaults:Profile"] = "Gpt5Mini", - ["Azure:Operations:ApplicationAnalysis:Profile"] = "Gpt4oMini", - ["Azure:OpenAI:Profiles:Gpt5Mini:DeploymentName"] = "gpt-5-mini", - ["Azure:OpenAI:Profiles:Gpt4oMini:DeploymentName"] = "gpt-4o-mini" - }) - .Build(); - - var resolver = new OpenAIConfigurationResolver(configuration); - - resolver.ResolveDeploymentName("ApplicationAnalysis").ShouldBe("gpt-4o-mini"); + var modelRepository = Substitute.For>(); + modelRepository + .GetListAsync(Arg.Any>>()) + .Returns(callInfo => + { + var predicate = callInfo.Arg>>(); + return Task.FromResult(new List + { + new(Guid.NewGuid(), "Gpt5Mini") + { + IsActive = true, + SettingsJson = JsonSerializer.Serialize(new AIModelSettings + { + MaxOutputTokenCountSupported = true, + Temperature = 0.35 + }) + } + }.Where(predicate.Compile()).ToList()); + }); + + var resolver = CreateResolver(modelRepository: modelRepository); + + resolver.ResolveProviderName().ShouldBe("OpenAI"); + (await resolver.ResolveDeploymentNameAsync()).ShouldBe("gpt-5-mini"); + (await resolver.ResolveEndpointAsync()).ShouldBe(new Uri("https://example.test")); + (await resolver.ResolveConfiguredTemperatureAsync()).ShouldBe(0.35); + (await resolver.ResolveMaxOutputTokenCountSupportedAsync()).ShouldBeTrue(); } [Fact] - public void ResolveDeploymentName_Should_Throw_When_Profile_DeploymentName_Is_Missing() + public async Task Should_Resolve_ApiKey_From_Provider_Secret() { - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary + var modelRepository = Substitute.For>(); + modelRepository + .GetListAsync(Arg.Any>>()) + .Returns(callInfo => { - ["Azure:Operations:Defaults:Provider"] = "OpenAI", - ["Azure:Operations:Defaults:Profile"] = "Gpt5Mini" - }) - .Build(); - - var resolver = new OpenAIConfigurationResolver(configuration); + var predicate = callInfo.Arg>>(); + return Task.FromResult(new List + { + new(Guid.NewGuid(), "Default") + { + IsActive = true, + SettingsJson = JsonSerializer.Serialize(new AIModelSettings + { + MaxOutputTokenCountSupported = true + }) + } + }.Where(predicate.Compile()).ToList()); + }); + + var resolver = CreateResolver( + new Dictionary + { + ["Azure:OpenAI:ApiKey"] = "secret" + }, + modelRepository); - var ex = Should.Throw(() => resolver.ResolveDeploymentName()); - ex.Message.ShouldContain("Azure:OpenAI:Profiles:Gpt5Mini:DeploymentName"); + (await resolver.ResolveApiKeyAsync()).ShouldBe("secret"); } [Fact] - public void ResolveConfiguredTemperature_Should_Return_Profile_Temperature() + public async Task Should_Resolve_Operation_Settings_From_Host_Context() { - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary + var modelRepository = Substitute.For>(); + var operationRepository = Substitute.For>(); + var promptRepository = Substitute.For>(); + var multiTenantDataFilter = Substitute.For>(); + multiTenantDataFilter.Disable().Returns(Substitute.For()); + + var modelId = Guid.NewGuid(); + var promptId = Guid.NewGuid(); + + modelRepository + .GetAsync(modelId, cancellationToken: Arg.Any()) + .Returns(new AIModel(modelId, "Gpt5Mini") { - ["Azure:Operations:Defaults:Provider"] = "OpenAI", - ["Azure:Operations:Defaults:Profile"] = "Gpt4oMini", - ["Azure:OpenAI:Profiles:Gpt4oMini:Temperature"] = "0.3" - }) - .Build(); + IsActive = true, + SettingsJson = JsonSerializer.Serialize(new AIModelSettings + { + Temperature = 0.1 + }) + }); + + operationRepository + .GetListAsync(Arg.Any>>()) + .Returns(callInfo => + { + var predicate = callInfo.Arg>>(); + return Task.FromResult(new List + { + new(Guid.NewGuid(), AIPromptTypes.ApplicationAnalysis, modelId, promptId) + { + IsActive = true, + CompletionTokens = 2000 + } + }.Where(predicate.Compile()).ToList()); + }); + + promptRepository + .GetAsync(promptId, cancellationToken: Arg.Any()) + .Returns(Task.FromResult(new AIPrompt(promptId, AIPromptTypes.ApplicationAnalysis, 1, "system", "user") + { + IsActive = true + })); + + var resolver = CreateResolver( + new Dictionary + { + ["Azure:OpenAI:ApiKey"] = "secret" + }, + modelRepository, + operationRepository, + promptRepository, + multiTenantDataFilter); - var resolver = new OpenAIConfigurationResolver(configuration); + var settings = await resolver.ResolveOperationSettingsAsync(AIPromptTypes.ApplicationAnalysis); - resolver.ResolveConfiguredTemperature().ShouldBe(0.3); + settings.PromptVersion.ShouldBe("v1"); + multiTenantDataFilter.Received().Disable(); } - [Theory] - [InlineData(null)] - [InlineData("not-a-number")] - public void ResolveConfiguredTemperature_Should_Return_Null_When_Profile_Temperature_Is_Missing_Or_Invalid(string? temperature) + private static OpenAIConfigurationResolver CreateResolver( + IReadOnlyDictionary? values = null, + IRepository? modelRepository = null, + IRepository? operationRepository = null, + IRepository? promptRepository = null, + IDataFilter? multiTenantDataFilter = null) { - var values = new Dictionary + var configurationValues = new Dictionary { ["Azure:Operations:Defaults:Provider"] = "OpenAI", - ["Azure:Operations:Defaults:Profile"] = "Gpt4oMini" + ["Azure:Operations:Defaults:Profile"] = "Gpt5Mini", + ["Azure:OpenAI:Endpoint"] = "https://example.test", + ["Azure:OpenAI:ApiKey"] = "secret", + ["Azure:OpenAI:Profiles:Gpt5Mini:DeploymentName"] = "gpt-5-mini", + ["Azure:OpenAI:Profiles:Gpt5Mini:MaxOutputTokenCountSupported"] = "true" }; - if (temperature != null) + if (values != null) { - values["Azure:OpenAI:Profiles:Gpt4oMini:Temperature"] = temperature; + foreach (var pair in values) + { + configurationValues[pair.Key] = pair.Value; + } } var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(values) + .AddInMemoryCollection(configurationValues) .Build(); - var resolver = new OpenAIConfigurationResolver(configuration); + var filter = multiTenantDataFilter ?? Substitute.For>(); + filter.Disable().Returns(Substitute.For()); - resolver.ResolveConfiguredTemperature().ShouldBeNull(); + return new OpenAIConfigurationResolver( + modelRepository ?? CreateEmptyModelRepository(), + operationRepository ?? CreateEmptyOperationRepository(), + promptRepository ?? CreateEmptyPromptRepository(), + configuration, + filter); } - [Theory] - [InlineData(null, true)] - [InlineData("true", true)] - [InlineData("false", false)] - public void ResolveMaxOutputTokenCountSupported_Should_Use_Profile_Setting_Or_Default_True( - string? configuredValue, - bool expected) + private static IRepository CreateEmptyModelRepository() { - var values = new Dictionary - { - ["Azure:Operations:Defaults:Provider"] = "OpenAI", - ["Azure:Operations:Defaults:Profile"] = "Gpt5Mini" - }; - - if (configuredValue != null) - { - values["Azure:OpenAI:Profiles:Gpt5Mini:MaxOutputTokenCountSupported"] = configuredValue; - } - - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(values) - .Build(); + var modelRepository = Substitute.For>(); + modelRepository + .GetListAsync(Arg.Any>>()) + .Returns(Task.FromResult(new List())); + return modelRepository; + } - var resolver = new OpenAIConfigurationResolver(configuration); + private static IRepository CreateEmptyOperationRepository() + { + var operationRepository = Substitute.For>(); + operationRepository + .GetListAsync(Arg.Any>>()) + .Returns(Task.FromResult(new List())); + return operationRepository; + } - resolver.ResolveMaxOutputTokenCountSupported().ShouldBe(expected); + private static IRepository CreateEmptyPromptRepository() + { + var promptRepository = Substitute.For>(); + promptRepository + .GetAsync(Arg.Any(), cancellationToken: Arg.Any()) + .Returns(callInfo => Task.FromResult(new AIPrompt(callInfo.Arg(), "Default", 1, "system", "user"))); + return promptRepository; } } diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIRuntimeServiceTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIRuntimeServiceTests.cs new file mode 100644 index 0000000000..8c48f3985e --- /dev/null +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIRuntimeServiceTests.cs @@ -0,0 +1,65 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Text.Json; +using System.Threading.Tasks; +using Unity.AI.Domain; +using Unity.AI.Operations; +using Unity.AI.Requests; +using Unity.AI.Runtime; +using Volo.Abp.Data; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.MultiTenancy; +using Xunit; + +namespace Unity.GrantManager.AI.Runtime; + +public class OpenAIRuntimeServiceTests +{ + [Fact] + public async Task Should_Throw_When_Analysis_Operation_Is_Not_Configured() + { + var modelRepository = Substitute.For>(); + modelRepository + .GetListAsync(Arg.Any>>()) + .Returns(new List()); + + var operationRepository = Substitute.For>(); + operationRepository + .GetListAsync(Arg.Any>>()) + .Returns(new List()); + + var promptRepository = Substitute.For>(); + var configuration = new ConfigurationBuilder().Build(); + var multiTenantDataFilter = Substitute.For>(); + multiTenantDataFilter.Disable().Returns(Substitute.For()); + + var resolver = new OpenAIConfigurationResolver( + modelRepository, + operationRepository, + promptRepository, + configuration, + multiTenantDataFilter); + + var logger = Substitute.For>(); + var runtimeService = new OpenAIRuntimeService( + logger, + null!, + resolver, + null!, + null!); + + var ex = await Should.ThrowAsync(() => + runtimeService.GenerateApplicationAnalysisAsync(new ApplicationAnalysisRequest + { + Schema = JsonSerializer.SerializeToElement(new { project = "x" }), + Data = JsonSerializer.SerializeToElement(new { project = "x" }) + })); + + ex.Message.ShouldContain("AI operation"); + } +} From a8baa4a3aa26d7bff40048363701e55242be7056 Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Fri, 26 Jun 2026 08:31:59 -0700 Subject: [PATCH 02/61] AB#32307 wire AI generation request plumbing --- .../AIGenerationRequestDto.cs | 1 + .../AIGenerationStatusAppService.cs | 33 ++++++- .../ApplicationAIGenerationQueue.cs | 28 +++++- .../RunApplicationAIPipelineJob.cs | 12 ++- .../GrantApplicationAppService.cs | 74 ++++++++++------ .../GrantManagerApplicationMapperlyProfile.cs | 1 - .../AIGenerationRequestKeyHelper.cs | 16 ++++ .../GrantApplications/AIGenerationRequest.cs | 6 +- .../Automation/AIGenerationQueueTests.cs | 64 ++++++++++---- .../AIGenerationStatusAppServiceTests.cs | 88 ++++++++++++++++++- .../RunApplicationAIPipelineJobTests.cs | 2 +- ...GrantApplicationAIGenerationStatusTests.cs | 45 +++++++++- 12 files changed, 308 insertions(+), 62 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/AIGenerationRequestDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/AIGenerationRequestDto.cs index 0dfccaa949..6a5f5b7f66 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/AIGenerationRequestDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/AIGenerationRequestDto.cs @@ -6,6 +6,7 @@ namespace Unity.GrantManager.GrantApplications; public class AIGenerationRequestDto : EntityDto { public Guid? ApplicationId { get; set; } + public Guid OperationId { get; set; } public string OperationType { get; set; } = string.Empty; public string RequestKey { get; set; } = string.Empty; public AIGenerationRequestStatus Status { get; set; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/AIGenerationStatusAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/AIGenerationStatusAppService.cs index e887a1fc8a..92b930052c 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/AIGenerationStatusAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/AIGenerationStatusAppService.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Unity.AI.Domain; using Unity.GrantManager.GrantApplications; using Volo.Abp.Application.Services; using Volo.Abp.Domain.Repositories; @@ -10,18 +11,32 @@ namespace Unity.GrantManager.GrantApplications; public class AIGenerationStatusAppService( IRepository generationRequestRepository, + IRepository operationRepository, ICurrentTenant currentTenant) : ApplicationService, IAIGenerationStatusAppService { public virtual async Task GetLatestAsync(Guid applicationId, string operationType, Guid? tenantId = null) { + var operationName = AIGenerationRequestKeyHelper.ResolveOperationName(operationType); + + if (operationName == null) + { + return null; + } + + var operation = await ResolveOperationAsync(operationName); + if (operation == null) + { + return null; + } + var query = await generationRequestRepository.GetQueryableAsync(); var resolvedTenantId = tenantId ?? currentTenant.Id; var item = query .Where(x => x.ApplicationId == applicationId && - x.OperationType == operationType && + x.OperationId == operation.Id && x.TenantId == resolvedTenantId) .OrderByDescending(x => x.CreationTime) .ThenByDescending(x => x.Id) @@ -33,7 +48,8 @@ public class AIGenerationStatusAppService( { Id = item.Id, ApplicationId = item.ApplicationId, - OperationType = item.OperationType, + OperationId = item.OperationId, + OperationType = operationType, RequestKey = item.RequestKey, Status = item.Status, StartedAt = item.StartedAt, @@ -42,4 +58,17 @@ public class AIGenerationStatusAppService( IsActive = item.IsActive }; } + + private async Task ResolveOperationAsync(string operationName) + { + var operations = await operationRepository.GetQueryableAsync(); + var activeOperations = operations + .Where(operation => operation.IsActive) + .ToList(); + + return activeOperations.FirstOrDefault(operation => + string.Equals(operation.Name, operationName, StringComparison.OrdinalIgnoreCase)) + ?? activeOperations.FirstOrDefault(operation => + string.Equals(operation.Name, "Default", StringComparison.OrdinalIgnoreCase)); + } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/ApplicationAIGenerationQueue.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/ApplicationAIGenerationQueue.cs index c2aa5f6a2c..d564ccba88 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/ApplicationAIGenerationQueue.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/ApplicationAIGenerationQueue.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Unity.AI.Domain; using Unity.AI.Automation; using Unity.AI.Features; using Unity.AI.Localization; @@ -24,6 +25,7 @@ namespace Unity.GrantManager.GrantApplications.Automation; public class ApplicationAIGenerationQueue( IBackgroundJobManager backgroundJobManager, IRepository generationRequestRepository, + IRepository operationRepository, IDistributedLockProvider distributedLockProvider, IAIGenerationPrerequisiteValidator aiGenerationPrerequisiteValidator, IFeatureChecker featureChecker, @@ -155,10 +157,12 @@ private async Task EnsureRequestAndEnqueueAsync( // The limiter is a no-op for system/background callers without an authenticated user. await aiRateLimiter.EnsureAsync(); + var operation = await ResolveOperationAsync(operationType); + var request = new AIGenerationRequest( Guid.NewGuid(), tenantId, - operationType, + operation.Id, applicationId, requestKey); @@ -176,6 +180,28 @@ private async Task EnsureRequestAndEnqueueAsync( } } + private static string ResolveOperationName(string operationType) + => AIGenerationRequestKeyHelper.ResolveOperationName(operationType) + ?? throw new UserFriendlyException($"AI operation '{operationType}' is not configured."); + + private async Task ResolveOperationAsync(string operationType) + { + var operationName = ResolveOperationName(operationType); + var activeOperations = await operationRepository.GetListAsync(operation => operation.IsActive); + + var operation = activeOperations.FirstOrDefault(operation => + string.Equals(operation.Name, operationName, StringComparison.OrdinalIgnoreCase)) + ?? activeOperations.FirstOrDefault(operation => + string.Equals(operation.Name, "Default", StringComparison.OrdinalIgnoreCase)); + + if (operation == null) + { + throw new UserFriendlyException($"AI operation '{operationType}' is not configured."); + } + + return operation; + } + private async Task EnsureAnyPipelineStageAvailableAsync(Guid applicationId) { var hasEnabledStage = false; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/BackgroundJobs/RunApplicationAIPipelineJob.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/BackgroundJobs/RunApplicationAIPipelineJob.cs index 8dec6009b1..3c76f230da 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/BackgroundJobs/RunApplicationAIPipelineJob.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/BackgroundJobs/RunApplicationAIPipelineJob.cs @@ -140,9 +140,12 @@ await localEventBus.PublishAsync(new ApplicationAIScoringGeneratedEvent } } - if (scoringException != null) + if (analysisException != null && scoringException != null) { - throw scoringException; + throw new AggregateException( + $"AI pipeline failed for application {args.ApplicationId} in multiple stages.", + analysisException, + scoringException); } if (analysisException != null) @@ -150,6 +153,11 @@ await localEventBus.PublishAsync(new ApplicationAIScoringGeneratedEvent throw analysisException; } + if (scoringException != null) + { + throw scoringException; + } + await AIGenerationRequestJobHelper.StampRateLimitBestEffortAsync(aiRateLimiter, logger, args.RequestedByUserId, args.ApplicationId, args.RequestKey); await AIGenerationRequestJobHelper.MarkCompletedInNewUowAsync(unitOfWorkManager, generationRequestRepository, args.RequestKey); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs index 469414348b..b980b8bef0 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs @@ -1187,13 +1187,17 @@ public async Task QueueApplicationAnalysisAsync(Guid appl await EnsureAIAnalysisEnabledAsync(); await aiGenerationQueue.QueueApplicationAnalysisAsync(applicationId, CurrentTenant.Id, promptVersion); - var request = await aiGenerationStatusAppService.GetLatestAsync( - applicationId, - AIGenerationRequestKeyHelper.ApplicationAnalysisOperationType, - CurrentTenant.Id); - - return await CreateGenerationStatusAsync( - request ?? throw new UserFriendlyException("Unable to queue AI analysis request.")); + var request = await aiGenerationStatusAppService.GetLatestAsync( + applicationId, + AIGenerationRequestKeyHelper.ApplicationAnalysisOperationType, + CurrentTenant.Id); + + if (request == null) + { + throw new UserFriendlyException("Unable to queue AI analysis request."); + } + + return await CreateGenerationStatusAsync(request); } [Authorize(AIPermissions.Analysis.GenerateAttachmentSummaries)] @@ -1203,13 +1207,17 @@ public async Task QueueAttachmentSummaryAsync(QueueAttach var attachmentIds = await ResolveAttachmentSummaryIdsAsync(input); await aiGenerationQueue.QueueAttachmentSummaryAsync(input.ApplicationId, CurrentTenant.Id, promptVersion, attachmentIds); - var request = await aiGenerationStatusAppService.GetLatestAsync( - input.ApplicationId, - AIGenerationRequestKeyHelper.AttachmentSummaryOperationType, - CurrentTenant.Id); - - return await CreateGenerationStatusAsync( - request ?? throw new UserFriendlyException("Unable to queue AI attachment summary request.")); + var request = await aiGenerationStatusAppService.GetLatestAsync( + input.ApplicationId, + AIGenerationRequestKeyHelper.AttachmentSummaryOperationType, + CurrentTenant.Id); + + if (request == null) + { + throw new UserFriendlyException("Unable to queue AI attachment summary request."); + } + + return await CreateGenerationStatusAsync(request); } [Authorize(AIPermissions.Analysis.GenerateScoring)] @@ -1218,13 +1226,17 @@ public async Task QueueApplicationScoringAsync(Guid appli await EnsureScoringEnabledAsync(); await aiGenerationQueue.QueueApplicationScoringAsync(applicationId, CurrentTenant.Id, promptVersion); - var request = await aiGenerationStatusAppService.GetLatestAsync( - applicationId, - AIGenerationRequestKeyHelper.ApplicationScoringOperationType, - CurrentTenant.Id); - - return await CreateGenerationStatusAsync( - request ?? throw new UserFriendlyException("Unable to queue AI scoring request.")); + var request = await aiGenerationStatusAppService.GetLatestAsync( + applicationId, + AIGenerationRequestKeyHelper.ApplicationScoringOperationType, + CurrentTenant.Id); + + if (request == null) + { + throw new UserFriendlyException("Unable to queue AI scoring request."); + } + + return await CreateGenerationStatusAsync(request); } public async Task GetAIGenerationStatusAsync(Guid applicationId, string operationType, string? promptVersion = null) @@ -1244,14 +1256,18 @@ public async Task QueueAllAIStagesAsync(Guid applicationI await EnsureScoringEnabledAsync(); await aiGenerationQueue.QueueAllAIStagesAsync(applicationId, CurrentTenant.Id, promptVersion); - var request = await aiGenerationStatusAppService.GetLatestAsync( - applicationId, - AIGenerationRequestKeyHelper.PipelineOperationType, - CurrentTenant.Id); - - return await CreateGenerationStatusAsync( - request ?? throw new UserFriendlyException("Unable to queue AI generation request.")); - } + var request = await aiGenerationStatusAppService.GetLatestAsync( + applicationId, + AIGenerationRequestKeyHelper.PipelineOperationType, + CurrentTenant.Id); + + if (request == null) + { + throw new UserFriendlyException("Unable to queue AI generation request."); + } + + return await CreateGenerationStatusAsync(request); + } private async Task CreateGenerationStatusAsync(AIGenerationRequestDto? request) { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationMapperlyProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationMapperlyProfile.cs index b30669f1ee..994dbe1d99 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationMapperlyProfile.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationMapperlyProfile.cs @@ -538,7 +538,6 @@ public partial class ApplicationActionResultItemToDtoMapper : MapperBase { public override partial CommunityDto Map(Community source); public override partial void Map(Community source, CommunityDto destination); } [Mapper] public partial class RegionalDistrictToDtoMapper : MapperBase { public override partial RegionalDistrictDto Map(RegionalDistrict source); public override partial void Map(RegionalDistrict source, RegionalDistrictDto destination); } [Mapper] public partial class ApplicationTagsToDtoMapper : MapperBase { public override partial ApplicationTagsDto Map(ApplicationTags source); public override partial void Map(ApplicationTags source, ApplicationTagsDto destination); } -[Mapper] public partial class AIGenerationRequestToDtoMapper : MapperBase { public override partial AIGenerationRequestDto Map(AIGenerationRequest source); public override partial void Map(AIGenerationRequest source, AIGenerationRequestDto destination); } [Mapper(AllowNullPropertyAssignment = true)] public partial class ApplicantToGrantApplicationApplicantDtoMapper : MapperBase { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/GrantApplications/AIGenerationRequestKeyHelper.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/GrantApplications/AIGenerationRequestKeyHelper.cs index 0492a5d6ad..d478b3af4f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/GrantApplications/AIGenerationRequestKeyHelper.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/GrantApplications/AIGenerationRequestKeyHelper.cs @@ -19,4 +19,20 @@ public static string BuildRequestKey(Guid? tenantId, Guid applicationId, string applicationId.ToString("D"), operationType.Trim().ToLowerInvariant()); } + + /// + /// Maps an operation type key (e.g. "application-analysis") to the canonical operation name + /// stored in the AIOperations table (e.g. "ApplicationAnalysis"). + /// + public static string? ResolveOperationName(string operationType) + { + return operationType switch + { + ApplicationAnalysisOperationType => "ApplicationAnalysis", + AttachmentSummaryOperationType => "AttachmentSummary", + ApplicationScoringOperationType => "ApplicationScoring", + PipelineOperationType => "Default", + _ => null + }; + } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/GrantApplications/AIGenerationRequest.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/GrantApplications/AIGenerationRequest.cs index 7ab2d9a8e5..94fc5a1bf1 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/GrantApplications/AIGenerationRequest.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/GrantApplications/AIGenerationRequest.cs @@ -8,7 +8,7 @@ public class AIGenerationRequest : FullAuditedAggregateRoot, IMultiTenant { public Guid? TenantId { get; set; } public Guid? ApplicationId { get; set; } - public string OperationType { get; set; } = string.Empty; + public Guid OperationId { get; set; } public string RequestKey { get; set; } = string.Empty; public AIGenerationRequestStatus Status { get; set; } public DateTime? StartedAt { get; set; } @@ -23,13 +23,13 @@ protected AIGenerationRequest() public AIGenerationRequest( Guid id, Guid? tenantId, - string operationType, + Guid operationId, Guid? applicationId, string requestKey) : base(id) { TenantId = tenantId; - OperationType = operationType; + OperationId = operationId; ApplicationId = applicationId; RequestKey = requestKey; Status = AIGenerationRequestStatus.Queued; diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/Automation/AIGenerationQueueTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/Automation/AIGenerationQueueTests.cs index 99e3a4c22f..3df4f8195b 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/Automation/AIGenerationQueueTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/Automation/AIGenerationQueueTests.cs @@ -6,8 +6,10 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; +using Unity.AI.Domain; using Unity.AI.Features; using Unity.AI.Localization; using Unity.AI.RateLimit; @@ -37,6 +39,7 @@ public async Task QueueAllAIStagesAsync_Should_Enqueue_Pipeline_Job_When_None_Ex repository.GetQueryableAsync().Returns(Task.FromResult>(Array.Empty().AsQueryable())); repository.InsertAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(callInfo => Task.FromResult(callInfo.Arg())); + var operationRepository = CreateOperationRepository(); RunApplicationAIPipelineJobArgs? capturedArgs = null; var backgroundJobManager = Substitute.For(); @@ -50,7 +53,7 @@ public async Task QueueAllAIStagesAsync_Should_Enqueue_Pipeline_Job_When_None_Ex return Task.FromResult(string.Empty); }); - var queue = CreateQueue(backgroundJobManager, repository); + var queue = CreateQueue(backgroundJobManager, repository, operationRepository: operationRepository); await queue.QueueAllAIStagesAsync(applicationId, tenantId, "v1"); @@ -64,7 +67,7 @@ public async Task QueueAllAIStagesAsync_Should_Enqueue_Pipeline_Job_When_None_Ex await repository.Received(1).InsertAsync(Arg.Is(r => r.ApplicationId == applicationId && r.TenantId == tenantId && - r.OperationType == AIGenerationRequestKeyHelper.PipelineOperationType && + r.OperationId != Guid.Empty && r.RequestKey == capturedArgs.RequestKey && r.Status == AIGenerationRequestStatus.Queued), Arg.Any(), Arg.Any()); } @@ -78,6 +81,7 @@ public async Task QueueAllAIStagesAsync_Should_Enqueue_When_Any_Enabled_Stage_Ha repository.GetQueryableAsync().Returns(Task.FromResult>(Array.Empty().AsQueryable())); repository.InsertAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(callInfo => Task.FromResult(callInfo.Arg())); + var operationRepository = CreateOperationRepository(); var backgroundJobManager = Substitute.For(); var prerequisiteValidator = Substitute.For(); @@ -90,6 +94,7 @@ public async Task QueueAllAIStagesAsync_Should_Enqueue_When_Any_Enabled_Stage_Ha var queue = CreateQueue( backgroundJobManager, repository, + operationRepository: operationRepository, prerequisiteValidator: prerequisiteValidator); await queue.QueueAllAIStagesAsync(applicationId, tenantId); @@ -105,6 +110,7 @@ public async Task QueueAllAIStagesAsync_Should_Not_Insert_Or_Enqueue_When_No_Ena var tenantId = Guid.NewGuid(); var repository = Substitute.For>(); repository.GetQueryableAsync().Returns(Task.FromResult>(Array.Empty().AsQueryable())); + var operationRepository = CreateOperationRepository(); var backgroundJobManager = Substitute.For(); var rateLimiter = Substitute.For(); @@ -121,7 +127,8 @@ public async Task QueueAllAIStagesAsync_Should_Not_Insert_Or_Enqueue_When_No_Ena backgroundJobManager, repository, rateLimiter, - prerequisiteValidator); + prerequisiteValidator, + operationRepository: operationRepository); await Should.ThrowAsync(() => queue.QueueAllAIStagesAsync(applicationId, tenantId)); @@ -137,6 +144,7 @@ public async Task QueueAllAIStagesAsync_Should_Not_Insert_Or_Enqueue_When_No_AI_ var tenantId = Guid.NewGuid(); var repository = Substitute.For>(); repository.GetQueryableAsync().Returns(Task.FromResult>(Array.Empty().AsQueryable())); + var operationRepository = CreateOperationRepository(); var backgroundJobManager = Substitute.For(); var rateLimiter = Substitute.For(); @@ -152,7 +160,8 @@ public async Task QueueAllAIStagesAsync_Should_Not_Insert_Or_Enqueue_When_No_AI_ repository, rateLimiter, prerequisiteValidator, - featureChecker); + featureChecker, + operationRepository: operationRepository); await Should.ThrowAsync(() => queue.QueueAllAIStagesAsync(applicationId, tenantId)); @@ -174,7 +183,7 @@ public async Task QueueApplicationAnalysisAsync_Should_Not_Enqueue_When_An_Activ var request = new AIGenerationRequest( Guid.NewGuid(), tenantId, - AIGenerationRequestKeyHelper.ApplicationAnalysisOperationType, + Guid.NewGuid(), applicationId, requestKey); @@ -184,7 +193,7 @@ public async Task QueueApplicationAnalysisAsync_Should_Not_Enqueue_When_An_Activ var backgroundJobManager = Substitute.For(); var rateLimiter = Substitute.For(); rateLimiter.EnsureAsync().Returns(Task.CompletedTask); - var queue = CreateQueue(backgroundJobManager, repository, rateLimiter); + var queue = CreateQueue(backgroundJobManager, repository, rateLimiter: rateLimiter); await queue.QueueApplicationAnalysisAsync(applicationId, tenantId, promptVersion); @@ -229,7 +238,7 @@ public async Task QueueApplicationAnalysisAsync_Should_Enqueue_New_Request_When_ await repository.Received(1).InsertAsync(Arg.Is(r => r.ApplicationId == applicationId && r.TenantId == tenantId && - r.OperationType == AIGenerationRequestKeyHelper.ApplicationAnalysisOperationType && + r.OperationId != Guid.Empty && r.RequestKey == capturedArgs.RequestKey && r.Status == AIGenerationRequestStatus.Queued), Arg.Any(), Arg.Any()); } @@ -247,7 +256,7 @@ public async Task QueueApplicationAnalysisAsync_Should_Check_Rate_Limit_Before_E var backgroundJobManager = Substitute.For(); var rateLimiter = Substitute.For(); rateLimiter.EnsureAsync().Returns(Task.CompletedTask); - var queue = CreateQueue(backgroundJobManager, repository, rateLimiter); + var queue = CreateQueue(backgroundJobManager, repository, rateLimiter: rateLimiter); await queue.QueueApplicationAnalysisAsync(applicationId, tenantId); @@ -267,7 +276,7 @@ public async Task QueueApplicationAnalysisAsync_Should_Not_Insert_Or_Enqueue_Whe var backgroundJobManager = Substitute.For(); var rateLimiter = Substitute.For(); rateLimiter.EnsureAsync().Returns(_ => throw new InvalidOperationException("rate limited")); - var queue = CreateQueue(backgroundJobManager, repository, rateLimiter); + var queue = CreateQueue(backgroundJobManager, repository, rateLimiter: rateLimiter); await Should.ThrowAsync(() => queue.QueueApplicationAnalysisAsync(applicationId, tenantId)); @@ -290,7 +299,7 @@ public async Task QueueAttachmentSummaryAsync_Should_Not_Insert_Or_Enqueue_When_ var prerequisiteValidator = Substitute.For(); prerequisiteValidator.EnsureAttachmentSummaryAvailableAsync(applicationId) .Returns(_ => throw new UserFriendlyException("No attachments are available to summarize.")); - var queue = CreateQueue(backgroundJobManager, repository, rateLimiter, prerequisiteValidator); + var queue = CreateQueue(backgroundJobManager, repository, rateLimiter: rateLimiter, prerequisiteValidator: prerequisiteValidator); await Should.ThrowAsync(() => queue.QueueAttachmentSummaryAsync(applicationId, tenantId)); @@ -309,7 +318,7 @@ public async Task QueueAttachmentSummaryAsync_Should_Not_Enqueue_When_An_Active_ var request = new AIGenerationRequest( Guid.NewGuid(), tenantId, - AIGenerationRequestKeyHelper.AttachmentSummaryOperationType, + Guid.NewGuid(), applicationId, requestKey); @@ -335,6 +344,7 @@ public async Task QueueAttachmentSummaryAsync_Should_Enqueue_New_Request_When_No repository.GetQueryableAsync().Returns(Task.FromResult>(Array.Empty().AsQueryable())); repository.InsertAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(callInfo => Task.FromResult(callInfo.Arg())); + var operationRepository = CreateOperationRepository(); GenerateAttachmentSummaryBackgroundJobArgs? capturedArgs = null; var backgroundJobManager = Substitute.For(); @@ -348,7 +358,7 @@ public async Task QueueAttachmentSummaryAsync_Should_Enqueue_New_Request_When_No return Task.FromResult(string.Empty); }); - var queue = CreateQueue(backgroundJobManager, repository); + var queue = CreateQueue(backgroundJobManager, repository, operationRepository: operationRepository); await queue.QueueAttachmentSummaryAsync(applicationId, tenantId, promptVersion); @@ -361,7 +371,7 @@ public async Task QueueAttachmentSummaryAsync_Should_Enqueue_New_Request_When_No await repository.Received(1).InsertAsync(Arg.Is(r => r.ApplicationId == applicationId && r.TenantId == tenantId && - r.OperationType == AIGenerationRequestKeyHelper.AttachmentSummaryOperationType && + r.OperationId != Guid.Empty && r.RequestKey == capturedArgs.RequestKey && r.Status == AIGenerationRequestStatus.Queued), Arg.Any(), Arg.Any()); } @@ -376,7 +386,7 @@ public async Task QueueApplicationScoringAsync_Should_Not_Enqueue_When_An_Active var request = new AIGenerationRequest( Guid.NewGuid(), tenantId, - AIGenerationRequestKeyHelper.ApplicationScoringOperationType, + Guid.NewGuid(), applicationId, requestKey); @@ -402,6 +412,7 @@ public async Task QueueApplicationScoringAsync_Should_Enqueue_New_Request_When_N repository.GetQueryableAsync().Returns(Task.FromResult>(Array.Empty().AsQueryable())); repository.InsertAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(callInfo => Task.FromResult(callInfo.Arg())); + var operationRepository = CreateOperationRepository(); GenerateApplicationScoringBackgroundJobArgs? capturedArgs = null; var backgroundJobManager = Substitute.For(); @@ -415,7 +426,7 @@ public async Task QueueApplicationScoringAsync_Should_Enqueue_New_Request_When_N return Task.FromResult(string.Empty); }); - var queue = CreateQueue(backgroundJobManager, repository); + var queue = CreateQueue(backgroundJobManager, repository, operationRepository: operationRepository); await queue.QueueApplicationScoringAsync(applicationId, tenantId, promptVersion); @@ -428,7 +439,7 @@ public async Task QueueApplicationScoringAsync_Should_Enqueue_New_Request_When_N await repository.Received(1).InsertAsync(Arg.Is(r => r.ApplicationId == applicationId && r.TenantId == tenantId && - r.OperationType == AIGenerationRequestKeyHelper.ApplicationScoringOperationType && + r.OperationId != Guid.Empty && r.RequestKey == capturedArgs.RequestKey && r.Status == AIGenerationRequestStatus.Queued), Arg.Any(), Arg.Any()); } @@ -475,7 +486,8 @@ private static ApplicationAIGenerationQueue CreateQueue( IRepository repository, Unity.AI.RateLimit.IAIRateLimiter? rateLimiter = null, IAIGenerationPrerequisiteValidator? prerequisiteValidator = null, - IFeatureChecker? featureChecker = null) + IFeatureChecker? featureChecker = null, + IRepository? operationRepository = null) { if (rateLimiter == null) { @@ -502,6 +514,7 @@ private static ApplicationAIGenerationQueue CreateQueue( return new ApplicationAIGenerationQueue( backgroundJobManager, repository, + operationRepository ?? CreateOperationRepository(), new TestDistributedLockProvider(), prerequisiteValidator, featureChecker, @@ -513,6 +526,23 @@ private static ApplicationAIGenerationQueue CreateQueue( private static readonly Guid CreateQueueCurrentUserId = Guid.NewGuid(); + private static IRepository CreateOperationRepository() + { + var operations = new List + { + new(Guid.NewGuid(), "AttachmentSummary", Guid.NewGuid(), Guid.NewGuid()) { IsActive = true }, + new(Guid.NewGuid(), "ApplicationAnalysis", Guid.NewGuid(), Guid.NewGuid()) { IsActive = true }, + new(Guid.NewGuid(), "ApplicationScoring", Guid.NewGuid(), Guid.NewGuid()) { IsActive = true }, + new(Guid.NewGuid(), "Default", Guid.NewGuid(), Guid.NewGuid()) { IsActive = true } + }; + + var repository = Substitute.For>(); + repository.GetQueryableAsync() + .Returns(Task.FromResult>(operations.AsQueryable())); + + return repository; + } + private static ICurrentUser CreateCurrentUser() { var currentUser = Substitute.For(); diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/Automation/AIGenerationStatusAppServiceTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/Automation/AIGenerationStatusAppServiceTests.cs index 432dfae6aa..c9e2fc6231 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/Automation/AIGenerationStatusAppServiceTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/Automation/AIGenerationStatusAppServiceTests.cs @@ -3,6 +3,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Unity.AI.Domain; using Unity.GrantManager.GrantApplications; using Volo.Abp.Domain.Repositories; using Volo.Abp.MultiTenancy; @@ -20,24 +21,105 @@ public async Task GetLatestAsync_Should_Respect_Current_Tenant() var tenantId = Guid.NewGuid(); var otherTenantId = Guid.NewGuid(); var requestKey = AIGenerationRequestKeyHelper.BuildRequestKey(tenantId, applicationId, AIGenerationRequestKeyHelper.ApplicationAnalysisOperationType); + var operationId = Guid.NewGuid(); + + var operations = new[] + { + new AIOperation(operationId, "ApplicationAnalysis", Guid.NewGuid(), Guid.NewGuid()) + { + IsActive = true + } + }; var requests = new[] { - new AIGenerationRequest(Guid.NewGuid(), otherTenantId, AIGenerationRequestKeyHelper.ApplicationAnalysisOperationType, applicationId, requestKey), - new AIGenerationRequest(Guid.NewGuid(), tenantId, AIGenerationRequestKeyHelper.ApplicationAnalysisOperationType, applicationId, requestKey) + new AIGenerationRequest(Guid.NewGuid(), otherTenantId, operationId, applicationId, requestKey), + new AIGenerationRequest(Guid.NewGuid(), tenantId, operationId, applicationId, requestKey) }; var repository = Substitute.For>(); repository.GetQueryableAsync().Returns(Task.FromResult>(requests.AsQueryable())); + var operationRepository = Substitute.For>(); + operationRepository.GetQueryableAsync().Returns(Task.FromResult>(operations.AsQueryable())); var currentTenant = Substitute.For(); currentTenant.Id.Returns(tenantId); - var service = new AIGenerationStatusAppService(repository, currentTenant); + var service = new AIGenerationStatusAppService(repository, operationRepository, currentTenant); var result = await service.GetLatestAsync(applicationId, AIGenerationRequestKeyHelper.ApplicationAnalysisOperationType); result.ShouldNotBeNull(); result.ApplicationId.ShouldBe(applicationId); } + + [Fact] + public async Task GetLatestAsync_Should_Return_History_For_Inactive_Operation() + { + var applicationId = Guid.NewGuid(); + var tenantId = Guid.NewGuid(); + var requestKey = AIGenerationRequestKeyHelper.BuildRequestKey(tenantId, applicationId, AIGenerationRequestKeyHelper.ApplicationAnalysisOperationType); + var operationId = Guid.NewGuid(); + + var operations = new[] + { + new AIOperation(operationId, "ApplicationAnalysis", Guid.NewGuid(), Guid.NewGuid()) + { + IsActive = false + } + }; + + var requests = new[] + { + new AIGenerationRequest(Guid.NewGuid(), tenantId, operationId, applicationId, requestKey) + }; + + var repository = Substitute.For>(); + repository.GetQueryableAsync().Returns(Task.FromResult>(requests.AsQueryable())); + var operationRepository = Substitute.For>(); + operationRepository.GetQueryableAsync().Returns(Task.FromResult>(operations.AsQueryable())); + + var currentTenant = Substitute.For(); + currentTenant.Id.Returns(tenantId); + + var service = new AIGenerationStatusAppService(repository, operationRepository, currentTenant); + + var result = await service.GetLatestAsync(applicationId, AIGenerationRequestKeyHelper.ApplicationAnalysisOperationType); + + result.ShouldNotBeNull(); + result!.OperationId.ShouldBe(operationId); + result.ApplicationId.ShouldBe(applicationId); + } + + [Fact] + public async Task GetLatestAsync_Should_Reject_Legacy_Operation_Name() + { + var applicationId = Guid.NewGuid(); + var tenantId = Guid.NewGuid(); + var operationId = Guid.NewGuid(); + + var operations = new[] + { + new AIOperation(operationId, "ApplicationAnalysis", Guid.NewGuid(), Guid.NewGuid()) + }; + + var requests = new[] + { + new AIGenerationRequest(Guid.NewGuid(), tenantId, operationId, applicationId, "legacy-operation-name") + }; + + var repository = Substitute.For>(); + repository.GetQueryableAsync().Returns(Task.FromResult>(requests.AsQueryable())); + var operationRepository = Substitute.For>(); + operationRepository.GetQueryableAsync().Returns(Task.FromResult>(operations.AsQueryable())); + + var currentTenant = Substitute.For(); + currentTenant.Id.Returns(tenantId); + + var service = new AIGenerationStatusAppService(repository, operationRepository, currentTenant); + + var result = await service.GetLatestAsync(applicationId, "legacy-operation-name"); + + result.ShouldBeNull(); + } } diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/Automation/RunApplicationAIPipelineJobTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/Automation/RunApplicationAIPipelineJobTests.cs index 8085bd5523..98fd04e712 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/Automation/RunApplicationAIPipelineJobTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/Automation/RunApplicationAIPipelineJobTests.cs @@ -303,7 +303,7 @@ private static AIGenerationRequest CreateRequest() return new AIGenerationRequest( Guid.NewGuid(), tenantId, - AIGenerationRequestKeyHelper.PipelineOperationType, + Guid.NewGuid(), applicationId, AIGenerationRequestKeyHelper.BuildRequestKey(tenantId, applicationId, AIGenerationRequestKeyHelper.PipelineOperationType)); } diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/GrantApplicationAIGenerationStatusTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/GrantApplicationAIGenerationStatusTests.cs index a8323f6cc8..9d23a533e3 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/GrantApplicationAIGenerationStatusTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/GrantApplications/GrantApplicationAIGenerationStatusTests.cs @@ -14,6 +14,7 @@ using Unity.Payments.PaymentRequests; using Volo.Abp.DependencyInjection; using Volo.Abp.Features; +using Volo.Abp; using Xunit; using Xunit.Abstractions; @@ -52,9 +53,47 @@ await aiGenerationStatusAppService.Received(1) await aiRateLimiter.Received(1).GetStateAsync(); } + [Fact] + public async Task QueueApplicationAnalysisAsync_Should_Throw_When_Latest_Request_Is_Null() + { + var applicationId = Guid.NewGuid(); + var aiGenerationStatusAppService = Substitute.For(); + aiGenerationStatusAppService + .GetLatestAsync(applicationId, AIGenerationRequestKeyHelper.ApplicationAnalysisOperationType, null) + .Returns((AIGenerationRequestDto?)null); + + var aiRateLimiter = Substitute.For(); + aiRateLimiter.GetStateAsync().Returns(new AIRateLimitStateDto + { + IsGenerating = true, + RetryAfterSeconds = 11 + }); + + var queue = Substitute.For(); + queue + .QueueApplicationAnalysisAsync(applicationId, null, null) + .Returns(Task.CompletedTask); + + var featureChecker = Substitute.For(); + featureChecker + .IsEnabledAsync("Unity.AI.ApplicationAnalysis") + .Returns(true); + + var appService = CreateAppService(aiGenerationStatusAppService, aiRateLimiter, queue, featureChecker); + + await Should.ThrowAsync(() => appService.QueueApplicationAnalysisAsync(applicationId)); + + await queue.Received(1).QueueApplicationAnalysisAsync(applicationId, null, null); + await aiGenerationStatusAppService.Received(1) + .GetLatestAsync(applicationId, AIGenerationRequestKeyHelper.ApplicationAnalysisOperationType, null); + await aiRateLimiter.DidNotReceive().GetStateAsync(); + } + private GrantApplicationAppService CreateAppService( IAIGenerationStatusAppService aiGenerationStatusAppService, - IAIRateLimiter aiRateLimiter) + IAIRateLimiter aiRateLimiter, + IApplicationAIGenerationQueue? aiGenerationQueue = null, + IFeatureChecker? featureChecker = null) { var appService = new GrantApplicationAppService( Substitute.For(), @@ -68,10 +107,10 @@ private GrantApplicationAppService CreateAppService( Substitute.For(), Substitute.For(), Substitute.For(), - Substitute.For(), + aiGenerationQueue ?? Substitute.For(), aiGenerationStatusAppService, aiRateLimiter, - Substitute.For()); + featureChecker ?? Substitute.For()); appService.LazyServiceProvider = GetRequiredService(); return appService; From 15e2a5a17c859be69f61a1a1b8b737b356afb8e4 Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Fri, 26 Jun 2026 08:32:06 -0700 Subject: [PATCH 03/61] AB#32307 repair AI migration chain --- .../GrantManagerDbContext.cs | 12 +- .../20260324221338_AddAIPromptTables.cs | 102 +- ...0618203824_AddUniqueIndexToAIPromptName.cs | 17 +- ...18210000_RefreshBuiltInAIPromptVersions.cs | 159 - ...20260624191335_RefreshAiSchema.Designer.cs | 3368 +++++++++++++++++ .../20260624191335_RefreshAiSchema.cs | 21 + .../GrantManagerDbContextModelSnapshot.cs | 162 +- 7 files changed, 3599 insertions(+), 242 deletions(-) create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.Designer.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbContext.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbContext.cs index aabd9ae426..06b877d8ee 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbContext.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbContext.cs @@ -53,7 +53,8 @@ public class GrantManagerDbContext : // Unity.AI entities public DbSet AIPrompts { get; set; } - public DbSet AIPromptVersions { get; set; } + public DbSet AIModels { get; set; } + public DbSet AIOperations { get; set; } #region Entities from the modules @@ -242,12 +243,17 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { b.ToTable(GrantManagerConsts.DbTablePrefix + "AIRequests", AIDbProperties.DbSchema); b.ConfigureByConvention(); - b.Property(x => x.OperationType).IsRequired().HasMaxLength(64); + b.Property(x => x.OperationId).IsRequired(); b.Property(x => x.RequestKey).IsRequired().HasMaxLength(256); b.Property(x => x.FailureReason).HasMaxLength(2000); b.Property(x => x.Status).IsRequired(); + b.HasOne() + .WithMany() + .HasForeignKey(x => x.OperationId) + .OnDelete(DeleteBehavior.Restrict); b.HasIndex(x => x.RequestKey); - b.HasIndex(x => new { x.TenantId, x.ApplicationId, x.OperationType, x.Status }); + b.HasIndex(x => x.OperationId); + b.HasIndex(x => new { x.TenantId, x.ApplicationId, x.OperationId, x.Status }); }); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260324221338_AddAIPromptTables.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260324221338_AddAIPromptTables.cs index e390d9dc19..2f973c1542 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260324221338_AddAIPromptTables.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260324221338_AddAIPromptTables.cs @@ -22,8 +22,11 @@ protected override void Up(MigrationBuilder migrationBuilder) Id = table.Column(type: "uuid", nullable: false), TenantId = table.Column(type: "uuid", nullable: true), Name = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), - Description = table.Column(type: "character varying(2000)", maxLength: 2000, nullable: true), - Type = table.Column(type: "integer", nullable: false), + VersionNumber = table.Column(type: "integer", nullable: false), + SystemPrompt = table.Column(type: "text", nullable: false), + UserPrompt = table.Column(type: "text", nullable: false), + MetadataJson = table.Column(type: "jsonb", nullable: true), + SeedHash = table.Column(type: "character varying(64)", maxLength: 64, nullable: true), IsActive = table.Column(type: "boolean", nullable: false), ExtraProperties = table.Column(type: "text", nullable: false), ConcurrencyStamp = table.Column(type: "character varying(40)", maxLength: 40, nullable: false), @@ -38,24 +41,15 @@ protected override void Up(MigrationBuilder migrationBuilder) }); migrationBuilder.CreateTable( - name: "AIPromptVersions", + name: "AIModels", schema: "AI", columns: table => new { Id = table.Column(type: "uuid", nullable: false), TenantId = table.Column(type: "uuid", nullable: true), - PromptId = table.Column(type: "uuid", nullable: false), - VersionNumber = table.Column(type: "integer", nullable: false), - SystemPrompt = table.Column(type: "text", nullable: false), - UserPromptTemplate = table.Column(type: "text", nullable: false), - DeveloperNotes = table.Column(type: "text", nullable: true), - TargetModel = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), - TargetProvider = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), - Temperature = table.Column(type: "double precision", nullable: false), - MaxTokens = table.Column(type: "integer", nullable: true), - IsPublished = table.Column(type: "boolean", nullable: false), - IsDeprecated = table.Column(type: "boolean", nullable: false), - MetadataJson = table.Column(type: "jsonb", nullable: true), + Name = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + IsActive = table.Column(type: "boolean", nullable: false), + SettingsJson = table.Column(type: "jsonb", nullable: false), ExtraProperties = table.Column(type: "text", nullable: false), ConcurrencyStamp = table.Column(type: "character varying(40)", maxLength: 40, nullable: false), CreationTime = table.Column(type: "timestamp without time zone", nullable: false), @@ -65,21 +59,79 @@ protected override void Up(MigrationBuilder migrationBuilder) }, constraints: table => { - table.PrimaryKey("PK_AIPromptVersions", x => x.Id); + table.PrimaryKey("PK_AIModels", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_AIPrompts_TenantId_Name_VersionNumber", + schema: "AI", + table: "AIPrompts", + columns: new[] { "TenantId", "Name", "VersionNumber" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AIModels_Name", + schema: "AI", + table: "AIModels", + column: "Name", + unique: true); + + migrationBuilder.CreateTable( + name: "AIOperations", + schema: "AI", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: true), + Name = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + AIModelId = table.Column(type: "uuid", nullable: false), + AIPromptId = table.Column(type: "uuid", nullable: false), + ExecutionMode = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + CompletionTokens = table.Column(type: "integer", nullable: false), + IsActive = table.Column(type: "boolean", nullable: false), + ExtraProperties = table.Column(type: "text", nullable: false), + ConcurrencyStamp = table.Column(type: "character varying(40)", maxLength: 40, nullable: false), + CreationTime = table.Column(type: "timestamp without time zone", nullable: false), + CreatorId = table.Column(type: "uuid", nullable: true), + LastModificationTime = table.Column(type: "timestamp without time zone", nullable: true), + LastModifierId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AIOperations", x => x.Id); table.ForeignKey( - name: "FK_AIPromptVersions_AIPrompts_PromptId", - column: x => x.PromptId, + name: "FK_AIOperations_AIModels_AIModelId", + column: x => x.AIModelId, + principalSchema: "AI", + principalTable: "AIModels", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_AIOperations_AIPrompts_AIPromptId", + column: x => x.AIPromptId, principalSchema: "AI", principalTable: "AIPrompts", principalColumn: "Id", - onDelete: ReferentialAction.Cascade); + onDelete: ReferentialAction.Restrict); }); migrationBuilder.CreateIndex( - name: "IX_AIPromptVersions_PromptId_VersionNumber", + name: "IX_AIOperations_AIModelId", + schema: "AI", + table: "AIOperations", + column: "AIModelId"); + + migrationBuilder.CreateIndex( + name: "IX_AIOperations_AIPromptId", schema: "AI", - table: "AIPromptVersions", - columns: new[] { "PromptId", "VersionNumber" }, + table: "AIOperations", + column: "AIPromptId"); + + migrationBuilder.CreateIndex( + name: "IX_AIOperations_Name", + schema: "AI", + table: "AIOperations", + column: "Name", unique: true); } @@ -87,7 +139,11 @@ protected override void Up(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( - name: "AIPromptVersions", + name: "AIOperations", + schema: "AI"); + + migrationBuilder.DropTable( + name: "AIModels", schema: "AI"); migrationBuilder.DropTable( diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618203824_AddUniqueIndexToAIPromptName.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618203824_AddUniqueIndexToAIPromptName.cs index 75b13a5f7e..68c43ad654 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618203824_AddUniqueIndexToAIPromptName.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618203824_AddUniqueIndexToAIPromptName.cs @@ -10,11 +10,22 @@ public partial class AddUniqueIndexToAIPromptName : Migration /// protected override void Up(MigrationBuilder migrationBuilder) { + migrationBuilder.Sql( + """ + ALTER TABLE "AI"."AIPrompts" + ADD COLUMN IF NOT EXISTS "VersionNumber" integer NOT NULL DEFAULT 1; + """); + + migrationBuilder.Sql( + """ + DROP INDEX IF EXISTS "AI"."IX_AIPrompts_Name"; + """); + migrationBuilder.CreateIndex( - name: "IX_AIPrompts_Name", + name: "IX_AIPrompts_TenantId_Name_VersionNumber", schema: "AI", table: "AIPrompts", - column: "Name", + columns: new[] { "TenantId", "Name", "VersionNumber" }, unique: true); } @@ -22,7 +33,7 @@ protected override void Up(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropIndex( - name: "IX_AIPrompts_Name", + name: "IX_AIPrompts_TenantId_Name_VersionNumber", schema: "AI", table: "AIPrompts"); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618210000_RefreshBuiltInAIPromptVersions.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618210000_RefreshBuiltInAIPromptVersions.cs index 7efc8de94b..4aacd26ff8 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618210000_RefreshBuiltInAIPromptVersions.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618210000_RefreshBuiltInAIPromptVersions.cs @@ -1,177 +1,18 @@ -using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text.Json; -using Unity.GrantManager.EntityFrameworkCore; #nullable disable namespace Unity.GrantManager.Migrations.HostMigrations { - [DbContext(typeof(GrantManagerDbContext))] [Migration("20260618210000_RefreshBuiltInAIPromptVersions")] public partial class RefreshBuiltInAIPromptVersions : Migration { - private static readonly Guid AnalysisPromptId = new("4a100001-1000-4000-a000-000000000001"); - private static readonly Guid AttachmentPromptId = new("4a100001-1000-4000-a000-000000000002"); - private static readonly Guid ScoringPromptId = new("4a100001-1000-4000-a000-000000000003"); - protected override void Up(MigrationBuilder migrationBuilder) { - migrationBuilder.Sql( - """ - UPDATE "AI"."AIPrompts" - SET "Name" = 'ApplicationAnalysis', - "Description" = 'Grant application analysis and review', - "Type" = 1, - "IsActive" = TRUE - WHERE "Id" = '4a100001-1000-4000-a000-000000000001'; - - UPDATE "AI"."AIPrompts" - SET "Name" = 'AttachmentSummary', - "Description" = 'Attachment summarization for grant review', - "Type" = 1, - "IsActive" = TRUE - WHERE "Id" = '4a100001-1000-4000-a000-000000000002'; - - UPDATE "AI"."AIPrompts" - SET "Name" = 'ApplicationScoring', - "Description" = 'Scoresheet section answering assistant', - "Type" = 1, - "IsActive" = TRUE - WHERE "Id" = '4a100001-1000-4000-a000-000000000003'; - """); - - UpdatePromptVersion( - migrationBuilder, - AnalysisPromptId, - 0, - ReadPromptFile("v0", "application-analysis.system.txt"), - ReadPromptFile("v0", "application-analysis.user.txt"), - "v0 - initial single-file analysis prompt", - null); - - UpdatePromptVersion( - migrationBuilder, - AnalysisPromptId, - 1, - ReadPromptFile("v1", "application-analysis.system.txt"), - ReadPromptFile("v1", "application-analysis.user.txt"), - "v1 - modular prompt with separate rubric, score, output, and rules sections", - BuildSectionsJson(new Dictionary - { - ["RUBRIC"] = ReadPromptFile("v1", "application-analysis.rubric.txt"), - ["SCORE"] = ReadPromptFile("v1", "application-analysis.score.txt"), - ["OUTPUT"] = ReadPromptFile("v1", "application-analysis.output.txt"), - ["RULES"] = ReadPromptFile("v1", "application-analysis.rules.txt"), - ["COMMON_RULES"] = ReadPromptFile("v1", "common.rules.txt") - })); - - UpdatePromptVersion( - migrationBuilder, - AttachmentPromptId, - 0, - ReadPromptFile("v0", "attachment-summary.system.txt"), - ReadPromptFile("v0", "attachment-summary.user.txt"), - "v0 - initial single-file attachment prompt", - null); - - UpdatePromptVersion( - migrationBuilder, - AttachmentPromptId, - 1, - ReadPromptFile("v1", "attachment-summary.system.txt"), - ReadPromptFile("v1", "attachment-summary.user.txt"), - "v1 - modular prompt with separate output and rules sections", - BuildSectionsJson(new Dictionary - { - ["OUTPUT"] = ReadPromptFile("v1", "attachment-summary.output.txt"), - ["RULES"] = ReadPromptFile("v1", "attachment-summary.rules.txt"), - ["COMMON_RULES"] = ReadPromptFile("v1", "common.rules.txt") - })); - - UpdatePromptVersion( - migrationBuilder, - ScoringPromptId, - 0, - ReadPromptFile("v0", "application-scoring.system.txt"), - ReadPromptFile("v0", "application-scoring.user.txt"), - "v0 - initial single-file scoresheet prompt", - null); - - UpdatePromptVersion( - migrationBuilder, - ScoringPromptId, - 1, - ReadPromptFile("v1", "application-scoring.system.txt"), - ReadPromptFile("v1", "application-scoring.user.txt"), - "v1 - modular prompt with separate output and rules sections", - BuildSectionsJson(new Dictionary - { - ["OUTPUT"] = ReadPromptFile("v1", "application-scoring.output.txt"), - ["RULES"] = ReadPromptFile("v1", "application-scoring.rules.txt"), - ["COMMON_RULES"] = ReadPromptFile("v1", "common.rules.txt") - })); } protected override void Down(MigrationBuilder migrationBuilder) { - // No-op: prompt version content is managed by seeded defaults. - } - - private static void UpdatePromptVersion( - MigrationBuilder migrationBuilder, - Guid promptId, - int versionNumber, - string systemPrompt, - string userPromptTemplate, - string developerNotes, - string metadataJson) - { - migrationBuilder.Sql($""" - UPDATE "AI"."AIPromptVersions" - SET "SystemPrompt" = '{EscapeSqlLiteral(systemPrompt)}', - "UserPromptTemplate" = '{EscapeSqlLiteral(userPromptTemplate)}', - "DeveloperNotes" = '{EscapeSqlLiteral(developerNotes)}', - "IsPublished" = TRUE, - "IsDeprecated" = FALSE, - "MetadataJson" = {FormatNullableSqlString(metadataJson)} - WHERE "PromptId" = '{promptId}' - AND "VersionNumber" = {versionNumber}; - """); - } - - private static string ReadPromptFile(string version, string fileName) - { - var path = Path.Combine(AppContext.BaseDirectory, "AI", "Prompts", "Versions", version, fileName); - if (!File.Exists(path)) - { - throw new InvalidOperationException($"Missing prompt asset required by migration: {path}"); - } - - return File.ReadAllText(path); - } - - private static string BuildSectionsJson(Dictionary sections) - { - return JsonSerializer.Serialize(new { sections }); - } - - private static string EscapeSqlLiteral(string value) - { - return value.Replace("'", "''", StringComparison.Ordinal); - } - - private static string FormatNullableSqlString(string value) - { - if (value == null) - { - return "NULL"; - } - - return $"'{EscapeSqlLiteral(value)}'"; } } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.Designer.cs new file mode 100644 index 0000000000..3ba04bd744 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.Designer.cs @@ -0,0 +1,3368 @@ +// +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.HostMigrations +{ + [DbContext(typeof(GrantManagerDbContext))] + [Migration("20260624191335_RefreshAiSchema")] + partial class RefreshAiSchema + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "10.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzBlobTrigger", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("TriggerName") + .HasColumnType("text") + .HasColumnName("trigger_name"); + + b.Property("TriggerGroup") + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.Property("BlobData") + .HasColumnType("bytea") + .HasColumnName("blob_data"); + + b.HasKey("SchedulerName", "TriggerName", "TriggerGroup"); + + b.ToTable("qrtz_blob_triggers", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzCalendar", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("CalendarName") + .HasColumnType("text") + .HasColumnName("calendar_name"); + + b.Property("Calendar") + .IsRequired() + .HasColumnType("bytea") + .HasColumnName("calendar"); + + b.HasKey("SchedulerName", "CalendarName"); + + b.ToTable("qrtz_calendars", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzCronTrigger", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("TriggerName") + .HasColumnType("text") + .HasColumnName("trigger_name"); + + b.Property("TriggerGroup") + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.Property("CronExpression") + .IsRequired() + .HasColumnType("text") + .HasColumnName("cron_expression"); + + b.Property("TimeZoneId") + .HasColumnType("text") + .HasColumnName("time_zone_id"); + + b.HasKey("SchedulerName", "TriggerName", "TriggerGroup"); + + b.ToTable("qrtz_cron_triggers", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzFiredTrigger", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("EntryId") + .HasColumnType("text") + .HasColumnName("entry_id"); + + b.Property("FiredTime") + .HasColumnType("bigint") + .HasColumnName("fired_time"); + + b.Property("InstanceName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("instance_name"); + + b.Property("IsNonConcurrent") + .HasColumnType("bool") + .HasColumnName("is_nonconcurrent"); + + b.Property("JobGroup") + .HasColumnType("text") + .HasColumnName("job_group"); + + b.Property("JobName") + .HasColumnType("text") + .HasColumnName("job_name"); + + b.Property("Priority") + .HasColumnType("integer") + .HasColumnName("priority"); + + b.Property("RequestsRecovery") + .HasColumnType("bool") + .HasColumnName("requests_recovery"); + + b.Property("ScheduledTime") + .HasColumnType("bigint") + .HasColumnName("sched_time"); + + b.Property("State") + .IsRequired() + .HasColumnType("text") + .HasColumnName("state"); + + b.Property("TriggerGroup") + .IsRequired() + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.Property("TriggerName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("trigger_name"); + + b.HasKey("SchedulerName", "EntryId"); + + b.HasIndex("InstanceName") + .HasDatabaseName("idx_qrtz_ft_trig_inst_name"); + + b.HasIndex("JobGroup") + .HasDatabaseName("idx_qrtz_ft_job_group"); + + b.HasIndex("JobName") + .HasDatabaseName("idx_qrtz_ft_job_name"); + + b.HasIndex("RequestsRecovery") + .HasDatabaseName("idx_qrtz_ft_job_req_recovery"); + + b.HasIndex("TriggerGroup") + .HasDatabaseName("idx_qrtz_ft_trig_group"); + + b.HasIndex("TriggerName") + .HasDatabaseName("idx_qrtz_ft_trig_name"); + + b.HasIndex("SchedulerName", "TriggerName", "TriggerGroup") + .HasDatabaseName("idx_qrtz_ft_trig_nm_gp"); + + b.ToTable("qrtz_fired_triggers", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzJobDetail", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("JobName") + .HasColumnType("text") + .HasColumnName("job_name"); + + b.Property("JobGroup") + .HasColumnType("text") + .HasColumnName("job_group"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("IsDurable") + .HasColumnType("bool") + .HasColumnName("is_durable"); + + b.Property("IsNonConcurrent") + .HasColumnType("bool") + .HasColumnName("is_nonconcurrent"); + + b.Property("IsUpdateData") + .HasColumnType("bool") + .HasColumnName("is_update_data"); + + b.Property("JobClassName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("job_class_name"); + + b.Property("JobData") + .HasColumnType("bytea") + .HasColumnName("job_data"); + + b.Property("RequestsRecovery") + .HasColumnType("bool") + .HasColumnName("requests_recovery"); + + b.HasKey("SchedulerName", "JobName", "JobGroup"); + + b.HasIndex("RequestsRecovery") + .HasDatabaseName("idx_qrtz_j_req_recovery"); + + b.ToTable("qrtz_job_details", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzLock", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("LockName") + .HasColumnType("text") + .HasColumnName("lock_name"); + + b.HasKey("SchedulerName", "LockName"); + + b.ToTable("qrtz_locks", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzPausedTriggerGroup", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("TriggerGroup") + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.HasKey("SchedulerName", "TriggerGroup"); + + b.ToTable("qrtz_paused_trigger_grps", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSchedulerState", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("InstanceName") + .HasColumnType("text") + .HasColumnName("instance_name"); + + b.Property("CheckInInterval") + .HasColumnType("bigint") + .HasColumnName("checkin_interval"); + + b.Property("LastCheckInTime") + .HasColumnType("bigint") + .HasColumnName("last_checkin_time"); + + b.HasKey("SchedulerName", "InstanceName"); + + b.ToTable("qrtz_scheduler_state", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimplePropertyTrigger", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("TriggerName") + .HasColumnType("text") + .HasColumnName("trigger_name"); + + b.Property("TriggerGroup") + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.Property("BooleanProperty1") + .HasColumnType("bool") + .HasColumnName("bool_prop_1"); + + b.Property("BooleanProperty2") + .HasColumnType("bool") + .HasColumnName("bool_prop_2"); + + b.Property("DecimalProperty1") + .HasColumnType("numeric") + .HasColumnName("dec_prop_1"); + + b.Property("DecimalProperty2") + .HasColumnType("numeric") + .HasColumnName("dec_prop_2"); + + b.Property("IntegerProperty1") + .HasColumnType("integer") + .HasColumnName("int_prop_1"); + + b.Property("IntegerProperty2") + .HasColumnType("integer") + .HasColumnName("int_prop_2"); + + b.Property("LongProperty1") + .HasColumnType("bigint") + .HasColumnName("long_prop_1"); + + b.Property("LongProperty2") + .HasColumnType("bigint") + .HasColumnName("long_prop_2"); + + b.Property("StringProperty1") + .HasColumnType("text") + .HasColumnName("str_prop_1"); + + b.Property("StringProperty2") + .HasColumnType("text") + .HasColumnName("str_prop_2"); + + b.Property("StringProperty3") + .HasColumnType("text") + .HasColumnName("str_prop_3"); + + b.Property("TimeZoneId") + .HasColumnType("text") + .HasColumnName("time_zone_id"); + + b.HasKey("SchedulerName", "TriggerName", "TriggerGroup"); + + b.ToTable("qrtz_simprop_triggers", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimpleTrigger", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("TriggerName") + .HasColumnType("text") + .HasColumnName("trigger_name"); + + b.Property("TriggerGroup") + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.Property("RepeatCount") + .HasColumnType("bigint") + .HasColumnName("repeat_count"); + + b.Property("RepeatInterval") + .HasColumnType("bigint") + .HasColumnName("repeat_interval"); + + b.Property("TimesTriggered") + .HasColumnType("bigint") + .HasColumnName("times_triggered"); + + b.HasKey("SchedulerName", "TriggerName", "TriggerGroup"); + + b.ToTable("qrtz_simple_triggers", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("TriggerName") + .HasColumnType("text") + .HasColumnName("trigger_name"); + + b.Property("TriggerGroup") + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.Property("CalendarName") + .HasColumnType("text") + .HasColumnName("calendar_name"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("EndTime") + .HasColumnType("bigint") + .HasColumnName("end_time"); + + b.Property("JobData") + .HasColumnType("bytea") + .HasColumnName("job_data"); + + b.Property("JobGroup") + .IsRequired() + .HasColumnType("text") + .HasColumnName("job_group"); + + b.Property("JobName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("job_name"); + + b.Property("MisfireInstruction") + .HasColumnType("smallint") + .HasColumnName("misfire_instr"); + + b.Property("NextFireTime") + .HasColumnType("bigint") + .HasColumnName("next_fire_time"); + + b.Property("PreviousFireTime") + .HasColumnType("bigint") + .HasColumnName("prev_fire_time"); + + b.Property("Priority") + .HasColumnType("integer") + .HasColumnName("priority"); + + b.Property("StartTime") + .HasColumnType("bigint") + .HasColumnName("start_time"); + + b.Property("TriggerState") + .IsRequired() + .HasColumnType("text") + .HasColumnName("trigger_state"); + + b.Property("TriggerType") + .IsRequired() + .HasColumnType("text") + .HasColumnName("trigger_type"); + + b.HasKey("SchedulerName", "TriggerName", "TriggerGroup"); + + b.HasIndex("NextFireTime") + .HasDatabaseName("idx_qrtz_t_next_fire_time"); + + b.HasIndex("TriggerState") + .HasDatabaseName("idx_qrtz_t_state"); + + b.HasIndex("NextFireTime", "TriggerState") + .HasDatabaseName("idx_qrtz_t_nft_st"); + + b.HasIndex("SchedulerName", "JobName", "JobGroup"); + + b.ToTable("qrtz_triggers", (string)null); + }); + + modelBuilder.Entity("Unity.AI.Domain.AIModel", 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("IsActive") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("SettingsJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AIModels", "AI"); + }); + + modelBuilder.Entity("Unity.AI.Domain.AIOperation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AIModelId") + .HasColumnType("uuid"); + + b.Property("AIPromptId") + .HasColumnType("uuid"); + + b.Property("CompletionTokens") + .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("ExecutionMode") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("AIModelId"); + + b.HasIndex("AIPromptId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AIOperations", "AI"); + }); + + modelBuilder.Entity("Unity.AI.Domain.AIPrompt", 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("IsActive") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MetadataJson") + .HasColumnType("jsonb"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("SystemPrompt") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserPrompt") + .IsRequired() + .HasColumnType("text"); + + b.Property("VersionNumber") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .HasDatabaseName("IX_AIPrompts_Name"); + + b.HasIndex("TenantId", "Name", "VersionNumber") + .IsUnique(); + + b.ToTable("AIPrompts", "AI"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applicants.ApplicantTenantMap", 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("LastUpdated") + .HasColumnType("timestamp without time zone"); + + b.Property("OidcSubUsername") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TenantName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OidcSubUsername"); + + b.HasIndex("OidcSubUsername", "TenantId") + .IsUnique(); + + b.ToTable("ApplicantTenantMaps", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.GrantApplications.AIGenerationRequest", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("CompletedAt") + .HasColumnType("timestamp without time zone"); + + 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("FailureReason") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + 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("OperationId") + .HasColumnType("uuid"); + + b.Property("RequestKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("StartedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("OperationId"); + + b.HasIndex("RequestKey"); + + b.HasIndex("TenantId", "ApplicationId", "OperationId", "Status"); + + b.ToTable("AIRequests", "AI"); + }); + + modelBuilder.Entity("Unity.GrantManager.Integrations.CasClientCode", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClientCode") + .IsRequired() + .HasMaxLength(3) + .HasColumnType("character varying(3)"); + + b.Property("ClientId") + .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("FinancialMinistry") + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + 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("LastUpdatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("MinistryPrefix") + .IsRequired() + .HasMaxLength(3) + .HasColumnType("character varying(3)"); + + b.HasKey("Id"); + + b.ToTable("CasClientCodes", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Integrations.DynamicUrl", 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("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("KeyName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + 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("Url") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("DynamicUrls", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.Community", 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("RegionalDistrictCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Communities", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.EconomicRegion", 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("EconomicRegionCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("EconomicRegionName") + .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.HasKey("Id"); + + b.ToTable("EconomicRegions", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.ElectoralDistrict", 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("ElectoralDistrictCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("ElectoralDistrictName") + .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.HasKey("Id"); + + b.ToTable("ElectoralDistricts", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.RegionalDistrict", 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("EconomicRegionCode") + .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("RegionalDistrictCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegionalDistrictName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("RegionalDistricts", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.Sector", 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("SectorCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("SectorName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Sectors", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.SubSector", 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("SectorId") + .HasColumnType("uuid"); + + b.Property("SubSectorCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("SubSectorName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("SectorId"); + + b.ToTable("SubSectors", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Messaging.InboxMessage", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DataType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Details") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + 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("MessageId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Payload") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ProcessedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ReceivedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RetryCount") + .HasColumnType("integer"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MessageId") + .IsUnique(); + + b.HasIndex("Source", "Status"); + + b.ToTable("InboxMessages", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Messaging.OutboxMessage", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AckStatus") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DataType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Details") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + 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("MessageId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("OriginalMessageId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("PublishedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RetryCount") + .HasColumnType("integer"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Source", "Status"); + + b.ToTable("OutboxMessages", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Tokens.TenantToken", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + 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("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("TenantTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("character varying(96)") + .HasColumnName("ApplicationName"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("BrowserInfo"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("ClientId"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("ClientIpAddress"); + + b.Property("ClientName") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("ClientName"); + + b.Property("Comments") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Comments"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("CorrelationId"); + + b.Property("Exceptions") + .HasColumnType("text"); + + b.Property("ExecutionDuration") + .HasColumnType("integer") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("HttpMethod") + .HasMaxLength(16) + .HasColumnType("character varying(16)") + .HasColumnName("HttpMethod"); + + b.Property("HttpStatusCode") + .HasColumnType("integer") + .HasColumnName("HttpStatusCode"); + + b.Property("ImpersonatorTenantId") + .HasColumnType("uuid") + .HasColumnName("ImpersonatorTenantId"); + + b.Property("ImpersonatorTenantName") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("ImpersonatorTenantName"); + + b.Property("ImpersonatorUserId") + .HasColumnType("uuid") + .HasColumnName("ImpersonatorUserId"); + + b.Property("ImpersonatorUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("ImpersonatorUserName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("TenantName"); + + b.Property("Url") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Url"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("UserId"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ExecutionTime"); + + b.HasIndex("TenantId", "UserId", "ExecutionTime"); + + b.ToTable("AuditLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AuditLogId") + .HasColumnType("uuid") + .HasColumnName("AuditLogId"); + + b.Property("ExecutionDuration") + .HasColumnType("integer") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("MethodName") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("MethodName"); + + b.Property("Parameters") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)") + .HasColumnName("Parameters"); + + b.Property("ServiceName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("ServiceName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); + + b.ToTable("AuditLogActions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogExcelFile", 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("FileName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("FileName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AuditLogExcelFiles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AuditLogId") + .HasColumnType("uuid") + .HasColumnName("AuditLogId"); + + b.Property("ChangeTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("ChangeTime"); + + b.Property("ChangeType") + .HasColumnType("smallint") + .HasColumnName("ChangeType"); + + b.Property("EntityId") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("EntityId"); + + b.Property("EntityTenantId") + .HasColumnType("uuid"); + + b.Property("EntityTypeFullName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("EntityTypeFullName"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); + + b.ToTable("EntityChanges", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EntityChangeId") + .HasColumnType("uuid"); + + b.Property("NewValue") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("NewValue"); + + b.Property("OriginalValue") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("OriginalValue"); + + b.Property("PropertyName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("PropertyName"); + + b.Property("PropertyTypeFullName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("PropertyTypeFullName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityChangeId"); + + b.ToTable("EntityPropertyChanges", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.BackgroundJobs.BackgroundJobRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + 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("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsAbandoned") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("JobArgs") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("character varying(1048576)"); + + b.Property("JobName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("LastTryTime") + .HasColumnType("timestamp without time zone"); + + b.Property("NextTryTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Priority") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((byte)15); + + b.Property("TryCount") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((short)0); + + b.HasKey("Id"); + + b.HasIndex("IsAbandoned", "NextTryTime"); + + b.ToTable("BackgroundJobs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllowedProviders") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("DefaultValue") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("IsAvailableToHost") + .HasColumnType("boolean"); + + b.Property("IsVisibleToClients") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ValueType") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Features", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FeatureGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("FeatureValues", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", 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("Description") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Required") + .HasColumnType("boolean"); + + b.Property("ValueType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("ClaimTypes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("SourceTenantId") + .HasColumnType("uuid"); + + b.Property("SourceUserId") + .HasColumnType("uuid"); + + b.Property("TargetTenantId") + .HasColumnType("uuid"); + + b.Property("TargetUserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique(); + + b.ToTable("LinkUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", 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("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("boolean") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("boolean") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("boolean") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("SecurityLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySession", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Device") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("DeviceInfo") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IpAddresses") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.Property("LastAccessed") + .HasColumnType("timestamp without time zone"); + + b.Property("SessionId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("SignedIn") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Device"); + + b.HasIndex("SessionId"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("Sessions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + 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("DisplayName") + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("boolean") + .HasColumnName("IsActive"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastPasswordChangeTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastSignInTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Leaved") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("Leaved"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("OidcSub") + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("character varying(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("SecurityStamp"); + + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("boolean"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("EndTime") + .HasColumnType("timestamp without time zone"); + + b.Property("SourceUserId") + .HasColumnType("uuid"); + + b.Property("StartTime") + .HasColumnType("timestamp without time zone"); + + b.Property("TargetUserId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("UserDelegations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("character varying(196)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("UserLogins", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("UserOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.Property("CredentialId") + .HasMaxLength(1024) + .HasColumnType("bytea"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("CredentialId"); + + b.HasIndex("UserId"); + + b.ToTable("UserPasskeys", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Password") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "Password"); + + b.ToTable("UserPasswordHistories", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("UserRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("character varying(95)") + .HasColumnName("Code"); + + 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("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DisplayName"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + 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("ParentId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("OrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("OrganizationUnitRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("ManagementPermissionName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("MultiTenancySide") + .HasColumnType("smallint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ResourceName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("ResourceName", "Name") + .IsUnique(); + + b.ToTable("Permissions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("PermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("PermissionGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.ResourcePermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ResourceKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ResourceName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ResourceName", "ResourceKey", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("ResourcePermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("Settings", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.SettingDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DefaultValue") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.Property("Description") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsEncrypted") + .HasColumnType("boolean"); + + b.Property("IsInherited") + .HasColumnType("boolean"); + + b.Property("IsVisibleToClients") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Providers") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SettingDefinitions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", 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("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + 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() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.HasIndex("NormalizedName"); + + b.ToTable("Tenants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.HasKey("TenantId", "Name"); + + b.ToTable("TenantConnectionStrings", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzBlobTrigger", b => + { + b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", "Trigger") + .WithMany("BlobTriggers") + .HasForeignKey("SchedulerName", "TriggerName", "TriggerGroup") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Trigger"); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzCronTrigger", b => + { + b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", "Trigger") + .WithMany("CronTriggers") + .HasForeignKey("SchedulerName", "TriggerName", "TriggerGroup") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Trigger"); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimplePropertyTrigger", b => + { + b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", "Trigger") + .WithMany("SimplePropertyTriggers") + .HasForeignKey("SchedulerName", "TriggerName", "TriggerGroup") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Trigger"); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimpleTrigger", b => + { + b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", "Trigger") + .WithMany("SimpleTriggers") + .HasForeignKey("SchedulerName", "TriggerName", "TriggerGroup") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Trigger"); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", b => + { + b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzJobDetail", "JobDetail") + .WithMany("Triggers") + .HasForeignKey("SchedulerName", "JobName", "JobGroup") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("JobDetail"); + }); + + modelBuilder.Entity("Unity.AI.Domain.AIOperation", b => + { + b.HasOne("Unity.AI.Domain.AIModel", "AIModel") + .WithMany() + .HasForeignKey("AIModelId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Unity.AI.Domain.AIPrompt", "AIPrompt") + .WithMany() + .HasForeignKey("AIPromptId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("AIModel"); + + b.Navigation("AIPrompt"); + }); + + modelBuilder.Entity("Unity.GrantManager.GrantApplications.AIGenerationRequest", b => + { + b.HasOne("Unity.AI.Domain.AIOperation", null) + .WithMany() + .HasForeignKey("OperationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.SubSector", b => + { + b.HasOne("Unity.GrantManager.Locality.Sector", "Sector") + .WithMany("SubSectors") + .HasForeignKey("SectorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Sector"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("Actions") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("EntityChanges") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.EntityChange", null) + .WithMany("PropertyChanges") + .HasForeignKey("EntityChangeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Passkeys") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Volo.Abp.Identity.IdentityPasskeyData", "Data", b1 => + { + b1.Property("IdentityUserPasskeyCredentialId"); + + b1.Property("AttestationObject"); + + b1.Property("ClientDataJson"); + + b1.Property("CreatedAt"); + + b1.Property("IsBackedUp"); + + b1.Property("IsBackupEligible"); + + b1.Property("IsUserVerified"); + + b1.Property("Name"); + + b1.Property("PublicKey"); + + b1.Property("SignCount"); + + b1.PrimitiveCollection("Transports"); + + b1.HasKey("IdentityUserPasskeyCredentialId"); + + b1.ToTable("UserPasskeys"); + + b1 + .ToJson("Data") + .HasColumnType("jsonb"); + + b1.WithOwner() + .HasForeignKey("IdentityUserPasskeyCredentialId"); + }); + + b.Navigation("Data"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("PasswordHistories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.HasOne("Volo.Abp.TenantManagement.Tenant", null) + .WithMany("ConnectionStrings") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzJobDetail", b => + { + b.Navigation("Triggers"); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", b => + { + b.Navigation("BlobTriggers"); + + b.Navigation("CronTriggers"); + + b.Navigation("SimplePropertyTriggers"); + + b.Navigation("SimpleTriggers"); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.Sector", b => + { + b.Navigation("SubSectors"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Navigation("Actions"); + + b.Navigation("EntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Navigation("PropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Passkeys"); + + b.Navigation("PasswordHistories"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => + { + b.Navigation("ConnectionStrings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs new file mode 100644 index 0000000000..941b46a531 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs @@ -0,0 +1,21 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Unity.GrantManager.Migrations.HostMigrations +{ + /// + public partial class RefreshAiSchema : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/GrantManagerDbContextModelSnapshot.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/GrantManagerDbContextModelSnapshot.cs index 822f2a4b2e..fb414ed178 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/GrantManagerDbContextModelSnapshot.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/GrantManagerDbContextModelSnapshot.cs @@ -467,7 +467,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("qrtz_triggers", (string)null); }); - modelBuilder.Entity("Unity.AI.Domain.AIPrompt", b => + modelBuilder.Entity("Unity.AI.Domain.AIModel", b => { b.Property("Id") .HasColumnType("uuid"); @@ -487,10 +487,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("uuid") .HasColumnName("CreatorId"); - b.Property("Description") - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - b.Property("ExtraProperties") .IsRequired() .HasColumnType("text") @@ -512,26 +508,32 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(200) .HasColumnType("character varying(200)"); - b.Property("TenantId") - .HasColumnType("uuid") - .HasColumnName("TenantId"); - - b.Property("Type") - .HasColumnType("integer"); + b.Property("SettingsJson") + .IsRequired() + .HasColumnType("jsonb"); b.HasKey("Id"); b.HasIndex("Name") .IsUnique(); - b.ToTable("AIPrompts", "AI"); + b.ToTable("AIModels", "AI"); }); - modelBuilder.Entity("Unity.AI.Domain.AIPromptVersion", b => + modelBuilder.Entity("Unity.AI.Domain.AIOperation", b => { b.Property("Id") .HasColumnType("uuid"); + b.Property("AIModelId") + .HasColumnType("uuid"); + + b.Property("AIPromptId") + .HasColumnType("uuid"); + + b.Property("CompletionTokens") + .HasColumnType("integer"); + b.Property("ConcurrencyStamp") .IsConcurrencyToken() .IsRequired() @@ -547,18 +549,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("uuid") .HasColumnName("CreatorId"); - b.Property("DeveloperNotes") - .HasColumnType("text"); + b.Property("ExecutionMode") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); b.Property("ExtraProperties") .IsRequired() .HasColumnType("text") .HasColumnName("ExtraProperties"); - b.Property("IsDeprecated") - .HasColumnType("boolean"); - - b.Property("IsPublished") + b.Property("IsActive") .HasColumnType("boolean"); b.Property("LastModificationTime") @@ -569,35 +570,76 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("uuid") .HasColumnName("LastModifierId"); - b.Property("MaxTokens") - .HasColumnType("integer"); + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); - b.Property("MetadataJson") - .HasColumnType("jsonb"); + b.HasKey("Id"); + + b.HasIndex("AIModelId"); + + b.HasIndex("AIPromptId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AIOperations", "AI"); + }); - b.Property("PromptId") + modelBuilder.Entity("Unity.AI.Domain.AIPrompt", b => + { + b.Property("Id") .HasColumnType("uuid"); - b.Property("SystemPrompt") + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() .IsRequired() - .HasColumnType("text"); + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); - b.Property("TargetModel") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); - b.Property("TargetProvider") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MetadataJson") + .HasColumnType("jsonb"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); - b.Property("Temperature") - .HasColumnType("double precision"); + b.Property("SystemPrompt") + .IsRequired() + .HasColumnType("text"); b.Property("TenantId") .HasColumnType("uuid") .HasColumnName("TenantId"); - b.Property("UserPromptTemplate") + b.Property("UserPrompt") .IsRequired() .HasColumnType("text"); @@ -606,10 +648,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("PromptId", "VersionNumber") - .IsUnique(); + b.HasIndex("TenantId", "Name", "VersionNumber") + .IsUnique(); - b.ToTable("AIPromptVersions", "AI"); + b.ToTable("AIPrompts", "AI"); }); modelBuilder.Entity("Unity.GrantManager.Applicants.ApplicantTenantMap", b => @@ -718,10 +760,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("uuid") .HasColumnName("LastModifierId"); - b.Property("OperationType") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); + b.Property("OperationId") + .HasColumnType("uuid"); b.Property("RequestKey") .IsRequired() @@ -740,9 +780,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); + b.HasIndex("OperationId"); + b.HasIndex("RequestKey"); - b.HasIndex("TenantId", "ApplicationId", "OperationType", "Status"); + b.HasIndex("TenantId", "ApplicationId", "OperationId", "Status"); b.ToTable("AIRequests", "AI"); }); @@ -3031,15 +3073,32 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("JobDetail"); }); - modelBuilder.Entity("Unity.AI.Domain.AIPromptVersion", b => + modelBuilder.Entity("Unity.AI.Domain.AIOperation", b => { - b.HasOne("Unity.AI.Domain.AIPrompt", "Prompt") - .WithMany("Versions") - .HasForeignKey("PromptId") - .OnDelete(DeleteBehavior.Cascade) + b.HasOne("Unity.AI.Domain.AIModel", "AIModel") + .WithMany() + .HasForeignKey("AIModelId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Unity.AI.Domain.AIPrompt", "AIPrompt") + .WithMany() + .HasForeignKey("AIPromptId") + .OnDelete(DeleteBehavior.Restrict) .IsRequired(); - b.Navigation("Prompt"); + b.Navigation("AIModel"); + + b.Navigation("AIPrompt"); + }); + + modelBuilder.Entity("Unity.GrantManager.GrantApplications.AIGenerationRequest", b => + { + b.HasOne("Unity.AI.Domain.AIOperation", null) + .WithMany() + .HasForeignKey("OperationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); }); modelBuilder.Entity("Unity.GrantManager.Locality.SubSector", b => @@ -3249,11 +3308,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("SimpleTriggers"); }); - modelBuilder.Entity("Unity.AI.Domain.AIPrompt", b => - { - b.Navigation("Versions"); - }); - modelBuilder.Entity("Unity.GrantManager.Locality.Sector", b => { b.Navigation("SubSectors"); From 804f187ba3621f2cc74f1d23e831cab4313caba2 Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Fri, 26 Jun 2026 08:40:48 -0700 Subject: [PATCH 04/61] AB#32307 fix AI generation test regressions --- .../Prompts/AIPromptVersionAppService.cs | 1 - .../GrantApplications/AIGenerationStatusAppService.cs | 8 +++----- .../Automation/ApplicationAIGenerationQueue.cs | 5 ++++- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs index 7084c9cc10..c213c5067d 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs @@ -85,7 +85,6 @@ public override async Task CreateAsync(CreateUpdateAIPromptV input.SystemPrompt, input.UserPrompt) { - TenantId = prompt.TenantId, MetadataJson = input.MetadataJson, IsActive = input.IsActive }); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/AIGenerationStatusAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/AIGenerationStatusAppService.cs index 92b930052c..1162fbea33 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/AIGenerationStatusAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/AIGenerationStatusAppService.cs @@ -62,13 +62,11 @@ public class AIGenerationStatusAppService( private async Task ResolveOperationAsync(string operationName) { var operations = await operationRepository.GetQueryableAsync(); - var activeOperations = operations - .Where(operation => operation.IsActive) - .ToList(); + var allOperations = (operations ?? Enumerable.Empty()).ToList(); - return activeOperations.FirstOrDefault(operation => + return allOperations.FirstOrDefault(operation => string.Equals(operation.Name, operationName, StringComparison.OrdinalIgnoreCase)) - ?? activeOperations.FirstOrDefault(operation => + ?? allOperations.FirstOrDefault(operation => string.Equals(operation.Name, "Default", StringComparison.OrdinalIgnoreCase)); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/ApplicationAIGenerationQueue.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/ApplicationAIGenerationQueue.cs index d564ccba88..3a891123af 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/ApplicationAIGenerationQueue.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/ApplicationAIGenerationQueue.cs @@ -187,7 +187,10 @@ private static string ResolveOperationName(string operationType) private async Task ResolveOperationAsync(string operationType) { var operationName = ResolveOperationName(operationType); - var activeOperations = await operationRepository.GetListAsync(operation => operation.IsActive); + var operations = await operationRepository.GetQueryableAsync(); + var activeOperations = (operations ?? Enumerable.Empty()) + .Where(operation => operation.IsActive) + .ToList(); var operation = activeOperations.FirstOrDefault(operation => string.Equals(operation.Name, operationName, StringComparison.OrdinalIgnoreCase)) From 73e444606c9cb0b370245db09ffff14094d05fc8 Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Fri, 26 Jun 2026 09:15:24 -0700 Subject: [PATCH 05/61] AB#32307 address Copilot review fixes --- .../AI/Runtime/AIPromptTemplateProvider.cs | 3 ++- .../Prompts/AIPromptVersionAppService.cs | 3 ++- .../Automation/ApplicationAIGenerationQueue.cs | 12 ++++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateProvider.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateProvider.cs index d744c67c6b..c502fd5de6 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateProvider.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIPromptTemplateProvider.cs @@ -23,7 +23,8 @@ public async Task GetRequiredPromptAsync( using (multiTenantDataFilter.Disable()) { - var prompt = await promptRepository.FindAsync(p => p.Name == promptType && p.VersionNumber == versionNumber); + var prompt = await promptRepository.FindAsync(p => + p.TenantId == null && p.Name == promptType && p.VersionNumber == versionNumber); if (prompt == null || !prompt.IsActive) { throw new InvalidOperationException( diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs index c213c5067d..94349658ee 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs @@ -83,7 +83,8 @@ public override async Task CreateAsync(CreateUpdateAIPromptV prompt.Name, input.VersionNumber, input.SystemPrompt, - input.UserPrompt) + input.UserPrompt, + prompt.TenantId) { MetadataJson = input.MetadataJson, IsActive = input.IsActive diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/ApplicationAIGenerationQueue.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/ApplicationAIGenerationQueue.cs index 3a891123af..e847a57a5b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/ApplicationAIGenerationQueue.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/ApplicationAIGenerationQueue.cs @@ -188,13 +188,12 @@ private async Task ResolveOperationAsync(string operationType) { var operationName = ResolveOperationName(operationType); var operations = await operationRepository.GetQueryableAsync(); - var activeOperations = (operations ?? Enumerable.Empty()) - .Where(operation => operation.IsActive) + var allOperations = (operations ?? Enumerable.Empty()) .ToList(); - var operation = activeOperations.FirstOrDefault(operation => + var operation = allOperations.FirstOrDefault(operation => string.Equals(operation.Name, operationName, StringComparison.OrdinalIgnoreCase)) - ?? activeOperations.FirstOrDefault(operation => + ?? allOperations.FirstOrDefault(operation => string.Equals(operation.Name, "Default", StringComparison.OrdinalIgnoreCase)); if (operation == null) @@ -202,6 +201,11 @@ private async Task ResolveOperationAsync(string operationType) throw new UserFriendlyException($"AI operation '{operationType}' is not configured."); } + if (!operation.IsActive) + { + throw new UserFriendlyException($"AI operation '{operationType}' is not configured."); + } + return operation; } From c971382f08ff73f045b08aaa8bef76f84f2e1d11 Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Fri, 26 Jun 2026 09:22:53 -0700 Subject: [PATCH 06/61] AB#32307 fix payload validator formatting --- .../AI/Runtime/AIProviderPayloadValidator.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIProviderPayloadValidator.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIProviderPayloadValidator.cs index 99ecee6f77..eabab49597 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIProviderPayloadValidator.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/AIProviderPayloadValidator.cs @@ -26,12 +26,12 @@ public static AIResponseValidationResult ValidateApplicationAnalysisJson(string return AIResponseValidationResult.Invalid($"Application analysis response is missing or invalid required field '{AIJsonKeys.Decision}' (expected string)."); } - var normalizedDecision = (decision.GetString() ?? string.Empty).Trim().ToUpperInvariant(); - if (normalizedDecision != "PROCEED" && normalizedDecision != "HOLD") - { - return AIResponseValidationResult.Invalid( - $"Application analysis response has invalid '{AIJsonKeys.Decision}' value. Expected 'PROCEED' or 'HOLD'."); - } + var normalizedDecision = (decision.GetString() ?? string.Empty).Trim().ToUpperInvariant(); + if (normalizedDecision != "PROCEED" && normalizedDecision != "HOLD") + { + return AIResponseValidationResult.Invalid( + $"Application analysis response has invalid '{AIJsonKeys.Decision}' value. Expected 'PROCEED' or 'HOLD'."); + } if (!root.TryGetProperty(AIJsonKeys.Errors, out var errors) || errors.ValueKind != JsonValueKind.Array) { From e471a5285d3472e2c8aff8a6325646bbb54adc99 Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Fri, 26 Jun 2026 09:40:35 -0700 Subject: [PATCH 07/61] AB#32307 add forward AI schema repair migration --- ...0618203824_AddUniqueIndexToAIPromptName.cs | 17 +-- .../20260624191335_RefreshAiSchema.cs | 138 ++++++++++++++++++ 2 files changed, 141 insertions(+), 14 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618203824_AddUniqueIndexToAIPromptName.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618203824_AddUniqueIndexToAIPromptName.cs index 68c43ad654..75b13a5f7e 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618203824_AddUniqueIndexToAIPromptName.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618203824_AddUniqueIndexToAIPromptName.cs @@ -10,22 +10,11 @@ public partial class AddUniqueIndexToAIPromptName : Migration /// protected override void Up(MigrationBuilder migrationBuilder) { - migrationBuilder.Sql( - """ - ALTER TABLE "AI"."AIPrompts" - ADD COLUMN IF NOT EXISTS "VersionNumber" integer NOT NULL DEFAULT 1; - """); - - migrationBuilder.Sql( - """ - DROP INDEX IF EXISTS "AI"."IX_AIPrompts_Name"; - """); - migrationBuilder.CreateIndex( - name: "IX_AIPrompts_TenantId_Name_VersionNumber", + name: "IX_AIPrompts_Name", schema: "AI", table: "AIPrompts", - columns: new[] { "TenantId", "Name", "VersionNumber" }, + column: "Name", unique: true); } @@ -33,7 +22,7 @@ ALTER TABLE "AI"."AIPrompts" protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropIndex( - name: "IX_AIPrompts_TenantId_Name_VersionNumber", + name: "IX_AIPrompts_Name", schema: "AI", table: "AIPrompts"); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs index 941b46a531..1bc60b6449 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs @@ -11,11 +11,149 @@ public partial class RefreshAiSchema : Migration /// protected override void Up(MigrationBuilder migrationBuilder) { + migrationBuilder.Sql( + """ + DROP INDEX IF EXISTS "AI"."IX_AIPrompts_Name"; + """); + + migrationBuilder.Sql( + """ + ALTER TABLE "AI"."AIRequests" + ADD COLUMN IF NOT EXISTS "OperationId" uuid; + """); + + migrationBuilder.Sql( + """ + UPDATE "AI"."AIRequests" r + SET "OperationId" = o."Id" + FROM "AI"."AIOperations" o + WHERE r."OperationId" IS NULL + AND ( + (r."OperationType" = 'application-analysis' AND o."Name" = 'ApplicationAnalysis') + OR (r."OperationType" = 'attachment-summary' AND o."Name" = 'AttachmentSummary') + OR (r."OperationType" = 'application-scoring' AND o."Name" = 'ApplicationScoring') + OR (r."OperationType" = 'pipeline' AND o."Name" = 'Default') + ); + """); + + migrationBuilder.Sql( + """ + DO $$ + BEGIN + IF EXISTS ( + SELECT 1 + FROM "AI"."AIRequests" + WHERE "OperationId" IS NULL + ) THEN + RAISE EXCEPTION 'AIRequests contains rows that cannot be mapped to OperationId.'; + END IF; + END $$; + """); + + migrationBuilder.Sql( + """ + ALTER TABLE "AI"."AIRequests" + ALTER COLUMN "OperationId" SET NOT NULL; + """); + + migrationBuilder.Sql( + """ + DROP INDEX IF EXISTS "AI"."IX_AIRequests_TenantId_ApplicationId_OperationType_Status"; + """); + + migrationBuilder.Sql( + """ + ALTER TABLE "AI"."AIRequests" + DROP COLUMN IF EXISTS "OperationType"; + """); + + migrationBuilder.CreateIndex( + name: "IX_AIRequests_TenantId_ApplicationId_OperationId_Status", + schema: "AI", + table: "AIRequests", + columns: new[] { "TenantId", "ApplicationId", "OperationId", "Status" }); + + migrationBuilder.CreateIndex( + name: "IX_AIRequests_OperationId", + schema: "AI", + table: "AIRequests", + column: "OperationId"); + + migrationBuilder.Sql( + """ + ALTER TABLE "AI"."AIRequests" + ADD CONSTRAINT "FK_AIRequests_AIOperations_OperationId" + FOREIGN KEY ("OperationId") REFERENCES "AI"."AIOperations" ("Id") ON DELETE RESTRICT; + """); } /// protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.Sql( + """ + DROP INDEX IF EXISTS "AI"."IX_AIRequests_TenantId_ApplicationId_OperationType_Status"; + """); + + migrationBuilder.Sql( + """ + ALTER TABLE "AI"."AIRequests" + DROP CONSTRAINT IF EXISTS "FK_AIRequests_AIOperations_OperationId"; + """); + + migrationBuilder.DropIndex( + name: "IX_AIRequests_OperationId", + schema: "AI", + table: "AIRequests"); + + migrationBuilder.DropIndex( + name: "IX_AIRequests_TenantId_ApplicationId_OperationId_Status", + schema: "AI", + table: "AIRequests"); + + migrationBuilder.Sql( + """ + ALTER TABLE "AI"."AIRequests" + ADD COLUMN IF NOT EXISTS "OperationType" character varying(64) NOT NULL DEFAULT ''; + """); + + migrationBuilder.Sql( + """ + UPDATE "AI"."AIRequests" + SET "OperationType" = CASE + WHEN "OperationId" IS NOT NULL THEN + COALESCE( + (SELECT CASE o."Name" + WHEN 'ApplicationAnalysis' THEN 'application-analysis' + WHEN 'AttachmentSummary' THEN 'attachment-summary' + WHEN 'ApplicationScoring' THEN 'application-scoring' + WHEN 'Default' THEN 'pipeline' + END + FROM "AI"."AIOperations" o + WHERE o."Id" = "OperationId"), + 'application-analysis' + ) + ELSE 'application-analysis' + END; + """); + + migrationBuilder.Sql( + """ + ALTER TABLE "AI"."AIRequests" + ALTER COLUMN "OperationType" DROP DEFAULT; + """); + + migrationBuilder.Sql( + """ + ALTER TABLE "AI"."AIRequests" + ALTER COLUMN "OperationType" SET NOT NULL; + """); + + migrationBuilder.Sql( + """ + CREATE UNIQUE INDEX IF NOT EXISTS "IX_AIRequests_TenantId_ApplicationId_OperationType_Status" + ON "AI"."AIRequests" ("TenantId", "ApplicationId", "OperationType", "Status"); + """); } } } From b4c9154f6b01bd19ab0a97f7caf0765b0f58d37f Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Fri, 26 Jun 2026 10:11:48 -0700 Subject: [PATCH 08/61] AB#32307 tighten AI operation resolution --- .../AI/Runtime/OpenAIConfigurationResolver.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIConfigurationResolver.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIConfigurationResolver.cs index a1fbefa6dc..be191ce6f3 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIConfigurationResolver.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIConfigurationResolver.cs @@ -201,13 +201,19 @@ public async Task ResolveProfileNameAsync(string? modelName = null, Canc private async Task ResolveOperationAsync(string operationName, CancellationToken cancellationToken) { - var activeOperations = await _operationRepository.GetListAsync(operation => operation.IsActive); + var operations = await _operationRepository.GetListAsync(); + var activeOperations = operations.Where(operation => operation.IsActive).ToList(); - var specificOperation = activeOperations.FirstOrDefault(operation => + var configuredOperation = operations.FirstOrDefault(operation => string.Equals(operation.Name, operationName, StringComparison.OrdinalIgnoreCase)); - if (specificOperation != null) + if (configuredOperation != null) { - return specificOperation; + if (!configuredOperation.IsActive) + { + return null; + } + + return configuredOperation; } return activeOperations.FirstOrDefault(operation => From c3bbf2c7a95000c0405a7ed810ee4a960e1090ef Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Fri, 26 Jun 2026 14:38:32 -0700 Subject: [PATCH 09/61] AB#32307 restore historical AI migrations --- .../20260324221338_AddAIPromptTables.cs | 102 +++-------- ...18210000_RefreshBuiltInAIPromptVersions.cs | 159 ++++++++++++++++++ 2 files changed, 182 insertions(+), 79 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260324221338_AddAIPromptTables.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260324221338_AddAIPromptTables.cs index 2f973c1542..e390d9dc19 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260324221338_AddAIPromptTables.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260324221338_AddAIPromptTables.cs @@ -22,11 +22,8 @@ protected override void Up(MigrationBuilder migrationBuilder) Id = table.Column(type: "uuid", nullable: false), TenantId = table.Column(type: "uuid", nullable: true), Name = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), - VersionNumber = table.Column(type: "integer", nullable: false), - SystemPrompt = table.Column(type: "text", nullable: false), - UserPrompt = table.Column(type: "text", nullable: false), - MetadataJson = table.Column(type: "jsonb", nullable: true), - SeedHash = table.Column(type: "character varying(64)", maxLength: 64, nullable: true), + Description = table.Column(type: "character varying(2000)", maxLength: 2000, nullable: true), + Type = table.Column(type: "integer", nullable: false), IsActive = table.Column(type: "boolean", nullable: false), ExtraProperties = table.Column(type: "text", nullable: false), ConcurrencyStamp = table.Column(type: "character varying(40)", maxLength: 40, nullable: false), @@ -41,54 +38,24 @@ protected override void Up(MigrationBuilder migrationBuilder) }); migrationBuilder.CreateTable( - name: "AIModels", + name: "AIPromptVersions", schema: "AI", columns: table => new { Id = table.Column(type: "uuid", nullable: false), TenantId = table.Column(type: "uuid", nullable: true), - Name = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), - IsActive = table.Column(type: "boolean", nullable: false), - SettingsJson = table.Column(type: "jsonb", nullable: false), - ExtraProperties = table.Column(type: "text", nullable: false), - ConcurrencyStamp = table.Column(type: "character varying(40)", maxLength: 40, nullable: false), - CreationTime = table.Column(type: "timestamp without time zone", nullable: false), - CreatorId = table.Column(type: "uuid", nullable: true), - LastModificationTime = table.Column(type: "timestamp without time zone", nullable: true), - LastModifierId = table.Column(type: "uuid", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AIModels", x => x.Id); - }); - - migrationBuilder.CreateIndex( - name: "IX_AIPrompts_TenantId_Name_VersionNumber", - schema: "AI", - table: "AIPrompts", - columns: new[] { "TenantId", "Name", "VersionNumber" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_AIModels_Name", - schema: "AI", - table: "AIModels", - column: "Name", - unique: true); - - migrationBuilder.CreateTable( - name: "AIOperations", - schema: "AI", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - TenantId = table.Column(type: "uuid", nullable: true), - Name = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), - AIModelId = table.Column(type: "uuid", nullable: false), - AIPromptId = table.Column(type: "uuid", nullable: false), - ExecutionMode = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - CompletionTokens = table.Column(type: "integer", nullable: false), - IsActive = table.Column(type: "boolean", nullable: false), + PromptId = table.Column(type: "uuid", nullable: false), + VersionNumber = table.Column(type: "integer", nullable: false), + SystemPrompt = table.Column(type: "text", nullable: false), + UserPromptTemplate = table.Column(type: "text", nullable: false), + DeveloperNotes = table.Column(type: "text", nullable: true), + TargetModel = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), + TargetProvider = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), + Temperature = table.Column(type: "double precision", nullable: false), + MaxTokens = table.Column(type: "integer", nullable: true), + IsPublished = table.Column(type: "boolean", nullable: false), + IsDeprecated = table.Column(type: "boolean", nullable: false), + MetadataJson = table.Column(type: "jsonb", nullable: true), ExtraProperties = table.Column(type: "text", nullable: false), ConcurrencyStamp = table.Column(type: "character varying(40)", maxLength: 40, nullable: false), CreationTime = table.Column(type: "timestamp without time zone", nullable: false), @@ -98,40 +65,21 @@ protected override void Up(MigrationBuilder migrationBuilder) }, constraints: table => { - table.PrimaryKey("PK_AIOperations", x => x.Id); + table.PrimaryKey("PK_AIPromptVersions", x => x.Id); table.ForeignKey( - name: "FK_AIOperations_AIModels_AIModelId", - column: x => x.AIModelId, - principalSchema: "AI", - principalTable: "AIModels", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "FK_AIOperations_AIPrompts_AIPromptId", - column: x => x.AIPromptId, + name: "FK_AIPromptVersions_AIPrompts_PromptId", + column: x => x.PromptId, principalSchema: "AI", principalTable: "AIPrompts", principalColumn: "Id", - onDelete: ReferentialAction.Restrict); + onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( - name: "IX_AIOperations_AIModelId", - schema: "AI", - table: "AIOperations", - column: "AIModelId"); - - migrationBuilder.CreateIndex( - name: "IX_AIOperations_AIPromptId", + name: "IX_AIPromptVersions_PromptId_VersionNumber", schema: "AI", - table: "AIOperations", - column: "AIPromptId"); - - migrationBuilder.CreateIndex( - name: "IX_AIOperations_Name", - schema: "AI", - table: "AIOperations", - column: "Name", + table: "AIPromptVersions", + columns: new[] { "PromptId", "VersionNumber" }, unique: true); } @@ -139,11 +87,7 @@ protected override void Up(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( - name: "AIOperations", - schema: "AI"); - - migrationBuilder.DropTable( - name: "AIModels", + name: "AIPromptVersions", schema: "AI"); migrationBuilder.DropTable( diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618210000_RefreshBuiltInAIPromptVersions.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618210000_RefreshBuiltInAIPromptVersions.cs index 4aacd26ff8..7efc8de94b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618210000_RefreshBuiltInAIPromptVersions.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260618210000_RefreshBuiltInAIPromptVersions.cs @@ -1,18 +1,177 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using Unity.GrantManager.EntityFrameworkCore; #nullable disable namespace Unity.GrantManager.Migrations.HostMigrations { + [DbContext(typeof(GrantManagerDbContext))] [Migration("20260618210000_RefreshBuiltInAIPromptVersions")] public partial class RefreshBuiltInAIPromptVersions : Migration { + private static readonly Guid AnalysisPromptId = new("4a100001-1000-4000-a000-000000000001"); + private static readonly Guid AttachmentPromptId = new("4a100001-1000-4000-a000-000000000002"); + private static readonly Guid ScoringPromptId = new("4a100001-1000-4000-a000-000000000003"); + protected override void Up(MigrationBuilder migrationBuilder) { + migrationBuilder.Sql( + """ + UPDATE "AI"."AIPrompts" + SET "Name" = 'ApplicationAnalysis', + "Description" = 'Grant application analysis and review', + "Type" = 1, + "IsActive" = TRUE + WHERE "Id" = '4a100001-1000-4000-a000-000000000001'; + + UPDATE "AI"."AIPrompts" + SET "Name" = 'AttachmentSummary', + "Description" = 'Attachment summarization for grant review', + "Type" = 1, + "IsActive" = TRUE + WHERE "Id" = '4a100001-1000-4000-a000-000000000002'; + + UPDATE "AI"."AIPrompts" + SET "Name" = 'ApplicationScoring', + "Description" = 'Scoresheet section answering assistant', + "Type" = 1, + "IsActive" = TRUE + WHERE "Id" = '4a100001-1000-4000-a000-000000000003'; + """); + + UpdatePromptVersion( + migrationBuilder, + AnalysisPromptId, + 0, + ReadPromptFile("v0", "application-analysis.system.txt"), + ReadPromptFile("v0", "application-analysis.user.txt"), + "v0 - initial single-file analysis prompt", + null); + + UpdatePromptVersion( + migrationBuilder, + AnalysisPromptId, + 1, + ReadPromptFile("v1", "application-analysis.system.txt"), + ReadPromptFile("v1", "application-analysis.user.txt"), + "v1 - modular prompt with separate rubric, score, output, and rules sections", + BuildSectionsJson(new Dictionary + { + ["RUBRIC"] = ReadPromptFile("v1", "application-analysis.rubric.txt"), + ["SCORE"] = ReadPromptFile("v1", "application-analysis.score.txt"), + ["OUTPUT"] = ReadPromptFile("v1", "application-analysis.output.txt"), + ["RULES"] = ReadPromptFile("v1", "application-analysis.rules.txt"), + ["COMMON_RULES"] = ReadPromptFile("v1", "common.rules.txt") + })); + + UpdatePromptVersion( + migrationBuilder, + AttachmentPromptId, + 0, + ReadPromptFile("v0", "attachment-summary.system.txt"), + ReadPromptFile("v0", "attachment-summary.user.txt"), + "v0 - initial single-file attachment prompt", + null); + + UpdatePromptVersion( + migrationBuilder, + AttachmentPromptId, + 1, + ReadPromptFile("v1", "attachment-summary.system.txt"), + ReadPromptFile("v1", "attachment-summary.user.txt"), + "v1 - modular prompt with separate output and rules sections", + BuildSectionsJson(new Dictionary + { + ["OUTPUT"] = ReadPromptFile("v1", "attachment-summary.output.txt"), + ["RULES"] = ReadPromptFile("v1", "attachment-summary.rules.txt"), + ["COMMON_RULES"] = ReadPromptFile("v1", "common.rules.txt") + })); + + UpdatePromptVersion( + migrationBuilder, + ScoringPromptId, + 0, + ReadPromptFile("v0", "application-scoring.system.txt"), + ReadPromptFile("v0", "application-scoring.user.txt"), + "v0 - initial single-file scoresheet prompt", + null); + + UpdatePromptVersion( + migrationBuilder, + ScoringPromptId, + 1, + ReadPromptFile("v1", "application-scoring.system.txt"), + ReadPromptFile("v1", "application-scoring.user.txt"), + "v1 - modular prompt with separate output and rules sections", + BuildSectionsJson(new Dictionary + { + ["OUTPUT"] = ReadPromptFile("v1", "application-scoring.output.txt"), + ["RULES"] = ReadPromptFile("v1", "application-scoring.rules.txt"), + ["COMMON_RULES"] = ReadPromptFile("v1", "common.rules.txt") + })); } protected override void Down(MigrationBuilder migrationBuilder) { + // No-op: prompt version content is managed by seeded defaults. + } + + private static void UpdatePromptVersion( + MigrationBuilder migrationBuilder, + Guid promptId, + int versionNumber, + string systemPrompt, + string userPromptTemplate, + string developerNotes, + string metadataJson) + { + migrationBuilder.Sql($""" + UPDATE "AI"."AIPromptVersions" + SET "SystemPrompt" = '{EscapeSqlLiteral(systemPrompt)}', + "UserPromptTemplate" = '{EscapeSqlLiteral(userPromptTemplate)}', + "DeveloperNotes" = '{EscapeSqlLiteral(developerNotes)}', + "IsPublished" = TRUE, + "IsDeprecated" = FALSE, + "MetadataJson" = {FormatNullableSqlString(metadataJson)} + WHERE "PromptId" = '{promptId}' + AND "VersionNumber" = {versionNumber}; + """); + } + + private static string ReadPromptFile(string version, string fileName) + { + var path = Path.Combine(AppContext.BaseDirectory, "AI", "Prompts", "Versions", version, fileName); + if (!File.Exists(path)) + { + throw new InvalidOperationException($"Missing prompt asset required by migration: {path}"); + } + + return File.ReadAllText(path); + } + + private static string BuildSectionsJson(Dictionary sections) + { + return JsonSerializer.Serialize(new { sections }); + } + + private static string EscapeSqlLiteral(string value) + { + return value.Replace("'", "''", StringComparison.Ordinal); + } + + private static string FormatNullableSqlString(string value) + { + if (value == null) + { + return "NULL"; + } + + return $"'{EscapeSqlLiteral(value)}'"; } } } From b83aa896bbbe826b2e10af9033e81f43326157b6 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Mon, 29 Jun 2026 09:57:16 -0700 Subject: [PATCH 10/61] [AB#33555] Add ExternalStatusVisibility to Applications and UI --- .../CreateUpdateApplicationResultsDto.cs | 3 +- .../GrantApplications/GrantApplicationDto.cs | 1 + .../GrantApplicationAppService.cs | 5 +- .../appsettings.json | 6 +- .../Localization/GrantManager/en.json | 1 + .../Applications/Application.cs | 5 +- ...lStatusVisibilityToApplication.Designer.cs | 5230 +++++++++++++++++ ...ddExternalStatusVisibilityToApplication.cs | 29 + .../GrantTenantDbContextModelSnapshot.cs | 253 +- .../AssessmentResults/AssessmentResults.cs | 1 + .../AssessmentResultsViewModel.cs | 3 + .../AssessmentResults/Default.cshtml | 5 + .../Components/AssessmentResults/Default.js | 3 +- 13 files changed, 5442 insertions(+), 103 deletions(-) create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.Designer.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.cs diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/CreateUpdateApplicationResultsDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/CreateUpdateApplicationResultsDto.cs index d399a559a4..578a7e8295 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/CreateUpdateApplicationResultsDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/CreateUpdateApplicationResultsDto.cs @@ -20,6 +20,7 @@ public class CreateUpdateAssessmentResultsDto : CustomDataFieldDto public decimal? RecommendedAmount { get; set; } public string? DeclineRational { get; set; } public string? AssessmentResultStatus { get; set; } - public string? RiskRanking { get; set;} + public string? RiskRanking { get; set; } + public bool ExternalStatusVisibility { get; set; } = false; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/GrantApplicationDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/GrantApplicationDto.cs index 53fda330fa..bcd98265cf 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/GrantApplicationDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/GrantApplicationDto.cs @@ -39,6 +39,7 @@ public class GrantApplicationDto : AuditedEntityDto public string? DeclineRational { get; set; } = string.Empty; public string? Notes { get; set; } = string.Empty; public string? AssessmentResultStatus { get; set; } = string.Empty; + public bool ExternalStatusVisibility { get; set; } = false; public DateTime? AssessmentResultDate { get; set; } public GrantApplicationState StatusCode { get; set; } public DateTime? FinalDecisionDate { get; set; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs index 87a4db3b4b..651fabbab2 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs @@ -380,7 +380,8 @@ public async Task UpdateAssessmentResultsAsync(Guid id, Cre input.LikelihoodOfFunding, input.TotalProjectBudget, input.NotificationDate, - input.RiskRanking + input.RiskRanking, + input.ExternalStatusVisibility ); if (application.IsInFinalDecisionState()) @@ -508,6 +509,7 @@ private async Task SanitizeAssessmentResultsZoneInputs(CreateUpdateAssessmentRes input.DueDiligenceStatus ??= application.DueDiligenceStatus; input.AssessmentResultStatus ??= application.AssessmentResultStatus; input.DeclineRational ??= application.DeclineRational; + input.ExternalStatusVisibility = application.ExternalStatusVisibility; input.NotificationDate ??= application.NotificationDate; input.DueDate ??= application.DueDate; @@ -522,6 +524,7 @@ private async Task SanitizeAssessmentResultsZoneInputs(CreateUpdateAssessmentRes input.DueDiligenceStatus ??= application.DueDiligenceStatus; input.AssessmentResultStatus ??= application.AssessmentResultStatus; input.DeclineRational ??= application.DeclineRational; + input.ExternalStatusVisibility = application.ExternalStatusVisibility; } } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json index 2d97676b33..9239fc32ef 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json @@ -1,8 +1,8 @@ { "ConnectionStrings": { - "Default": "Host=localhost;port=5432;Database=UnityGrantManager;Username=postgres;", - "Tenant": "Host=localhost;port=5432;Database=UnityGrantTenant;Username=postgres;", - "Onboarding": "Host=localhost;port=5432;Database=Onboarding;Username=postgres;" + "Default": "Host=localhost;port=5435;Database=UnityGrantManager;Username=postgres;Password=admin", + "Tenant": "Host=localhost;port=5435;Database=UnityGrantTenant;Username=postgres;Password=admin", + "Onboarding": "Host=localhost;port=5435;Database=Onboarding;Username=postgres;Password=admin" }, "StringEncryption": { "DefaultPassPhrase": "g2IuZx7PwXDvCmlW" 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 ec090bfc29..17551a73fc 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 @@ -285,6 +285,7 @@ "AssessmentResultsView:AssessmentResultsForm.DueDate": "Due Date", "AssessmentResultsView:AssessmentResultsForm.NotificationDate": "Notification Date", "AssessmentResultsView:AssessmentResultsForm.RiskRanking": "Risk Ranking", + "AssessmentResultsView:AssessmentResultsForm.Published": "Published", "GrantApplication:ActionButtonName": "Status Actions", "GrantApplication:ActionButton.RedStopWarning": "This application is from an applicant with a Red-Stop. Status actions are not permitted.", diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/Application.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/Application.cs index 7b82663d1e..70cc18a334 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/Application.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/Application.cs @@ -84,6 +84,8 @@ public virtual ApplicationStatus ApplicationStatus public string? SubStatus { get; set; } + public bool ExternalStatusVisibility { get; set; } = false; + public string? DeclineRational { get; set; } public string? Notes { get; set; } @@ -150,7 +152,7 @@ public bool IsInFinalDecisionState() return GrantApplicationStateGroups.FinalDecisionStates.Contains(ApplicationStatus.StatusCode); } - public void UpdateAlwaysChangeableFields(string? notes, string? subStatus, string? likelihoodOfFunding, decimal? totalProjectBudget, DateTime? notificationDate, string? riskRanking) + public void UpdateAlwaysChangeableFields(string? notes, string? subStatus, string? likelihoodOfFunding, decimal? totalProjectBudget, DateTime? notificationDate, string? riskRanking, bool externalStatusVisibility) { Notes = notes; SubStatus = subStatus; @@ -158,6 +160,7 @@ public void UpdateAlwaysChangeableFields(string? notes, string? subStatus, strin TotalProjectBudget = totalProjectBudget ?? 0; NotificationDate = notificationDate; RiskRanking = riskRanking; + ExternalStatusVisibility = externalStatusVisibility; // Recalculate percentage when TotalProjectBudget changes UpdatePercentageTotalProjectBudget(); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.Designer.cs new file mode 100644 index 0000000000..e1d38ed77f --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.Designer.cs @@ -0,0 +1,5230 @@ +// +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("20260629164239_AB33555_AddExternalStatusVisibilityToApplication")] + partial class AB33555_AddExternalStatusVisibilityToApplication + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "10.0.3") + .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("IsArchived") + .HasColumnType("boolean"); + + 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("IsArchived") + .HasColumnType("boolean"); + + 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("Definition") + .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("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("AuditComments") + .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("DeleterId") + .HasColumnType("uuid"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FiscalDay") + .HasColumnType("integer"); + + b.Property("FiscalMonth") + .HasColumnType("text"); + + b.Property("FundingHistoryComments") + .HasColumnType("text"); + + b.Property("IndigenousOrgInd") + .HasColumnType("text"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("IsDuplicated") + .HasColumnType("boolean"); + + b.Property("IssueTrackingComments") + .HasColumnType("text"); + + 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("OrganizationType") + .HasColumnType("text"); + + b.Property("RedStop") + .HasColumnType("boolean"); + + b.Property("ReportsComments") + .HasColumnType("text"); + + b.Property("Sector") + .HasColumnType("text"); + + b.Property("SectorSubSectorIndustryDesc") + .HasColumnType("text"); + + 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.HasIndex("OrgName"); + + b.HasIndex("OrgNumber"); + + b.HasIndex("Status"); + + b.HasIndex("SupplierId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UnityApplicantId"); + + b.HasIndex("TenantId", "IsDeleted", "CreationTime") + .HasFilter("\"IsDeleted\" = false"); + + 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.HasIndex("TenantId", "ApplicationId"); + + b.ToTable("ApplicantAgents", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .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("ApplicantId"); + + b.ToTable("ApplicantAttachments", (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("DefaultSiteId") + .HasColumnType("uuid"); + + 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("ExternalStatusVisibility") + .HasColumnType("boolean"); + + 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.HasIndex("ReferenceNo"); + + b.HasIndex("TenantId", "SubmissionDate") + .HasFilter("\"IsDeleted\" = false"); + + 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.HasIndex("TenantId", "ApplicationId"); + + 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("AutomaticallyGenerateAIAnalysis") + .HasColumnType("boolean"); + + 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("ManuallyInitiateAIAnalysis") + .HasColumnType("boolean"); + + b.Property("ParentFormId") + .HasColumnType("uuid"); + + b.Property("Payable") + .HasColumnType("boolean"); + + b.Property("PaymentApprovalThreshold") + .HasColumnType("numeric"); + + b.Property("Prefix") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PreventPayment") + .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.HasIndex("TenantId", "IsDeleted") + .HasFilter("\"IsDeleted\" = false"); + + 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("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.HasIndex("TenantId", "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("NotifiedStatus") + .HasColumnType("text"); + + 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.HasIndex("TenantId", "ApplicationId"); + + 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.Applications.AuditHistory", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("AuditDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AuditNote") + .HasColumnType("text"); + + b.Property("AuditStatus") + .HasColumnType("text"); + + b.Property("AuditTrackingNumber") + .HasColumnType("text"); + + b.Property("AuditorName") + .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("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("ApplicantId"); + + b.ToTable("AuditHistories", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.FundingHistory", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApprovedAmount") + .HasColumnType("numeric"); + + 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("FundingNotes") + .HasColumnType("text"); + + b.Property("FundingYear") + .HasColumnType("text"); + + b.Property("GrantCategory") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OneTimeConsideration") + .HasColumnType("numeric"); + + b.Property("PaidDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ReconsiderationAmount") + .HasColumnType("numeric"); + + b.Property("RenewedFunding") + .HasColumnType("boolean"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TotalGrantAmount") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("FundingHistories", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.IssueTracking", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .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("IssueDescription") + .HasColumnType("text"); + + b.Property("IssueHeading") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ResolutionNote") + .HasColumnType("text"); + + b.Property("Resolved") + .HasColumnType("boolean"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Year") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("IssueTrackings", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ReportsHistory", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .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("FiscalYear") + .HasColumnType("text"); + + b.Property("IncompleteReport") + .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("Outstanding") + .HasColumnType("boolean"); + + b.Property("ReportDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("ReportsHistories", (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("IsAiAssessment") + .HasColumnType("boolean"); + + 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.ApplicantComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .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("ApplicantId"); + + b.HasIndex("CommenterId"); + + b.ToTable("ApplicantComments", (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.HasIndex("TenantId"); + + 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.GrantManager.Notifications.ScheduledNotification", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationStatus") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ApplicationStatusId") + .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("DateField") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EmailTemplateId") + .HasColumnType("uuid"); + + b.Property("EventType") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormId") + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + 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("RecipientCategory") + .HasColumnType("text"); + + b.Property("RecipientIdentifier") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TriggerDetail") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("TriggerType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ScheduledNotifications", "Notifications"); + }); + + modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotificationTracking", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("DateField") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NotificationSentDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ScheduledNotificationId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("CreationTime"); + + b.HasIndex("ScheduledNotificationId"); + + b.HasIndex("ApplicationId", "ScheduledNotificationId", "DateField") + .IsUnique(); + + b.ToTable("ScheduledNotificationTracking", "Notifications"); + }); + + 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("EmailType") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + 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("Recipient") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("RetryAttempts") + .HasColumnType("integer"); + + b.Property("ScheduledNotificationId") + .HasColumnType("uuid"); + + 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("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.ApplicantAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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("ApplicationLinks") + .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.Applications.AuditHistory", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.FundingHistory", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.IssueTracking", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ReportsHistory", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId"); + }); + + 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.ApplicantComment", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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.GrantManager.Notifications.ScheduledNotificationTracking", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Notifications.ScheduledNotification", null) + .WithMany() + .HasForeignKey("ScheduledNotificationId") + .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); + + 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("ApplicationLinks"); + + 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/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.cs new file mode 100644 index 0000000000..dde7768fba --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + /// + public partial class AB33555_AddExternalStatusVisibilityToApplication : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ExternalStatusVisibility", + table: "Applications", + type: "boolean", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ExternalStatusVisibility", + table: "Applications"); + } + } +} 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 595756df54..eabfeae2ed 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 @@ -1290,6 +1290,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ElectoralDistrict") .HasColumnType("text"); + b.Property("ExternalStatusVisibility") + .HasColumnType("boolean"); + b.Property("ExtraProperties") .IsRequired() .HasColumnType("text") @@ -3047,6 +3050,142 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Intakes", (string)null); }); + modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotification", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationStatus") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ApplicationStatusId") + .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("DateField") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EmailTemplateId") + .HasColumnType("uuid"); + + b.Property("EventType") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormId") + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + 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("RecipientCategory") + .HasColumnType("text"); + + b.Property("RecipientIdentifier") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TriggerDetail") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("TriggerType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ScheduledNotifications", "Notifications"); + }); + + modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotificationTracking", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("DateField") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NotificationSentDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ScheduledNotificationId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("CreationTime"); + + b.HasIndex("ScheduledNotificationId"); + + b.HasIndex("ApplicationId", "ScheduledNotificationId", "DateField") + .IsUnique(); + + b.ToTable("ScheduledNotificationTracking", "Notifications"); + }); + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroup", b => { b.Property("Id") @@ -3249,6 +3388,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("RetryAttempts") .HasColumnType("integer"); + b.Property("ScheduledNotificationId") + .HasColumnType("uuid"); + b.Property("SendOnDateTime") .HasColumnType("timestamp without time zone"); @@ -3358,102 +3500,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("EmailLogAttachments", "Notifications"); }); - modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotification", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .IsRequired() - .HasMaxLength(40) - .HasColumnType("character varying(40)") - .HasColumnName("ConcurrencyStamp"); - - b.Property("ExtraProperties") - .IsRequired() - .HasColumnType("text") - .HasColumnName("ExtraProperties"); - - b.Property("FormId") - .HasColumnType("uuid"); - - b.Property("EmailTemplateId") - .HasColumnType("uuid"); - - b.Property("TriggerType") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("text"); - - b.Property("TriggerDetail") - .HasMaxLength(1000) - .HasColumnType("text"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("EventType") - .HasMaxLength(128) - .HasColumnType("text"); - - b.Property("ApplicationStatusId") - .HasColumnType("uuid"); - - b.Property("ApplicationStatus") - .HasMaxLength(128) - .HasColumnType("text"); - - b.Property("RecipientCategory") - .HasColumnType("text"); - - b.Property("RecipientIdentifier") - .HasColumnType("text"); - - b.Property("DateField") - .HasMaxLength(128) - .HasColumnType("text"); - - b.Property("TenantId") - .HasColumnType("uuid") - .HasColumnName("TenantId"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("boolean") - .HasDefaultValue(false) - .HasColumnName("IsDeleted"); - - b.Property("DeleterId") - .HasColumnType("uuid") - .HasColumnName("DeleterId"); - - b.Property("DeletionTime") - .HasColumnType("timestamp without time zone") - .HasColumnName("DeletionTime"); - - 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.HasKey("Id"); - - b.ToTable("ScheduledNotifications", "Notifications"); - }); - modelBuilder.Entity("Unity.Notifications.Templates.EmailTemplate", b => { b.Property("Id") @@ -4969,6 +5015,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotificationTracking", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Notifications.ScheduledNotification", null) + .WithMany() + .HasForeignKey("ScheduledNotificationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroupUser", b => { b.HasOne("Unity.Notifications.EmailGroups.EmailGroup", null) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResults.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResults.cs index e1861fd94d..8ae354c95b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResults.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResults.cs @@ -88,6 +88,7 @@ public async Task InvokeAsync(Guid applicationId, Guid app NotificationDate = application.NotificationDate, DueDate = application.DueDate, ProjectSummary = application.ProjectSummary, + ExternalStatusVisibility = application.ExternalStatusVisibility, }; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResultsViewModel.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResultsViewModel.cs index 0d35c45fac..15ce5611cc 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResultsViewModel.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResultsViewModel.cs @@ -88,6 +88,9 @@ public class AssessmentResultsModel [Display(Name = "AssessmentResultsView:AssessmentResultsForm.RiskRanking")] [SelectItems(nameof(RiskRankingList))] public string? RiskRanking { get; set; } + + [Display(Name = "AssessmentResultsView:AssessmentResultsForm.Published")] + public bool ExternalStatusVisibility { get; set; } = false; } public List FundingRiskList { get; set; } = FormatOptionsList(AssessmentResultsOptionsList.FundingList); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/Default.cshtml index d849163af3..4d50756ca4 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/Default.cshtml @@ -139,6 +139,11 @@ + + + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/Default.js index bc77bf1c35..d42cf25888 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/Default.js @@ -38,7 +38,8 @@ // Update checkboxes which are serialized if unchecked $(`#assessmentResultForm input:checkbox`).each(function () { - assessmentResultObj[this.name] = (this.checked).toString(); + let propertyName = this.name.includes('.') ? this.name.split('.').pop() : this.name; + assessmentResultObj[propertyName] = this.checked; }); From 5b612e730fa121763aad9139c13a06ffee1013f2 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:07:37 -0700 Subject: [PATCH 11/61] [AB#33555] Add ExternalStatusVisibility to breadcrumb widget --- .../GrantApplications/ApplicationApplicantInfoDto.cs | 1 + .../ApplicationApplicantAppService.cs | 1 + .../ApplicationBreadcrumbWidget.cs | 1 + .../ApplicationBreadcrumbWidgetViewModel.cs | 1 + .../ApplicationBreadcrumbWidget/Default.cshtml | 6 +++++- .../Components/ApplicationBreadcrumbWidget/Default.css | 10 ++++++++++ 6 files changed, 19 insertions(+), 1 deletion(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicationApplicantInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicationApplicantInfoDto.cs index 502af75bcc..53d68e3670 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicationApplicantInfoDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicationApplicantInfoDto.cs @@ -20,6 +20,7 @@ public class ApplicationApplicantInfoDto : GrantApplicationApplicantDto public string SigningAuthorityCellPhone { get; set; } = string.Empty; public string ApplicationReferenceNo { get; set; } = string.Empty; public string ApplicationStatus { get; set; } = string.Empty; + public bool ExternalStatusVisibility { get; set; } = false; public GrantApplicationState ApplicationStatusCode { get; set; } public List ApplicantAddresses { get; set; } = []; public Guid ApplicationFormId { get; set; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationApplicantAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationApplicantAppService.cs index e2043e9a16..a1a83b12db 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationApplicantAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationApplicantAppService.cs @@ -106,6 +106,7 @@ public async Task GetApplicantInfoBasicAsync(Guid a ApplicantName = applicantInfo.Applicant?.ApplicantName ?? string.Empty, ApplicationReferenceNo = applicantInfo.ReferenceNo, ApplicationStatus = applicantInfo.ApplicationStatus.InternalStatus, + ExternalStatusVisibility = applicantInfo.ExternalStatusVisibility, ApplicationStatusCode = applicantInfo.ApplicationStatus.StatusCode }; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/ApplicationBreadcrumbWidget.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/ApplicationBreadcrumbWidget.cs index aafb08a420..e2a9c9030a 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/ApplicationBreadcrumbWidget.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/ApplicationBreadcrumbWidget.cs @@ -29,6 +29,7 @@ public async Task InvokeAsync(Guid applicationId) ApplicantId = applicationApplicant.ApplicantId, ApplicantName = applicationApplicant.ApplicantName ?? string.Empty, ApplicationStatus = applicationApplicant.ApplicationStatus, + ExternalStatusVisibility = applicationApplicant.ExternalStatusVisibility, ReferenceNo = applicationApplicant.ApplicationReferenceNo, ApplicationFormId = formDetails.ApplicationFormId, diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/ApplicationBreadcrumbWidgetViewModel.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/ApplicationBreadcrumbWidgetViewModel.cs index 5a664ddc66..24b96f595f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/ApplicationBreadcrumbWidgetViewModel.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/ApplicationBreadcrumbWidgetViewModel.cs @@ -8,6 +8,7 @@ public class ApplicationBreadcrumbWidgetViewModel public Guid ApplicantId { get; set; } = Guid.Empty; public string ApplicantName { get; set; } = string.Empty; public string ApplicationStatus { get; set; } = string.Empty; + public bool ExternalStatusVisibility { get; set; } = false; public Guid ApplicationFormId { get; set; } = Guid.Empty; public string ApplicationFormName { get; set; } = string.Empty; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.cshtml index 3b9d1d321e..3156f161c3 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.cshtml @@ -29,7 +29,11 @@ }
@Model.SubmissionFormDescription
-
@Model.ApplicationStatus
+
@Model.ApplicationStatus
+ @if (Model.ExternalStatusVisibility) + { +
Status Published
+ } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.css b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.css index f92c40d013..91a1807a41 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.css +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.css @@ -41,3 +41,13 @@ margin-top: 2px; } +.application-details-breadcrumb .published-status { + font-weight: 700; + color: #2f6f3e; + border: 3px solid #2f6f3e; + border-radius: 1rem; + font-size: 0.8rem; + padding: 0.125rem 0.5rem; + margin-top: 2px; +} + From 3c5a9f049faa17703d892e2a6ce64b33728ed05e Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Mon, 29 Jun 2026 13:18:33 -0700 Subject: [PATCH 12/61] [AB#33555] Change External Status Label --- .../Localization/GrantManager/en.json | 2 +- .../Pages/ApplicantPortalSettings/Index.cshtml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 17551a73fc..5a69633cff 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 @@ -525,7 +525,7 @@ "ApplicantPortalSettings:PortalStatusHeading": "Applicant Portal Status", "ApplicantPortalSettings:InternalStatus": "Internal Status", "ApplicantPortalSettings:PortalStatusLabel": "External Status", - "ApplicantPortalSettings:PortalNotifiedStatusLabel": "Notified Status", + "ApplicantPortalSettings:PortalPublishedStatusLabel": "Published Status", "ApplicantPortalSettings:SaveChanges": "Save Changes", "ApplicantPortalSettings:ResetChanges": "Reset", "ApplicantPortalSettings:NoChanges": "No changes to save.", diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicantPortalSettings/Index.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicantPortalSettings/Index.cshtml index d9c8912392..1bb47de3d3 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicantPortalSettings/Index.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicantPortalSettings/Index.cshtml @@ -45,7 +45,7 @@ @L["ApplicantPortalSettings:InternalStatus"] @L["ApplicantPortalSettings:PortalStatusLabel"] - @L["ApplicantPortalSettings:PortalNotifiedStatusLabel"] + @L["ApplicantPortalSettings:PortalPublishedStatusLabel"] From 632d2e924f214704d2964557e0ed4fa13b078667 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:02:29 -0700 Subject: [PATCH 13/61] [AB#33555] Implement external status visibility updates --- .../CreateUpdateApplicationResultsDto.cs | 1 - .../IGrantApplicationAppService.cs | 29 ++++++----- .../GrantApplicationAppService.cs | 14 +++-- .../Localization/GrantManager/en.json | 9 ++++ .../Applications/Application.cs | 3 +- .../Default.cshtml | 2 +- .../AssessmentResults/AssessmentResults.cs | 1 - .../AssessmentResultsViewModel.cs | 3 -- .../AssessmentResults/Default.cshtml | 5 -- .../DetailsActionBar/Default.cshtml | 10 +++- .../Components/DetailsActionBar/Default.js | 52 +++++++++++++++++++ .../DetailsActionBar/DetailsActionBar.cs | 30 +++++++++-- .../DetailsActionBarViewModel.cs | 10 ++++ 13 files changed, 134 insertions(+), 35 deletions(-) create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/DetailsActionBar/DetailsActionBarViewModel.cs diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/CreateUpdateApplicationResultsDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/CreateUpdateApplicationResultsDto.cs index 578a7e8295..e2273582f6 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/CreateUpdateApplicationResultsDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/CreateUpdateApplicationResultsDto.cs @@ -21,6 +21,5 @@ public class CreateUpdateAssessmentResultsDto : CustomDataFieldDto public string? DeclineRational { get; set; } public string? AssessmentResultStatus { get; set; } public string? RiskRanking { get; set; } - public bool ExternalStatusVisibility { get; set; } = false; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/IGrantApplicationAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/IGrantApplicationAppService.cs index 2b6421fd8a..2cecd069ab 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/IGrantApplicationAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/IGrantApplicationAppService.cs @@ -1,18 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Unity.Modules.Shared; -using Volo.Abp.Application.Dtos; - -namespace Unity.GrantManager.GrantApplications; - -public interface IGrantApplicationAppService -{ - Task GetApplicationStatusAsync(Guid id); - Task> GetActions(Guid applicationId, bool includeInternal = false); - Task UpdateProjectInfoAsync(Guid id, CreateUpdateProjectInfoDto input); - Task UpdatePartialProjectInfoAsync(Guid id, PartialUpdateDto input); +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Unity.Modules.Shared; +using Volo.Abp.Application.Dtos; + +namespace Unity.GrantManager.GrantApplications; + +public interface IGrantApplicationAppService +{ + Task GetApplicationStatusAsync(Guid id); + Task> GetActions(Guid applicationId, bool includeInternal = false); + Task UpdateProjectInfoAsync(Guid id, CreateUpdateProjectInfoDto input); + Task UpdatePartialProjectInfoAsync(Guid id, PartialUpdateDto input); Task UpdateAssessmentResultsAsync(Guid id, CreateUpdateAssessmentResultsDto input); + Task UpdateExternalStatusVisibilityAsync(Guid id, bool externalStatusVisibility); Task UpdateSupplierNumberAsync(Guid applicationId, string supplierNumber); Task> GetAllApplicationsAsync(); Task> GetApplicationDetailsListAsync(List applicationIds); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs index 651fabbab2..b1bd1fcad9 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs @@ -380,8 +380,7 @@ public async Task UpdateAssessmentResultsAsync(Guid id, Cre input.LikelihoodOfFunding, input.TotalProjectBudget, input.NotificationDate, - input.RiskRanking, - input.ExternalStatusVisibility + input.RiskRanking ); if (application.IsInFinalDecisionState()) @@ -423,6 +422,15 @@ public async Task UpdateAssessmentResultsAsync(Guid id, Cre return ObjectMapper.Map(application); } + [Authorize(UnitySelector.Review.AssessmentResults.Update.Default)] + public async Task UpdateExternalStatusVisibilityAsync(Guid id, bool externalStatusVisibility) + { + var application = await applicationRepository.GetAsync(id); + application.ExternalStatusVisibility = externalStatusVisibility; + await applicationRepository.UpdateAsync(application); + return ObjectMapper.Map(application); + } + private async Task PublishCustomFieldsAsync(Guid applicationId, UpdateProjectInfoDto dto) { if (dto.WorksheetIds?.Count > 0) @@ -509,7 +517,6 @@ private async Task SanitizeAssessmentResultsZoneInputs(CreateUpdateAssessmentRes input.DueDiligenceStatus ??= application.DueDiligenceStatus; input.AssessmentResultStatus ??= application.AssessmentResultStatus; input.DeclineRational ??= application.DeclineRational; - input.ExternalStatusVisibility = application.ExternalStatusVisibility; input.NotificationDate ??= application.NotificationDate; input.DueDate ??= application.DueDate; @@ -524,7 +531,6 @@ private async Task SanitizeAssessmentResultsZoneInputs(CreateUpdateAssessmentRes input.DueDiligenceStatus ??= application.DueDiligenceStatus; input.AssessmentResultStatus ??= application.AssessmentResultStatus; input.DeclineRational ??= application.DeclineRational; - input.ExternalStatusVisibility = application.ExternalStatusVisibility; } } } 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 5a69633cff..28c0bdd3d9 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 @@ -286,6 +286,15 @@ "AssessmentResultsView:AssessmentResultsForm.NotificationDate": "Notification Date", "AssessmentResultsView:AssessmentResultsForm.RiskRanking": "Risk Ranking", "AssessmentResultsView:AssessmentResultsForm.Published": "Published", + "DetailsActionBar:PublishButton": "Publish", + "DetailsActionBar:UnpublishButton": "Unpublish", + "DetailsActionBar:ConfirmActionTitle": "Confirm Action", + "DetailsActionBar:PublishConfirmationText": "Are you sure you want to publish this application status?", + "DetailsActionBar:UnpublishConfirmationText": "Are you sure you want to unpublish this application status?", + "DetailsActionBar:ConfirmButton": "Confirm", + "DetailsActionBar:CancelButton": "Cancel", + "DetailsActionBar:PublishStatusUpdated": "Publish status has been updated.", + "DetailsActionBar:PublishStatusUpdateFailed": "Failed to update publish status.", "GrantApplication:ActionButtonName": "Status Actions", "GrantApplication:ActionButton.RedStopWarning": "This application is from an applicant with a Red-Stop. Status actions are not permitted.", diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/Application.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/Application.cs index 70cc18a334..ff5f68410b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/Application.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/Application.cs @@ -152,7 +152,7 @@ public bool IsInFinalDecisionState() return GrantApplicationStateGroups.FinalDecisionStates.Contains(ApplicationStatus.StatusCode); } - public void UpdateAlwaysChangeableFields(string? notes, string? subStatus, string? likelihoodOfFunding, decimal? totalProjectBudget, DateTime? notificationDate, string? riskRanking, bool externalStatusVisibility) + public void UpdateAlwaysChangeableFields(string? notes, string? subStatus, string? likelihoodOfFunding, decimal? totalProjectBudget, DateTime? notificationDate, string? riskRanking) { Notes = notes; SubStatus = subStatus; @@ -160,7 +160,6 @@ public void UpdateAlwaysChangeableFields(string? notes, string? subStatus, strin TotalProjectBudget = totalProjectBudget ?? 0; NotificationDate = notificationDate; RiskRanking = riskRanking; - ExternalStatusVisibility = externalStatusVisibility; // Recalculate percentage when TotalProjectBudget changes UpdatePercentageTotalProjectBudget(); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.cshtml index 3156f161c3..5b3f136d2a 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/Default.cshtml @@ -32,7 +32,7 @@
@Model.ApplicationStatus
@if (Model.ExternalStatusVisibility) { -
Status Published
+
STATUS PUBLISHED
} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResults.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResults.cs index 8ae354c95b..e1861fd94d 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResults.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResults.cs @@ -88,7 +88,6 @@ public async Task InvokeAsync(Guid applicationId, Guid app NotificationDate = application.NotificationDate, DueDate = application.DueDate, ProjectSummary = application.ProjectSummary, - ExternalStatusVisibility = application.ExternalStatusVisibility, }; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResultsViewModel.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResultsViewModel.cs index 15ce5611cc..0d35c45fac 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResultsViewModel.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/AssessmentResultsViewModel.cs @@ -88,9 +88,6 @@ public class AssessmentResultsModel [Display(Name = "AssessmentResultsView:AssessmentResultsForm.RiskRanking")] [SelectItems(nameof(RiskRankingList))] public string? RiskRanking { get; set; } - - [Display(Name = "AssessmentResultsView:AssessmentResultsForm.Published")] - public bool ExternalStatusVisibility { get; set; } = false; } public List FundingRiskList { get; set; } = FormatOptionsList(AssessmentResultsOptionsList.FundingList); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/Default.cshtml index 4d50756ca4..d849163af3 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentResults/Default.cshtml @@ -139,11 +139,6 @@ - - - diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/DetailsActionBar/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/DetailsActionBar/Default.cshtml index e43cb89266..e47847b901 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/DetailsActionBar/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/DetailsActionBar/Default.cshtml @@ -1,15 +1,23 @@ @using Unity.GrantManager.Localization; @using Microsoft.Extensions.Localization; @using Unity.GrantManager.Web.Views.Shared.Components.ApplicationActionWidget; +@using Unity.GrantManager.Web.Views.Shared.Components.DetailsActionBar; @inject IStringLocalizer L +@model DetailsActionBarViewModel
@await Component.InvokeAsync(typeof(ApplicationActionWidget), new { applicationId = @Model.ApplicationId })
- @* Items are included here through the Review List JS*@ +
{ + if (!result.isConfirmed) { + return; + } + + let nextPublishedState = !isPublished; + + unity.grantManager.grantApplications.grantApplication + .updateExternalStatusVisibility(selectedApplicationIds, nextPublishedState) + .then(function () { + $publishButton.attr('data-is-published', nextPublishedState.toString()); + $publishButton.text(nextPublishedState + ? l('DetailsActionBar:UnpublishButton') + : l('DetailsActionBar:PublishButton')); + + abp.notify.success(l('DetailsActionBar:PublishStatusUpdated')); + PubSub.publish('application_status_changed', nextPublishedState ? 'Publish' : 'Unpublish'); + PubSub.publish('refresh_detail_panel_summary'); + }) + .catch(function (error) { + abp.notify.error(l('DetailsActionBar:PublishStatusUpdateFailed')); + console.error('Error updating publish status:', error); + }); + }); + }); + + function getPublishConfirmationDetails(isPublished) { + return { + title: l('DetailsActionBar:ConfirmActionTitle'), + text: isPublished + ? l('DetailsActionBar:UnpublishConfirmationText') + : l('DetailsActionBar:PublishConfirmationText'), + confirmButtonText: l('DetailsActionBar:ConfirmButton') + }; + } }); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/DetailsActionBar/DetailsActionBar.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/DetailsActionBar/DetailsActionBar.cs index 03c0ece84f..dc9893a026 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/DetailsActionBar/DetailsActionBar.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/DetailsActionBar/DetailsActionBar.cs @@ -1,5 +1,9 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using System; +using System.Threading.Tasks; +using Unity.GrantManager.GrantApplications; +using Unity.Modules.Shared; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.UI.Widgets; @@ -12,9 +16,29 @@ public class DetailsActionBar : AbpViewComponent [BindProperty] public Guid SelectedApplicationId { get; set; } - public IViewComponentResult Invoke(Guid applicationId) + private readonly IGrantApplicationAppService _grantApplicationAppService; + private readonly IAuthorizationService _authorizationService; + + public DetailsActionBar( + IGrantApplicationAppService grantApplicationAppService, + IAuthorizationService authorizationService) + { + _grantApplicationAppService = grantApplicationAppService; + _authorizationService = authorizationService; + } + + public async Task InvokeAsync(Guid applicationId) { SelectedApplicationId = applicationId; - return View(); + + var application = await _grantApplicationAppService.GetAsync(applicationId); + var canUpdateExternalStatusVisibility = await _authorizationService.IsGrantedAsync(UnitySelector.Review.AssessmentResults.Update.Default); + + return View(new DetailsActionBarViewModel + { + ApplicationId = applicationId, + ExternalStatusVisibility = application.ExternalStatusVisibility, + CanUpdateExternalStatusVisibility = canUpdateExternalStatusVisibility + }); } } \ No newline at end of file diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/DetailsActionBar/DetailsActionBarViewModel.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/DetailsActionBar/DetailsActionBarViewModel.cs new file mode 100644 index 0000000000..9bb87e8c81 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/DetailsActionBar/DetailsActionBarViewModel.cs @@ -0,0 +1,10 @@ +using System; + +namespace Unity.GrantManager.Web.Views.Shared.Components.DetailsActionBar; + +public class DetailsActionBarViewModel +{ + public Guid ApplicationId { get; set; } + public bool ExternalStatusVisibility { get; set; } + public bool CanUpdateExternalStatusVisibility { get; set; } +} From 8ca2445fc54d8a96756800f3390f0f7f1bd53b11 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:10:04 -0700 Subject: [PATCH 14/61] [AB#33555] Update database connection ports in appsettings --- .../src/Unity.GrantManager.DbMigrator/appsettings.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json index 9239fc32ef..79b4f9af85 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json @@ -1,8 +1,8 @@ { "ConnectionStrings": { - "Default": "Host=localhost;port=5435;Database=UnityGrantManager;Username=postgres;Password=admin", - "Tenant": "Host=localhost;port=5435;Database=UnityGrantTenant;Username=postgres;Password=admin", - "Onboarding": "Host=localhost;port=5435;Database=Onboarding;Username=postgres;Password=admin" + "Default": "Host=localhost;port=5432;Database=UnityGrantManager;Username=postgres", + "Tenant": "Host=localhost;port=5432;Database=UnityGrantTenant;Username=postgres", + "Onboarding": "Host=localhost;port=5432;Database=Onboarding;Username=postgres" }, "StringEncryption": { "DefaultPassPhrase": "g2IuZx7PwXDvCmlW" From 64e25f146f06d8c8d64acb27e779f0a7ea1c493d Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Tue, 30 Jun 2026 07:59:11 -0700 Subject: [PATCH 15/61] [AB#33555] Revert EF migration for fix --- ...lStatusVisibilityToApplication.Designer.cs | 5230 ----------------- ...ddExternalStatusVisibilityToApplication.cs | 29 - .../GrantTenantDbContextModelSnapshot.cs | 157 - 3 files changed, 5416 deletions(-) delete mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.Designer.cs delete mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.cs diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.Designer.cs deleted file mode 100644 index e1d38ed77f..0000000000 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.Designer.cs +++ /dev/null @@ -1,5230 +0,0 @@ -// -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("20260629164239_AB33555_AddExternalStatusVisibilityToApplication")] - partial class AB33555_AddExternalStatusVisibilityToApplication - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) - .HasAnnotation("ProductVersion", "10.0.3") - .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("IsArchived") - .HasColumnType("boolean"); - - 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("IsArchived") - .HasColumnType("boolean"); - - 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("Definition") - .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("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("AuditComments") - .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("DeleterId") - .HasColumnType("uuid"); - - b.Property("DeletionTime") - .HasColumnType("timestamp without time zone"); - - b.Property("ExtraProperties") - .IsRequired() - .HasColumnType("text") - .HasColumnName("ExtraProperties"); - - b.Property("FiscalDay") - .HasColumnType("integer"); - - b.Property("FiscalMonth") - .HasColumnType("text"); - - b.Property("FundingHistoryComments") - .HasColumnType("text"); - - b.Property("IndigenousOrgInd") - .HasColumnType("text"); - - b.Property("IsDeleted") - .HasColumnType("boolean"); - - b.Property("IsDuplicated") - .HasColumnType("boolean"); - - b.Property("IssueTrackingComments") - .HasColumnType("text"); - - 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("OrganizationType") - .HasColumnType("text"); - - b.Property("RedStop") - .HasColumnType("boolean"); - - b.Property("ReportsComments") - .HasColumnType("text"); - - b.Property("Sector") - .HasColumnType("text"); - - b.Property("SectorSubSectorIndustryDesc") - .HasColumnType("text"); - - 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.HasIndex("OrgName"); - - b.HasIndex("OrgNumber"); - - b.HasIndex("Status"); - - b.HasIndex("SupplierId"); - - b.HasIndex("TenantId"); - - b.HasIndex("UnityApplicantId"); - - b.HasIndex("TenantId", "IsDeleted", "CreationTime") - .HasFilter("\"IsDeleted\" = false"); - - 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.HasIndex("TenantId", "ApplicationId"); - - b.ToTable("ApplicantAgents", (string)null); - }); - - modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAttachment", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("ApplicantId") - .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("ApplicantId"); - - b.ToTable("ApplicantAttachments", (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("DefaultSiteId") - .HasColumnType("uuid"); - - 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("ExternalStatusVisibility") - .HasColumnType("boolean"); - - 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.HasIndex("ReferenceNo"); - - b.HasIndex("TenantId", "SubmissionDate") - .HasFilter("\"IsDeleted\" = false"); - - 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.HasIndex("TenantId", "ApplicationId"); - - 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("AutomaticallyGenerateAIAnalysis") - .HasColumnType("boolean"); - - 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("ManuallyInitiateAIAnalysis") - .HasColumnType("boolean"); - - b.Property("ParentFormId") - .HasColumnType("uuid"); - - b.Property("Payable") - .HasColumnType("boolean"); - - b.Property("PaymentApprovalThreshold") - .HasColumnType("numeric"); - - b.Property("Prefix") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("PreventPayment") - .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.HasIndex("TenantId", "IsDeleted") - .HasFilter("\"IsDeleted\" = false"); - - 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("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.HasIndex("TenantId", "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("NotifiedStatus") - .HasColumnType("text"); - - 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.HasIndex("TenantId", "ApplicationId"); - - 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.Applications.AuditHistory", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("ApplicantId") - .HasColumnType("uuid"); - - b.Property("AuditDate") - .HasColumnType("timestamp without time zone"); - - b.Property("AuditNote") - .HasColumnType("text"); - - b.Property("AuditStatus") - .HasColumnType("text"); - - b.Property("AuditTrackingNumber") - .HasColumnType("text"); - - b.Property("AuditorName") - .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("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("ApplicantId"); - - b.ToTable("AuditHistories", (string)null); - }); - - modelBuilder.Entity("Unity.GrantManager.Applications.FundingHistory", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("ApplicantId") - .HasColumnType("uuid"); - - b.Property("ApprovedAmount") - .HasColumnType("numeric"); - - 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("FundingNotes") - .HasColumnType("text"); - - b.Property("FundingYear") - .HasColumnType("text"); - - b.Property("GrantCategory") - .HasColumnType("text"); - - b.Property("LastModificationTime") - .HasColumnType("timestamp without time zone") - .HasColumnName("LastModificationTime"); - - b.Property("LastModifierId") - .HasColumnType("uuid") - .HasColumnName("LastModifierId"); - - b.Property("OneTimeConsideration") - .HasColumnType("numeric"); - - b.Property("PaidDate") - .HasColumnType("timestamp without time zone"); - - b.Property("ReconsiderationAmount") - .HasColumnType("numeric"); - - b.Property("RenewedFunding") - .HasColumnType("boolean"); - - b.Property("TenantId") - .HasColumnType("uuid") - .HasColumnName("TenantId"); - - b.Property("TotalGrantAmount") - .HasColumnType("numeric"); - - b.HasKey("Id"); - - b.HasIndex("ApplicantId"); - - b.ToTable("FundingHistories", (string)null); - }); - - modelBuilder.Entity("Unity.GrantManager.Applications.IssueTracking", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("ApplicantId") - .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("IssueDescription") - .HasColumnType("text"); - - b.Property("IssueHeading") - .HasColumnType("text"); - - b.Property("LastModificationTime") - .HasColumnType("timestamp without time zone") - .HasColumnName("LastModificationTime"); - - b.Property("LastModifierId") - .HasColumnType("uuid") - .HasColumnName("LastModifierId"); - - b.Property("ResolutionNote") - .HasColumnType("text"); - - b.Property("Resolved") - .HasColumnType("boolean"); - - b.Property("TenantId") - .HasColumnType("uuid") - .HasColumnName("TenantId"); - - b.Property("Year") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ApplicantId"); - - b.ToTable("IssueTrackings", (string)null); - }); - - modelBuilder.Entity("Unity.GrantManager.Applications.ReportsHistory", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("ApplicantId") - .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("FiscalYear") - .HasColumnType("text"); - - b.Property("IncompleteReport") - .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("Outstanding") - .HasColumnType("boolean"); - - b.Property("ReportDate") - .HasColumnType("timestamp without time zone"); - - b.Property("TenantId") - .HasColumnType("uuid") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("ApplicantId"); - - b.ToTable("ReportsHistories", (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("IsAiAssessment") - .HasColumnType("boolean"); - - 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.ApplicantComment", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("ApplicantId") - .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("ApplicantId"); - - b.HasIndex("CommenterId"); - - b.ToTable("ApplicantComments", (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.HasIndex("TenantId"); - - 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.GrantManager.Notifications.ScheduledNotification", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("ApplicationStatus") - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("ApplicationStatusId") - .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("DateField") - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("DeleterId") - .HasColumnType("uuid") - .HasColumnName("DeleterId"); - - b.Property("DeletionTime") - .HasColumnType("timestamp without time zone") - .HasColumnName("DeletionTime"); - - b.Property("EmailTemplateId") - .HasColumnType("uuid"); - - b.Property("EventType") - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("ExtraProperties") - .IsRequired() - .HasColumnType("text") - .HasColumnName("ExtraProperties"); - - b.Property("FormId") - .HasColumnType("uuid"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - 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("RecipientCategory") - .HasColumnType("text"); - - b.Property("RecipientIdentifier") - .HasColumnType("text"); - - b.Property("TenantId") - .HasColumnType("uuid") - .HasColumnName("TenantId"); - - b.Property("TriggerDetail") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("TriggerType") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ScheduledNotifications", "Notifications"); - }); - - modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotificationTracking", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("ApplicationId") - .HasColumnType("uuid"); - - b.Property("CreationTime") - .HasColumnType("timestamp without time zone"); - - b.Property("CreatorId") - .HasColumnType("uuid"); - - b.Property("DateField") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("NotificationSentDate") - .HasColumnType("timestamp without time zone"); - - b.Property("ScheduledNotificationId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("ApplicationId"); - - b.HasIndex("CreationTime"); - - b.HasIndex("ScheduledNotificationId"); - - b.HasIndex("ApplicationId", "ScheduledNotificationId", "DateField") - .IsUnique(); - - b.ToTable("ScheduledNotificationTracking", "Notifications"); - }); - - 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("EmailType") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - 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("Recipient") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("RetryAttempts") - .HasColumnType("integer"); - - b.Property("ScheduledNotificationId") - .HasColumnType("uuid"); - - 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("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.ApplicantAttachment", b => - { - b.HasOne("Unity.GrantManager.Applications.Applicant", null) - .WithMany() - .HasForeignKey("ApplicantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - 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("ApplicationLinks") - .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.Applications.AuditHistory", b => - { - b.HasOne("Unity.GrantManager.Applications.Applicant", null) - .WithMany() - .HasForeignKey("ApplicantId"); - }); - - modelBuilder.Entity("Unity.GrantManager.Applications.FundingHistory", b => - { - b.HasOne("Unity.GrantManager.Applications.Applicant", null) - .WithMany() - .HasForeignKey("ApplicantId"); - }); - - modelBuilder.Entity("Unity.GrantManager.Applications.IssueTracking", b => - { - b.HasOne("Unity.GrantManager.Applications.Applicant", null) - .WithMany() - .HasForeignKey("ApplicantId"); - }); - - modelBuilder.Entity("Unity.GrantManager.Applications.ReportsHistory", b => - { - b.HasOne("Unity.GrantManager.Applications.Applicant", null) - .WithMany() - .HasForeignKey("ApplicantId"); - }); - - 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.ApplicantComment", b => - { - b.HasOne("Unity.GrantManager.Applications.Applicant", null) - .WithMany() - .HasForeignKey("ApplicantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Unity.GrantManager.Identity.Person", null) - .WithMany() - .HasForeignKey("CommenterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - 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.GrantManager.Notifications.ScheduledNotificationTracking", b => - { - b.HasOne("Unity.GrantManager.Applications.Application", null) - .WithMany() - .HasForeignKey("ApplicationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Unity.GrantManager.Notifications.ScheduledNotification", null) - .WithMany() - .HasForeignKey("ScheduledNotificationId") - .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); - - 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("ApplicationLinks"); - - 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/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.cs deleted file mode 100644 index dde7768fba..0000000000 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260629164239_AB33555_AddExternalStatusVisibilityToApplication.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Unity.GrantManager.Migrations.TenantMigrations -{ - /// - public partial class AB33555_AddExternalStatusVisibilityToApplication : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "ExternalStatusVisibility", - table: "Applications", - type: "boolean", - nullable: false, - defaultValue: false); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "ExternalStatusVisibility", - table: "Applications"); - } - } -} 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 eabfeae2ed..396dd9ff5b 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 @@ -1290,9 +1290,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ElectoralDistrict") .HasColumnType("text"); - b.Property("ExternalStatusVisibility") - .HasColumnType("boolean"); - b.Property("ExtraProperties") .IsRequired() .HasColumnType("text") @@ -3050,142 +3047,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Intakes", (string)null); }); - modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotification", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("ApplicationStatus") - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("ApplicationStatusId") - .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("DateField") - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("DeleterId") - .HasColumnType("uuid") - .HasColumnName("DeleterId"); - - b.Property("DeletionTime") - .HasColumnType("timestamp without time zone") - .HasColumnName("DeletionTime"); - - b.Property("EmailTemplateId") - .HasColumnType("uuid"); - - b.Property("EventType") - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("ExtraProperties") - .IsRequired() - .HasColumnType("text") - .HasColumnName("ExtraProperties"); - - b.Property("FormId") - .HasColumnType("uuid"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - 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("RecipientCategory") - .HasColumnType("text"); - - b.Property("RecipientIdentifier") - .HasColumnType("text"); - - b.Property("TenantId") - .HasColumnType("uuid") - .HasColumnName("TenantId"); - - b.Property("TriggerDetail") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("TriggerType") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Id"); - - b.HasIndex("TenantId"); - - b.ToTable("ScheduledNotifications", "Notifications"); - }); - - modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotificationTracking", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("ApplicationId") - .HasColumnType("uuid"); - - b.Property("CreationTime") - .HasColumnType("timestamp without time zone"); - - b.Property("CreatorId") - .HasColumnType("uuid"); - - b.Property("DateField") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("NotificationSentDate") - .HasColumnType("timestamp without time zone"); - - b.Property("ScheduledNotificationId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("ApplicationId"); - - b.HasIndex("CreationTime"); - - b.HasIndex("ScheduledNotificationId"); - - b.HasIndex("ApplicationId", "ScheduledNotificationId", "DateField") - .IsUnique(); - - b.ToTable("ScheduledNotificationTracking", "Notifications"); - }); - modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroup", b => { b.Property("Id") @@ -3388,9 +3249,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("RetryAttempts") .HasColumnType("integer"); - b.Property("ScheduledNotificationId") - .HasColumnType("uuid"); - b.Property("SendOnDateTime") .HasColumnType("timestamp without time zone"); @@ -5015,21 +4873,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); - modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotificationTracking", b => - { - b.HasOne("Unity.GrantManager.Applications.Application", null) - .WithMany() - .HasForeignKey("ApplicationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Unity.GrantManager.Notifications.ScheduledNotification", null) - .WithMany() - .HasForeignKey("ScheduledNotificationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroupUser", b => { b.HasOne("Unity.Notifications.EmailGroups.EmailGroup", null) From 8695b8c0f09b44e0502f38829aab73b077dfe342 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Tue, 30 Jun 2026 08:48:52 -0700 Subject: [PATCH 16/61] [AB#33555] Add back ExternalStatusVisibility migration --- ...lStatusVisibilityToApplication.Designer.cs | 5239 +++++++++++++++++ ...ddExternalStatusVisibilityToApplication.cs | 29 + .../GrantTenantDbContextModelSnapshot.cs | 157 + 3 files changed, 5425 insertions(+) create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630150247_AB33555_AddExternalStatusVisibilityToApplication.Designer.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630150247_AB33555_AddExternalStatusVisibilityToApplication.cs diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630150247_AB33555_AddExternalStatusVisibilityToApplication.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630150247_AB33555_AddExternalStatusVisibilityToApplication.Designer.cs new file mode 100644 index 0000000000..c7835d268d --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630150247_AB33555_AddExternalStatusVisibilityToApplication.Designer.cs @@ -0,0 +1,5239 @@ +// +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("20260630150247_AB33555_AddExternalStatusVisibilityToApplication")] + partial class AB33555_AddExternalStatusVisibilityToApplication + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "10.0.3") + .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("IsArchived") + .HasColumnType("boolean"); + + 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("IsArchived") + .HasColumnType("boolean"); + + 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("Definition") + .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("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("AuditComments") + .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("DeleterId") + .HasColumnType("uuid"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FiscalDay") + .HasColumnType("integer"); + + b.Property("FiscalMonth") + .HasColumnType("text"); + + b.Property("FundingHistoryComments") + .HasColumnType("text"); + + b.Property("IndigenousOrgInd") + .HasColumnType("text"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("IsDuplicated") + .HasColumnType("boolean"); + + b.Property("IssueTrackingComments") + .HasColumnType("text"); + + 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("OrganizationType") + .HasColumnType("text"); + + b.Property("RedStop") + .HasColumnType("boolean"); + + b.Property("ReportsComments") + .HasColumnType("text"); + + b.Property("Sector") + .HasColumnType("text"); + + b.Property("SectorSubSectorIndustryDesc") + .HasColumnType("text"); + + 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.HasIndex("OrgName"); + + b.HasIndex("OrgNumber"); + + b.HasIndex("Status"); + + b.HasIndex("SupplierId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UnityApplicantId"); + + b.HasIndex("TenantId", "IsDeleted", "CreationTime") + .HasFilter("\"IsDeleted\" = false"); + + 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.HasIndex("TenantId", "ApplicationId"); + + b.ToTable("ApplicantAgents", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .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("ApplicantId"); + + b.ToTable("ApplicantAttachments", (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("DefaultSiteId") + .HasColumnType("uuid"); + + 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("ExternalStatusVisibility") + .HasColumnType("boolean"); + + 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.HasIndex("ReferenceNo"); + + b.HasIndex("TenantId", "SubmissionDate") + .HasFilter("\"IsDeleted\" = false"); + + 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.HasIndex("TenantId", "ApplicationId"); + + 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("AutomaticallyGenerateAIAnalysis") + .HasColumnType("boolean"); + + 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("ManuallyInitiateAIAnalysis") + .HasColumnType("boolean"); + + b.Property("ParentFormId") + .HasColumnType("uuid"); + + b.Property("Payable") + .HasColumnType("boolean"); + + b.Property("PaymentApprovalThreshold") + .HasColumnType("numeric"); + + b.Property("Prefix") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PreventPayment") + .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.HasIndex("TenantId", "IsDeleted") + .HasFilter("\"IsDeleted\" = false"); + + 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("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.HasIndex("TenantId", "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("NotifiedStatus") + .HasColumnType("text"); + + 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.HasIndex("TenantId", "ApplicationId"); + + 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.Applications.AuditHistory", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("AuditDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AuditNote") + .HasColumnType("text"); + + b.Property("AuditStatus") + .HasColumnType("text"); + + b.Property("AuditTrackingNumber") + .HasColumnType("text"); + + b.Property("AuditorName") + .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("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("ApplicantId"); + + b.ToTable("AuditHistories", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.FundingHistory", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApprovedAmount") + .HasColumnType("numeric"); + + 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("FundingNotes") + .HasColumnType("text"); + + b.Property("FundingYear") + .HasColumnType("text"); + + b.Property("GrantCategory") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OneTimeConsideration") + .HasColumnType("numeric"); + + b.Property("PaidDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ReconsiderationAmount") + .HasColumnType("numeric"); + + b.Property("RenewedFunding") + .HasColumnType("boolean"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TotalGrantAmount") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("FundingHistories", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.IssueTracking", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .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("IssueDescription") + .HasColumnType("text"); + + b.Property("IssueHeading") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ResolutionNote") + .HasColumnType("text"); + + b.Property("Resolved") + .HasColumnType("boolean"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Year") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("IssueTrackings", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ReportsHistory", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .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("FiscalYear") + .HasColumnType("text"); + + b.Property("IncompleteReport") + .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("Outstanding") + .HasColumnType("boolean"); + + b.Property("ReportDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("ReportsHistories", (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("IsAiAssessment") + .HasColumnType("boolean"); + + 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.ApplicantComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .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("ApplicantId"); + + b.HasIndex("CommenterId"); + + b.ToTable("ApplicantComments", (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.HasIndex("TenantId"); + + 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.GrantManager.Notifications.ScheduledNotification", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationStatus") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ApplicationStatusId") + .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("DateField") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EmailTemplateId") + .HasColumnType("uuid"); + + b.Property("EventType") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormId") + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + 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("RecipientCategory") + .HasColumnType("text"); + + b.Property("RecipientIdentifier") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TriggerDetail") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("TriggerType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ScheduledNotifications", "Notifications"); + }); + + modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotificationTracking", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("DateField") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NotificationSentDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ScheduledNotificationId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("CreationTime"); + + b.HasIndex("ScheduledNotificationId"); + + b.HasIndex("ApplicationId", "ScheduledNotificationId", "DateField") + .IsUnique(); + + b.ToTable("ScheduledNotificationTracking", "Notifications"); + }); + + 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("EmailType") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + 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("Recipient") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("RetryAttempts") + .HasColumnType("integer"); + + b.Property("ScheduledNotificationId") + .HasColumnType("uuid"); + + 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("CorrelationId"); + + b.HasIndex("CreationTime"); + + b.HasIndex("FsbNotificationEmailLogId"); + + b.HasIndex("ReferenceNumber") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.HasIndex("Status"); + + b.HasIndex("TenantId", "CreationTime") + .HasFilter("\"IsDeleted\" = false"); + + 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("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.ApplicantAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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("ApplicationLinks") + .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.Applications.AuditHistory", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.FundingHistory", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.IssueTracking", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ReportsHistory", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId"); + }); + + 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.ApplicantComment", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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.GrantManager.Notifications.ScheduledNotificationTracking", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Notifications.ScheduledNotification", null) + .WithMany() + .HasForeignKey("ScheduledNotificationId") + .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); + + 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("ApplicationLinks"); + + 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/20260630150247_AB33555_AddExternalStatusVisibilityToApplication.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630150247_AB33555_AddExternalStatusVisibilityToApplication.cs new file mode 100644 index 0000000000..dde7768fba --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630150247_AB33555_AddExternalStatusVisibilityToApplication.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + /// + public partial class AB33555_AddExternalStatusVisibilityToApplication : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ExternalStatusVisibility", + table: "Applications", + type: "boolean", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ExternalStatusVisibility", + table: "Applications"); + } + } +} 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 38dad53484..f702d3824d 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 @@ -1290,6 +1290,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ElectoralDistrict") .HasColumnType("text"); + b.Property("ExternalStatusVisibility") + .HasColumnType("boolean"); + b.Property("ExtraProperties") .IsRequired() .HasColumnType("text") @@ -3047,6 +3050,142 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Intakes", (string)null); }); + modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotification", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationStatus") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ApplicationStatusId") + .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("DateField") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EmailTemplateId") + .HasColumnType("uuid"); + + b.Property("EventType") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormId") + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + 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("RecipientCategory") + .HasColumnType("text"); + + b.Property("RecipientIdentifier") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TriggerDetail") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("TriggerType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ScheduledNotifications", "Notifications"); + }); + + modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotificationTracking", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("DateField") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NotificationSentDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ScheduledNotificationId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("CreationTime"); + + b.HasIndex("ScheduledNotificationId"); + + b.HasIndex("ApplicationId", "ScheduledNotificationId", "DateField") + .IsUnique(); + + b.ToTable("ScheduledNotificationTracking", "Notifications"); + }); + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroup", b => { b.Property("Id") @@ -3249,6 +3388,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("RetryAttempts") .HasColumnType("integer"); + b.Property("ScheduledNotificationId") + .HasColumnType("uuid"); + b.Property("SendOnDateTime") .HasColumnType("timestamp without time zone"); @@ -4882,6 +5024,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotificationTracking", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Notifications.ScheduledNotification", null) + .WithMany() + .HasForeignKey("ScheduledNotificationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroupUser", b => { b.HasOne("Unity.Notifications.EmailGroups.EmailGroup", null) From fac7855d59fc97350442e88178b6baf15098f66f Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Tue, 30 Jun 2026 09:37:25 -0700 Subject: [PATCH 17/61] [AB#33555] Fix connection string edit --- .../src/Unity.GrantManager.DbMigrator/appsettings.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json index 79b4f9af85..2d97676b33 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json @@ -1,8 +1,8 @@ { "ConnectionStrings": { - "Default": "Host=localhost;port=5432;Database=UnityGrantManager;Username=postgres", - "Tenant": "Host=localhost;port=5432;Database=UnityGrantTenant;Username=postgres", - "Onboarding": "Host=localhost;port=5432;Database=Onboarding;Username=postgres" + "Default": "Host=localhost;port=5432;Database=UnityGrantManager;Username=postgres;", + "Tenant": "Host=localhost;port=5432;Database=UnityGrantTenant;Username=postgres;", + "Onboarding": "Host=localhost;port=5432;Database=Onboarding;Username=postgres;" }, "StringEncryption": { "DefaultPassPhrase": "g2IuZx7PwXDvCmlW" From cb56da6dea96d3b21c565349802ac88344dd9b21 Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Tue, 30 Jun 2026 12:20:47 -0700 Subject: [PATCH 18/61] AB#32307 repair AI schema and seeding --- .../AI/Runtime/OpenAIConfigurationResolver.cs | 3 +- .../DataSeed/AIDataSeeder.cs | 18 ++ .../DataSeed/AIModelDataSeeder.cs | 91 +++----- .../DataSeed/AIOperationDataSeeder.cs | 180 ++++++--------- .../DataSeed/AIPromptDataSeeder.cs | 2 +- .../AIGenerationRequestDto.cs | 2 +- .../AIGenerationStatusAppService.cs | 2 +- .../GrantApplications/AIGenerationRequest.cs | 2 +- .../GrantManagerDbContext.cs | 20 +- .../20260624191335_RefreshAiSchema.cs | 212 +++++++++++------- 10 files changed, 254 insertions(+), 278 deletions(-) create mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIDataSeeder.cs diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIConfigurationResolver.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIConfigurationResolver.cs index be191ce6f3..5b3cc353f9 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIConfigurationResolver.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Runtime/OpenAIConfigurationResolver.cs @@ -256,8 +256,7 @@ private static AIModelSettings ResolveModelSettings(AIModel model) } } - return activeModels.FirstOrDefault(model => - string.Equals(model.Name, "Default", StringComparison.OrdinalIgnoreCase)); + return null; } private string Required(string key) diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIDataSeeder.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIDataSeeder.cs new file mode 100644 index 0000000000..07b0a29f08 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIDataSeeder.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; + +namespace Unity.AI.DataSeed; + +public class AIDataSeeder( + AIPromptDataSeeder promptDataSeeder, + AIModelDataSeeder modelDataSeeder, + AIOperationDataSeeder operationDataSeeder) : IDataSeedContributor, ITransientDependency +{ + public async Task SeedAsync(DataSeedContext context) + { + await promptDataSeeder.SeedAsync(context); + await modelDataSeeder.SeedAsync(context); + await operationDataSeeder.SeedAsync(context); + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIModelDataSeeder.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIModelDataSeeder.cs index 68cce573ed..facd43663e 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIModelDataSeeder.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIModelDataSeeder.cs @@ -1,12 +1,8 @@ using System; using System.Collections.Generic; -using System.Globalization; -using System.Linq; using System.Text.Json; using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; using Unity.AI.Domain; -using Unity.AI.Prompts; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; @@ -14,9 +10,15 @@ namespace Unity.AI.DataSeed; public class AIModelDataSeeder( - IRepository modelRepository, - IConfiguration configuration) : IDataSeedContributor, ITransientDependency + IRepository modelRepository) : ITransientDependency { + private static readonly BuiltInModelDefinition[] BuiltInModels = + [ + new("Gpt4oMini", true, 0.3d), + new("Gpt5Mini", false, null), + new("Gpt5Nano", false, null) + ]; + public async Task SeedAsync(DataSeedContext context) { if (context.TenantId != null) @@ -24,48 +26,21 @@ public async Task SeedAsync(DataSeedContext context) return; } - var providerName = Optional("Azure:Operations:Defaults:Provider"); - var defaultProfileName = Optional("Azure:Operations:Defaults:Profile"); - if (providerName == null || defaultProfileName == null) - { - return; - } - - var profilesSection = configuration.GetSection($"Azure:{providerName}:Profiles"); - var profileNames = profilesSection - .GetChildren() - .Select(section => section.Key) - .Where(name => !string.IsNullOrWhiteSpace(name)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - if (!profileNames.Contains(defaultProfileName, StringComparer.OrdinalIgnoreCase)) + foreach (var model in BuiltInModels) { - profileNames.Add(defaultProfileName); - } - - foreach (var profileName in profileNames) - { - var deploymentName = Optional($"Azure:{providerName}:Profiles:{profileName}:DeploymentName"); - if (deploymentName == null) - { - continue; - } - - await EnsureModelAsync( - profileName, - new AIModelSettings - { - MaxOutputTokenCountSupported = OptionalBool($"Azure:{providerName}:Profiles:{profileName}:MaxOutputTokenCountSupported") ?? true, - Temperature = OptionalDouble($"Azure:{providerName}:Profiles:{profileName}:Temperature") - }); + await EnsureModelAsync(model); } - } - private async Task EnsureModelAsync(string modelName, AIModelSettings settings) + private async Task EnsureModelAsync(BuiltInModelDefinition definition) { - var existing = await modelRepository.FirstOrDefaultAsync(model => model.Name == modelName); + var settings = new AIModelSettings + { + MaxOutputTokenCountSupported = definition.MaxOutputTokenCountSupported, + Temperature = definition.Temperature + }; + + var existing = await modelRepository.FirstOrDefaultAsync(model => model.Name == definition.Name); if (existing != null) { existing.IsActive = true; @@ -75,32 +50,16 @@ private async Task EnsureModelAsync(string modelName, AIModelSettings settings) } await modelRepository.InsertAsync( - new AIModel(Guid.CreateVersion7(), modelName) + new AIModel(Guid.CreateVersion7(), definition.Name) { IsActive = true, SettingsJson = JsonSerializer.Serialize(settings) - }); - } - - private string? Optional(string key) - { - var value = configuration[key]; - return string.IsNullOrWhiteSpace(value) ? null : value.Trim(); + }, + autoSave: true); } - private bool? OptionalBool(string key) - { - var value = Optional(key); - return value != null && bool.TryParse(value, out var parsedValue) - ? parsedValue - : null; - } - - private double? OptionalDouble(string key) - { - var value = Optional(key); - return value != null && double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsedValue) - ? parsedValue - : null; - } + private sealed record BuiltInModelDefinition( + string Name, + bool MaxOutputTokenCountSupported, + double? Temperature); } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIOperationDataSeeder.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIOperationDataSeeder.cs index ed22ba9ca4..18d3da31e9 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIOperationDataSeeder.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIOperationDataSeeder.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System.Threading.Tasks; using Unity.AI.Domain; using Unity.AI.Operations; using Unity.AI.Prompts; +using Unity.GrantManager.GrantApplications; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; @@ -18,12 +18,19 @@ public class AIOperationDataSeeder( IRepository operationRepository, IRepository modelRepository, IRepository promptRepository, - IConfiguration configuration, + IRepository requestRepository, ICurrentTenant currentTenant, - ILogger logger) : IDataSeedContributor, ITransientDependency + ILogger logger) : ITransientDependency { - private const string DefaultOperationName = "Default"; - private const string DefaultOperationPromptType = AIPromptTypes.ApplicationAnalysis; + private const string DefaultModelName = "Gpt5Mini"; + + private static readonly BuiltInOperationDefinition[] BuiltInOperations = + [ + new("Default", AIPromptTypes.ApplicationAnalysis, 4000, true), + new(AIPromptTypes.ApplicationAnalysis, AIPromptTypes.ApplicationAnalysis, 4000), + new(AIPromptTypes.AttachmentSummary, AIPromptTypes.AttachmentSummary, 2000), + new(AIPromptTypes.ApplicationScoring, AIPromptTypes.ApplicationScoring, 8000) + ]; public async Task SeedAsync(DataSeedContext context) { @@ -34,124 +41,64 @@ public async Task SeedAsync(DataSeedContext context) using (currentTenant.Change(null)) { - var model = await EnsureConfiguredDefaultModelAsync(); + var model = await EnsureModelAsync(DefaultModelName); if (model == null) { - logger.LogWarning("AI operation seeding skipped: no model is configured. Check Azure:Operations:Defaults:Provider and Azure:Operations:Defaults:Profile settings."); + logger.LogWarning("AI operation seeding skipped: model '{ModelName}' is missing.", DefaultModelName); return; } - await EnsureOperationAsync(DefaultOperationName, DefaultOperationPromptType, model, isDefaultOperation: true); - await EnsureOperationAsync(AIPromptTypes.ApplicationAnalysis, AIPromptTypes.ApplicationAnalysis, model); - await EnsureOperationAsync(AIPromptTypes.AttachmentSummary, AIPromptTypes.AttachmentSummary, model); - await EnsureOperationAsync(AIPromptTypes.ApplicationScoring, AIPromptTypes.ApplicationScoring, model); + foreach (var definition in BuiltInOperations) + { + await EnsureOperationAsync(definition, model); + } + + await BackfillRequestOperationIdsAsync(); } } - private async Task EnsureOperationAsync( - string operationName, - string promptName, - AIModel model, - bool isDefaultOperation = false) + private async Task EnsureOperationAsync(BuiltInOperationDefinition definition, AIModel model) { - var prompt = await ResolveLatestActivePromptAsync(promptName); + var prompt = await ResolveLatestActivePromptAsync(definition.PromptName); if (prompt == null) { - if (isDefaultOperation) - { - logger.LogWarning("AI default operation seeding skipped: no active prompt found for '{PromptName}'.", promptName); - } - else - { - logger.LogWarning("AI operation seeding skipped: no active prompt found for operation '{OperationName}' and prompt '{PromptName}'.", operationName, promptName); - } - return; - } - - var completionTokens = ResolveCompletionTokens(promptName); - if (completionTokens == null) - { - if (isDefaultOperation) + if (definition.IsDefaultOperation) { - logger.LogWarning("AI default operation seeding skipped: MaxCompletionTokens not configured for '{PromptName}'.", promptName); + logger.LogWarning("AI default operation seeding skipped: no active prompt found for '{PromptName}'.", definition.PromptName); } else { - logger.LogWarning("AI operation seeding skipped: MaxCompletionTokens not configured for operation '{OperationName}' (prompt '{PromptName}').", operationName, promptName); + logger.LogWarning("AI operation seeding skipped: no active prompt found for operation '{OperationName}' and prompt '{PromptName}'.", definition.OperationName, definition.PromptName); } return; } - var existing = await operationRepository.FirstOrDefaultAsync(op => op.Name == operationName); + var existing = await operationRepository.FirstOrDefaultAsync(op => op.Name == definition.OperationName); if (existing != null) { existing.AIModelId = model.Id; existing.AIPromptId = prompt.Id; existing.ExecutionMode = AIExecutionMode.Sequential; - existing.CompletionTokens = completionTokens.Value; + existing.CompletionTokens = definition.CompletionTokens; existing.IsActive = true; await operationRepository.UpdateAsync(existing); return; } await operationRepository.InsertAsync( - new AIOperation(Guid.CreateVersion7(), operationName, model.Id, prompt.Id) + new AIOperation(Guid.CreateVersion7(), definition.OperationName, model.Id, prompt.Id) { ExecutionMode = AIExecutionMode.Sequential, - CompletionTokens = completionTokens.Value, + CompletionTokens = definition.CompletionTokens, IsActive = true - }); + }, + autoSave: true); } - private async Task EnsureConfiguredDefaultModelAsync() + private async Task EnsureModelAsync(string modelName) { - var providerName = Optional("Azure:Operations:Defaults:Provider"); - var profileName = Optional("Azure:Operations:Defaults:Profile"); - if (providerName == null || profileName == null) - { - return null; - } - - var deploymentName = Optional($"Azure:{providerName}:Profiles:{profileName}:DeploymentName"); - if (deploymentName == null) - { - return null; - } - - var existing = await modelRepository.FirstOrDefaultAsync(model => model.Name == profileName && model.IsActive); - if (existing != null) - { - existing.SettingsJson = System.Text.Json.JsonSerializer.Serialize(new AIModelSettings - { - MaxOutputTokenCountSupported = OptionalBool($"Azure:{providerName}:Profiles:{profileName}:MaxOutputTokenCountSupported") ?? true, - Temperature = OptionalDouble($"Azure:{providerName}:Profiles:{profileName}:Temperature") - }); - await modelRepository.UpdateAsync(existing); - return existing; - } - - var settings = new AIModelSettings - { - MaxOutputTokenCountSupported = OptionalBool($"Azure:{providerName}:Profiles:{profileName}:MaxOutputTokenCountSupported") ?? true, - Temperature = OptionalDouble($"Azure:{providerName}:Profiles:{profileName}:Temperature") - }; - - var existingInactive = await modelRepository.FirstOrDefaultAsync(model => model.Name == profileName); - if (existingInactive != null) - { - existingInactive.IsActive = true; - existingInactive.SettingsJson = System.Text.Json.JsonSerializer.Serialize(settings); - return await modelRepository.UpdateAsync(existingInactive); - } - - var model = await modelRepository.InsertAsync( - new AIModel(Guid.CreateVersion7(), profileName) - { - IsActive = true, - SettingsJson = System.Text.Json.JsonSerializer.Serialize(settings) - }); - - return model; + var models = await modelRepository.GetListAsync(model => model.Name == modelName && model.IsActive); + return models.FirstOrDefault(); } private async Task ResolveLatestActivePromptAsync(string promptName) @@ -162,38 +109,45 @@ await operationRepository.InsertAsync( .FirstOrDefault(); } - private string? Optional(string key) + private async Task BackfillRequestOperationIdsAsync() { - var value = configuration[key]; - return string.IsNullOrWhiteSpace(value) ? null : value.Trim(); - } + var requests = await requestRepository.GetListAsync(request => request.OperationId == null); + if (requests.Count == 0) + { + return; + } - private int? OptionalPositiveInt(string key) - { - var value = configuration.GetValue(key); - return value is > 0 ? value : null; - } + var operations = await operationRepository.GetListAsync(); + var operationsByName = operations.ToDictionary(operation => operation.Name, StringComparer.OrdinalIgnoreCase); - private int? ResolveCompletionTokens(string operationName) - { - var value = OptionalPositiveInt($"Azure:Operations:{operationName}:MaxCompletionTokens") - ?? OptionalPositiveInt("Azure:Operations:Defaults:MaxCompletionTokens"); - return value; - } + foreach (var request in requests) + { + var operationType = ResolveOperationTypeFromRequestKey(request.RequestKey); + if (operationType == null) + { + continue; + } - private bool? OptionalBool(string key) - { - var value = Optional(key); - return value != null && bool.TryParse(value, out var parsedValue) - ? parsedValue - : null; + var operationName = AIGenerationRequestKeyHelper.ResolveOperationName(operationType); + if (operationName == null || !operationsByName.TryGetValue(operationName, out var operation)) + { + continue; + } + + request.OperationId = operation.Id; + await requestRepository.UpdateAsync(request, autoSave: true); + } } - private double? OptionalDouble(string key) + private static string? ResolveOperationTypeFromRequestKey(string requestKey) { - var value = Optional(key); - return value != null && double.TryParse(value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out var parsedValue) - ? parsedValue - : null; + var parts = requestKey.Split(':', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + return parts.Length == 3 ? parts[2] : null; } + + private sealed record BuiltInOperationDefinition( + string OperationName, + string PromptName, + int CompletionTokens, + bool IsDefaultOperation = false); } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIPromptDataSeeder.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIPromptDataSeeder.cs index 13e2896aae..86eef4e885 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIPromptDataSeeder.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/DataSeed/AIPromptDataSeeder.cs @@ -17,7 +17,7 @@ namespace Unity.AI.DataSeed; /// public class AIPromptDataSeeder( IRepository promptRepository, - ICurrentTenant currentTenant) : IDataSeedContributor, ITransientDependency + ICurrentTenant currentTenant) : ITransientDependency { public async Task SeedAsync(DataSeedContext context) { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/AIGenerationRequestDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/AIGenerationRequestDto.cs index 6a5f5b7f66..60232e3acc 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/AIGenerationRequestDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/AIGenerationRequestDto.cs @@ -6,7 +6,7 @@ namespace Unity.GrantManager.GrantApplications; public class AIGenerationRequestDto : EntityDto { public Guid? ApplicationId { get; set; } - public Guid OperationId { get; set; } + public Guid? OperationId { get; set; } public string OperationType { get; set; } = string.Empty; public string RequestKey { get; set; } = string.Empty; public AIGenerationRequestStatus Status { get; set; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/AIGenerationStatusAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/AIGenerationStatusAppService.cs index 1162fbea33..9d2fae3b32 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/AIGenerationStatusAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/AIGenerationStatusAppService.cs @@ -36,7 +36,7 @@ public class AIGenerationStatusAppService( var item = query .Where(x => x.ApplicationId == applicationId && - x.OperationId == operation.Id && + x.OperationId == operation.Id && x.TenantId == resolvedTenantId) .OrderByDescending(x => x.CreationTime) .ThenByDescending(x => x.Id) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/GrantApplications/AIGenerationRequest.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/GrantApplications/AIGenerationRequest.cs index 94fc5a1bf1..0d01a27416 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/GrantApplications/AIGenerationRequest.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/GrantApplications/AIGenerationRequest.cs @@ -8,7 +8,7 @@ public class AIGenerationRequest : FullAuditedAggregateRoot, IMultiTenant { public Guid? TenantId { get; set; } public Guid? ApplicationId { get; set; } - public Guid OperationId { get; set; } + public Guid? OperationId { get; set; } public string RequestKey { get; set; } = string.Empty; public AIGenerationRequestStatus Status { get; set; } public DateTime? StartedAt { get; set; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbContext.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbContext.cs index 06b877d8ee..ed7a01c5ad 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbContext.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbContext.cs @@ -239,16 +239,16 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) b.HasIndex(x => new { x.Source, x.Status }); }); - modelBuilder.Entity(b => - { - b.ToTable(GrantManagerConsts.DbTablePrefix + "AIRequests", AIDbProperties.DbSchema); - b.ConfigureByConvention(); - b.Property(x => x.OperationId).IsRequired(); - b.Property(x => x.RequestKey).IsRequired().HasMaxLength(256); - b.Property(x => x.FailureReason).HasMaxLength(2000); - b.Property(x => x.Status).IsRequired(); - b.HasOne() - .WithMany() + modelBuilder.Entity(b => + { + b.ToTable(GrantManagerConsts.DbTablePrefix + "AIRequests", AIDbProperties.DbSchema); + b.ConfigureByConvention(); + b.Property(x => x.OperationId); + b.Property(x => x.RequestKey).IsRequired().HasMaxLength(256); + b.Property(x => x.FailureReason).HasMaxLength(2000); + b.Property(x => x.Status).IsRequired(); + b.HasOne() + .WithMany() .HasForeignKey(x => x.OperationId) .OnDelete(DeleteBehavior.Restrict); b.HasIndex(x => x.RequestKey); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs index 1bc60b6449..75f6662ddd 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs @@ -13,146 +13,192 @@ protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.Sql( """ - DROP INDEX IF EXISTS "AI"."IX_AIPrompts_Name"; + DROP TABLE IF EXISTS "AI"."AIPromptVersions"; + DROP TABLE IF EXISTS "AI"."AIPrompts"; """); migrationBuilder.Sql( """ - ALTER TABLE "AI"."AIRequests" - ADD COLUMN IF NOT EXISTS "OperationId" uuid; + CREATE TABLE "AI"."AIModels" ( + "Id" uuid NOT NULL, + "Name" character varying(200) NOT NULL, + "IsActive" boolean NOT NULL, + "SettingsJson" jsonb NOT NULL, + "ExtraProperties" text NOT NULL, + "ConcurrencyStamp" character varying(40) NOT NULL, + "CreationTime" timestamp without time zone NOT NULL, + "CreatorId" uuid NULL, + "LastModificationTime" timestamp without time zone NULL, + "LastModifierId" uuid NULL, + "DeleterId" uuid NULL, + "DeletionTime" timestamp without time zone NULL, + "IsDeleted" boolean NOT NULL DEFAULT FALSE, + PRIMARY KEY ("Id") + ); """); migrationBuilder.Sql( """ - UPDATE "AI"."AIRequests" r - SET "OperationId" = o."Id" - FROM "AI"."AIOperations" o - WHERE r."OperationId" IS NULL - AND ( - (r."OperationType" = 'application-analysis' AND o."Name" = 'ApplicationAnalysis') - OR (r."OperationType" = 'attachment-summary' AND o."Name" = 'AttachmentSummary') - OR (r."OperationType" = 'application-scoring' AND o."Name" = 'ApplicationScoring') - OR (r."OperationType" = 'pipeline' AND o."Name" = 'Default') - ); + CREATE UNIQUE INDEX IF NOT EXISTS "IX_AIModels_Name" + ON "AI"."AIModels" ("Name"); """); migrationBuilder.Sql( """ - DO $$ - BEGIN - IF EXISTS ( - SELECT 1 - FROM "AI"."AIRequests" - WHERE "OperationId" IS NULL - ) THEN - RAISE EXCEPTION 'AIRequests contains rows that cannot be mapped to OperationId.'; - END IF; - END $$; + CREATE TABLE "AI"."AIPrompts" ( + "Id" uuid NOT NULL, + "TenantId" uuid NULL, + "Name" character varying(200) NOT NULL, + "VersionNumber" integer NOT NULL, + "SystemPrompt" text NOT NULL, + "UserPrompt" text NOT NULL, + "MetadataJson" jsonb NULL, + "IsActive" boolean NOT NULL, + "ExtraProperties" text NOT NULL, + "ConcurrencyStamp" character varying(40) NOT NULL, + "CreationTime" timestamp without time zone NOT NULL, + "CreatorId" uuid NULL, + "LastModificationTime" timestamp without time zone NULL, + "LastModifierId" uuid NULL, + "DeleterId" uuid NULL, + "DeletionTime" timestamp without time zone NULL, + "IsDeleted" boolean NOT NULL DEFAULT FALSE, + PRIMARY KEY ("Id") + ); """); migrationBuilder.Sql( """ - ALTER TABLE "AI"."AIRequests" - ALTER COLUMN "OperationId" SET NOT NULL; + CREATE UNIQUE INDEX "IX_AIPrompts_Name_VersionNumber" + ON "AI"."AIPrompts" ("TenantId", "Name", "VersionNumber"); """); migrationBuilder.Sql( """ - DROP INDEX IF EXISTS "AI"."IX_AIRequests_TenantId_ApplicationId_OperationType_Status"; + CREATE TABLE "AI"."AIOperations" ( + "Id" uuid NOT NULL, + "Name" character varying(200) NOT NULL, + "AIModelId" uuid NOT NULL, + "AIPromptId" uuid NOT NULL, + "ExecutionMode" character varying(20) NOT NULL, + "CompletionTokens" integer NOT NULL, + "IsActive" boolean NOT NULL, + "ExtraProperties" text NOT NULL, + "ConcurrencyStamp" character varying(40) NOT NULL, + "CreationTime" timestamp without time zone NOT NULL, + "CreatorId" uuid NULL, + "LastModificationTime" timestamp without time zone NULL, + "LastModifierId" uuid NULL, + "DeleterId" uuid NULL, + "DeletionTime" timestamp without time zone NULL, + "IsDeleted" boolean NOT NULL DEFAULT FALSE, + PRIMARY KEY ("Id") + ); """); migrationBuilder.Sql( """ - ALTER TABLE "AI"."AIRequests" - DROP COLUMN IF EXISTS "OperationType"; + CREATE UNIQUE INDEX IF NOT EXISTS "IX_AIOperations_Name" + ON "AI"."AIOperations" ("Name"); """); - migrationBuilder.CreateIndex( - name: "IX_AIRequests_TenantId_ApplicationId_OperationId_Status", - schema: "AI", - table: "AIRequests", - columns: new[] { "TenantId", "ApplicationId", "OperationId", "Status" }); - - migrationBuilder.CreateIndex( - name: "IX_AIRequests_OperationId", - schema: "AI", - table: "AIRequests", - column: "OperationId"); - migrationBuilder.Sql( """ - ALTER TABLE "AI"."AIRequests" - ADD CONSTRAINT "FK_AIRequests_AIOperations_OperationId" - FOREIGN KEY ("OperationId") REFERENCES "AI"."AIOperations" ("Id") ON DELETE RESTRICT; + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 + FROM pg_constraint + WHERE conname = 'FK_AIOperations_AIModels_AIModelId' + ) THEN + ALTER TABLE "AI"."AIOperations" + ADD CONSTRAINT "FK_AIOperations_AIModels_AIModelId" + FOREIGN KEY ("AIModelId") REFERENCES "AI"."AIModels" ("Id") ON DELETE RESTRICT; + END IF; + END $$; """); - } - /// - protected override void Down(MigrationBuilder migrationBuilder) - { migrationBuilder.Sql( """ - DROP INDEX IF EXISTS "AI"."IX_AIRequests_TenantId_ApplicationId_OperationType_Status"; + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 + FROM pg_constraint + WHERE conname = 'FK_AIOperations_AIPrompts_AIPromptId' + ) THEN + ALTER TABLE "AI"."AIOperations" + ADD CONSTRAINT "FK_AIOperations_AIPrompts_AIPromptId" + FOREIGN KEY ("AIPromptId") REFERENCES "AI"."AIPrompts" ("Id") ON DELETE RESTRICT; + END IF; + END $$; """); migrationBuilder.Sql( """ - ALTER TABLE "AI"."AIRequests" - DROP CONSTRAINT IF EXISTS "FK_AIRequests_AIOperations_OperationId"; + DROP TABLE IF EXISTS "AI"."AIPromptVersions"; """); - migrationBuilder.DropIndex( - name: "IX_AIRequests_OperationId", - schema: "AI", - table: "AIRequests"); - - migrationBuilder.DropIndex( - name: "IX_AIRequests_TenantId_ApplicationId_OperationId_Status", - schema: "AI", - table: "AIRequests"); + migrationBuilder.Sql( + """ + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_schema = 'AI' + AND table_name = 'AIRequests' + AND column_name = 'OperationId' + ) THEN + ALTER TABLE "AI"."AIRequests" + ADD COLUMN "OperationId" uuid NULL; + END IF; + END $$; + """); migrationBuilder.Sql( """ - ALTER TABLE "AI"."AIRequests" - ADD COLUMN IF NOT EXISTS "OperationType" character varying(64) NOT NULL DEFAULT ''; + CREATE INDEX IF NOT EXISTS "IX_AIRequests_RequestKey" + ON "AI"."AIRequests" ("RequestKey"); """); migrationBuilder.Sql( """ - UPDATE "AI"."AIRequests" - SET "OperationType" = CASE - WHEN "OperationId" IS NOT NULL THEN - COALESCE( - (SELECT CASE o."Name" - WHEN 'ApplicationAnalysis' THEN 'application-analysis' - WHEN 'AttachmentSummary' THEN 'attachment-summary' - WHEN 'ApplicationScoring' THEN 'application-scoring' - WHEN 'Default' THEN 'pipeline' - END - FROM "AI"."AIOperations" o - WHERE o."Id" = "OperationId"), - 'application-analysis' - ) - ELSE 'application-analysis' - END; + CREATE INDEX IF NOT EXISTS "IX_AIRequests_OperationId" + ON "AI"."AIRequests" ("OperationId"); """); migrationBuilder.Sql( """ - ALTER TABLE "AI"."AIRequests" - ALTER COLUMN "OperationType" DROP DEFAULT; + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 + FROM pg_constraint + WHERE conname = 'FK_AIRequests_AIOperations_OperationId' + ) THEN + ALTER TABLE "AI"."AIRequests" + ADD CONSTRAINT "FK_AIRequests_AIOperations_OperationId" + FOREIGN KEY ("OperationId") REFERENCES "AI"."AIOperations" ("Id") ON DELETE RESTRICT; + END IF; + END $$; """); migrationBuilder.Sql( """ - ALTER TABLE "AI"."AIRequests" - ALTER COLUMN "OperationType" SET NOT NULL; + CREATE INDEX "IX_AIRequests_TenantId_ApplicationId_OperationId_Status" + ON "AI"."AIRequests" ("TenantId", "ApplicationId", "OperationId", "Status"); """); + } + /// + protected override void Down(MigrationBuilder migrationBuilder) + { migrationBuilder.Sql( """ - CREATE UNIQUE INDEX IF NOT EXISTS "IX_AIRequests_TenantId_ApplicationId_OperationType_Status" - ON "AI"."AIRequests" ("TenantId", "ApplicationId", "OperationType", "Status"); + DROP TABLE IF EXISTS "AI"."AIRequests"; + DROP TABLE IF EXISTS "AI"."AIPromptVersions"; + DROP TABLE IF EXISTS "AI"."AIPrompts"; """); } } From 9ce185dd8ac898a4569d86133d20a091f5f9899f Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Tue, 30 Jun 2026 12:20:58 -0700 Subject: [PATCH 19/61] AB#32307 flatten AI prompt editing --- .../Prompts/AIPromptDto.cs | 1 - .../Prompts/AIPromptVersionDto.cs | 14 -- .../Prompts/CreateUpdateAIPromptDto.cs | 6 +- .../Prompts/CreateUpdateAIPromptVersionDto.cs | 27 ---- .../Prompts/IAIPromptAppService.cs | 1 + .../Prompts/IAIPromptVersionAppService.cs | 14 -- .../AI/Prompts/Versions/README.md | 48 ------- .../AIApplicationMapperlyProfile.cs | 9 +- .../Prompts/AIPromptAppService.cs | 40 +++++- .../Prompts/AIPromptVersionAppService.cs | 121 ------------------ .../CreateEntryModal.cshtml} | 8 +- .../Entries/CreateEntryModal.cshtml.cs | 34 +++++ .../EditEntryModal.cshtml} | 8 +- .../EditEntryModal.cshtml.cs} | 18 +-- .../Versions/CreateVersionModal.cshtml.cs | 34 ----- 15 files changed, 94 insertions(+), 289 deletions(-) delete mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptVersionDto.cs delete mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptVersionDto.cs delete mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/IAIPromptVersionAppService.cs delete mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Prompts/Versions/README.md delete mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs rename applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/{Versions/CreateVersionModal.cshtml => Entries/CreateEntryModal.cshtml} (70%) create mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/CreateEntryModal.cshtml.cs rename applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/{Versions/EditVersionModal.cshtml => Entries/EditEntryModal.cshtml} (72%) rename applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/{Versions/EditVersionModal.cshtml.cs => Entries/EditEntryModal.cshtml.cs} (56%) delete mode 100644 applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/CreateVersionModal.cshtml.cs diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptDto.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptDto.cs index 5903cdc248..d5b673b699 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptDto.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Volo.Abp.Application.Dtos; namespace Unity.AI.Prompts; diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptVersionDto.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptVersionDto.cs deleted file mode 100644 index f21d2e8d4e..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/AIPromptVersionDto.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Volo.Abp.Application.Dtos; - -namespace Unity.AI.Prompts; - -public class AIPromptVersionDto : AuditedEntityDto -{ - public string Name { get; set; } = string.Empty; - public int VersionNumber { get; set; } - public string SystemPrompt { get; set; } = string.Empty; - public string UserPrompt { get; set; } = string.Empty; - public string? MetadataJson { get; set; } - public bool IsActive { get; set; } -} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptDto.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptDto.cs index 37435424f7..e26973030a 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptDto.cs @@ -1,3 +1,4 @@ +using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; @@ -5,10 +6,7 @@ namespace Unity.AI.Prompts; public class CreateUpdateAIPromptDto { - [Required] - [MaxLength(200)] - [DisplayName("PromptName")] - public string Name { get; set; } = string.Empty; + public Guid PromptId { get; set; } [DisplayName("VersionNumber")] public int VersionNumber { get; set; } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptVersionDto.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptVersionDto.cs deleted file mode 100644 index 9ce8423b96..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/CreateUpdateAIPromptVersionDto.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; - -namespace Unity.AI.Prompts; - -public class CreateUpdateAIPromptVersionDto -{ - public Guid PromptId { get; set; } - - [DisplayName("VersionNumber")] - public int VersionNumber { get; set; } - - [Required] - [DisplayName("SystemPrompt")] - public string SystemPrompt { get; set; } = string.Empty; - - [Required] - [DisplayName("UserPrompt")] - public string UserPrompt { get; set; } = string.Empty; - - [DisplayName("MetadataJson")] - public string? MetadataJson { get; set; } - - [DisplayName("PromptIsActive")] - public bool IsActive { get; set; } = true; -} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/IAIPromptAppService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/IAIPromptAppService.cs index c259996db0..7aca79853d 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/IAIPromptAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/IAIPromptAppService.cs @@ -10,4 +10,5 @@ public interface IAIPromptAppService : ICrudAppService< PagedAndSortedResultRequestDto, CreateUpdateAIPromptDto> { + System.Threading.Tasks.Task> GetByPromptAsync(Guid promptId); } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/IAIPromptVersionAppService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/IAIPromptVersionAppService.cs deleted file mode 100644 index 269029e5ec..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Prompts/IAIPromptVersionAppService.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Volo.Abp.Application.Dtos; -using Volo.Abp.Application.Services; - -namespace Unity.AI.Prompts; - -public interface IAIPromptVersionAppService : ICrudAppService< - AIPromptVersionDto, - Guid, - PagedAndSortedResultRequestDto, - CreateUpdateAIPromptVersionDto> -{ - System.Threading.Tasks.Task> GetByPromptAsync(Guid promptId); -} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Prompts/Versions/README.md b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Prompts/Versions/README.md deleted file mode 100644 index 0f6146d2ab..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Prompts/Versions/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# Runtime Prompt Templates - -Runtime prompts are now resolved from the database-backed `AIPrompts` and `AIPromptVersions` records seeded by the AI module. -These files are retained as prompt asset references and seed inputs, not as the runtime source of truth. - -Current prompt asset references: - -- `application-analysis.system.txt` -- `application-analysis.user.txt` -- `application-analysis.rubric.txt` (optional, when `{{RUBRIC}}` is used) -- `application-analysis.score.txt` (optional, when `{{SCORE}}` is used) -- `application-analysis.output.txt` (optional, when `{{OUTPUT}}` is used) -- `application-analysis.rules.txt` (optional, when `{{RULES}}` is used) -- `common.*.txt` (optional shared fragments for `{{COMMON_*}}` placeholders) -- `attachment-summary.system.txt` -- `attachment-summary.user.txt` -- `attachment-summary.output.txt` (optional, when `{{OUTPUT}}` is used) -- `attachment-summary.rules.txt` (optional, when `{{RULES}}` is used) -- `application-scoring.system.txt` -- `application-scoring.user.txt` -- `application-scoring.output.txt` (optional, when `{{OUTPUT}}` is used) -- `application-scoring.rules.txt` (optional, when `{{RULES}}` is used) - -Placeholders: - -- `{{SCHEMA}}` -- `{{DATA}}` -- `{{ATTACHMENTS}}` -- `{{RUBRIC}}` -- `{{SCORE}}` -- `{{OUTPUT}}` -- `{{RULES}}` -- `{{ATTACHMENT}}` -- `{{DATA}}` -- `{{ATTACHMENTS}}` -- `{{SECTION}}` -- `{{RESPONSE}}` - -Version selection: - -- Required: `Azure:Operations:Defaults:PromptVersion = v0|v1`, with optional overrides under `Azure:Operations::PromptVersion`. -- Unknown or missing version values fail at runtime. - -Template loading is strict: - -- Core prompt records are required for each version. -- Missing required prompt records fail fast at runtime with a configuration error. -- Runtime prompt rendering resolves placeholders from the stored template text plus the version metadata sections. diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationMapperlyProfile.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationMapperlyProfile.cs index 589ac6aea2..b799fbd3ea 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationMapperlyProfile.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationMapperlyProfile.cs @@ -27,6 +27,7 @@ private static AIPrompt CreateAIPrompt() => [MapperIgnoreTarget(nameof(AIPrompt.CreatorId))] [MapperIgnoreTarget(nameof(AIPrompt.LastModificationTime))] [MapperIgnoreTarget(nameof(AIPrompt.LastModifierId))] + [MapperIgnoreTarget(nameof(AIPrompt.Name))] public override partial AIPrompt Map(CreateUpdateAIPromptDto source); [MapperIgnoreTarget(nameof(AIPrompt.TenantId))] @@ -35,13 +36,7 @@ private static AIPrompt CreateAIPrompt() => [MapperIgnoreTarget(nameof(AIPrompt.CreatorId))] [MapperIgnoreTarget(nameof(AIPrompt.LastModificationTime))] [MapperIgnoreTarget(nameof(AIPrompt.LastModifierId))] + [MapperIgnoreTarget(nameof(AIPrompt.Name))] public override partial void Map(CreateUpdateAIPromptDto source, AIPrompt destination); } -[Mapper] -public partial class AIPromptToAIPromptVersionDtoMapper : MapperBase -{ - public override partial AIPromptVersionDto Map(AIPrompt source); - - public override partial void Map(AIPrompt source, AIPromptVersionDto destination); -} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptAppService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptAppService.cs index 9a3f66ec94..de45c9b88e 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptAppService.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Unity.AI.Domain; using Unity.Modules.Shared.Permissions; @@ -38,6 +40,19 @@ public AIPromptAppService( DeletePolicyName = IdentityConsts.ITOperationsPolicyName; } + [HttpGet("by-prompt/{promptId}")] + public async Task> GetByPromptAsync(Guid promptId) + { + using (_multiTenantDataFilter.Disable()) + { + var selected = await Repository.GetAsync(promptId); + var items = await Repository.GetListAsync(v => v.TenantId == selected.TenantId && v.Name == selected.Name); + var sorted = items.OrderBy(v => v.VersionNumber).ToList(); + return new ListResultDto( + ObjectMapper.Map, List>(sorted)); + } + } + [HttpGet("{id}")] public override async Task GetAsync(Guid id) { @@ -61,7 +76,21 @@ public override async Task CreateAsync(CreateUpdateAIPromptDto inpu { using (_multiTenantDataFilter.Disable()) { - return await base.CreateAsync(input); + var prompt = await Repository.GetAsync(input.PromptId); + var entity = await Repository.InsertAsync( + new AIPrompt( + Guid.CreateVersion7(), + prompt.Name, + input.VersionNumber, + input.SystemPrompt, + input.UserPrompt, + prompt.TenantId) + { + MetadataJson = input.MetadataJson, + IsActive = input.IsActive + }); + + return ObjectMapper.Map(entity); } } @@ -70,7 +99,14 @@ public override async Task UpdateAsync(Guid id, CreateUpdateAIPromp { using (_multiTenantDataFilter.Disable()) { - return await base.UpdateAsync(id, input); + var entity = await Repository.GetAsync(id); + entity.VersionNumber = input.VersionNumber; + entity.SystemPrompt = input.SystemPrompt; + entity.UserPrompt = input.UserPrompt; + entity.MetadataJson = input.MetadataJson; + entity.IsActive = input.IsActive; + entity = await Repository.UpdateAsync(entity); + return ObjectMapper.Map(entity); } } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs deleted file mode 100644 index 94349658ee..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Prompts/AIPromptVersionAppService.cs +++ /dev/null @@ -1,121 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Unity.AI.Domain; -using Unity.Modules.Shared.Permissions; -using Volo.Abp.Data; -using Volo.Abp.Application.Dtos; -using Volo.Abp.Application.Services; -using Volo.Abp.Domain.Repositories; -using Volo.Abp.MultiTenancy; - -namespace Unity.AI.Prompts; - -[Authorize(IdentityConsts.ITOperationsPolicyName)] -[Route("api/app/ai/prompt-versions")] -public class AIPromptVersionAppService : - CrudAppService< - AIPrompt, - AIPromptVersionDto, - Guid, - PagedAndSortedResultRequestDto, - CreateUpdateAIPromptVersionDto>, - IAIPromptVersionAppService -{ - private readonly IDataFilter _multiTenantDataFilter; - - public AIPromptVersionAppService( - IRepository repository, - IDataFilter multiTenantDataFilter) - : base(repository) - { - _multiTenantDataFilter = multiTenantDataFilter; - GetPolicyName = IdentityConsts.ITOperationsPolicyName; - GetListPolicyName = IdentityConsts.ITOperationsPolicyName; - CreatePolicyName = IdentityConsts.ITOperationsPolicyName; - UpdatePolicyName = IdentityConsts.ITOperationsPolicyName; - DeletePolicyName = IdentityConsts.ITOperationsPolicyName; - } - - [HttpGet("by-prompt/{promptId}")] - public async Task> GetByPromptAsync(Guid promptId) - { - using (_multiTenantDataFilter.Disable()) - { - var selected = await Repository.GetAsync(promptId); - var items = await Repository.GetListAsync(v => v.TenantId == selected.TenantId && v.Name == selected.Name); - var sorted = items.OrderBy(v => v.VersionNumber).ToList(); - return new ListResultDto( - ObjectMapper.Map, List>(sorted)); - } - } - - [HttpGet("{id}")] - public override async Task GetAsync(Guid id) - { - using (_multiTenantDataFilter.Disable()) - { - return await base.GetAsync(id); - } - } - - [HttpGet] - public override async Task> GetListAsync(PagedAndSortedResultRequestDto input) - { - using (_multiTenantDataFilter.Disable()) - { - return await base.GetListAsync(input); - } - } - - [HttpPost] - public override async Task CreateAsync(CreateUpdateAIPromptVersionDto input) - { - using (_multiTenantDataFilter.Disable()) - { - var prompt = await Repository.GetAsync(input.PromptId); - var entity = await Repository.InsertAsync( - new AIPrompt( - Guid.CreateVersion7(), - prompt.Name, - input.VersionNumber, - input.SystemPrompt, - input.UserPrompt, - prompt.TenantId) - { - MetadataJson = input.MetadataJson, - IsActive = input.IsActive - }); - - return ObjectMapper.Map(entity); - } - } - - [HttpPut("{id}")] - public override async Task UpdateAsync(Guid id, CreateUpdateAIPromptVersionDto input) - { - using (_multiTenantDataFilter.Disable()) - { - var entity = await Repository.GetAsync(id); - entity.VersionNumber = input.VersionNumber; - entity.SystemPrompt = input.SystemPrompt; - entity.UserPrompt = input.UserPrompt; - entity.MetadataJson = input.MetadataJson; - entity.IsActive = input.IsActive; - entity = await Repository.UpdateAsync(entity); - return ObjectMapper.Map(entity); - } - } - - [HttpDelete("{id}")] - public override async Task DeleteAsync(Guid id) - { - using (_multiTenantDataFilter.Disable()) - { - await base.DeleteAsync(id); - } - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/CreateVersionModal.cshtml b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/CreateEntryModal.cshtml similarity index 70% rename from applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/CreateVersionModal.cshtml rename to applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/CreateEntryModal.cshtml index 38acee10e0..85da100816 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/CreateVersionModal.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/CreateEntryModal.cshtml @@ -1,17 +1,17 @@ @page @using Unity.AI.Localization -@using Unity.AI.Web.Pages.Prompts.Versions +@using Unity.AI.Web.Pages.Prompts.Entries @using Microsoft.Extensions.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal -@model CreateVersionModalModel +@model CreateEntryModalModel @inject IStringLocalizer L @{ Layout = null; } - + - + diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/CreateEntryModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/CreateEntryModal.cshtml.cs new file mode 100644 index 0000000000..ee1e53654a --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/CreateEntryModal.cshtml.cs @@ -0,0 +1,34 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Unity.AI.Prompts; +using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; + +namespace Unity.AI.Web.Pages.Prompts.Entries; + +public class CreateEntryModalModel : AbpPageModel +{ + [BindProperty] + public CreateUpdateAIPromptDto Prompt { get; set; } = new(); + + private readonly IAIPromptAppService _promptAppService; + + public CreateEntryModalModel(IAIPromptAppService promptAppService) + { + _promptAppService = promptAppService; + } + + public void OnGet(Guid promptId) + { + Prompt = new CreateUpdateAIPromptDto + { + PromptId = promptId + }; + } + + public async Task OnPostAsync() + { + await _promptAppService.CreateAsync(Prompt); + return NoContent(); + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/EditVersionModal.cshtml b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/EditEntryModal.cshtml similarity index 72% rename from applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/EditVersionModal.cshtml rename to applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/EditEntryModal.cshtml index 2f1e96ea4f..6ca56cf1c7 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/EditVersionModal.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/EditEntryModal.cshtml @@ -1,17 +1,17 @@ @page @using Unity.AI.Localization -@using Unity.AI.Web.Pages.Prompts.Versions +@using Unity.AI.Web.Pages.Prompts.Entries @using Microsoft.Extensions.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal -@model EditVersionModalModel +@model EditEntryModalModel @inject IStringLocalizer L @{ Layout = null; } - + - + diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/EditVersionModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/EditEntryModal.cshtml.cs similarity index 56% rename from applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/EditVersionModal.cshtml.cs rename to applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/EditEntryModal.cshtml.cs index cf9947f77d..b2f2a5dcc0 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/EditVersionModal.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Entries/EditEntryModal.cshtml.cs @@ -4,28 +4,28 @@ using Unity.AI.Prompts; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; -namespace Unity.AI.Web.Pages.Prompts.Versions; +namespace Unity.AI.Web.Pages.Prompts.Entries; -public class EditVersionModalModel : AbpPageModel +public class EditEntryModalModel : AbpPageModel { [HiddenInput] [BindProperty(SupportsGet = true)] public Guid Id { get; set; } [BindProperty] - public CreateUpdateAIPromptVersionDto Version { get; set; } = new(); + public CreateUpdateAIPromptDto Prompt { get; set; } = new(); - private readonly IAIPromptVersionAppService _versionAppService; + private readonly IAIPromptAppService _promptAppService; - public EditVersionModalModel(IAIPromptVersionAppService versionAppService) + public EditEntryModalModel(IAIPromptAppService promptAppService) { - _versionAppService = versionAppService; + _promptAppService = promptAppService; } public async Task OnGetAsync() { - var dto = await _versionAppService.GetAsync(Id); - Version = new CreateUpdateAIPromptVersionDto + var dto = await _promptAppService.GetAsync(Id); + Prompt = new CreateUpdateAIPromptDto { PromptId = dto.Id, VersionNumber = dto.VersionNumber, @@ -38,7 +38,7 @@ public async Task OnGetAsync() public async Task OnPostAsync() { - await _versionAppService.UpdateAsync(Id, Version); + await _promptAppService.UpdateAsync(Id, Prompt); return NoContent(); } } diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/CreateVersionModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/CreateVersionModal.cshtml.cs deleted file mode 100644 index 53b3b0c54f..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/Versions/CreateVersionModal.cshtml.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using System; -using System.Threading.Tasks; -using Unity.AI.Prompts; -using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; - -namespace Unity.AI.Web.Pages.Prompts.Versions; - -public class CreateVersionModalModel : AbpPageModel -{ - [BindProperty] - public CreateUpdateAIPromptVersionDto Version { get; set; } = new(); - - private readonly IAIPromptVersionAppService _versionAppService; - - public CreateVersionModalModel(IAIPromptVersionAppService versionAppService) - { - _versionAppService = versionAppService; - } - - public void OnGet(Guid promptId) - { - Version = new CreateUpdateAIPromptVersionDto - { - PromptId = promptId - }; - } - - public async Task OnPostAsync() - { - await _versionAppService.CreateAsync(Version); - return NoContent(); - } -} From a28ba7c1a8014a7b43e614bb9f1b8f0b18741f45 Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Tue, 30 Jun 2026 12:21:05 -0700 Subject: [PATCH 20/61] AB#32307 update AI tests for strict seeding --- .../AI/DataSeed/AIModelDataSeederTests.cs | 38 ++++------ .../AI/DataSeed/AIOperationDataSeederTests.cs | 73 ++++++++----------- .../OpenAIConfigurationResolverTests.cs | 35 +++++++++ .../AI/Runtime/OpenAIRuntimeServiceTests.cs | 38 ++++------ 4 files changed, 94 insertions(+), 90 deletions(-) diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIModelDataSeederTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIModelDataSeederTests.cs index ae6380b57b..f0a66345d1 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIModelDataSeederTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIModelDataSeederTests.cs @@ -1,8 +1,8 @@ -using Microsoft.Extensions.Configuration; using NSubstitute; using Shouldly; using System; using System.Collections.Generic; +using System.Linq; using System.Text.Json; using System.Threading.Tasks; using Unity.AI.DataSeed; @@ -24,7 +24,7 @@ public async Task Should_Seed_All_Configured_Profiles() .FirstOrDefaultAsync(Arg.Any>>()) .Returns((AIModel?)null); modelRepository - .InsertAsync(Arg.Any()) + .InsertAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(callInfo => { var model = callInfo.Arg(); @@ -32,35 +32,25 @@ public async Task Should_Seed_All_Configured_Profiles() return Task.FromResult(model); }); - var configuration = BuildConfiguration(new Dictionary - { - ["Azure:Operations:Defaults:Provider"] = "OpenAI", - ["Azure:Operations:Defaults:Profile"] = "Gpt5Mini", - ["Azure:OpenAI:Profiles:Gpt5Mini:DeploymentName"] = "gpt-5-mini", - ["Azure:OpenAI:Profiles:Gpt5Mini:Temperature"] = "0.15", - ["Azure:OpenAI:Profiles:Gpt5Nano:DeploymentName"] = "gpt-5-nano", - ["Azure:OpenAI:Endpoint"] = "https://example.test" - }); - - var seeder = new AIModelDataSeeder(modelRepository, configuration); + var seeder = new AIModelDataSeeder(modelRepository); await seeder.SeedAsync(new DataSeedContext()); - insertedModels.Count.ShouldBe(2); + insertedModels.Count.ShouldBe(3); + insertedModels.ShouldContain(model => model.Name == "Gpt4oMini" && model.IsActive); insertedModels.ShouldContain(model => model.Name == "Gpt5Mini" && model.IsActive); insertedModels.ShouldContain(model => model.Name == "Gpt5Nano" && model.IsActive); - var gpt5MiniModel = insertedModels.Find(model => model.Name == "Gpt5Mini"); - gpt5MiniModel.ShouldNotBeNull(); - DeserializeSettings(gpt5MiniModel.SettingsJson).MaxOutputTokenCountSupported.ShouldBeTrue(); - DeserializeSettings(gpt5MiniModel.SettingsJson).Temperature.ShouldBe(0.15); - } + var gpt4oMini = insertedModels.Single(model => model.Name == "Gpt4oMini"); + var gpt5Mini = insertedModels.Single(model => model.Name == "Gpt5Mini"); + var gpt5Nano = insertedModels.Single(model => model.Name == "Gpt5Nano"); - private static IConfiguration BuildConfiguration(IReadOnlyDictionary values) - { - return new ConfigurationBuilder() - .AddInMemoryCollection(values) - .Build(); + DeserializeSettings(gpt4oMini.SettingsJson).MaxOutputTokenCountSupported.ShouldBeTrue(); + DeserializeSettings(gpt4oMini.SettingsJson).Temperature.ShouldBe(0.3); + DeserializeSettings(gpt5Mini.SettingsJson).MaxOutputTokenCountSupported.ShouldBeFalse(); + DeserializeSettings(gpt5Mini.SettingsJson).Temperature.ShouldBeNull(); + DeserializeSettings(gpt5Nano.SettingsJson).MaxOutputTokenCountSupported.ShouldBeFalse(); + DeserializeSettings(gpt5Nano.SettingsJson).Temperature.ShouldBeNull(); } private static AIModelSettings DeserializeSettings(string settingsJson) diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIOperationDataSeederTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIOperationDataSeederTests.cs index 5cff2c9648..401f1568e8 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIOperationDataSeederTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/DataSeed/AIOperationDataSeederTests.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using NSubstitute; using Shouldly; @@ -12,6 +11,7 @@ using Unity.AI.DataSeed; using Unity.AI.Domain; using Unity.AI.Prompts; +using Unity.GrantManager.GrantApplications; using Volo.Abp.Data; using Volo.Abp.Domain.Repositories; using Volo.Abp.MultiTenancy; @@ -22,26 +22,36 @@ namespace Unity.GrantManager.AI.DataSeed; public class AIOperationDataSeederTests { [Fact] - public async Task Should_Seed_Configured_Default_Profile_Model_When_Missing() + public async Task Should_Seed_BuiltIn_Model_And_Operations() { var operationRepository = Substitute.For>(); operationRepository .GetQueryableAsync() .Returns(Task.FromResult(new List().AsQueryable())); + operationRepository + .GetListAsync(Arg.Any>>()) + .Returns(Task.FromResult(new List())); var modelRepository = Substitute.For>(); - var insertedModels = new List(); + var model = new AIModel(Guid.NewGuid(), "Gpt5Mini") + { + IsActive = true, + SettingsJson = """ + { + "MaxOutputTokenCountSupported": true, + "Temperature": null + } + """ + }; modelRepository .GetQueryableAsync() - .Returns(Task.FromResult(new List().AsQueryable())); + .Returns(Task.FromResult(new List { model }.AsQueryable())); modelRepository - .InsertAsync(Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(callInfo => - { - var model = callInfo.Arg(); - insertedModels.Add(model); - return Task.FromResult(model); - }); + .GetListAsync() + .Returns(Task.FromResult(new List { model })); + modelRepository + .GetListAsync(Arg.Any>>()) + .Returns(Task.FromResult(new List { model })); var insertedOperations = new List(); operationRepository @@ -68,46 +78,25 @@ public async Task Should_Seed_Configured_Default_Profile_Model_When_Missing() return Task.FromResult(prompts.Where(predicate).ToList()); }); + var requestRepository = Substitute.For>(); + requestRepository + .GetListAsync(Arg.Any>>()) + .Returns(Task.FromResult(new List())); var currentTenant = Substitute.For(); - var configuration = BuildConfiguration(new Dictionary - { - ["Azure:Operations:Defaults:Provider"] = "OpenAI", - ["Azure:Operations:Defaults:Profile"] = "Gpt5Mini", - ["Azure:OpenAI:Profiles:Gpt5Mini:DeploymentName"] = "gpt-5-mini", - ["Azure:OpenAI:Endpoint"] = "https://example.test", - ["Azure:Operations:ApplicationAnalysis:MaxCompletionTokens"] = "4000", - ["Azure:Operations:AttachmentSummary:MaxCompletionTokens"] = "2000", - ["Azure:Operations:ApplicationScoring:MaxCompletionTokens"] = "8000" - }); - var seeder = new AIOperationDataSeeder( operationRepository, modelRepository, promptRepository, - configuration, + requestRepository, currentTenant, Substitute.For>()); await seeder.SeedAsync(new DataSeedContext()); - insertedModels.Count.ShouldBe(1); - insertedModels[0].Name.ShouldBe("Gpt5Mini"); - DeserializeSettings(insertedModels[0].SettingsJson).MaxOutputTokenCountSupported.ShouldBeTrue(); - DeserializeSettings(insertedModels[0].SettingsJson).Temperature.ShouldBeNull(); - - } - - private static IConfiguration BuildConfiguration(IReadOnlyDictionary values) - { - return new ConfigurationBuilder() - .AddInMemoryCollection(values) - .Build(); - } - - private static AIModelSettings DeserializeSettings(string settingsJson) - { - var settings = JsonSerializer.Deserialize(settingsJson); - settings.ShouldNotBeNull(); - return settings; + insertedOperations.Count.ShouldBe(4); + insertedOperations.ShouldContain(operation => operation.Name == "Default" && operation.IsActive); + insertedOperations.ShouldContain(operation => operation.Name == AIPromptTypes.ApplicationAnalysis && operation.CompletionTokens == 4000); + insertedOperations.ShouldContain(operation => operation.Name == AIPromptTypes.AttachmentSummary && operation.CompletionTokens == 2000); + insertedOperations.ShouldContain(operation => operation.Name == AIPromptTypes.ApplicationScoring && operation.CompletionTokens == 8000); } } diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIConfigurationResolverTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIConfigurationResolverTests.cs index e81d02f899..e0099c5d10 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIConfigurationResolverTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIConfigurationResolverTests.cs @@ -52,6 +52,17 @@ public async Task Should_Resolve_Operation_Strictly_From_Database() }) }); + operationRepository + .GetListAsync() + .Returns(Task.FromResult(new List + { + new(Guid.NewGuid(), AIPromptTypes.ApplicationAnalysis, modelId, promptId) + { + ExecutionMode = AIExecutionMode.Sequential, + CompletionTokens = 2222, + IsActive = true + } + })); operationRepository .GetListAsync(Arg.Any>>()) .Returns(callInfo => @@ -117,6 +128,17 @@ public async Task Should_Fallback_To_Default_Operation_When_Override_Is_Missing( }) }); + operationRepository + .GetListAsync() + .Returns(Task.FromResult(new List + { + new(Guid.NewGuid(), "Default", modelId, promptId) + { + ExecutionMode = AIExecutionMode.Sequential, + CompletionTokens = 2000, + IsActive = true + } + })); operationRepository .GetListAsync(Arg.Any>>()) .Returns(callInfo => @@ -244,6 +266,16 @@ public async Task Should_Resolve_Operation_Settings_From_Host_Context() }) }); + operationRepository + .GetListAsync() + .Returns(Task.FromResult(new List + { + new(Guid.NewGuid(), AIPromptTypes.ApplicationAnalysis, modelId, promptId) + { + IsActive = true, + CompletionTokens = 2000 + } + })); operationRepository .GetListAsync(Arg.Any>>()) .Returns(callInfo => @@ -334,6 +366,9 @@ private static IRepository CreateEmptyModelRepository() private static IRepository CreateEmptyOperationRepository() { var operationRepository = Substitute.For>(); + operationRepository + .GetListAsync() + .Returns(Task.FromResult(new List())); operationRepository .GetListAsync(Arg.Any>>()) .Returns(Task.FromResult(new List())); diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIRuntimeServiceTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIRuntimeServiceTests.cs index 8c48f3985e..68c07143a9 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIRuntimeServiceTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Runtime/OpenAIRuntimeServiceTests.cs @@ -1,15 +1,13 @@ -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using NSubstitute; using Shouldly; using System; using System.Collections.Generic; using System.Linq.Expressions; -using System.Text.Json; using System.Threading.Tasks; using Unity.AI.Domain; using Unity.AI.Operations; -using Unity.AI.Requests; +using Unity.AI.Prompts; using Unity.AI.Runtime; using Volo.Abp.Data; using Volo.Abp.Domain.Repositories; @@ -22,44 +20,36 @@ public class OpenAIRuntimeServiceTests { [Fact] public async Task Should_Throw_When_Analysis_Operation_Is_Not_Configured() + { + var resolver = CreateResolverWithNoOperations(); + + var ex = await Should.ThrowAsync(() => + resolver.ResolveOperationSettingsAsync(AIPromptTypes.ApplicationAnalysis)); + + } + + private static OpenAIConfigurationResolver CreateResolverWithNoOperations() { var modelRepository = Substitute.For>(); modelRepository .GetListAsync(Arg.Any>>()) - .Returns(new List()); + .Returns(Task.FromResult(new List())); var operationRepository = Substitute.For>(); operationRepository .GetListAsync(Arg.Any>>()) - .Returns(new List()); + .Returns(Task.FromResult(new List())); var promptRepository = Substitute.For>(); - var configuration = new ConfigurationBuilder().Build(); + var configuration = new Microsoft.Extensions.Configuration.ConfigurationBuilder().Build(); var multiTenantDataFilter = Substitute.For>(); multiTenantDataFilter.Disable().Returns(Substitute.For()); - var resolver = new OpenAIConfigurationResolver( + return new OpenAIConfigurationResolver( modelRepository, operationRepository, promptRepository, configuration, multiTenantDataFilter); - - var logger = Substitute.For>(); - var runtimeService = new OpenAIRuntimeService( - logger, - null!, - resolver, - null!, - null!); - - var ex = await Should.ThrowAsync(() => - runtimeService.GenerateApplicationAnalysisAsync(new ApplicationAnalysisRequest - { - Schema = JsonSerializer.SerializeToElement(new { project = "x" }), - Data = JsonSerializer.SerializeToElement(new { project = "x" }) - })); - - ex.Message.ShouldContain("AI operation"); } } From 41722211f2e0a9afd96bc01f251945af3b43e3c6 Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Tue, 30 Jun 2026 12:27:55 -0700 Subject: [PATCH 21/61] AB#32307 fix prompt edit modal compile break --- .../Unity.AI/src/Unity.AI.Web/Pages/Prompts/EditModal.cshtml.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/EditModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/EditModal.cshtml.cs index ea394f2c2a..b99da8ecf8 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/EditModal.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Pages/Prompts/EditModal.cshtml.cs @@ -27,7 +27,6 @@ public async Task OnGetAsync() var dto = await _promptAppService.GetAsync(Id); Prompt = new CreateUpdateAIPromptDto { - Name = dto.Name, VersionNumber = dto.VersionNumber, SystemPrompt = dto.SystemPrompt, UserPrompt = dto.UserPrompt, From 458846c7bf71b965c07a56dd36ad29b23e682074 Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Tue, 30 Jun 2026 15:19:03 -0700 Subject: [PATCH 22/61] AB#32307 simplify AI schema rebuild --- .../20260624191335_RefreshAiSchema.cs | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs index 75f6662ddd..781ffddf29 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260624191335_RefreshAiSchema.cs @@ -13,6 +13,9 @@ protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.Sql( """ + DROP TABLE IF EXISTS "AI"."AIRequests"; + DROP TABLE IF EXISTS "AI"."AIOperations"; + DROP TABLE IF EXISTS "AI"."AIModels"; DROP TABLE IF EXISTS "AI"."AIPromptVersions"; DROP TABLE IF EXISTS "AI"."AIPrompts"; """); @@ -136,24 +139,27 @@ ADD CONSTRAINT "FK_AIOperations_AIPrompts_AIPromptId" migrationBuilder.Sql( """ - DROP TABLE IF EXISTS "AI"."AIPromptVersions"; - """); - - migrationBuilder.Sql( - """ - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 - FROM information_schema.columns - WHERE table_schema = 'AI' - AND table_name = 'AIRequests' - AND column_name = 'OperationId' - ) THEN - ALTER TABLE "AI"."AIRequests" - ADD COLUMN "OperationId" uuid NULL; - END IF; - END $$; + CREATE TABLE "AI"."AIRequests" ( + "Id" uuid NOT NULL, + "TenantId" uuid NULL, + "ApplicationId" uuid NULL, + "OperationId" uuid NULL, + "RequestKey" character varying(255) NOT NULL, + "Status" integer NOT NULL, + "StartedAt" timestamp without time zone NULL, + "CompletedAt" timestamp without time zone NULL, + "FailureReason" character varying(2000) NULL, + "IsDeleted" boolean NOT NULL DEFAULT FALSE, + "DeleterId" uuid NULL, + "DeletionTime" timestamp without time zone NULL, + "ExtraProperties" text NOT NULL, + "ConcurrencyStamp" character varying(40) NOT NULL, + "CreationTime" timestamp without time zone NOT NULL, + "CreatorId" uuid NULL, + "LastModificationTime" timestamp without time zone NULL, + "LastModifierId" uuid NULL, + PRIMARY KEY ("Id") + ); """); migrationBuilder.Sql( @@ -186,7 +192,7 @@ ADD CONSTRAINT "FK_AIRequests_AIOperations_OperationId" migrationBuilder.Sql( """ - CREATE INDEX "IX_AIRequests_TenantId_ApplicationId_OperationId_Status" + CREATE INDEX IF NOT EXISTS "IX_AIRequests_TenantId_ApplicationId_OperationId_Status" ON "AI"."AIRequests" ("TenantId", "ApplicationId", "OperationId", "Status"); """); } @@ -197,6 +203,8 @@ protected override void Down(MigrationBuilder migrationBuilder) migrationBuilder.Sql( """ DROP TABLE IF EXISTS "AI"."AIRequests"; + DROP TABLE IF EXISTS "AI"."AIOperations"; + DROP TABLE IF EXISTS "AI"."AIModels"; DROP TABLE IF EXISTS "AI"."AIPromptVersions"; DROP TABLE IF EXISTS "AI"."AIPrompts"; """); From 5badab4bdbff58bf1852e9372b3b0dc92b1d7601 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Tue, 30 Jun 2026 15:19:58 -0700 Subject: [PATCH 23/61] AB#33228: Cancel Payment Transaction - Initial Draft --- .../Enums/PaymentRequestStatus.cs | 1 + .../IPaymentRequestAppService.cs | 1 + .../PaymentRequests/PaymentRequestDto.cs | 5 + .../Domain/PaymentRequests/PaymentRequest.cs | 13 + .../Domain/Services/IPaymentsManager.cs | 4 +- .../Domain/Services/PaymentsManager.cs | 32 +- .../Domain/Shared/PaymentsAction.cs | 3 +- ...aymentsDbContextModelCreatingExtensions.cs | 5 + .../Repositories/PaymentRequestRepository.cs | 1 + .../PaymentRequestAppService.cs | 28 +- .../PaymentsPermissionDefinitionProvider.cs | 1 + .../Localization/Payments/en.json | 2 + .../Permissions/PaymentsPermissions.cs | 1 + .../Pages/PaymentRequests/Index.js | 102 +- ...dCancellationToPaymentRequests.Designer.cs | 5249 +++++++++++++++++ ...211933_AddCancellationToPaymentRequests.cs | 57 + .../GrantTenantDbContextModelSnapshot.cs | 263 +- 17 files changed, 5667 insertions(+), 101 deletions(-) create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630211933_AddCancellationToPaymentRequests.Designer.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630211933_AddCancellationToPaymentRequests.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/Enums/PaymentRequestStatus.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/Enums/PaymentRequestStatus.cs index 9d0bd15462..63d6e4e348 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/Enums/PaymentRequestStatus.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/Enums/PaymentRequestStatus.cs @@ -19,5 +19,6 @@ public enum PaymentRequestStatus Failed = 11, FSB = 12, // Financial Services Branch - Prevent CAS Payment HistoricalPayment = 13, + Cancelled = 14, } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs index d4b8dd0de1..3040e3e8ba 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs @@ -25,5 +25,6 @@ public interface IPaymentRequestAppService : IApplicationService Task> GetPaymentPendingListByCorrelationIdsAsync(IEnumerable correlationIds); Task GetApplicationPaymentRollupAsync(Guid applicationId); Task> GetApplicationPaymentRollupBatchAsync(List applicationIds); + Task CancelAsync(Guid paymentRequestId); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/PaymentRequestDto.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/PaymentRequestDto.cs index c959af41f9..ac0498a57f 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/PaymentRequestDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/PaymentRequestDto.cs @@ -51,6 +51,11 @@ public class PaymentRequestDto : AuditedEntityDto, IMultiTenant public string? Category { get; set; } public Guid? TenantId { get; set; } + // Cancellation tracking + public DateTime? CancelledOn { get; set; } + public Guid? CancelledById { get; set; } + public string? CancelledBy { get; set; } + public static explicit operator PaymentRequestDto(CreatePaymentRequestDto v) { throw new NotImplementedException(); diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/PaymentRequest.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/PaymentRequest.cs index 8a2f4d4314..4742e2178b 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/PaymentRequest.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/PaymentRequest.cs @@ -64,6 +64,11 @@ public class PaymentRequest : FullAuditedAggregateRoot, IMultiTenant, ICor public virtual DateTime? FsbNotificationSentDate { get; private set; } public virtual string? FsbApNotified { get; private set; } + // Cancellation tracking + public virtual DateTime? CancelledOn { get; private set; } + public virtual Guid? CancelledById { get; private set; } + public virtual string? CancelledBy { get; private set; } + protected PaymentRequest() { ExpenseApprovals = []; @@ -222,6 +227,14 @@ public PaymentRequest ClearFsbNotificationEmailLog() return this; } + public PaymentRequest SetCancellation(DateTime cancelledOn, Guid cancelledById, string cancelledBy) + { + CancelledOn = cancelledOn; + CancelledById = cancelledById; + CancelledBy = cancelledBy; + return this; + } + public PaymentRequest ValidatePaymentRequest() { if (Amount <= 0) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Services/IPaymentsManager.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Services/IPaymentsManager.cs index bccb0910c3..a69beb5b69 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Services/IPaymentsManager.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Services/IPaymentsManager.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Unity.Payments.Domain.PaymentRequests; using Unity.Payments.Domain.Shared; namespace Unity.Payments.Domain.Services @@ -7,7 +8,8 @@ namespace Unity.Payments.Domain.Services public interface IPaymentsManager { Task UpdatePaymentStatusAsync(Guid paymentRequestId, PaymentApprovalAction triggerAction); + Task CancelPaymentAsync(Guid paymentRequestId); Task GetFormPreventPaymentStatusByPaymentRequestId(Guid paymentRequestId); - Task GetFormPreventPaymentStatusByApplicationId(Guid applicationId); + Task GetFormPreventPaymentStatusByApplicationId(Guid applicationId); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Services/PaymentsManager.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Services/PaymentsManager.cs index b7413f3c9d..1c2a57b101 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Services/PaymentsManager.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Services/PaymentsManager.cs @@ -49,10 +49,20 @@ private void ConfigureWorkflow(StateMachine HasPermissionAsync(PaymentsPermissions.Payments.L3ApproveOrDecline).GetAwaiter().GetResult()) - .PermitIf(PaymentApprovalAction.L3Decline, PaymentRequestStatus.L3Declined, () => HasPermissionAsync(PaymentsPermissions.Payments.L3ApproveOrDecline).GetAwaiter().GetResult()); + .PermitIf(PaymentApprovalAction.L3Decline, PaymentRequestStatus.L3Declined, () => HasPermissionAsync(PaymentsPermissions.Payments.L3ApproveOrDecline).GetAwaiter().GetResult()) + .PermitIf(PaymentApprovalAction.Cancel, PaymentRequestStatus.Cancelled, () => HasPermissionAsync(PaymentsPermissions.Payments.CancelPayment).GetAwaiter().GetResult()); paymentStateMachine.Configure(PaymentRequestStatus.L2Declined) .PermitIf(PaymentApprovalAction.Submit, PaymentRequestStatus.Submitted, () => HasPermissionAsync(PaymentsPermissions.Payments.L2ApproveOrDecline).GetAwaiter().GetResult()); + + paymentStateMachine.Configure(PaymentRequestStatus.L1Pending) + .PermitIf(PaymentApprovalAction.Cancel, PaymentRequestStatus.Cancelled, () => HasPermissionAsync(PaymentsPermissions.Payments.CancelPayment).GetAwaiter().GetResult()); + + paymentStateMachine.Configure(PaymentRequestStatus.L2Pending) + .PermitIf(PaymentApprovalAction.Cancel, PaymentRequestStatus.Cancelled, () => HasPermissionAsync(PaymentsPermissions.Payments.CancelPayment).GetAwaiter().GetResult()); + + paymentStateMachine.Configure(PaymentRequestStatus.HistoricalPayment) + .PermitIf(PaymentApprovalAction.Cancel, PaymentRequestStatus.Cancelled, () => HasPermissionAsync(PaymentsPermissions.Payments.CancelPayment).GetAwaiter().GetResult()); } private async Task HasPermissionAsync(string permission) @@ -194,5 +204,25 @@ public async Task UpdatePaymentStatusAsync(Guid paymentRequestId, PaymentApprova await uow.SaveChangesAsync(); } + + [Volo.Abp.Uow.UnitOfWork] + public virtual async Task CancelPaymentAsync(Guid paymentRequestId) + { + var paymentRequest = await paymentRequestRepository.GetAsync(paymentRequestId, true); + var statusChange = paymentRequest.Status; + + var workflow = new PaymentsWorkflow( + () => statusChange, s => statusChange = s, ConfigureWorkflow); + + await workflow.ExecuteActionAsync(PaymentApprovalAction.Cancel); + + paymentRequest.SetPaymentRequestStatus(PaymentRequestStatus.Cancelled); + paymentRequest.SetCancellation( + Clock.Now, + currentUser.GetId(), + $"{currentUser.Name} {currentUser.SurName}".Trim()); + + return await paymentRequestRepository.UpdateAsync(paymentRequest); + } } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Shared/PaymentsAction.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Shared/PaymentsAction.cs index c449f1402e..26ad4fc611 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Shared/PaymentsAction.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Shared/PaymentsAction.cs @@ -24,5 +24,6 @@ public enum PaymentApprovalAction L2Decline, L3Approve, L3Decline, - Submit + Submit, + Cancel } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContextModelCreatingExtensions.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContextModelCreatingExtensions.cs index 1953c6caf4..2594d6aef9 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContextModelCreatingExtensions.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContextModelCreatingExtensions.cs @@ -55,6 +55,11 @@ public static void ConfigurePayments( b.Property(x => x.FsbNotificationSentDate).IsRequired(false); b.Property(x => x.FsbApNotified).IsRequired(false).HasMaxLength(10); b.HasIndex(x => x.FsbNotificationEmailLogId); + + // Cancellation tracking + b.Property(x => x.CancelledOn).HasColumnName("CancelledOn").IsRequired(false); + b.Property(x => x.CancelledById).HasColumnName("CancelledById").IsRequired(false); + b.Property(x => x.CancelledBy).HasColumnName("CancelledBy").HasMaxLength(256).IsRequired(false); }); diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/Repositories/PaymentRequestRepository.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/Repositories/PaymentRequestRepository.cs index 98ac8546ee..4910b5e003 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/Repositories/PaymentRequestRepository.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/Repositories/PaymentRequestRepository.cs @@ -58,6 +58,7 @@ public async Task GetTotalPaymentRequestAmountByCorrelationIdAsync(Guid .Where(p => p.Status != PaymentRequestStatus.L1Declined && p.Status != PaymentRequestStatus.L2Declined && p.Status != PaymentRequestStatus.L3Declined + && p.Status != PaymentRequestStatus.Cancelled && p.InvoiceStatus != CasPaymentRequestStatus.Cancelled && p.InvoiceStatus != CasPaymentRequestStatus.NotFound && p.InvoiceStatus != CasPaymentRequestStatus.ErrorFromCas) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs index 58a7ae9520..df3bde3fee 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs @@ -143,7 +143,10 @@ private static PaymentRequestDto MapToPaymentRequestDto(PaymentRequest result) CreationTime = result.CreationTime, Status = result.Status, ReferenceNumber = result.ReferenceNumber, - SubmissionConfirmationCode = result.SubmissionConfirmationCode + SubmissionConfirmationCode = result.SubmissionConfirmationCode, + CancelledOn = result.CancelledOn, + CancelledById = result.CancelledById, + CancelledBy = result.CancelledBy }; } @@ -425,5 +428,28 @@ public async Task> GetApplicationP var childApplicationIdsByParent = await applicationLinksService.Value.GetChildApplicationIdsByParentIdsAsync(applicationIds); return await paymentRequestQueryManager.GetApplicationPaymentRollupBatchAsync(applicationIds, childApplicationIdsByParent); } + + [Authorize(PaymentsPermissions.Payments.CancelPayment)] + public virtual async Task CancelAsync(Guid paymentRequestId) + { + var payment = await paymentRequestQueryManager.GetPaymentRequestByIdAsync(paymentRequestId) + ?? throw new BusinessException("Payments:PaymentRequestNotFound") + .WithData("Id", paymentRequestId); + + PaymentRequestStatus[] eligibleStatuses = + [ + PaymentRequestStatus.HistoricalPayment, + PaymentRequestStatus.L1Pending, + PaymentRequestStatus.L2Pending, + PaymentRequestStatus.L3Pending + ]; + + if (!eligibleStatuses.Contains(payment.Status)) + throw new BusinessException("Payments:CancellationNotAllowed") + .WithData("Status", payment.Status.ToString()); + + var result = await paymentsManager.CancelPaymentAsync(paymentRequestId); + return MapToPaymentRequestDto(result); + } } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs index e4186e3b76..9dd29990d0 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs @@ -20,6 +20,7 @@ public override void Define(IPermissionDefinitionContext context) paymentsPermissions.AddChild(PaymentsPermissions.Payments.RequestPayment, L("Permission:Payments.RequestPayment")); paymentsPermissions.AddChild(PaymentsPermissions.Payments.AccountCodingOverride, L("Permission:Payments.AccountCodingOverride")); paymentsPermissions.AddChild(PaymentsPermissions.Payments.AddHistoricalPayment, L("Permission:Payments.AddHistoricalPayment")); + paymentsPermissions.AddChild(PaymentsPermissions.Payments.CancelPayment, L("Permission:Payments.CancelPayment")); //-- PAYMENT INFO PERMISSIONS grantApplicationPermissionsGroup.Add_PaymentInfo_Permissions(); diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json index 4dcdee5d03..ff25b18a72 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json @@ -130,6 +130,8 @@ "Permission:Payments.AccountCodingOverride": "Override Account Coding", "Permission:Payments.EditFormPaymentConfiguration": "Edit Form Payment Configuration", "Permission:Payments.AddHistoricalPayment": "Add Historical Payment", + "Permission:Payments.CancelPayment": "Cancel Payment", + "Enum:PaymentRequestStatus.Cancelled": "Cancelled", "Enum:PaymentRequestStatus.L1Pending": "L1 Pending", "Enum:PaymentRequestStatus.L1Approved": "L1 Approved", "Enum:PaymentRequestStatus.L1Declined": "L1 Declined", diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Permissions/PaymentsPermissions.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Permissions/PaymentsPermissions.cs index a0b470a799..efd2fb0af4 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Permissions/PaymentsPermissions.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Permissions/PaymentsPermissions.cs @@ -18,6 +18,7 @@ public static class Payments public const string EditSupplierInfo = Default + ".EditSupplierInfo"; public const string EditFormPaymentConfiguration = Default + ".EditFormPaymentConfiguration"; public const string AddHistoricalPayment = Default + ".AddHistoricalPayment"; + public const string CancelPayment = Default + ".CancelPayment"; } public static string[] GetAll() diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js index 0c2d346be4..5aa96c5473 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js @@ -91,6 +91,7 @@ $(function () { payment_approve_buttons.disable(); payment_check_status_buttons.disable(); history_button.disable(); + if (cancel_button) cancel_button.disable(); selectedPaymentIds = []; PubSub.publish("deselect_batchpayment_application", "reset_data"); }) @@ -137,6 +138,38 @@ $(function () { }); } }, + ...(abp.auth.isGranted('PaymentsPermissions.Payments.CancelPayment') ? [{ + text: 'Cancel', + className: 'custom-table-btn flex-none btn btn-secondary payment-cancel', + action: function (e, dt, node, config) { + if (!selectedPaymentIds || selectedPaymentIds.length !== 1) return; + const rowData = dt.rows({ selected: true }).data().toArray()[0]; + abp.message.confirm( + `Are you sure you want to cancel the payment: "${rowData.referenceNumber}"?`, + 'Cancel Payment', + function (confirmed) { + if (!confirmed) return; + unity.payments.paymentRequests.paymentRequest + .cancel(selectedPaymentIds[0]) + .then(function () { + abp.notify.success('Payment has been cancelled successfully.'); + $(".select-all-payments").prop("checked", false); + payment_approve_buttons.disable(); + payment_check_status_buttons.disable(); + history_button.disable(); + if (cancel_button) cancel_button.disable(); + selectedPaymentIds = []; + PubSub.publish("deselect_batchpayment_application", "reset_data"); + dataTable.ajax.reload(null, false); + }) + .catch(function (err) { + abp.notify.error('Failed to cancel payment. Please try again.'); + console.warn('Cancel payment error:', err); + }); + } + ); + } + }] : []), { text: 'History', className: 'custom-table-btn flex-none btn btn-secondary history', @@ -366,10 +399,14 @@ $(function () { let payment_approve_buttons = dataTable.buttons(['.payment-status']); let payment_check_status_buttons = dataTable.buttons(['.payment-check-status']); let history_button = dataTable.buttons(['.history']); + let cancel_button = abp.auth.isGranted('PaymentsPermissions.Payments.CancelPayment') + ? dataTable.buttons(['.payment-cancel']) + : null; payment_approve_buttons.disable(); payment_check_status_buttons.disable(); history_button.disable(); + if (cancel_button) cancel_button.disable(); dataTable.on('search.dt', () => handleSearch()); function checkAllRowsHaveState(states) { @@ -452,7 +489,8 @@ $(function () { payment_check_status_buttons.disable(); } let hasHistoricalPayment = dataTable.rows('.selected').data().toArray().some(row => row.status === 'HistoricalPayment'); - if (dataTable.rows({ selected: true }).indexes().length > 0 && !isInSentState && !hasHistoricalPayment) { + let hasCancelledPayment = dataTable.rows('.selected').data().toArray().some(row => row.status === 'Cancelled'); + if (dataTable.rows({ selected: true }).indexes().length > 0 && !isInSentState && !hasHistoricalPayment && !hasCancelledPayment) { if (abp.auth.isGranted('PaymentsPermissions.Payments.L1ApproveOrDecline') || abp.auth.isGranted('PaymentsPermissions.Payments.L2ApproveOrDecline') || abp.auth.isGranted('PaymentsPermissions.Payments.L3ApproveOrDecline')) { @@ -468,6 +506,21 @@ $(function () { payment_approve_buttons.disable(); checkEnableHistoryButton(dataTable, history_button); } + + if (cancel_button) { + const eligibleCancelStatuses = ['HistoricalPayment', 'L1Pending', 'L2Pending', 'L3Pending']; + const selectedCount = dataTable.rows({ selected: true }).indexes().length; + if (selectedCount === 1) { + const rowData = dataTable.rows({ selected: true }).data().toArray()[0]; + if (eligibleCancelStatuses.includes(rowData.status)) { + cancel_button.enable(); + } else { + cancel_button.disable(); + } + } else { + cancel_button.disable(); + } + } } function handleSearch() { @@ -517,11 +570,53 @@ $(function () { getNoteColumn(columnIndex++), getAccountDistributionColumn(columnIndex++), getFsbNotifiedColumn(columnIndex++), + getCancelledColumn(columnIndex++), + getCancelledByColumn(columnIndex++), + getCancelledOnColumn(columnIndex++), ] return columns.map((column) => ({ ...column, targets: [column.index], orderData: [column.index, 0] })); } + function getCancelledColumn(columnIndex) { + return { + title: 'Cancelled', + name: 'cancelled', + data: null, + className: 'data-table-header', + index: columnIndex, + render: function (data, type, row) { + return row.status === 'Cancelled' ? 'Cancelled' : ''; + } + }; + } + + function getCancelledByColumn(columnIndex) { + return { + title: 'Cancelled By', + name: 'cancelledBy', + data: 'cancelledBy', + className: 'data-table-header', + index: columnIndex, + render: function (data) { + return data ?? ''; + } + }; + } + + function getCancelledOnColumn(columnIndex) { + return { + title: 'Cancelled On', + name: 'cancelledOn', + data: 'cancelledOn', + className: 'data-table-header', + index: columnIndex, + render: function (data, type) { + return DateUtils.formatUtcDateToLocal(data, type); + } + }; + } + function getPaymentReferenceColumn(columnIndex) { return { title: l('ApplicationPaymentListTable:PaymentID'), @@ -994,6 +1089,7 @@ $(function () { payment_approve_buttons.disable(); payment_check_status_buttons.disable(); history_button.disable(); + if (cancel_button) cancel_button.disable(); selectedPaymentIds = []; PubSub.publish("deselect_batchpayment_application", "reset_data"); }); @@ -1028,6 +1124,9 @@ $(function () { case "Failed": return "#CE3E39"; + case "Cancelled": + return "#6c757d"; + default: return "#053662"; } @@ -1050,6 +1149,7 @@ $(function () { payment_approve_buttons.disable(); payment_check_status_buttons.disable(); history_button.disable(); + if (cancel_button) cancel_button.disable(); selectedPaymentIds = []; PubSub.publish("deselect_batchpayment_application", "reset_data"); PubSub.publish('clear_selected_payment'); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630211933_AddCancellationToPaymentRequests.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630211933_AddCancellationToPaymentRequests.Designer.cs new file mode 100644 index 0000000000..fadcbc3a93 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630211933_AddCancellationToPaymentRequests.Designer.cs @@ -0,0 +1,5249 @@ +// +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("20260630211933_AddCancellationToPaymentRequests")] + partial class AddCancellationToPaymentRequests + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "10.0.3") + .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("IsArchived") + .HasColumnType("boolean"); + + 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("IsArchived") + .HasColumnType("boolean"); + + 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("Definition") + .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("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("AuditComments") + .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("DeleterId") + .HasColumnType("uuid"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FiscalDay") + .HasColumnType("integer"); + + b.Property("FiscalMonth") + .HasColumnType("text"); + + b.Property("FundingHistoryComments") + .HasColumnType("text"); + + b.Property("IndigenousOrgInd") + .HasColumnType("text"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("IsDuplicated") + .HasColumnType("boolean"); + + b.Property("IssueTrackingComments") + .HasColumnType("text"); + + 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("OrganizationType") + .HasColumnType("text"); + + b.Property("RedStop") + .HasColumnType("boolean"); + + b.Property("ReportsComments") + .HasColumnType("text"); + + b.Property("Sector") + .HasColumnType("text"); + + b.Property("SectorSubSectorIndustryDesc") + .HasColumnType("text"); + + 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.HasIndex("OrgName"); + + b.HasIndex("OrgNumber"); + + b.HasIndex("Status"); + + b.HasIndex("SupplierId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UnityApplicantId"); + + b.HasIndex("TenantId", "IsDeleted", "CreationTime") + .HasFilter("\"IsDeleted\" = false"); + + 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.HasIndex("TenantId", "ApplicationId"); + + b.ToTable("ApplicantAgents", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .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("ApplicantId"); + + b.ToTable("ApplicantAttachments", (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("DefaultSiteId") + .HasColumnType("uuid"); + + 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.HasIndex("ReferenceNo"); + + b.HasIndex("TenantId", "SubmissionDate") + .HasFilter("\"IsDeleted\" = false"); + + 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.HasIndex("TenantId", "ApplicationId"); + + 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("AutomaticallyGenerateAIAnalysis") + .HasColumnType("boolean"); + + 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("ManuallyInitiateAIAnalysis") + .HasColumnType("boolean"); + + b.Property("ParentFormId") + .HasColumnType("uuid"); + + b.Property("Payable") + .HasColumnType("boolean"); + + b.Property("PaymentApprovalThreshold") + .HasColumnType("numeric"); + + b.Property("Prefix") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PreventPayment") + .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.HasIndex("TenantId", "IsDeleted") + .HasFilter("\"IsDeleted\" = false"); + + 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("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.HasIndex("TenantId", "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("NotifiedStatus") + .HasColumnType("text"); + + 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.HasIndex("TenantId", "ApplicationId"); + + 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.Applications.AuditHistory", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("AuditDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AuditNote") + .HasColumnType("text"); + + b.Property("AuditStatus") + .HasColumnType("text"); + + b.Property("AuditTrackingNumber") + .HasColumnType("text"); + + b.Property("AuditorName") + .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("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("ApplicantId"); + + b.ToTable("AuditHistories", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.FundingHistory", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApprovedAmount") + .HasColumnType("numeric"); + + 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("FundingNotes") + .HasColumnType("text"); + + b.Property("FundingYear") + .HasColumnType("text"); + + b.Property("GrantCategory") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OneTimeConsideration") + .HasColumnType("numeric"); + + b.Property("PaidDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ReconsiderationAmount") + .HasColumnType("numeric"); + + b.Property("RenewedFunding") + .HasColumnType("boolean"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TotalGrantAmount") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("FundingHistories", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.IssueTracking", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .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("IssueDescription") + .HasColumnType("text"); + + b.Property("IssueHeading") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ResolutionNote") + .HasColumnType("text"); + + b.Property("Resolved") + .HasColumnType("boolean"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Year") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("IssueTrackings", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ReportsHistory", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .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("FiscalYear") + .HasColumnType("text"); + + b.Property("IncompleteReport") + .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("Outstanding") + .HasColumnType("boolean"); + + b.Property("ReportDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("ReportsHistories", (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("IsAiAssessment") + .HasColumnType("boolean"); + + 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.ApplicantComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .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("ApplicantId"); + + b.HasIndex("CommenterId"); + + b.ToTable("ApplicantComments", (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.HasIndex("TenantId"); + + 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.GrantManager.Notifications.ScheduledNotification", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationStatus") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ApplicationStatusId") + .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("DateField") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EmailTemplateId") + .HasColumnType("uuid"); + + b.Property("EventType") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormId") + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + 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("RecipientCategory") + .HasColumnType("text"); + + b.Property("RecipientIdentifier") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TriggerDetail") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("TriggerType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ScheduledNotifications", "Notifications"); + }); + + modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotificationTracking", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("DateField") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NotificationSentDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ScheduledNotificationId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("CreationTime"); + + b.HasIndex("ScheduledNotificationId"); + + b.HasIndex("ApplicationId", "ScheduledNotificationId", "DateField") + .IsUnique(); + + b.ToTable("ScheduledNotificationTracking", "Notifications"); + }); + + 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("EmailType") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + 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("Recipient") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("RetryAttempts") + .HasColumnType("integer"); + + b.Property("ScheduledNotificationId") + .HasColumnType("uuid"); + + 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("CancelledBy") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("CancelledBy"); + + b.Property("CancelledById") + .HasColumnType("uuid") + .HasColumnName("CancelledById"); + + b.Property("CancelledOn") + .HasColumnType("timestamp without time zone") + .HasColumnName("CancelledOn"); + + 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("CorrelationId"); + + b.HasIndex("CreationTime"); + + b.HasIndex("FsbNotificationEmailLogId"); + + b.HasIndex("ReferenceNumber") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.HasIndex("Status"); + + b.HasIndex("TenantId", "CreationTime") + .HasFilter("\"IsDeleted\" = false"); + + 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("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.ApplicantAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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("ApplicationLinks") + .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.Applications.AuditHistory", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.FundingHistory", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.IssueTracking", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ReportsHistory", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId"); + }); + + 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.ApplicantComment", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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.GrantManager.Notifications.ScheduledNotificationTracking", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Notifications.ScheduledNotification", null) + .WithMany() + .HasForeignKey("ScheduledNotificationId") + .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); + + 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("ApplicationLinks"); + + 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/20260630211933_AddCancellationToPaymentRequests.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630211933_AddCancellationToPaymentRequests.cs new file mode 100644 index 0000000000..f9388a1860 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20260630211933_AddCancellationToPaymentRequests.cs @@ -0,0 +1,57 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + /// + public partial class AddCancellationToPaymentRequests : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CancelledBy", + schema: "Payments", + table: "PaymentRequests", + type: "character varying(256)", + maxLength: 256, + nullable: true); + + migrationBuilder.AddColumn( + name: "CancelledById", + schema: "Payments", + table: "PaymentRequests", + type: "uuid", + nullable: true); + + migrationBuilder.AddColumn( + name: "CancelledOn", + schema: "Payments", + table: "PaymentRequests", + type: "timestamp without time zone", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + migrationBuilder.DropColumn( + name: "CancelledBy", + schema: "Payments", + table: "PaymentRequests"); + + migrationBuilder.DropColumn( + name: "CancelledById", + schema: "Payments", + table: "PaymentRequests"); + + migrationBuilder.DropColumn( + name: "CancelledOn", + schema: "Payments", + table: "PaymentRequests"); + } + } +} 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 f9b2cabbe5..84e61474fa 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 @@ -3047,6 +3047,142 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Intakes", (string)null); }); + modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotification", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationStatus") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ApplicationStatusId") + .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("DateField") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EmailTemplateId") + .HasColumnType("uuid"); + + b.Property("EventType") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormId") + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + 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("RecipientCategory") + .HasColumnType("text"); + + b.Property("RecipientIdentifier") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TriggerDetail") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("TriggerType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ScheduledNotifications", "Notifications"); + }); + + modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotificationTracking", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("DateField") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NotificationSentDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ScheduledNotificationId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("CreationTime"); + + b.HasIndex("ScheduledNotificationId"); + + b.HasIndex("ApplicationId", "ScheduledNotificationId", "DateField") + .IsUnique(); + + b.ToTable("ScheduledNotificationTracking", "Notifications"); + }); + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroup", b => { b.Property("Id") @@ -3249,6 +3385,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("RetryAttempts") .HasColumnType("integer"); + b.Property("ScheduledNotificationId") + .HasColumnType("uuid"); + b.Property("SendOnDateTime") .HasColumnType("timestamp without time zone"); @@ -3358,102 +3497,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("EmailLogAttachments", "Notifications"); }); - modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotification", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .IsRequired() - .HasMaxLength(40) - .HasColumnType("character varying(40)") - .HasColumnName("ConcurrencyStamp"); - - b.Property("ExtraProperties") - .IsRequired() - .HasColumnType("text") - .HasColumnName("ExtraProperties"); - - b.Property("FormId") - .HasColumnType("uuid"); - - b.Property("EmailTemplateId") - .HasColumnType("uuid"); - - b.Property("TriggerType") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("text"); - - b.Property("TriggerDetail") - .HasMaxLength(1000) - .HasColumnType("text"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("EventType") - .HasMaxLength(128) - .HasColumnType("text"); - - b.Property("ApplicationStatusId") - .HasColumnType("uuid"); - - b.Property("ApplicationStatus") - .HasMaxLength(128) - .HasColumnType("text"); - - b.Property("RecipientCategory") - .HasColumnType("text"); - - b.Property("RecipientIdentifier") - .HasColumnType("text"); - - b.Property("DateField") - .HasMaxLength(128) - .HasColumnType("text"); - - b.Property("TenantId") - .HasColumnType("uuid") - .HasColumnName("TenantId"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("boolean") - .HasDefaultValue(false) - .HasColumnName("IsDeleted"); - - b.Property("DeleterId") - .HasColumnType("uuid") - .HasColumnName("DeleterId"); - - b.Property("DeletionTime") - .HasColumnType("timestamp without time zone") - .HasColumnName("DeletionTime"); - - 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.HasKey("Id"); - - b.ToTable("ScheduledNotifications", "Notifications"); - }); - modelBuilder.Entity("Unity.Notifications.Templates.EmailTemplate", b => { b.Property("Id") @@ -4069,6 +4112,19 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("BatchNumber") .HasColumnType("numeric"); + b.Property("CancelledBy") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("CancelledBy"); + + b.Property("CancelledById") + .HasColumnType("uuid") + .HasColumnName("CancelledById"); + + b.Property("CancelledOn") + .HasColumnType("timestamp without time zone") + .HasColumnName("CancelledOn"); + b.Property("CasHttpStatusCode") .HasColumnType("integer"); @@ -4978,6 +5034,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("Unity.GrantManager.Notifications.ScheduledNotificationTracking", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Notifications.ScheduledNotification", null) + .WithMany() + .HasForeignKey("ScheduledNotificationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroupUser", b => { b.HasOne("Unity.Notifications.EmailGroups.EmailGroup", null) From 4bd020c493aa99a24cd026c698340b5ce7fd29ea Mon Sep 17 00:00:00 2001 From: Jacob Smith Date: Tue, 30 Jun 2026 15:54:30 -0700 Subject: [PATCH 24/61] AB#32307 queue concrete AI stages for all generation --- .../Generation/AIGenerationAppService.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Generation/AIGenerationAppService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Generation/AIGenerationAppService.cs index d814818c6b..dd243aa279 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Generation/AIGenerationAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Generation/AIGenerationAppService.cs @@ -18,7 +18,6 @@ namespace Unity.AI.Generation; [Route("api/app/ai/generation")] public class AIGenerationAppService( - IAttachmentSummaryService attachmentSummaryService, IApplicationAIGenerationQueue aiGenerationQueue, AIFeatureGuard featureGuard, ICurrentTenant currentTenant) @@ -37,12 +36,15 @@ await featureGuard.EnsureEnabledAsync( return []; } - var summaries = await attachmentSummaryService.GenerateForApplicationAsync( + await aiGenerationQueue.QueueAttachmentSummaryAsync( input.ApplicationId, + currentTenant.Id, input.PromptVersion, input.AttachmentIds); - return summaries.Select(_ => new AttachmentSummaryResultDto { Completed = true }).ToList(); + return input.AttachmentIds + .Select(_ => new AttachmentSummaryResultDto { Completed = false }) + .ToList(); } [Authorize(AIPermissions.Analysis.GenerateApplicationAnalysis)] @@ -79,8 +81,10 @@ public virtual async Task GenerateContentAsync(Guid await featureGuard.EnsureEnabledAsync(AIFeatures.ApplicationAnalysis, AILocalizationKeys.GenerateAllDisabled); await featureGuard.EnsureEnabledAsync(AIFeatures.Scoring, AILocalizationKeys.GenerateAllDisabled); - await aiGenerationQueue.QueueAllAIStagesAsync(applicationId, currentTenant.Id, promptVersion); + await aiGenerationQueue.QueueAttachmentSummaryAsync(applicationId, currentTenant.Id, promptVersion); + await aiGenerationQueue.QueueApplicationAnalysisAsync(applicationId, currentTenant.Id, promptVersion); + await aiGenerationQueue.QueueApplicationScoringAsync(applicationId, currentTenant.Id, promptVersion); - return new ApplicationContentResultDto { Completed = true }; + return new ApplicationContentResultDto { Completed = false }; } } From 07b51db02db19bfaddc501c0af8c0ba7135b0641 Mon Sep 17 00:00:00 2001 From: David Bright Date: Thu, 2 Jul 2026 11:29:16 -0700 Subject: [PATCH 25/61] #AB33663 - Removed category as a default column --- .../src/Unity.Payments.Web/Pages/PaymentRequests/Index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js index f07a18be78..e85137544c 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js @@ -28,8 +28,7 @@ $(function () { 'l2ApprovalDate', 'l3ApprovalDate', 'CASResponse', - 'accountCodingDisplay', - 'category' + 'accountCodingDisplay' ]; let initialLoad = true; let isRestoringState = false; From c0cdd7f04b5d146c4df43e00459a59d7fe0f0f21 Mon Sep 17 00:00:00 2001 From: JamesPasta Date: Thu, 2 Jul 2026 13:29:56 -0700 Subject: [PATCH 26/61] features/AB#33374-NotificationsRolePermissions --- .../Pages/ApplicationForms/Mapping.cshtml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml index 502039731d..c27118c845 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml @@ -4,6 +4,7 @@ @using Volo.Abp.AspNetCore.Mvc.UI.Layout; @using Unity.GrantManager.Web.Pages.ApplicationForms; @using Unity.GrantManager.Permissions; +@using Unity.Notifications.Permissions; @using Volo.Abp.Authorization.Permissions; @using Unity.GrantManager.Web.Views.Shared.Components.Notifications; @@ -76,7 +77,11 @@ } + + @if (await PermissionChecker.IsGrantedAsync(NotificationsPermissions.Email.NotificationsTab)) + { + } @if (Model?.ShowAITab == true) {